You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[seam → cloud] Census the cloud repo for readers that treat a positions[] / sys_user_position NAME as authority (the out-of-reach half of #15972's first deliverable) #17045
Named reader: the repo:cloud execution seat (#6026), at its queue-scan step. Seam card: the work lands in objectstack-ai/cloud, which is not reachable from the filing session, so per the cross-repo rule it lives here with repo:cloud. Filed by the director seat (summon #20, session_01Tep4AYXZvyBA7jsvne5KZV, os-bill) executing the maintainer's ruling A on #15972 (decision batch #105 item 4, 2026-09-09T04:3xZ; ruling comment on #15972: "Ruling recorded — A: refuse the built-in identity names on sys_position.name at write time").
What is asked (one deliverable, measurement only)
A census over the cloud repository of every reader that turns a name found in positions[] (session payload) or in a sys_user_position row into authority — positions.includes(<built-in name>), string comparison against platform_admin / org_owner / org_admin, or any equivalent — instead of reading the capability rung. The objectstack/objectui half of this census is delivered in the PR that implements #15972 (its ## 验收备注); this card is the cloud half.
Every hit is listed with file:line and classified: reads the rung (fine) · reads the name as authority (defect) · other.
Each name-as-authority hit becomes its own card in cloud (dedupe first), linked back here; zero hits closes this card with the control on record.
⛔ No fix is written from this card; it is a measurement.
Why it exists
#15972 (ruled A): the platform will refuse built-in identity names on sys_position.name at write time, so the row can no longer be minted. Readers outside this repository that already trust such a name would keep a live hole until the write-side refusal is deployed everywhere and existing rows are reported; the card's first deliverable was this fleet census, and the cloud repo was out of reach for every seat that has held it (#15972 body §"Out-of-repo readers are unmeasured"; 5555586823).
Governing text: ADR-0068 (built-in identity roles); packages/coreresolve-authz-context.ts:1125-1129 (「Read the RUNG — never positions.includes(...)」); #15136 / PR #15948 ruling A.
Blocked-by: none — this census does not depend on the platform-side refusal landing.
Census delivered: zero readers in cloud turn a built-in identity NAME into authority. Controls fire on the identical shape, so the zero is a reading.
repo:cloud execution seat, R38, session session_01TAUTP6Yky8QWoHUAPDKNJQ, 2026-09-15T15:59Z. Measured on cloud cb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8 — the REST tip of main (2026-09-15T15:12:03Z), ⛔ not the container clone's self-report, which is shallow. Measurement only, per acceptance item 4: ⛔ no fix is written from this card.
Acceptance 1 — the grep set, and the control that fires
#
pattern
hits
T1
positions\??\.(includes|has)\(
2
T2
(===|==|!==|!=) against 'platform_admin'|'org_owner'|'org_admin', either side
Firing controls — same instrument, same corpus, same command shape, differing only in the literal:
T2's shape with a role-ish literal that does occur → 6 files, e.g. organization-lifecycle.ts:871role === 'owner' || role === 'admin', environment-lifecycle.ts:556, package-install.ts:1092.
T3's shape exactly, with 'owner'/'admin' → environment-authz.ts:97roles.includes('owner') || roles.includes('admin').
⇒ The instrument demonstrably matches this construction in this repository; only the three built-in identity literals are absent. That is what makes T2/T3's zeros readings rather than a silent miss — the condition #15972 set ("with a control that fires").
not a read — a comment, and a conforming one: it records that "objectstack#15948 forbids positions.includes('platform_admin') outright, because the array now sits on an axis a tenant admin can write via sys_user_position and could therefore mint the name", and that user.isPlatformAdmin "is derived from the posture rung — never from this array"
T4 — the 5 non-test sys_user_position readers, none of them name-as-authority
file
classification
security-enterprise/src/hierarchy/resolver.ts
reads the anchor, fine — takes sys_user_position.business_unit_id, an id, never the name
security-enterprise/src/plugin.ts:238
other — the table name appears in a STRUCTURAL cache-invalidation set
service-ai/src/routes/agent-access-lint.ts
other — reads live assignments to validate an agent's declared entries; a lint, not a gate
T5 — the 7 non-test files naming one of the three, classified
False positives of the grep, worth recording so the next census does not re-derive them:control-plane-org-scope-plugin.ts:774,836 and environment-crud.ts:753,783 match only because the audit event namescross_org_admin_read / cross_org_admin_write contain the substring org_admin. ⛔ Not identity names at all.
Comments / vocabulary, not reads:env-owner-admin-grant.ts:44, ai-routes.ts:46, agent-access-lint.ts:58,72.
A name, but not an authority read:app-cloud-admin/src/admin.app.ts:31 — name: 'platform_admin' is the App's own name, kept "for stable identity (deep links, RBAC, approver refs)". Its actual gate is ADMIN_ONLY = ctx.user.isPlatformAdmin == true — the rung.
An approver reference:marketplace-review-flow.ts:50 — approvers: [{ type: 'user', value: 'platform_admin' }]. A routing target for review, ⛔ not a decision taken on a caller's positions. ⚠️ Recorded because type: 'user' carrying an identity name rather than a user id is unusual enough that a later reader will stop on it; it grants nothing.
⭐ And the positive half of the census, which matters as much as the zero: cloud's own isPlatformAdmin (service-cloud/src/platform-admin.ts:68-73) resolves through sys_user_permission_set → sys_permission_set, a permission-set link — ⛔ never a position name. That is the correct pattern, in the one place in this repository that answers "is this caller a platform admin".
Acceptance 3 — zero name-as-authority hits ⇒ no cards filed, and this card closes
⚠️One reading gets a paragraph rather than a card, stated so the judgement is auditable rather than silent.evaluateAgentAccess (service-ai/src/routes/agent-access.ts) is the only place in cloud where a position name carries any authority:
const held = new Set([...(user.permissions ?? []), ...(user.positions ?? [])]) at L75, so an agent.permissions entry — documented as "Required permission-set capabilities" — is satisfiable by a position name;
positions.has(entry) at L89 matches agent.access entries against position names, which is ADR-0057 D4's intended ACL-by-position mechanism, and agent-access-lint.ts exists to validate those entries against live assignments.
⛔ It is not in this card's class, for a reason the card's own scope draws: it hard-codes no built-in identity name. The names it compares are supplied by an agent author, and the function's own docblock records the union as deliberate — before protocol 17 removed the roles alias, "a permissions entry naming one could not be satisfied". Ruling A closes the mint side for the built-in names at write time, which is exactly the exposure that would make this reading dangerous. ⇒ Nothing here is owed by #15972's first deliverable; it is recorded so the next census does not re-open it as a find, and so that anyone widening ruling A knows where cloud would feel it.
⛔ No fix, no card, no re-grade. Closing per acceptance item 3 with the controls on record, pm:queue stripped in the same stroke.
Activity
hotlong commentedon Sep 15, 2026
Census delivered: zero readers in cloud turn a built-in identity NAME into authority. Controls fire on the identical shape, so the zero is a reading.
repo:cloudexecution seat, R38, sessionsession_01TAUTP6Yky8QWoHUAPDKNJQ, 2026-09-15T15:59Z. Measured on cloudcb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8— the REST tip ofmain(2026-09-15T15:12:03Z), ⛔ not the container clone's self-report, which is shallow. Measurement only, per acceptance item 4: ⛔ no fix is written from this card.Acceptance 1 — the grep set, and the control that fires
positions\??\.(includes|has)\((===|==|!==|!=)against'platform_admin'|'org_owner'|'org_admin', either side\.(includes|has)\(\s*['"](platform_admin|org_owner|org_admin)['"]sys_user_positionFiring controls — same instrument, same corpus, same command shape, differing only in the literal:
organization-lifecycle.ts:871role === 'owner' || role === 'admin',environment-lifecycle.ts:556,package-install.ts:1092.'owner'/'admin'→environment-authz.ts:97roles.includes('owner') || roles.includes('admin').⇒ The instrument demonstrably matches this construction in this repository; only the three built-in identity literals are absent. That is what makes T2/T3's zeros readings rather than a silent miss — the condition #15972 set ("with a control that fires").
Acceptance 2 — every hit, classified
T1 — 2 hits
file:linepackages/service-ai/src/routes/agent-access.ts:89—allowList.some((entry) => entry === user.userId || positions.has(entry))apps/objectos-ee/test/signup-membership-policy.e2e.test.ts:585positions.includes('platform_admin')outright, because the array now sits on an axis a tenant admin can write viasys_user_positionand could therefore mint the name", and thatuser.isPlatformAdmin"is derived from the posture rung — never from this array"T4 — the 5 non-test
sys_user_positionreaders, none of them name-as-authoritysecurity-enterprise/src/hierarchy/resolver.tssys_user_position.business_unit_id, an id, never the namesecurity-enterprise/src/plugin.ts:238STRUCTURALcache-invalidation setservice-ai/src/routes/agent-access-lint.tsservice-ai/src/pending-action-actor.ts:155service-cloud/src/migrations/rbac-orgless-claim.ts:14T5 — the 7 non-test files naming one of the three, classified
control-plane-org-scope-plugin.ts:774,836andenvironment-crud.ts:753,783match only because the audit event namescross_org_admin_read/cross_org_admin_writecontain the substringorg_admin. ⛔ Not identity names at all.env-owner-admin-grant.ts:44,ai-routes.ts:46,agent-access-lint.ts:58,72.app-cloud-admin/src/admin.app.ts:31—name: 'platform_admin'is the App's own name, kept "for stable identity (deep links, RBAC, approver refs)". Its actual gate isADMIN_ONLY = ctx.user.isPlatformAdmin == true— the rung.marketplace-review-flow.ts:50—approvers: [{ type: 'user', value: 'platform_admin' }]. A routing target for review, ⛔ not a decision taken on a caller's positions.type: 'user'carrying an identity name rather than a user id is unusual enough that a later reader will stop on it; it grants nothing.⭐ And the positive half of the census, which matters as much as the zero: cloud's own
isPlatformAdmin(service-cloud/src/platform-admin.ts:68-73) resolves throughsys_user_permission_set→sys_permission_set, a permission-set link — ⛔ never a position name. That is the correct pattern, in the one place in this repository that answers "is this caller a platform admin".Acceptance 3 — zero name-as-authority hits ⇒ no cards filed, and this card closes
evaluateAgentAccess(service-ai/src/routes/agent-access.ts) is the only place in cloud where a position name carries any authority:const held = new Set([...(user.permissions ?? []), ...(user.positions ?? [])])at L75, so anagent.permissionsentry — documented as "Required permission-set capabilities" — is satisfiable by a position name;positions.has(entry)at L89 matchesagent.accessentries against position names, which is ADR-0057 D4's intended ACL-by-position mechanism, andagent-access-lint.tsexists to validate those entries against live assignments.⛔ It is not in this card's class, for a reason the card's own scope draws: it hard-codes no built-in identity name. The names it compares are supplied by an agent author, and the function's own docblock records the union as deliberate — before protocol 17 removed the
rolesalias, "apermissionsentry naming one could not be satisfied". Ruling A closes the mint side for the built-in names at write time, which is exactly the exposure that would make this reading dangerous. ⇒ Nothing here is owed by #15972's first deliverable; it is recorded so the next census does not re-open it as a find, and so that anyone widening ruling A knows where cloud would feel it.⛔ No fix, no card, no re-grade. Closing per acceptance item 3 with the controls on record,
pm:queuestripped in the same stroke.Generated by Claude Code