Skip to content

rest/runtime: under a wall, the /meta history, audit and package-commits doors admit setup.access, which organization admins hold, so an organization admin reads the environment-wide authoring trail of any item #23546

Closed

Description

@objectstack-fleet

Ruled: 6190477105 · letter A1 (the fork of 6187280122; /diff included; batch #349 record 6190660761) · 2026-10-15T11:13Z
Ruled: 6187280122 · letter A · 2026-10-15T07:54Z

Filing gate: (c) an observation from a contract round, read from source and not run end to end.

Filed by domain:engine seat 1 · marchtian · session session_01Rerax7QTjKMPCUZxQUtPFR. ⛔ Not a claim.

What the dev read (at PR #23469's head 3bde441f81)

  • The trail doors. /meta/:type/:name/history and /meta/:type/:name/audit admit a caller holding system, studio.access, setup.access or manage_metadata, through mayReadPendingDrafts → isObjectSchemaMaskExempt. /packages/:id/commits admits studio.access or setup.access.
  • Organization admins hold setup.access. plugin-security's PLATFORM_ADMIN_ONLY_CAPABILITIES excludes it on purpose.
  • So, under a wall (an organization posture), an organization admin reads the environment-wide history and audit of any metadata item, and every package's commit trail, through these doors.
  • This predates S2. Environment metadata is shared under ADR-0131 D6, so the item bodies themselves are not organization-private. The trail adds authors, timestamps and superseded bodies.
  • S2 does not change these doors. For the data door on the same three tables (sys_metadata_audit, _history, _commit), S2 adds requiredPermissions: studio.access, which refuses an organization admin there. After S2, the data door and the /meta doors therefore disagree on who reads the trail.

Wanted

  1. Measure first, on a real kernel under a wall, as an organization admin with setup.access and without studio.access: GET history, audit and package commits for an item that admin did not author. Record what each door answers.
  2. Then the lane proposes one of:
    • (a) narrow the three doors to studio.access / manage_metadata (or system), matching S2's data-door gate. This narrows a door organization admins use today, so it is a Clause-② narrowing and goes to the maintainer as a decision before it is built.
    • (b) keep the doors as they are, and state in the security docs, in writing, that organization admins read the environment's authoring trail. S2's data-door gate then needs its rationale restated.

Order: after S2 (PR #23469) is on main, so the data-door gate it compares against exists.

Dedupe

The words setup.access organization admin meta history audit commits trail door studio.access mayReadPendingDrafts isObjectSchemaMaskExempt match #23429 (S2's E2 gate) only, and that card does not change these doors.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch (engine seat 2, in-session) item 1 · letter A · maintainer 「23546 同意 A」 2026-10-15T07:53Z

    domain:engine seat 2 · os-steve · session session_01ADzJtzYTLUfgrRZHxkagkX. The seat presented this card in the director-decision format on the maintainer's 「从业务的角度给我具体解释,现在就和我讨论决策。」 and 「按照总监决裁的格式。」 (both in this session). The maintainer's 「23546 同意 A」 takes the recommendation. The analysis is recorded below, because a ruling exists only on its card.

    Premises (re-run at main 7c6b7f4a35)

    • P1. The data door is narrowed in every posture. sys_metadata_audit, _history and _commit carry requiredPermissions: ['studio.access'] (packages/metadata-core/src/objects/sys-metadata-audit.object.ts:237; the other two read the same).
      • Re-check: git grep -n "requiredPermissions" origin/main -- 'packages/metadata-core/src/objects/sys-metadata-*.object.ts'
    • P2. The three /meta doors admit setup.access.
      • /meta/:type/:name/history and /audit admit through mayReadPendingDrafts → isObjectSchemaMaskExempt (system, studio.access, setup.access, manage_metadata) at packages/runtime/src/domains/meta.ts:227.
      • /packages/:id/commits admits studio.access or setup.access (packages/runtime/src/domains/packages.ts:328).
      • Re-check: git grep -n "mayReadPendingDrafts" origin/main -- packages/runtime/src
    • P3. Organization admins hold setup.access. See packages/plugins/plugin-security/src/objects/default-permission-sets.ts:487. PLATFORM_ADMIN_ONLY_CAPABILITIES (security-plugin.ts:203) lists manage_metadata, manage_platform_settings, studio.access and manage_users, and leaves setup.access out on purpose.
      • Re-check: git grep -n -A6 "PLATFORM_ADMIN_ONLY_CAPABILITIES *=" origin/main -- packages/plugins/plugin-security/src
    • P4. New reading: organization admins author no environment metadata. ADR-0131 C5 retired organization-scoped writes of the five tier-A types (docs/adr/0131-total-organization-ownership-no-null-organization-id.md:947). The trail an organization admin reads is therefore not a trail of their own work.
    • Not run end to end. The card's Wanted 1 measurement on a real kernel under a wall has not been done yet; the letter binds it as the first step.

    Options presented

    • A. Drop setup.access from the three doors, so they follow the data door's rule. Organization admins get 403 from these doors; platform operators and metadata authors are unaffected. Workload: one PR, estimated 200–400 lines. Precedent: fix(metadata-protocol): a first draft of a sealed package-shipped item names the edit remedy; a refused first-write pin's 409 states its assertion #23565 (3b289052a6, one admission change with tests, 6 files +314/−19). Clause-②: yes.
    • B. Keep the doors, state in the security docs that organization admins read the environment's authoring trail, and restate S2's data-door rationale. Workload: tens of doc lines. No precedent.
    • C. Narrow only under a wall and keep single unchanged. Workload: A plus a posture branch and tests in both postures. No precedent.

    四维分析

    • ① 项目长远合理性。 两年后应该是:一份数据只有一条读取规则,从哪个入口读都一样。主流平台(ServiceNow 的 update set 与变更记录、Atlassian Cloud、Shopify)都不向租户管理员公开平台侧的运维改动。A 去掉一扇比规则更宽的门;B 把两个入口的不一致写成永久契约;C 新增一个部署形态特例。
    • ② 实际业务拉动。 ADR-0131 C5 之后组织管理员改不了环境配置,读改动记录没有对应的工作。已知真实读者是 Studio 里的元数据作者(持 studio.access),A 不影响他们。唯一测不到的读者是 objectui 的 Setup 应用会不会给组织管理员显示历史页。
    • ③ 防 AI 犯错。 现在:AI 生成的多组织应用里,配置改过之后旧版本内容留在历史里,任何客户组织的管理员都能读到,没人报错,属于静默泄露。A 之后,越权读取得到明确的 403;一条规则只有一种写法,AI 抄不到宽松的门。
    • ④ 创业阶段不扩散。 A 删一条访问路径,不新增能力也不新增门禁;B 把"组织管理员可读"声明成永久义务;C 多一条长期维护的分支。
    os-decision-facets
    ① 项目长远合理性:A 缩小特例(三个接口并入数据入口已有的同一条规则);B 把两个入口的不一致写成永久契约;C 新增部署形态特例。
    ② 实际业务拉动:C5 之后组织管理员改不了环境配置,读改动记录没有对应工作;唯一未测的读者是 objectui Setup。零实测拉动,默认收紧。
    ③ 防 AI 犯错:A 让越权读取变成明确的 403;B 维持静默可读,旧版本内容对每个客户管理员可见;一条规则一种写法,AI 抄不到宽松的门。
    ④ 创业阶段不扩散:A 删一条访问路径、不加门禁;B 把"组织管理员可读"声明成永久义务;C 多一条长期维护的分支。
    

    Prior rulings read: setup.access organization admin narrowing studio.access trail → 9 hits; ADR-0131 D6/D7 (the #22107 precedent, cited at sys-metadata-audit.object.ts:224), ADR-0131 C5; #10009 (a same-shape finding where org admins were wider than the platform-admin posture, closed completed; its landing not re-read line by line); thread: 0.

    Recommendation: A, fallback B. A costs about 5–10× B; A was still recommended because, on ① alone, B makes the inconsistency a permanent contract. Self-check: 只看①选 A;②③④ 是否翻转:否.

    What the ruling binds (letter A)

    1. Measure first (the card's Wanted 1). On a real kernel under a wall, act as an organization admin holding setup.access and not studio.access. GET the history, the audit and the package commits for an item that admin did not author. Record each door's answer in the PR body.
    2. Premise. All three doors answer that admin with the trail, and no objectui surface reads these doors as an organization admin.
      • If the measurement shows otherwise (a door already refuses, or a real organization-admin consumer exists), report a fork back to this card.
      • ⛔ Do not build A anyway, and do not quietly fall back to B.
    3. Narrow. Remove setup.access from the admission of /meta/:type/:name/history, /meta/:type/:name/audit and /packages/:id/commits.
      • What stays admitted: system, studio.access and, on history and audit only, manage_metadata. Every one is platform-scoped (P3).
      • ⛔ No door gains a capability it does not admit today.
    4. Split the admission. The trail doors stop sharing mayReadPendingDrafts, which also answers the draft switches (_drafts, ?preview=draft, ?state=draft). Those draft switches are out of this ruling; their admission does not change.
    5. Tests, under a wall unless noted:
      • an organization admin (setup.access, no studio.access) gets 403 on all three doors;
      • a studio.access author gets 200 on all three;
      • in the single posture, a manage_metadata author gets 200 on history and audit.
    6. Same-PR corrections. The comments on the three trail objects (packages/metadata-core/src/objects/sys-metadata-{audit,history,commit}.object.ts, about lines 224–236 of the audit file) say the doors admit setup.access. That becomes false, so they are corrected in the same PR.
    7. Changeset. It states the Clause-② narrowing: organization admins no longer read the environment authoring trail through these doors. Rationale: ADR-0131 D7 and S2's data-door gate (dd29bbe60d).

    Workload of the letter: one PR, estimated 200–400 lines (precedent #23565, 3b289052a6, +314/−19). Clause-②: yes. It touches no governed path. The lane is set by triage (see below).

    Execution

    • Body. In this act, the body's first line gets a Ruled: line.
    • Not dispatched by this seat. The maintainer's scope for this seat is 「你只处理你已经派发完成的开发收尾。新开发不要派。」. The card stays pm:queue for the lane that takes it.
    • pm:retriage added in this act, asking triage to set the lane before dispatch:
      • The fix lands in packages/runtime/src/domains/meta.ts and packages/runtime/src/domains/packages.ts. By the anchor table that is domain:cli; the card carries domain:engine.
      • Item 6's comment correction rides in packages/metadata-core (domain:engine).
      • Please re-anchor the domain and name the carrying lane for this one cross-domain PR. Execution seats do not change domain:*.

    Generated by Claude Code

  2. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 15, 2026
  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Retriage answered: p1 (protocol class) · lane domain:cli · target:v18 kept · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T08:59Z

    Read fresh: ruling 6187280122 (letter A, the maintainer's 「23546 同意 A」, 07:53Z) and what it binds.

    • Grade p1. Letter A removes setup.access from three REST doors' admission (/meta/:type/:name/history, /audit, /packages/:id/commits). An organization admin goes from 200 to 403.
      • That is a REST door narrowing (filing-gate.md 〈定级判据〉: 「REST/数据门收窄亦算」), so it is p1 + the major's target: in any lane.
    • Lane domain:cli. The landing is packages/runtime/src/domains/meta.ts (mayReadPendingDrafts split) and packages/runtime/src/domains/packages.ts, and packages/runtime is domain:cli by the lane table.
      • The ruling's item 6 adds comment-only corrections in packages/metadata-core/src/objects/sys-metadata-{audit,history,commit}.object.ts (domain:engine). They ride the same PR on the cross-lane exception path, and the claim names them in its file surface.
    • Order: none found open on meta.ts / packages.ts. No open PR touches those files (this read).
    • The ruling's item 1 (measure first) and item 2's fork stay binding as written.
    • pm:retriage leaves.
  4. added
    priority:p1High: required for production / M2
    and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 15, 2026
  5. 4 remaining items

  6. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量)· director seat (summon #42, session_01AKVFxqmRLqktJspVXwPE9A), read as batch #349 item 1, 2026-10-15T10:08Z

    Ruling-ref: 6187280122 (letter A, the maintainer's 「23546 同意 A」 at 2026-10-15T07:53Z). This comment presents item 2's fork, which the dev reported (6189071639) and the claim holder confirmed (6189110905): premise half 2 is false. The ruling's letter is not re-opened; its own clause sends the fork back to this card (「report a fork back to this card … ⛔ Do not build A anyway, and do not quietly fall back to B」), so the card is in the box for the fork alone. The claim (6188504102, domain:cli seat 2) stays.

    Premises re-run in this act, objectstack origin/main c5dd7fce30, objectui origin/main cf430cd10e:

    • P1 holds: the three trail objects carry requiredPermissions: ['studio.access'] (sys-metadata-audit.object.ts:237, sys-metadata-history.object.ts:193, sys-metadata-commit.object.ts:155).
    • P2's location was wrong and the dev's correction holds: /history, /audit and /diff are served by RestServer alone, through refuseNonAuthoringCaller (packages/rest/src/rest-server.ts:1878) over its mayReadPendingDrafts (:1819, which is isObjectSchemaMaskExempt), call sites :7583 (history), :7719 (audit), :8191 (diff). runtime/src/domains/meta.ts:227 governs the dispatcher's draft switches only; rest-route-ledger.ts:264 records that the dispatcher 404s /history. /packages/:id/commits admits studio.access or setup.access through requireReadCapability (runtime/src/domains/packages.ts:350), shared with GET /packages, /packages/:id and /export.
    • P3 holds: organization admins hold setup.access (default-permission-sets.ts:487).
    • Premise half 2 of the ruling is FALSE, read from source: the Setup app requires setup.access (packages/platform-objects/src/apps/setup.app.ts:47); plugin-security's Setup entries Positions / Capabilities / Permission Sets open /apps/setup/metadata/TYPE?scope=environment (security-plugin.ts:1545-1547); in objectui the History and Audit buttons of ResourceEditPage.tsx are gated by !createMode only (:2307-2328) and open HistoryPanel (client.history, ResourceHistoryPage.tsx:162) and AuditPanel (client.audit, AuditPanel.tsx:133); PermissionMatrixEditor.tsx:1180 has the same History button; the walled posture is read-only, not hidden (useWalledCatalogReadOnly, catalog-scope.ts:136). /commits has no organization-admin consumer (preview/commitHistory.ts:197 for the unpublished-app bar; Studio's packages-io).
    • The measurement table (6189071639: 200 on all four doors for the organization admin under isolated and group) was not re-run by this seat.
    • Prior rulings (check-prior-rulings --card 23546): 282 hits; ADR-0131 D3 / D7 / D13 and ADR-0106 D2 / D4 / D5 are term matches, none chooses between the fork's options; D7 is the data-door precedent the ruling already cites; thread: 1 ruling (6187280122).

    Facets (the dev's open_questions Q1 reading): ① agree — one read rule per table at every door, and the UI mirrors the server's rule instead of offering an action it refuses · ② agree — the consumer is incidental (objectui#7611 reused the Studio editor for Setup's catalog pages); under a wall an organization admin authors nothing in the catalog (ADR-0131 C5 / D3), and the measured trail held only the operator's entries · ③ agree — A2 ships two buttons that always answer 403, a dead control; B keeps the silent cross-organization read · ④ agree — A1 removes one access path and adds one UI condition, no new gate; B declares a permanent obligation.

    Recommend A1 with /diff included (Q3); fallback A2 (the server narrowing alone, the objectui companion filed as a follow-up card). Not B: it writes the inconsistency into the docs. 口径 for the executor, binding with the letter:

    1. Server (objectstack, domain:cli on the cross-lane path triage set at 6188395735): the trail doors get their own admission — system, studio.access, manage_metadata — inside refuseNonAuthoringCaller, so history, audit AND diff change together; mayReadPendingDrafts and the draft switches (:5961, :6189, :6646, :6654) do not move. /packages/:id/commits drops setup.access for the commits door only; GET /packages, /packages/:id and /export keep their cohort.
    2. objectui companion (domain:ui, one card): the History and Audit controls (both ResourceEditPage buttons; PermissionMatrixEditor's History button and its embedded sheet) render only for a caller the doors admit (system / studio.access / manage_metadata); the walled read-only posture is otherwise unchanged. It lands first or in the same window; the objectstack PR bumps .objectui-sha after it. Pins: an organization admin under a wall sees neither control; a studio.access author sees both.
    3. Q2 = (i), as the seat ruled: the claim extends to rest-server.ts, to refuseNonAuthoringCaller and its three call sites only; the hold on [maintainer] refactor(rest): split packages/rest/src/rest-server.ts (13,701 lines, 70 commits in 30 days) along its register*Endpoints seams, one move-only slice per PR, /meta after #22877 stage 2 #23050 stands.
    4. Pins (ruling item 5 plus diff): under a wall, an organization admin (setup.access, no studio.access) gets 403 on history, audit, diff and commits; a studio.access author gets 200 on all four; in single, a manage_metadata author gets 200 on history, audit and diff.
    5. Ruling items 6 (the metadata-core comments) and 7 (the changeset's Clause-② narrowing) are unchanged; the changeset also names /diff.

    Workload (added): A1 = objectstack 1 PR (rest-server.ts helper and three call sites, packages.ts commits door, three metadata-core comments, pins, changeset; estimated 200–400 lines, precedent #23565 3b289052a6 +314/−19) + objectui 1 PR (two files and pins; estimated 50–150 lines; no size precedent re-read) + one pin bump. A2 = the objectstack PR alone. B = tens of doc lines.

    自检:只看①选 A1(含 /diff);②③④ 是否翻转:否。

  7. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling on the item-2 fork: Q1 → A1, Q3 → include /diff · maintainer, in this seat's session · 2026-10-15T10:59Z

    domain:cli seat 2 (#22648) · sunhaolin · session_01Q9PZ5Pzqcus4woVvTZwWNU. The fork is 6189110905; the readings are 6189071639.

    The maintainer's answers, verbatim (to the seat's two questions in session chat):

    • Q1 (how the narrowing proceeds): 「A1 收窄 + 改 objectui (推荐)」
    • Q3 (whether /diff narrows too): 「一起收窄 /diff (推荐)」

    What this binds (it amends ruling 6187280122; items 4-7 stand):

    1. The doors narrowed: GET /meta/:type/:name/history, /audit, /diff and GET /packages/:id/commits. Each stops admitting setup.access.
      • What stays: system and studio.access on all four, plus manage_metadata on history, audit and diff.
      • ⛔ No door gains a capability it does not admit today.
    2. Where:
      • RestServer's refuseNonAuthoringCaller (packages/rest/src/rest-server.ts:1879) and its three call sites (:7584, :7720, :8192). The draft switches keep mayReadPendingDrafts unchanged (ruling item 4).
      • /packages/:id/commits in packages/runtime/src/domains/packages.ts.
      • The comment corrections in the three sys-metadata-*.object.ts files (item 6).
    3. The objectui companion (A1): Setup's catalog item editors show History and Audit only to a caller these doors admit. Filed in objectui as a follow-up card with Blocked-by: this card. The pin bump follows the objectui PR, through the repo's bump script.
    4. Grade: Clause-②: yes (narrowing). The changeset is minor, fix(rest,runtime)!:, with the ADR-0087 marker and a BREAKING line for each door. This seat writes a TIER_DEFAULT record before the queue.

    State: needs-user-decision is answered. The card goes back to pm:dispatched under this seat's amended claim, which follows this comment.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 18 (#23546, amended after the maintainer's ruling 6190477105: /meta/:type/:name/history, /audit and /diff and /packages/:id/commits stop admitting setup.access, so an organization admin gets 403 there; the objectui History/Audit companion is a follow-up card) · 2026-10-15T11:01Z
    Session: session_01Q9PZ5Pzqcus4woVvTZwWNU
    Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23546-trail-doors-setup-access
    Worktree: objectstack-issue-23546
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    Scope: batch 3, by 「并发恢复3」. This amends claim 6188504102: same card, same branch. The readings round is done (6189071639), the fork is ruled (6190477105), and this is the build.
    File surface (read on origin/main; stop on a breach and explain it in the report):

    • packages/rest/src/rest-server.ts (newly in surface, by the fork's Q2, decided by this seat in 6189110905):
      • refuseNonAuthoringCaller (:1878) and its three call sites (:7583 history, :7719 audit, :8191 diff);
      • the trail doors get their own admission (system, studio.access, and manage_metadata on all three).
      • ⛔ mayReadPendingDrafts (:1820) and every draft-switch call site keep their admission.
    • packages/runtime/src/domains/packages.ts: /packages/:id/commits admission only (system, studio.access). ⛔ GET /packages, /packages/:id and /export keep theirs.
    • packages/metadata-core/src/objects/sys-metadata-{audit,history,commit}.object.ts (domain:engine, comment-only; declared 6188566208 / 6188576321).
    • Every whole-file reader of rest-server.ts that counts the touched call sites (for example the meta-draft-read-door census), updated only as the split requires.
    • Pins and one .changeset/23546-*.md.
    • ⛔ Hold-offs:
    • Clause-②: yes (narrowing). The changeset is minor, fix(rest,runtime)!:, with the ADR-0087 marker and BREAKING lines.
    • This seat writes a TIER_DEFAULT record before the queue.
      Clause-②: yes (narrowing)
      Responsibility: the trail doors' admission in packages/rest RestServer and packages/runtime (this lane) | the trail objects' data-door gate in metadata-core (domain:engine), comments only; objectui's Setup History/Audit buttons (follow-up card in objectui) | every organization admin under a wall
      Thread-read: 6190477105
      Serial constraints cleared:
    • No open PR touches rest-server.ts, domains/packages.ts or the three object files (read at this act).
    • Seat 1's [maintainer] refactor(rest): split packages/rest/src/rest-server.ts (13,701 lines, 70 commits in 30 days) along its register*Endpoints seams, one move-only slice per PR, /meta after #22877 stage 2 #23050 slice 3 is claimed, but its PR is not open yet. It moves a disjoint region, and it widens the same whole-file readers (6190013305), so whichever lands second merges main.

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #349 item 1 · letter A1 (with /diff) · maintainer 「A1 含 /diff (推荐)」 2026-10-15T11:09Z

    Director seat, summon #42, session_01AKVFxqmRLqktJspVXwPE9A. This is the batch record for item 2's fork of ruling 6187280122, presented in this seat's session on the delta 6189611291; the maintainer's answer takes the recommendation.

    The ruling of record is 6190477105 (the domain:cli seat 2, in its own session, recorded first at 2026-10-15T10:59Z on the maintainer's 「A1 收窄 + 改 objectui (推荐)」 and 「一起收窄 /diff (推荐)」). The letters agree; this comment amends nothing in it and adds two execution readings where it is silent:

    1. The objectui companion is objectui#12475 (filed by that seat). It lands first or in the same window as the objectstack PR; the pin bump follows it. Its pins: an organization admin under a wall sees neither the History nor the Audit control on the Setup catalog editors (ResourceEditPage, PermissionMatrixEditor); a studio.access author sees both.
    2. The server pins (6187280122 item 5, with /diff): under a wall an organization admin (setup.access, no studio.access) gets 403 on history, audit, diff and commits; a studio.access author gets 200 on all four; in single a manage_metadata author gets 200 on history, audit and diff.

    Workload of the letter: objectstack 1 PR (estimated 200–400 lines, precedent #23565 +314/−19) + objectui#12475 (estimated 50–150 lines) + one pin bump.

    State: already pm:dispatched under the seat's amended claim; nothing moves in this act. The body's first line gets a Ruled: line naming 6190477105.

  10. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23546,
      "status": "done",
      "branch": "claude/issue-23546-trail-doors-setup-access",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23674",
      "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent; the dispatching seat's session, per claim 6190506257)",
      "premise_still_valid": true,
      "summary": "Built ruling 6187280122 as amended by 6190477105. GET /meta/:type/:name/history, /audit and /diff (RestServer) now admit through their own module-private predicate, mayReadAuthoringTrail (isSystem, studio.access, manage_metadata), which refuseNonAuthoringCaller asks. mayReadPendingDrafts and every draft-switch call site are untouched. GET /packages/:id/commits (runtime) has its own gate, requireCommitTrailReadCapability (isSystem, studio.access); GET /packages, /packages/:id and /export keep requireReadCapability. No door gains a capability. The three sys-metadata-* object comments are corrected (comment-only). The system-context census page gains row 8b for the two new isSystem reads. Two client-sdk.mdx code comments that this change made false are corrected. The changeset is minor for rest and runtime, fix(rest,runtime)!:, ADR-0087 not-required (no-migration-prescription), with a BREAKING line per door and objectui#12475 named. Measured on the readings' rig before and after: under isolated and group, the organization admin goes 200 to 403 on all four doors, and the draft switches and the other package reads answer it byte-for-byte as before. Head bf1192ef1f; draft PR #23674 with assignee sunhaolin.",
      "door_caller_table": {
        "rig": "@objectstack/verify bootStack(@objectstack/example-crm, multiTenant posture-only), OS_TENANCY_POSTURE=isolated|group, not degraded; before = base 286eb9ef32, after = 8264557efc (implementation commit); isolated and group identical",
        "walled": [
          "history: org admin (setup.access, setup.write, manage_org_users, manage_mailboxes) 200 -> 403 FORBIDDEN · org owner + studio.access 200 -> 200 · org owner + manage_metadata 200 -> 200 · operator 200 -> 200",
          "audit: org admin 200 -> 403 FORBIDDEN · studio 200 -> 200 · manage_metadata 200 -> 200 · operator 200 -> 200",
          "diff: org admin 200 -> 403 FORBIDDEN · studio 200 -> 200 · manage_metadata 200 -> 200 · operator 200 -> 200",
          "commits: org admin 200 -> 403 PERMISSION_DENIED · studio 200 -> 200 · org owner + manage_metadata (no studio.access) 200 -> 403 PERMISSION_DENIED (it held commits through setup.access) · operator 200 -> 200",
          "_drafts, ?state=draft, ?preview=draft, GET /meta/:type?preview=draft: every caller 200 -> 200, same body (control)",
          "GET /packages, /packages/:id, /packages/:id/export: every caller 200 -> 200 (control)"
        ],
        "single": [
          "history, audit, diff: member (no capability) 403 -> 403 · studio.access 200 -> 200 · manage_metadata 200 -> 200 · setup.access only: admitted -> 403 FORBIDDEN (the before reading is the ablation's red) · operator 200 -> 200",
          "commits: member 403 -> 403 · studio.access 200 -> 200 · manage_metadata 403 -> 403 · setup.access only: admitted -> 403 PERMISSION_DENIED · operator 200 -> 200"
        ]
      },
      "tests": "Final union at HEAD bf1192ef1f under os-verify-lock slot issue-23546 (VERDICT command-exit 0): pnpm --filter @objectstack/rest test -> 285 files passed, 5848 passed / 326 skipped; pnpm --filter @objectstack/runtime test -> 388 files passed, 5862 passed / 19 skipped; pnpm --filter @objectstack/metadata-core test -> 18 files, 728 passed; pnpm --filter @objectstack/dogfood exec vitest run --project isolated --maxWorkers=2 test/wall-authoring-trail-doors.dogfood.test.ts -> 31 passed (42 s, three boots); typecheck rest, runtime, metadata-core and dogfood -> exit 0 each (script names echoed). ABLATION (scripts/ablation-replace.mjs, nested WRAP with restore traps plus a shell trap, under the lock): 'setup.access' put back on AUTHORING_TRAIL_READ_CAPABILITIES (rest) and on the commits gate (runtime), with the marker ablation-23546. Landed on disk: anchor 1 -> 0; blobs f534523de931 -> 192df9a7b2f2 and 93319cef1c91 -> 0787e7b413f8. Then turbo build rest+runtime and ablation-dist-preflight (marker present in both dist/, exit 0). Red exactly on the narrowing pins: rest 4 failed / 15 passed, runtime 4 failed / 75 passed, dogfood 12 failed / 19 passed; every control stayed green; direction red as expected. Restore: blobs == HEAD and git diff HEAD empty; restore-leg rebuild; ablation-dist-preflight --absent exit 0 for both.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at bf1192ef1f: 97 commands, all run locally, every exit captured before any pipe, all 0. --ran with exit codes: '97 derived famil(ies) accounted for — 97 run, 0 NOT-MEASURED (a DERIVED zero — all 97 recorded an exit code and none of them is 3)'. The first pass at 00a11d97a3 had one real red, check-system-context-census (two new isSystem reads with no page row), fixed by row 8b in bf1192ef1f; on that pass check:skill-examples and check:dual-build-cjs-loads were exit 3 PREREQUISITE NOT MET (unbuilt dist outside the diff), and both were exit 0 on the second pass. pnpm lint at bf1192ef1f, under the lock: exit 0, no findings. check-adr-0087-registration: '[BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)' ✓; check-changeset-no-major: 'no major bump' ✓, its level axis NOT APPLICABLE locally (no pull_request payload; CI reads it from the PR). CI on PR #23674, one read at report time: 24 check-runs, 'No other open PR may claim the same issue' success, 'Packed-tarball smoke (opt-in)' skipped, the other 22 in_progress (Lint ·, Type Check ·, Governed Surface Queue Guard, Check Changeset, among others). Not waited on, per the role file.",
      "mcp_calls": "0",
      "api_writes": "3 REST writes in 2 relay strokes, each stroke one POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create, request fw-20261015T122334Z-ae910f, run 38734284307 -> POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/23674/assignees (sunhaolin); read back 12402 bytes sent, 12402 stored, identical. (2) this os-dev-report -> POST /repos/objectstack-ai/objectstack/issues/23546/comments via scripts/pm/post-stamped.mjs. git push x5 (not REST). label-write: zero (none named, skip-changeset does not apply). No claim posted; the card assignee was not written.",
      "files_changed": [
        ".changeset/23546-trail-doors-setup-access.md",
        "content/docs/api/client-sdk.mdx",
        "content/docs/permissions/system-context.mdx",
        "packages/metadata-core/src/objects/sys-metadata-audit.object.ts",
        "packages/metadata-core/src/objects/sys-metadata-commit.object.ts",
        "packages/metadata-core/src/objects/sys-metadata-history.object.ts",
        "packages/qa/dogfood/test/wall-authoring-trail-doors.dogfood.test.ts",
        "packages/rest/src/meta-history-diff-authoring-door.test.ts",
        "packages/rest/src/rest-server.ts",
        "packages/runtime/src/domains/packages-capability-gate.test.ts",
        "packages/runtime/src/domains/packages.ts"
      ],
      "deviations": [
        "content/docs/api/client-sdk.mdx is outside the claim's file surface. Its two code comments said setup.access admits diffItem and getAudit, which this change made false; the dev role file has published text the change falsifies corrected in the same PR.",
        "content/docs/permissions/system-context.mdx (row 8b) is the whole-file census reader the claim allows 'only as the split requires'. It is named here because the claim's example named a different reader (the meta-draft-read-door census, which this diff does not move).",
        "The changeset's per-door BREAKING lines say 'was 200 ... now 403' rather than a literal FROM/TO label. The content is the order's FROM-200 / TO-403; the ADR-0087 gate accepted the not-required (no-migration-prescription) disposition.",
        "pnpm lint ran locally because the order asks for it; the role file calls repo-wide scans CI-owned, not forbidden. Noted as a conflict, not an open question.",
        "origin/main moved five commits after the last merge (00a11d97a3); none touches a file in this diff, and it was not merged again before the PR. CI's merge ref covers the joint state.",
        "A scratch measurement file (packages/qa/dogfood/test/zz-measure-23546.dogfood.test.ts) took the before/after table. It was deleted before any commit and never pushed.",
        "Cleanup after this report: rm -rf ../objectstack-issue-23546/node_modules, then git worktree remove (no --force)."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed. packages/metadata-core/src/object-schema-fls.ts OBJECT_SCHEMA_READ_ONLY_EXEMPT_CAPABILITIES docblock still calls itself 'the /packages read cohort', which now holds for three of the four /packages reads; observation only, outside the file surface (PR Acceptance notes).",
        "carrier: none · noted, not filed. Mechanism hypothesis (a) falsified as stated: meta-draft-read-door-census.test.ts counts draft switches only and stayed green unedited; the reader the split needed was scripts/check-system-context-census.mjs (PR Acceptance notes)."
      ]
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23546,
      "status": "done",
      "round": "patch round 1 (REWORK, seat review 6192050253 on PR #23674)",
      "branch": "claude/issue-23546-trail-doors-setup-access",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23674",
      "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent; the dispatching seat's session, per claim 6190506257)",
      "premise_still_valid": true,
      "summary": "Item 1 fixed in .changeset/23546-trail-doors-setup-access.md alone, new head 82dae4a76e (one commit on top of bf1192ef1f, fast-forward push, no force). The BREAKING list now names each door's refused set. History, audit and diff refuse a caller holding setup.access and neither studio.access nor manage_metadata. The commits bullet names its own set: setup.access without studio.access, with or without manage_metadata, which never admitted this door; a manage_metadata holder beside setup.access was admitted only through setup.access. It names W3's shape (a walled organization owner granted manage_metadata inside its organization), which keeps history, audit and diff and loses commits. The 'not affected' sentence now says which metadata authors: studio.access holders (all four doors) and manage_metadata holders (history, audit and diff; commits never admitted it). 'What changes for you' adds that a manage_metadata holder without studio.access who read commits through setup.access needs studio.access. The ADR-0087 marker's reason text says the same. No code, test or docs change.",
      "pr_body": "Not edited (the dev writes it once). No line in it quotes the changeset's scoping sentence or the 'not affected' sentence; its table and Acceptance notes already name the manage_metadata cell. Stale only in that its Tests and Gates sections cite head bf1192ef1f. The code and tests at 82dae4a76e are byte-identical to bf1192ef1f, and the changeset gates were re-read on 82dae4a76e (below). If the seat wants the body to name the new head, the one-line change is: in Gates, 'at bf1192ef1f' becomes 'at bf1192ef1f (changeset gates re-read at 82dae4a76e)'.",
      "tests": "No code or test changed in this round (git diff bf1192ef1f..82dae4a76e touches .changeset/23546-trail-doors-setup-access.md only), so the round-0 union at bf1192ef1f stands: rest test 5848 passed / 326 skipped, runtime test 5862 passed / 19 skipped, metadata-core test 728 passed, dogfood wall-authoring-trail-doors 31 passed, four typechecks exit 0, and the ablation red-then-restored. Not re-run.",
      "gates": "On head 82dae4a76e, each exit captured before any pipe: node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; --base origin/main :: exit 0, '✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition. .changeset/23546-trail-doors-setup-access.md [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)'. node scripts/check-changeset-no-major.mjs --self-test :: exit 0; --base origin/main :: exit 0, '✓ This diff introduces no major bump', with the level axis NOT APPLICABLE without a payload; and --base origin/main --event (this PR's own pull_request object, read by GET /pulls/23674) :: exit 0, '✓ LEVEL AXIS: this PR declares clause-② yes (narrowing), and no package whose published source ... it moves is graded patch'. Also exit 0: check-empty-changeset --base origin/main, check:changeset-gate-self-tests, check:pm-changeset-deadline-census, check:objectui-changeset, check-changeset-fixed, check:nul-bytes, check:issue-citations. CI before the push, on bf1192ef1f: 26 success, 5 skipped, 8 in_progress (Test Core 1-6/6, Type Check · consumer gates, Type Check · workspace), none red, so there was nothing to fold in. After the push, 'Type Check · consumer gates' on bf1192ef1f reads cancelled (superseded by the new head, not a failure). On 82dae4a76e, one read: 11 check-runs, 10 in_progress, 1 skipped. Not waited on.",
      "mcp_calls": "0",
      "api_writes": "1 REST write in 1 relay stroke (one POST /repos/objectstack-ai/objectstack/dispatches): this patch-round os-dev-report -> POST /repos/objectstack-ai/objectstack/issues/23546/comments via scripts/pm/post-stamped.mjs. git push x1 (82dae4a76e, fast-forward; not REST). No PR body edit, no label write, no claim, no card-assignee write. Reads: the review comment 6192050253, PR #23674 (once, for the --event payload), the check-runs of bf1192ef1f and 82dae4a76e.",
      "files_changed": [
        ".changeset/23546-trail-doors-setup-access.md"
      ],
      "deviations": [
        "The worktree ../objectstack-issue-23546 had been removed after round 0. It was re-created on the branch at bf1192ef1f (git worktree add, no reset, no force), and pnpm install --frozen-lockfile was run. It is removed again after this report (rm -rf node_modules, then git worktree remove, no --force)."
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23546,
      "status": "done",
      "round": "patch round 2 (merge origin/main; diagnose the red Test Core (1/6) on 82dae4a76e)",
      "branch": "claude/issue-23546-trail-doors-setup-access",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23674",
      "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent; the dispatching seat's session, per claim 6190506257)",
      "premise_still_valid": true,
      "summary": "Merged origin/main 8d1fb1fb2d (#23050 slice 3, registerApprovalsEndpoints moved to approvals-routes.ts) into the branch: merge commit 6256d1f001. Clean, no conflict, no os-regen deferral, and no change forced, so the changeset, code, tests and docs are untouched. This PR's delta against main is still the same 11 files (+582/-53); mayReadAuthoringTrail and requireCommitTrailReadCapability are intact. Pushed fast-forward 82dae4a76e..6256d1f001, no force. driver-memory: PASS locally on the merged tree, 71 files / 1732 tests. Its inputs are byte-identical to origin/main 8d1fb1fb2d: git diff origin/main HEAD -- packages/drivers/driver-memory packages/core packages/spec packages/types is empty, and those are its only workspace dependencies. So a run on plain main reads the same inputs, and it was not run separately. The CI failure's assertion stays unknown (see gates). CI on the merged head 6256d1f001: all 41 check-runs completed, 36 success and 5 skipped, Test Core (1/6) through (6/6) and the Test Core roster included. Not this PR's defect on the evidence here; nothing filed.",
      "driver_memory_diagnosis": {
        "ci_red": "Test Core (1/6), check-run 116424168994, run 38735497549, head 82dae4a76e: step #12 'Run this shard's tests'; annotation: packages/drivers/driver-memory 'pnpm run test exited (1)'.",
        "job_log": "NOT MEASURED: GET /actions/jobs/116424168994/logs redirects to productionresultssa0.blob.core.windows.net, and this session's proxy refused it ('Request was cancelled'). node scripts/pm/ci-failure.mjs --run 38735497549 exited 2 (undetermined): no file-anchored assertion, the job log not retrieved.",
        "local_merged_tree": "pnpm --filter @objectstack/driver-memory test at 6256d1f001, after turbo build of its closure, under the lock: 'Test Files 71 passed (71) · Tests 1732 passed (1732)', exit 0.",
        "inputs_vs_main": "git diff --stat origin/main(8d1fb1fb2d) HEAD -- packages/drivers/driver-memory packages/core packages/spec packages/types: empty (exit 0). driver-memory's workspace dependencies are exactly core, spec and types.",
        "ci_merged_head": "Test Core (1/6) on 6256d1f001: completed success (check-run 116438643393). Whether that shard ran driver-memory is not read: the shard's package list is in the job log.",
        "reading": "Not reproducible locally. Identical inputs to main, and green on the merged head's CI. Most likely a transient failure on the 82dae4a76e run; the assertion is unknown, so that is a reading, not a finding."
      },
      "tests": "At 6256d1f001, under os-verify-lock slot issue-23546 (VERDICT command-exit 0, held 1731 s on a shared box), after turbo build --filter='@objectstack/dogfood^...' --filter='@objectstack/driver-memory^...' (65 tasks successful, 7 cached): driver-memory test 71 files / 1732 passed; rest pin src/meta-history-diff-authoring-door.test.ts 19 passed; runtime pin src/domains/packages-capability-gate.test.ts 79 passed; pnpm --filter @objectstack/rest test 285 files, 5858 passed / 326 skipped (the merge added 10 tests); pnpm --filter @objectstack/runtime test 388 files, 5862 passed / 19 skipped; dogfood wall-authoring-trail-doors 31 passed; rest and runtime typecheck exit 0. No ablation this round: no tested behaviour changed.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 6256d1f001: the same 97 commands as round 0. All run, every exit captured before any pipe. The first pass had 95 at exit 0 and 2 at exit 3 PREREQUISITE NOT MET (check:skill-examples and check:dual-build-cjs-loads: no dist/ in this fresh worktree for client-react, studio, embedder-openai, knowledge-memory, knowledge-ragflow, organizations, service-cluster-redis and service-knowledge). After building those 8 under the lock (59 tasks, all cache hits), both re-ran at exit 0: '263 prose examples type-check across 3 surface(s)' and 'check:dual-build-cjs-loads — 110 published require entry point(s) across 68 package(s) load'. --ran with exit codes: '97 derived famil(ies) accounted for — 97 run, 0 NOT-MEASURED (a DERIVED zero — all 97 recorded an exit code and none of them is 3)'. The list includes check-system-context-census, check-adr-0087-registration and check-changeset-no-major, all exit 0; the rest suite includes the census readers that now read the registrar list, green. CI on 6256d1f001, one read: 41 check-runs, 36 success, 5 skipped, none red or running (Build Core, Build Docs, Dogfood Regression Gate, Lint & Repo Gates, TypeScript Type Check, Test Core and all 6 shards, Governed Surface Queue Guard success). origin/main has since moved to 09dd537193 (2 commits, 16 files, none in this diff); not merged.",
      "mcp_calls": "0",
      "api_writes": "1 REST write in 1 relay stroke (one POST /repos/objectstack-ai/objectstack/dispatches): this patch-round os-dev-report -> POST /repos/objectstack-ai/objectstack/issues/23546/comments via scripts/pm/post-stamped.mjs. git push x1 (6256d1f001, fast-forward; not REST). No PR body edit, no label write, no claim, no card-assignee write. Reads: check-run 116424168994 and its annotations, GET /actions/jobs/116424168994/logs (refused at the blob host), ci-failure.mjs --run 38735497549, and the check-runs of 6256d1f001.",
      "files_changed": [],
      "merge": "6256d1f001 = merge of origin/main 8d1fb1fb2d into 82dae4a76e; 85 files from main; this PR's delta against main unchanged (11 files).",
      "deviations": [
        "The worktree ../objectstack-issue-23546 was re-created on the branch at 82dae4a76e (git worktree add, no reset, no force) and pnpm install --frozen-lockfile was run. It is removed after this report (rm -rf node_modules, then git worktree remove, no --force).",
        "The merge was pushed before the test run, not after (AGENTS.md: push before every minutes-long step). It is the same fast-forward push the order asks for; nothing was committed after it.",
        "driver-memory was not run on a separate plain-origin/main worktree. Its inputs are proven byte-identical by an empty git diff over its package and its three dependencies, so the run would read the same tree."
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  13. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23674 comment 6193622523 · TIER_DEFAULT record 6193599695 · domain:cli seat 2 · 2026-10-15T13:47Z


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23674 → c2635881e0 · 2026-10-15T14:55Z

    domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU · holder of the amended claim 6190506257, released by this landing. Review: REWORK 6192050253, then this seat's TIER_DEFAULT record 6193599695 (PASS) and ACCEPT 6193622523 on the PR (pointer on this card).

    Reading Value
    PR merged: true, merged_at 2026-10-15T14:54Z, through the merge queue (added_to_merge_queue 2026-10-15T13:52Z; ejected 2026-10-15T14:21Z by #23685's timeout, not this PR's; re-queued once 2026-10-15T14:27Z)
    Queue branch gh-readonly-queue/main/pr-23674-* absent (git ls-remote, 0 refs)
    origin/main c2635881e0 is an ancestor; one parent (361a1c46d3); 11 files, +582 / −53, as reviewed at 6256d1f001
    Closing keywords in the landed commit Fixes #23546 only
    Lane reconciliation 13 open domain:cli cards (read at this stamp), #23546 no longer among them

    State change: #23546 closed completed by the merge; pm:dispatched removed in this act. GET /meta/:type/:name/history, /audit, /diff and GET /packages/:id/commits no longer admit setup.access, in every posture, as rulings 6187280122 and 6190477105 bound.

    Cross-repo (ruling 6190477105 item 3):


    Generated by Claude Code

  15. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Pin follow-up named in the landed note 6195083853: filed as #23691 (the console pin to a commit carrying objectstack-ai/objectui#12475), for triage to route · domain:cli seat 2 · 2026-10-15T14:58Z


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions