Repository navigation
C3 #15204 stages 7a ∥ 7b → 8-post, build ahead: delete the permission-set projection and the position write-through that stage 8 leaves unreferenced, then the post-stage-8 catalog gates and residue #22975
Copy link
Copy link
Closed
Labels
domain:enginepriority:p1High: required for production / M2High: required for production / M2target:v18
Description
Part of #15204
Handed out of the #15194 epic subtree to the domain:engine lane. The epic PM (session_01Rerax7QTjKMPCUZxQUtPFR, marchtian) did this at the maintainer's request in its session on 2026-10-12. The maintainer wants the remaining work spread across accounts (「我是想把工作量分到别的账户」), and their tasks are priority:p1. This card is the lane's claim surface. Build ahead now. No PR opens before stage 8 (S8) is on main.
Where this sits
- Landing order (refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204, seat answer 6119027520): feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 → T1 test(plugin-security): retire the declared-permission seeder suites (#15204 stage 6b-2, T1) #22897 → T2 test(dogfood): fixtures read permission sets from the security catalog (#15204 stage 6b-2, T2) #22898 → D feat(plugin-security)!: no seeder or materializer writes a sys_permission_set row; the boot seeds no row for a declared set (#15204 stage 6b-2) #22900 → S8-T test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 → S8 → 7a ∥ 7b → 8-post → C7b (feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211). - S8 is not yet a PR. It lives on branch
claude/issue-15204-s8-catalog-objects@dbae752f6e, which ismain+ Dfcaedfdaa1+ one commit. S8:- unregisters
sys_position,sys_permission_set,sys_position_permission_setandsys_capability; - unwires the projector, both write-throughs and the position backfill (E1).
- unregisters
- After S8,
permission-set-projection.ts,position-write-through.tsand thewritesExecutedByDataDoorWeakSet are unreferenced. See the stage-8 report 6118994290, carrier "7a/7b". - Build on a local integration tree:
main+ D (feat(plugin-security)!: no seeder or materializer writes a sys_permission_set row; the boot seeds no row for a declared set (#15204 stage 6b-2) #22900 head) + S8-T (test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962) + the S8 branch. Use the report's merge recipe (d_merge_recipe_for_s8tin 6118994290). - ⛔ No stacked PRs. Each PR opens from
mainonce S8 has merged.
Scope
Read these first: the stage-8 tier record 6110777865, the rulings it cites, and #15204's body.
7a (about 2.45k lines of code):
- Delete
permission-set-projection.ts(1,763 lines),seed-name-lookup.ts(506) andseed-refusal-sink.ts(83), with their index exports. - Re-home
tryFind, and keep the liveness proof. - E5 → A: move the row→definition mapping (
permissionSetBodyFromRowand the legacy mapping) onto core's pure mappers. Those mappers are built in feat(core): pure row-to-definition mappers for the ADR-0131 upgrade ceremony (C7b build-ahead, PR 1 of 2) #22959 (C7b build-ahead, this same lane). Then delete the copies. - Whole-file test deletions (about 3.3k lines, for example
permission-set-projection.test.tsat 1,884) go in a test PR ahead of it.
7b (about 2.2k):
- Delete
position-write-through.ts. catalog-reference-report.tsimportsPOSITION_OBJECTandmetadataDoorAcceptsPositionNamefrom it. Either re-home those two, or drop them together with the position categories that stage 8 hands to C7. This obligation is recorded in 6095755866.- E5: move the position row→definition mapping (
position-environment-backfill.ts) onto core's mapper. - The Q (a) refusal (
PositionNameConflictError) goes with the module (Q4 → A).
8-post (about 0.75k):
- In
security-plugin.ts, remove the four catalog gates (assertPackageManagedWriteGate,assertSystemRowWriteGate,assertCuratedCapabilityNameGate,assertAudienceAnchorBindingGate) and their call sites. - Remove
SYSTEM_ROW_PROVENANCEand the delegated-admin catalog cases. - Do the comment sweep. The 8-post carriers in 6118994290:
- the descriptions that cite the retired objects in
sys-user-position.object.ts,sys-invitation.object.tsandsys-audience-binding-suggestion.object.ts; - the describes in spec
protocol.zod.ts,eval-user.zod.tsandposition.zod.ts; - the
PLATFORM_CAPABILITY_NAMESdrift, which S8 deliberately left alone; scripts/tenant-audit-census.mjs: its twoUNTYPED_RECEIVERSrows go with the deleted modules.
- the descriptions that cite the retired objects in
Every PR:
- at most 3,000 changed lines, or it is Tier H;
- a
Clause-②line perscripts/pm/clause2-line.mjs; - a contract review if
packages/specis touched (8-post's describe edits are).
Coordination
- The epic seat lands D, S8-T and S8, and posts "S8 on
main" on this card. - The S8 branch is held by the epic seat's stage-8 developer (
session_01MGoWgeE8rhsrig77V4oUZn). Questions about that tree go on this card; the epic seat relays them. - ⛔ Do not touch files that D, S8-T or S8 own until they land.
- Done when 7a, 7b and 8-post are merged. The epic seat then updates refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204's stage list.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
domain:enginepriority:p1High: required for production / M2High: required for production / M2target:v18
Activity
objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 · 2026-10-12T08:14Z · build-ahead for all three slices (7a with its test PR, 7b, 8-post); no PR opens before S8 is on
mainSession:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22975-c3-7a7b-8post(the build-ahead integration branch). The PR branches are cut frommainafter S8 lands:claude/issue-22975-7a-tests,claude/issue-22975-7a,claude/issue-22975-7bandclaude/issue-22975-8post. The PR that closes the card gets a freshClaim:naming its branch.Worktree:
objectstack-issue-22975(in the cloud session's own checkout)Domain:
domain:engine(handed out by the #15194 epic PM at the maintainer's request: 「我是想把工作量分到别的账户」)Seat:
domain:engine#2(seat post #20966)File surface (read on
origin/main246edf5b39and the card; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.packages/plugins/plugin-security/src/(adomain:servicespackage):permission-set-projection.ts,seed-name-lookup.ts,seed-refusal-sink.ts,position-write-through.tsandposition-environment-backfill.ts, with their index exports and tests;SYSTEM_ROW_PROVENANCEinsecurity-plugin.ts;catalog-reference-report.tsreads.packages/core/src/security/: read only. It supplies the mappers from PR feat(core): pure row-to-definition mappers for the ADR-0131 upgrade ceremony (C7b build-ahead, PR 1 of 2) #22959 (C7b build-ahead:os migrate organization-ownership --applyand E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937 PR 1), which is ACCEPTed and not yet onmain. The build-ahead tree carries that branch. ⛔ No edit to those files.packages/platform-objects(sys-user-position,sys-invitation,sys-audience-binding-suggestion);packages/spec(protocol.zod.ts,eval-user.zod.ts,position.zod.ts): describe text only,domain:spec, with a contract review owed;PLATFORM_CAPABILITY_NAMESdrift;UNTYPED_RECEIVERSrows inscripts/tenant-audit-census.mjs.claude/issue-15204-s8-catalog-objects) own until they land. ⛔ No stacked PRs. Each PR is at most 3,000 changed lines.Container & model:
XL(about 5.4k lines of code in three slices plus about 3.3k lines of test deletions),mode:cloud(a one-shotcreate_session),model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: no (narrowing)
plugin-securityexports whose only callers S8 removes. That narrows a published surface and widens nothing, so each of those PRs carries its ADR-0087 disposition (runtime-export-retired, the categoryda9c2bf2f2added). 8-post removes gates on objects S8 unregistered and edits describe text. Each PR declares its own line perscripts/pm/clause2-line.mjs. Contract reviews are owed for the narrowing PRs and for 8-post'spackages/specdescribes.Responsibility: n/a — not a defect card (an execution card under refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204, build ahead)Thread-read: none
Serial constraints cleared:
os migrate organization-ownership --applyand E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937 PR 1 (PR feat(core): pure row-to-definition mappers for the ADR-0131 upgrade ceremony (C7b build-ahead, PR 1 of 2) #22959, the core mappers) is this lane's and is ACCEPTed. 7a and 7b consume it, and their PRs open after it and S8 land.plugin-securityfiles (read at this stamp).singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 (6119027520): feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 → T1 test(plugin-security): retire the declared-permission seeder suites (#15204 stage 6b-2, T1) #22897 → T2 test(dogfood): fixtures read permission sets from the security catalog (#15204 stage 6b-2, T2) #22898 → D feat(plugin-security)!: no seeder or materializer writes a sys_permission_set row; the boot seeds no row for a declared set (#15204 stage 6b-2) #22900 → S8-T test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 → S8 → 7a ∥ 7b → 8-post → C7b (feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211).objectstack-fleet commentedon Oct 12, 2026
Note for the build-ahead ·
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T09:40Z. PR #22959 (core'spermissionSetDefinitionFromRow/positionDefinitionFromRow) is onmainase1deaefa8f. The integration tree no longer needs its branch. When the slices are re-cut frommainafter S8, the mappers are already there. Nothing else changes for this card.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 22975, "status": "done", "branch": "claude/issue-22975-c3-7a7b-8post (reference: integration tree plus every slice) · slices: claude/issue-22975-7a-tests-1, claude/issue-22975-7a-tests-2, claude/issue-22975-7a, claude/issue-22975-7b, claude/issue-22975-8post", "pr": null, "session": "session_01287UbjvrigpWwNfGDmdwpS", "premise_still_valid": true, "summary": "Built ahead on an integration tree (main 712361b7a8 + S8 dbae752f6e carrying D fcaedfdaa1 + S8-T 813dfed93e by the report's recipe + PR #22959's mappers 9e864370ea; head 06d8f97f01). 7a deletes permission-set-projection.ts, seed-name-lookup.ts and seed-refusal-sink.ts with their 7 index exports and 4 types, re-homes tryFind into its one live caller (packaged-permission-set-overlay-detection.ts) with a door-level pin, and drops the writesExecutedByDataDoor WeakSet and its stand-down; its test half is split in two PRs (2,182 and 1,922 lines). 7b deletes position-write-through.ts and position-environment-backfill.ts (both unreferenced after S8) and PositionNameConflictError, and drops the catalog reference report's two position-row categories instead of re-homing POSITION_OBJECT and metadataDoorAcceptsPositionName (measured: no composition registers sys_position after S8). 8-post removes the four catalog gates and SYSTEM_ROW_PROVENANCE, the delegated-admin binding and set-authoring cases, the now-dead PermissionSetNameConflictError and its error-ledger row, and sweeps the object descriptions and spec describes. No PR opened, per the card.", "integration_tree": { "head": "06d8f97f01c9c10bd3260bce9b28317ad1647090", "recipe": "main 712361b7a8 → merge S8 (claude/issue-15204-s8-catalog-objects @ dbae752f6e) → merge S8-T (#22962 @ 813dfed93e) per d_merge_recipe_for_s8t → merge claude/issue-22937-core-row-definition-mappers @ 9e864370ea → one integration-only commit", "conflicts_resolved": [ "security-plugin.ts (S8 vs main): main's #22895 (walled catalog data-door refusal, landed after S8 was cut) was kept; S8's removal of both write-throughs and the backfill import was taken.", "S8-T recipe applied as written: S8-T's deletions over D's edits; D's catalogPermissionSet reads kept in the four named dogfood files; S8-T's side in showcase-fls-read-mask-strip and showcase-permission-zoo; ensureLegacyPermissionSetRow deleted from catalog-permission-set.ts; the showcase-permission-seeding census guarded on getObject('sys_permission_set'); seedLegacyPlatformBucket import kept beside the testkit import.", "Integration-only commit 06d8f97f01: walled-catalog-data-door.test.ts (main's #22895) imports the four object files S8 deletes, so it failed to load on main+S8; it now reads them from S8-T's testkit (12/12 green). S8 owes its own resolution of this when it merges main; nothing in any slice depends on it." ], "baseline": "plugin-security on the integration tree: 185/185 files, 3,820 tests passed (45 skipped) after the integration-only fix (184/185 before it: the one load failure above); typecheck exit 0." }, "slices": [ { "slice": "7a tests, part 1", "branch": "claude/issue-22975-7a-tests-1", "head": "2c04b423f24015a86eea40d4c4036c86aad06467", "base": "integration tree 06d8f97f01", "line_budget": "5 files, +0/-2,182 = 2,182 changed (generated included: the three ledger JSONs)", "content": "Whole-file deletions: permission-set-projection.test.ts (1,886), permission-set-projection-heal-by-id.test.ts (272); engine-double-contract baseline and pinned rows and the objectql-double-limit row of the deleted doubles.", "gates": "62 derived, 62 run, all exit 0; --ran reconciles 62/62, 0 NOT-MEASURED, 0 UNRUN. plugin-security on this tree alone: 183/183 files, 3,740 tests passed; typecheck exit 0.", "clause2_line": "Clause-②: no", "changeset": "none: only test files (not in the package's files[]) and scripts/ ledgers change, so nothing publishes; skip-changeset at PR time." }, { "slice": "7a tests, part 2", "branch": "claude/issue-22975-7a-tests-2", "head": "d5480a41b4a084e5cc3b1909b9fc22744865e2de", "base": "integration tree 06d8f97f01 (parallel to part 1)", "line_budget": "8 files, +90/-1,832 = 1,922 changed (generated included)", "content": "Whole-file deletions: packaged-permission-set-restore-leg (470), permission-set-duplicate-name-refusal (279), seed-name-lookup-degradation-audible (246). packaged-permission-set-lock.test.ts keeps the #21789 classifier pins and the end-user copy pins, now driven through the metadata door's lock gate (the lock's one remaining door); its data-door pins go. engine-find-bare-array drops the two seed-name-lookup blocks. The overlay detection suite gains one pin of tryFind's contract at its door (a refused sys_metadata read is a reading of nothing, both type spellings asked under the shared page cap). Ledger rows of the deleted doubles go (--write for the pinned ledger).", "gates": "62 derived, 62 run, all exit 0; --ran reconciles 62/62, 0 NOT-MEASURED, 0 UNRUN. plugin-security on this tree alone: 182/182 files, 3,783 tests passed; typecheck exit 0.", "clause2_line": "Clause-②: no", "changeset": "none, same reason as part 1; skip-changeset at PR time." }, { "slice": "7a", "branch": "claude/issue-22975-7a", "head": "e6bc18a4a1172c9ebd3dd7388efc93f1b6410acd", "base": "integration tree + both test parts (merge b593c07da)", "line_budget": "source slice alone: 14 files, +81/-2,457 = 2,538 changed (generated included: tenant-audit census page and counts, liveness ledger)", "content": "Deletes permission-set-projection.ts (1,763), seed-name-lookup.ts (506), seed-refusal-sink.ts (83) and their index exports; tryFind re-homed as a private helper of packaged-permission-set-overlay-detection.ts, OverlayDetectionOptions.logger narrowed to the warn channel it uses; the writesExecutedByDataDoor WeakSet and its stand-down removed from security-plugin.ts; the projection's ADR anchor file, system-context row 11, tenant-audit UNTYPED_RECEIVERS row (census and prose figures regenerated, 225 to 222), the tabPermissions liveness pointer and the swallow-family positive control removed.", "gates": "119 derived; --ran reconciles 119: 118 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, exit 3, needs a full repo build), 0 UNRUN. Exit codes: 117 exit 0; check:platform-checklist exit 1 with 8 reds identical on a tree without 7a (symbols in metadata-protocol and service-storage this card does not touch; the same 8 S8's report lists as pre-existing). check:i18n, check:skill-examples and the teardown self-test first refused on unbuilt prerequisites (exit 3), then exit 0 after building them; check:type-check-debt timed out at 420s once, then exit 0. check:adr-0087-registration exit 0 (11 runtime-export-retired operands verified). plugin-security: 180/180 files, 3,703 tests passed; typecheck exit 0.", "clause2_line": "Clause-②: no (narrowing)", "changeset": ".changeset/15204-7a-permission-set-projection-retired.md — plugin-security minor (BREAKING on the v18 prerelease line), spec patch. ADR-0087 disposition: not-required (runtime-export-retired) naming the 11 operands permissionSetRowFields, permissionSetBodyFromRow, upsertEnvPermissionSet, projectPermissionMutation, registerPermissionSetProjection, createPermissionSetWriteThrough, reconcilePermissionSetProjection, PermissionSeedOutcome, ProjectionDeps, ProjectionReconcileOutcome, WriteThroughDeps. A consumer sees: each retired name with its FROM → TO line (permissionSetBodyFromRow → core's permissionSetDefinitionFromRow; upsertEnvPermissionSet → PUT /api/v1/meta/permission/:name; the rest 'delete the call'), and that the packaged-set lock and the overlay reading are unchanged." }, { "slice": "7b", "branch": "claude/issue-22975-7b", "head": "1bbcd057abaded9898995f1aad3472c85d0bb477", "base": "integration tree 06d8f97f01 (parallel to 7a)", "line_budget": "12 files, +73/-1,336 = 1,409 changed (generated included)", "content": "Deletes position-write-through.ts (583) and position-environment-backfill.ts (453); PositionNameConflictError goes with its module (Q4 → A); catalog-reference-report.ts drops its position categories 4 and 5 and the posture dependency they alone needed, with its suite trimmed to match; system-context row 11b and the tenant-audit row removed (census and prose regenerated).", "gates": "114 derived; --ran reconciles 114: 113 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, same reason), 0 UNRUN; all 113 exit 0 (check:i18n and check:skill-examples after building their prerequisites, check:type-check-debt on a longer budget). plugin-security: 185/185 files, 3,817 tests passed; typecheck exit 0.", "clause2_line": "Clause-②: no", "changeset": ".changeset/15204-7b-position-write-through-retired.md — plugin-security patch. No export of the package's entry changes (measured: neither module, nor the report, nor the error class is exported from src/index.ts, the one entry), so no ADR-0087 marker. A deployment sees: the boot reference report reads no sys_position row and loses its two position-row lines, which no composition could reach after stage 8; the Setup-create 409 of the deleted write-through goes with it." }, { "slice": "8-post", "branch": "claude/issue-22975-8post", "head": "00d10febd815d8baffd6e28becc91c6562664c25", "base": "7b + merge of 7a (24d088d984), because 8-post lands after both", "line_budget": "27 files, +81/-2,083 = 2,164 changed (generated included: two reference docs pages, two en translation bundles)", "content": "security-plugin.ts: the four gates and their call sites, SYSTEM_ROW_PROVENANCE, the package-position carve-out statics, the PLATFORM_CAPABILITY_NAMES import (the drift item) and two now-unused imports. delegated-admin-gate.ts: the sys_position_permission_set and sys_permission_set cases and their only helpers (checkStrictContainment, loadSetRowById, positionById, assignmentAnchorsOfPosition, BLAST_RADIUS_CAP), header updated. errors.ts: PermissionSetNameConflictError and its two constants (dead after 7a+7b), and the spec error-code ledger's plugin-security UNIQUE_VIOLATION row. Descriptions: sys_invitation.positions, sys_user_position (object and position field), sys_audience_binding_suggestion's set name, with es-ES/ja-JP/zh-CN values updated by hand and en regenerated. Spec: protocol.zod.ts projection/materializer describes, eval-user.zod.ts positions describe and TSDoc, position.zod.ts guidance prose and the activation TSDoc. Tests: the pins of the removed gates (49 cases in 6 files).", "gates": "116 derived; --ran reconciles 116: 115 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, same reason), 0 UNRUN; all 115 exit 0. spec check:generated exit 0 after --fix regenerated check:docs (the only stale artifact). Suites on this tree (which carries 7a and 7b): plugin-security 180/180 files, 3,610 tests; platform-objects 69/69 files, 1,078 tests; spec 706/706 files, 20,387 tests; typecheck exit 0 for all three.", "clause2_line": "Clause-②: no", "changeset": ".changeset/15204-8post-catalog-gates-retired.md — plugin-security, platform-objects, spec patch. A consumer sees: no export changes and no request answered differently; the removed gates guarded objects stage 8 unregistered; the delegated-admin gate governs the two assignment tables and sys_member; corrected description and describe text; the ledger drops one provenance row while UNIQUE_VIOLATION stays registered. A contract review is owed for the spec describe edits." } ], "tests": "All runs through os-verify-lock, exit codes read from its VERDICT line. Baseline (integration tree): plugin-security 185 files / 3,820 passed, typecheck 0. 7a-tests-1: 183 / 3,740, typecheck 0. 7a-tests-2: 182 / 3,783, typecheck 0. 7a: 180 / 3,703, typecheck 0. 7b: 185 / 3,817, typecheck 0. 8-post tree: plugin-security 180 / 3,610; platform-objects 69 / 1,078; spec 706 / 20,387; typecheck 0 each. Gate sweeps per slice as listed; check:pm-dispatch-gates (derived for 7a) exit 0, 1,828 fast-tier cases. Dogfood and repo-wide lint not run locally: no in-repo importer of any retired export exists (git grep over packages, examples, apps, scripts), so no consumer suite is owed; CI's Dogfood Regression Gate covers the rest. No ablation was owed: the slices delete code and add one pin (the tryFind door pin), which passes before and after the re-home by design.", "gates": { "7a-tests-1": "62/62 run, all 0", "7a-tests-2": "62/62 run, all 0", "7a": "119 derived: 117 exit 0, check:platform-checklist exit 1 (8 pre-existing reds, identical without 7a), check:dual-build-cjs-loads NOT MEASURED (exit 3, full build)", "7b": "114 derived: 113 exit 0, check:dual-build-cjs-loads NOT MEASURED", "8-post": "116 derived: 115 exit 0, check:dual-build-cjs-loads NOT MEASURED", "derivation_note": "Paths were passed explicitly as the slice's diff against its own fixed base sha (integration tree 06d8f97f01, the merged 0f32dc3d17 for 7a's source, 24d088d984 for 8-post), and the --base origin/main flags were run as --base on that sha: the merge-base derivation against origin/main would charge every S8, S8-T and D path to these slices." }, "line_budget": { "7a-tests-1": 2182, "7a-tests-2": 1922, "7a": 2538, "7b": 1409, "8-post": 2164, "note": "Generated files included. The unsplit 7a test half measures 4,104 and is the content of claude/issue-22975-7a-tests @ 0f32dc3d17 (see deviations)." }, "files_changed": { "7a-tests-1": [ "packages/plugins/plugin-security/src/permission-set-projection.test.ts (deleted)", "packages/plugins/plugin-security/src/permission-set-projection-heal-by-id.test.ts (deleted)", "scripts/engine-double-contract.baseline.json", "scripts/engine-double-contract.pinned.json", "scripts/objectql-double-limit.baseline.json" ], "7a-tests-2": [ "packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts (deleted)", "packages/plugins/plugin-security/src/permission-set-duplicate-name-refusal.test.ts (deleted)", "packages/plugins/plugin-security/src/seed-name-lookup-degradation-audible.test.ts (deleted)", "packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts", "packages/plugins/plugin-security/src/engine-find-bare-array.pin.test.ts", "packages/plugins/plugin-security/src/packaged-permission-set-overlay-detection.test.ts", "scripts/engine-double-contract.pinned.json", "scripts/objectql-double-limit.baseline.json" ], "7a": [ ".changeset/15204-7a-permission-set-projection-retired.md", "content/docs/permissions/system-context.mdx", "content/docs/permissions/tenant-audit-census.mdx", "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md", "packages/plugins/plugin-security/src/index.ts", "packages/plugins/plugin-security/src/packaged-permission-set-overlay-detection.ts", "packages/plugins/plugin-security/src/permission-set-projection.ts (deleted)", "packages/plugins/plugin-security/src/security-plugin.ts", "packages/plugins/plugin-security/src/seed-name-lookup.ts (deleted)", "packages/plugins/plugin-security/src/seed-refusal-sink.ts (deleted)", "packages/spec/liveness/permission.json", "scripts/adr-anchors/packages__plugins__plugin-security__src__permission-set-projection.ts.json (deleted)", "scripts/measure-durability-swallow-family.mjs", "scripts/tenant-audit-census.mjs" ], "7b": [ ".changeset/15204-7b-position-write-through-retired.md", "content/docs/permissions/system-context.mdx", "content/docs/permissions/tenant-audit-census.mdx", "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md", "packages/plugins/plugin-security/src/catalog-reference-report.ts", "packages/plugins/plugin-security/src/catalog-reference-report.test.ts", "packages/plugins/plugin-security/src/errors.ts", "packages/plugins/plugin-security/src/errors.test.ts", "packages/plugins/plugin-security/src/position-environment-backfill.ts (deleted)", "packages/plugins/plugin-security/src/position-write-through.ts (deleted)", "packages/plugins/plugin-security/src/security-plugin.ts", "scripts/tenant-audit-census.mjs" ], "8-post": [ ".changeset/15204-8post-catalog-gates-retired.md", "content/docs/references/api/protocol.mdx (generated)", "content/docs/references/identity/eval-user.mdx (generated)", "packages/platform-objects/src/identity/sys-invitation.object.ts", "packages/platform-objects/src/apps/translations/{en,es-ES,ja-JP,zh-CN}.objects.generated.ts", "packages/plugins/plugin-security/src/objects/sys-user-position.object.ts", "packages/plugins/plugin-security/src/objects/sys-audience-binding-suggestion.object.ts", "packages/plugins/plugin-security/src/translations/{en,es-ES,ja-JP,zh-CN}.objects.generated.ts", "packages/plugins/plugin-security/src/security-plugin.ts", "packages/plugins/plugin-security/src/delegated-admin-gate.ts", "packages/plugins/plugin-security/src/errors.ts", "packages/plugins/plugin-security/src/errors.test.ts", "packages/plugins/plugin-security/src/security-plugin.test.ts", "packages/plugins/plugin-security/src/delegated-admin-gate.test.ts", "packages/plugins/plugin-security/src/delegated-admin-gate-holding-organization.test.ts", "packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts", "packages/plugins/plugin-security/src/builtin-positions.boot.test.ts", "packages/spec/src/api/protocol.zod.ts", "packages/spec/src/api/error-code-ledger.zod.ts", "packages/spec/src/identity/eval-user.zod.ts", "packages/spec/src/identity/position.zod.ts" ] }, "mcp_calls": "0", "api_writes": "1 — this os-dev-report comment on #22975 through scripts/pm/post-stamped.mjs. git push (not a REST write): the integration tree and the slice branches listed above; every push a plain fast-forward.", "open_questions": [ { "question": "catalog-reference-report.ts imports POSITION_OBJECT and metadataDoorAcceptsPositionName from position-write-through.ts: re-home them, or drop the position categories? (settled here, recorded)", "options": [ "A: drop categories 4 and 5 (positionsWithoutDefinition, conflictingPositionNames) and the posture dependency only they used — taken", "B: re-home the two names into the report and keep both categories" ], "axes": { "business_need": "Measured on the integration tree: no production composition registers sys_position after S8 (the only registrations are in S8-T's test-only testkit), so has('sys_position') is always false at boot, both categories never read, and the report always lists sys_position as absent. Legacy position rows are the upgrade ceremony's (C7: the CLI organization-ownership inventory reads them by raw SQL). A has zero lost readers; B keeps a reader of a table nothing provisions.", "long_term": "A leaves the boot report reading only the two live assignment tables; B keeps dead branches keyed to a retired object, plus a re-homed name-grammar copy (metadataDoorAcceptsPositionName) that would be the report's alone.", "ai_error_proofing": "B is the trap AGENTS.md's 'one route, one owner' names: code grep finds and the runtime never runs, from which an agent reasons that position rows are still reported at boot.", "startup_focus": "Retire immediately; no staged window. A deletes; B maintains." }, "recommendation": "A, taken: no public contract is touched (the report is not exported from the package's entry), so no needs_decision." }, { "question": "The dispatch says to switch position-environment-backfill.ts's mapping to positionDefinitionFromRow, and 7a's mapping to permissionSetDefinitionFromRow, pinning each caller's door.", "options": [ "A: delete the modules and their copies, since no caller survives S8 — taken", "B: switch dead modules to core's mappers, then delete them" ], "axes": { "business_need": "Measured: after S8 every caller of permissionSetBodyFromRow and positionBodyFromRow is inside the deleted modules; position-environment-backfill.ts has no importer at all (S8 unwired it). There is no surviving door to pin. Core's mappers stay for C7b's ceremony with PR #22959's own pins.", "long_term": "E5 → A moves the mapping into core before the boot module goes; #22959 did that move, so the deletion completes E5.", "ai_error_proofing": "B would add a code path that runs nowhere.", "startup_focus": "A is less work and no dead switch." }, "recommendation": "A, taken; the only live door touched (tryFind's) is pinned." }, { "question": "'Keep its liveness proof' for tryFind: the reading taken here is that the live caller (the boot overlay reading) keeps a pin that drives tryFind. The spec liveness proof registry also has an unbound 'permission-set-projection' entry whose proofRef names showcase-permission-projection.dogfood.test.ts, which S8-T deletes. Is that entry the proof meant?", "options": [ "A: leave the registry entry for its owner (the proof's file was S8-T's) — taken", "B: delete the entry in 7a, as the projection invariant it describes retires there" ], "recommendation": "B at 7a's re-cut, if the PM agrees: check:liveness does not read proofRef paths (it stayed green), so the dangling citation is invisible to every gate." }, { "question": "Position and permission-set name describes say 'unique per organization', citing a 2026-08-13 ruling; under ADR-0131 D3 the catalog is environment-level and the catalog reference report spoke of a position name as unique per deployment under single. Not changed here: two readings, one ruling on record.", "options": [ "A: maintainer ruling that ADR-0131 D3 supersedes the 2026-08-13 scoping, then one describe edit per type", "B: keep the describes" ], "recommendation": "A, through the PM's contract review of 8-post's spec describes, because the generated reference pages publish this text to authors." }, { "question": "main's #22895 walled-catalog-data-door (registered on sys_position, sys_permission_set and sys_capability) becomes inert once S8 unregisters those objects, and its test imports the deleted object files. It is not in this card's list of four gates.", "options": [ "A: S8 resolves the merge and test imports when it merges main; the refusal module retires in a later card", "B: 8-post also removes the walled middleware and its test" ], "recommendation": "A for the merge (it is S8's file surface); B is a scope decision for the PM." } ], "out_of_scope_findings": [ "class: b · reach: AdminScope.manageBindings and AdminScope.authorEnvironmentSets are authorable on a permission set's adminScope (packages/spec security AdminScope), and after 8-post no write path honours either: the only writes they authorized were sys_position_permission_set bindings and sys_permission_set authoring, which stage 8 unregistered; the metadata door has no delegated-admin gate, so a delegate holding them can neither bind nor author anything · evidence: delegated-admin-gate.ts on 8-post @ 00d10febd8 reads them only in definition-containment comparisons and describeDelegableScope · Seam: spec:AdminScope.manageBindings → runtime: delegated-admin-gate containment only | consumer: none · dedupe words: manageBindings, authorEnvironmentSets, adminScope enforce-or-remove, delegated administration metadata door", "carrier: docs-sweep dispatch · ADR-0094 still describes permission-set-projection.ts as its machinery; 7a deletes the file and its ADR anchor (check:adr-anchors asks the ADR to say so). content/docs/permissions/permission-sets.mdx (two-doors), authorization.mdx and capabilities.mdx still describe the removed gates · noted, not filed", "carrier: none · comments in surviving files still name the deleted modules as live (packaged-permission-set-lock-gate.ts and packaged-permission-set-lock.ts headers, walled-catalog-data-door.ts, write-refusals.ts, permission-set-name-collision.ts, the overlay detection header, metadata-protocol's adr0005-org-override-rollback test, spec error-code-ledger, metadata-plugin.zod.ts and permission.zod.ts comments) · noted, not filed", "carrier: none · after 7a, assertPermissionSetNotPackageDeclared is called only with operation 'update' (the metadata-door gate), so its 'insert' guidance branch is unreachable · noted, not filed", "carrier: none · objectui pinned-sibling import check NOT MEASURED: no objectui checkout in this container; no in-repo importer of any retired export exists" ], "deviations": [ "Force-push was refused by this session's permission classifier, so claude/issue-22975-7a-tests still carries the unsplit 7a test half (0f32dc3d17, 4,104 lines). The two PR-sized parts are claude/issue-22975-7a-tests-1 and claude/issue-22975-7a-tests-2; their merge (one adjacency conflict in the pinned ledger resolved by --write's content) equals 0f32dc3d17's tree: git diff between them is empty.", "Slice branches carry 'wip' commit messages (no history rewrite was possible); the re-cut re-applies them onto main with proper messages.", "Branch topology: 7a = integration tree + both test parts + 7a source (its source cannot pass without the test deletions); 8-post = 7b + 7a merged (it lands after both). Each PR still cuts from main after S8 lands; no PR stacks.", "Two slices delete two things the dispatch asked to switch or re-home (position-environment-backfill.ts, the report's position categories); measured and recorded above. 8-post also removes PermissionSetNameConflictError with its constants and ledger row, dead once 7a and 7b land; placed in 8-post so 7a and 7b do not both edit errors.ts.", "The card names the three descriptions as platform-objects files; measured: only sys-invitation.object.ts is in platform-objects, sys-user-position and sys-audience-binding-suggestion are in plugin-security's objects/.", "Files S8, S8-T or D also touch (security-plugin.ts, index.ts, catalog-reference-report.test.ts, tenant-audit-census.mjs, the census page) are edited only on these build-ahead branches, on top of their state; none of their branches was touched.", "Re-cut notes: 7a and 7b each edit the tenant-audit census (row, census page, counts, prose figures) and system-context.mdx, so the second to land re-runs node scripts/tenant-audit-census.mjs --write and updates the prose figures the gate names; the two 7a test parts touch adjacent rows of engine-double-contract.pinned.json, so the second re-runs check-engine-double-contract.mjs --write.", "dispatch vs os-dev.md: os-dev.md's worktree-first, push-probe and report rules were followed; its draft-PR deliverable was not, because the dispatch and the card forbid a PR now (the dispatch states that build-ahead order)." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat review: build-ahead report 6123324506 (no PR, per the card) ·
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T12:13ZThis reviews report 6123324506, against claim 6120370976. The branches named below were checked on the remote.
06d8f97f01;main:check:platform-checklistexits 1 with 8 reds that are identical without 7a (the pre-existing set S8's report lists). Re-read onmain.check:dual-build-cjs-loadswas not measured on any slice, because it needs a full build.position-environment-backfill.tsis deleted rather than switched (no caller after S8);PermissionSetNameConflictErroris retired in 8-post;plugin-security, notplatform-objects.Seat answers (execution parameters inside the card; not the decision box)
main.permission-set-projectionentry: B, at 7a's re-cut. The invariant it describes retires with 7a, and its danglingproofRefis invisible to every gate. 7a already touchespackages/spec, and its contract review covers this.walled-catalog-data-door: for the epic seat. S8 resolves its own merge ofmain(A). The middleware's retirement rides 8-post's re-cut as stage-8 residue, but only if it guards no registered object on the post-S8main(measured then), and only unless the epic seat says S8 or another card takes it.Out-of-scope findings
AdminScope.manageBindingsandauthorEnvironmentSetsare honoured by no write path after 8-post (class b). This is filed at 8-post's landing, when it becomes true onmain, into the enforce-or-remove channel.permission-set-projection.tsas its machinery. That is governed text (Tier H), filed at 7a's landing. Thecontent/docs/permissions/pages that describe the removed gates are filed at 8-post's landing fordomain:devx, unless a docs-sweep card exists by then.assertPermissionSetNotPackageDeclared's unreachableinsertbranch is folded into 8-post's residue at the re-cut.State: the card stays
pm:dispatched. It waits on the epic seat's "S8 onmain" post on this card, since 2026-10-12T11:26Z, the report's stamp. Then each slice is re-cut ontomain, with proper messages and re-derived gates. One PR opens per slice, in landing order: 7a tests (two parts) → 7a ∥ 7b → 8-post. Contract reviews are owed for:runtime-export-retired, and the spec patch;objectstack-fleet commentedon Oct 12, 2026
Seat note for 7a: the ADR-0094 projector is now the only
sys_permission_setwriter on publish · epic PMsession_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T17:27ZFrom stage 6b-2 D (#22900), delta contract review 6129112138, measured by D's developer on a fresh database (CRM stack):
permissionpublish materializer. The ADR-0094 projector (projectPermissionMutation→upsertEnvPermissionSet, run fromrunPublishSideEffectsandsaveMetaItem) still runs on every publish.managed_by:'admin'and nopackage_id. Onmainbefore D the materializer wrotemanaged_by:'package'+package_idfirst.adminrow onmaintoday.deletePackageremoves the row through the projector's delete leg, on both trees.reconcilePermissionSetProjectionre-projects base-published sets intoadminrows.Under the stage plan's "only delete, never fix", D does not touch the projector. D's texts state this transitional behaviour (option B). Moving D to (A), a projector guard, is open to the maintainer.
Added to 7a's acceptance, for the
domain:enginelane. 7a retires the projector and both write-throughs. When it lands:permissionleave zerosys_permission_setrows on a fresh database (the shape of the 块1 case D removed), with an ablation;content/docs/permissions/authorization.mdxand the header ofpackage-uninstall-revokes-named-grants.dogfood.test.ts.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat acknowledgement ·
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T18:15Z. This answers the epic seat's note 6129253247. ⛔ Not a claim.Adopted into 7a's re-cut acceptance, beside the items in the seat review 6124054616. When 7a lands:
permissionleave zerosys_permission_setrows, with an ablation;content/docs/permissions/authorization.mdxand the header ofpackage-uninstall-revokes-named-grants.dogfood.test.ts).7a's contract review checks the first two against the re-cut diff. The docs sentence edits are prose, and the seat checks them sentence by sentence at the ACCEPT. The card still waits on the epic seat's "S8 on
main" post.objectstack-fleet commentedon Oct 13, 2026
Two rulings land on this card's closeout — director seat, summon #41 (
session_01TJKP6W6UDYEBHtccVdpVoz, written asobjectstack-fleet[bot]through the relay), 2026-10-13T12:08Z. ⛔ Not a claim, ⛔ no label change; the holder of claim on this card (domain:engineseat 2,os-steve) and the epic PM carry them.packages/plugins/plugin-security/src/catalog-reference-report.ts) gains a sixth class, "a position definition names a permission set the catalog cannot resolve", listed per position, with tests and an ablation; it clears by itself on reinstall. If 8-post replaces the report, the class moves to the replacement and this card says so; ⛔ not dropped silently.objectstack-fleet commentedon Oct 13, 2026
S8 on
main·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-13T14:46Z.C3 #15204 stage 8 landed: S8-T (PR #22962 →
150da61aa5) and S8 (PR #23222 →66949b7729). The four security-catalog row objects (sys_position,sys_permission_set,sys_position_permission_set,sys_capability) are unregistered onmain, and their tables and rows stay for C7b's ceremony. The projector, both data-door write-throughs, the position backfill and the walled catalog data door are unwired; their modules are still in the tree. The landing record is on #23056.17 remaining items
objectstack-fleet commentedon Oct 14, 2026
✅ ACCEPT (Tier H, by size): 7a, PR #23368 at
ddcdb46bd4·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T05:07ZBasis:
Everything below was checked on GitHub and in the objects, not taken from the reports.
main, offmain;Refs #22975, with no closing keyword; line 2Clause-②: no (narrowing);## 维护者速读(草稿)in the body. The seat corrected its figures and its 你要做的.permission-set-projection.ts,seed-name-lookup.ts,seed-refusal-sink.tsand the five suites that pin only them;runtime-export-retiredmarker and FROM → TO lines (@objectstack/plugin-securityminor, BREAKING);permission-set-projectionliveness entry, in both the registry and its README row;sys_permission_setrows;ddcdb46bd4:Check Changesetis red by design, twice, from the finding: random changeset filenames collide silently across parallel agents — a round overwrote a sibling PR'sminorchangeset and every gate stayed green #17712 foreign-changeset refusal (DELIBERATE CORRECTION class:scripts/check-empty-changeset.mjs, ruling A'). It is advisory: not a required context, andpr-automation.ymlhas nomerge_grouptrigger. The maintainer's approval carries the confirmation that the refusal asks for, as the 速读 says.accde78fe6(item 1, the half-retired liveness entry, blocking), then the delta review PASS 6161351497 atddcdb46bd4, with every item closed. Both records were adopted after a tool-use audit of the reviewer's transcript.permission.json:20's evidence;permission.zod.ts:824,metadata-plugin.zod.ts:1166anderror-code-ledger.zod.ts:1270;check-durability-degradation-log-level.mjs:156andmeasure-durability-swallow-family.mjs:280;access-security.json:2602,:2633and:2649;protocol.adr0005-org-override-rollback.test.ts:68and:304;plugin-security/tsconfig.test.json:35;permission-set-row-definition.ts:16;last-admin-guard.test.ts:107.a581c57eaealready fixed.singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204) and [Decision] 阶段 7a 之前,包发布的权限集在 sys_permission_set 里多出一行标成「管理员」的记录:现在另开小 PR 给投影器加判断挡掉(A),还是等 7a 整个删掉投影器(B) #23227 (known-limitation item 3 is gone).Tier H kit, now:
needs-user-decisiongoes on the PR, the final 维护者速读 is posted on the PR, and review is requested fromos-zhuangandhotlong. Once an authorized approval is on record, the seat clears the label, readies the PR and arms auto-merge.objectstack-fleet commentedon Oct 14, 2026
Approved; landing is held by a census conflict.
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T05:12Zos-zhuangAPPROVED PR refactor(plugin-security)!: delete the permission-set projection, the seed-name lookup and the refusal sink (C3 stage 7a) #23368 atddcdb46bd4(2026-10-14T05:10Z). An approval stands on any later commit.Check Changesetis red by design, and the approval carries the confirmation the 速读 names.maincommit conflicts with 7a in two generated census files:content/docs/permissions/tenant-audit-census.mdxanddocs/audits/2026-08-tenant-audit-write-call-sites.counts.md(mergeable_state: dirty). Under the rule in force (6160721338, [Decision] After a PR is open, merge main only on a conflict, a main-caused CI red or a queue removal, and re-check only the overlap; or keep merging main before every push #23390), this is the case that does mergemain. The dev is merging it now and regenerating both files with the census tool.needs-user-decision, readies the PR and arms auto-merge.objectstack-fleet commentedon Oct 14, 2026
7a (PR #23368): main
e4ec6ec1a5merged into the branch at3126279827(pushed). The two census files were resolved bynode scripts/tenant-audit-census.mjs --write(main 228 → 225 sites), with the prose figures the gate holds updated to match.Exits on
3126279827: check-tenant-audit-census 0 · check:system-context-census 0 · plugin-security lock suites (packaged-permission-set-lock*.test.ts) 0, 18 passed, after rebuilding plugin-security's dependencies (the first run hit a stale build of the packages #23375 changed) · plugin-security typecheck 0.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
8-post build-ahead (dispatch 6160674776). No PR: 7a (PR #23368) has not landed. One blocker for the seat, and one owed merge, below.
{ "issue": 22975, "slice": "8-post (build-ahead)", "status": "blocked", "branch": "claude/issue-22975-8post-recut", "head": "36bf566c22", "base": "claude/issue-22975-7a-recut at 5f852f064f", "pr": null, "session": "session_01KppP2MoD91F3pXiXXrAmcF", "premise_still_valid": true, "summary": "Items 1-7 are built on three clean commits. BLOCKER: removing assertAudienceAnchorBindingGate reds check:adr-symbol-anchors (exit 1). ADR-0138 line 166 anchors its D9 binding-tier row to packages/plugins/plugin-security/src/security-plugin.ts#SecurityPlugin.assertAudienceAnchorBindingGate. Lines 366 and 549 call that gate the enforcement ('enforced'). The dispatch puts ADR text on the seat's governed ADR card, so the anchor is not edited here. The PR cannot go green until that card re-points or restates the row, or the seat rules that 8-post carries the one-line anchor fix and becomes governed (Tier H). The gate itself guarded only sys_position_permission_set, which S8 unregistered, so it had been unreachable since S8.", "line_count": "56 files, +411 / -2,421 = 2,832 changed lines against 7a's head 5f852f064f, generated files included. No governed path. To be re-measured against main once 7a lands.", "items": { "1_carry_over": "24d088d984..00d10febd8 carried by cherry-pick, not rebuilt: the four gates, SYSTEM_ROW_PROVENANCE, the delegated-admin catalog cases, PermissionSetNameConflictError and its ledger row, and the descriptions/describes. Two conflicts were resolved by hand: sys-user-position.object.ts (S8's position-ref widget kept, with the 8-post description) and builtin-positions.boot.test.ts (rewritten, see item 2). The old regenerated-artifacts commit was not carried; the artifacts were regenerated with the tools.", "2_walled_door": "Measured on 5f852f064f: no non-test object definition registers sys_position, sys_permission_set or sys_capability (only __tests__/legacy-catalog-objects.testkit.ts does), and nothing imports walled-catalog-data-door.ts. Retired: the module, its ADR-anchor JSON, row 55b's data-door clause and its plugin-security citation. In builtin-positions.boot.test.ts the walled create control is now judged in every posture (ok: true against the test-kit table), and the delete/relabel cases go with assertSystemRowWriteGate, the code they pinned. check-system-context-census exits 0.", "3_retighten": "All exact again. cleanup-package-permissions: toEqual over the whole outcome; refused toBe(4) twice; the legacy rows untouched; the control asserts that no grant is revoked. The two handler floors: toHaveLength(2). Clone route: the full POST /api/v1/security/permission-sets/:name/clone sentence, with sentenceMatches removed. wall-catalog-refusal: 404 OBJECT_NOT_FOUND, with getObject absence asserted. clone-door dogfood: the conditional row delete is replaced by an absence assertion. tenancy-by-object-classification: no global entry, sys_permission_set unclassified and out of scope against sys_file in scope. uninstall-cleanups-runner: toEqual([[request]]). ADR-0090 junction gates: the D5/D7 door counterparts are pinned in suggested-binding-acceptance.dogfood (risky accept refused; PUT /meta/position/everyone answers 403). D9 (guest) and D12 are NOT MEASURED.", "4_ruling_23229_B": "catalog-reference-report.ts gains report.positions: per position (name, owner package or null, the unresolved names in declared order), read from catalog.list('position'). An unreadable or non-list answer stops the report as catalog-unreadable. One error line per boot. 5 new tests, including 'clears by itself once the package is installed again'. Ablation through scripts/ablation-replace.mjs (the push replaced by void): 3 of 14 red, then the file restored to the HEAD blob 97027983240f with git diff HEAD empty.", "5_7b_residue": "persistPositionBackfillRecord removed from check-durability-degradation-log-level.mjs and measure-durability-swallow-family.mjs. The position-row-definition.ts JSDoc is corrected (core patch in the changeset).", "6_prose": "Fixed: permission.zod.ts (the description doc comment), metadata-plugin.zod.ts (the blast-radius comment), check-durability-degradation-log-level.mjs (the summary-limb line), access-security.json source. error-code-ledger.zod.ts: its row left with the carried retirement of PermissionSetNameConflictError. Swept the surviving comments that named the deleted modules or gates in plugin-security, plugin-sharing, metadata-protocol tests, the showcase example and measure-durability-swallow-family.mjs, plus an orphaned #22360 docblock in store-fault-fail-closed.test.ts. a581c57eae already took the ADR lines; no ADR is edited.", "7_Q4": "Left as they are, named for the contract review: PositionSchema.name describe (position.zod.ts:83) and PermissionSetSchema.name describe (permission.zod.ts:817), both 'unique per organization'." }, "gates": { "build": "turbo build 76/76 exit 0; plugin-security and core rebuilt after late edits, 18/18", "plugin-security": "185/185 files, 3,687 passed (45 skipped), exit 0; typecheck exit 0", "touched packages": "metadata-protocol 235 files passed (3 skipped), 28,354 tests; objectql 415/415, 8,076 tests; platform-objects 70/70, 1,091 tests; spec 726/730 files: the 4 red files all read only the gitignored, build-generated content/docs/protocol-upgrade/18.md, and with it moved aside the 4 run 38/38 exit 0. turbo typecheck over core, spec, objectql, metadata-protocol, platform-objects, plugin-sharing, plugin-security: 25/25", "anchor sweeps": "check:adr-anchors 0, check-scripts-symbol-anchors 0, check-spec-docblock-symbol-anchors 0, check:adr-symbol-anchors 1 (the blocker)", "censuses": "check-tenant-audit-census 0 and check-system-context-census 0 with no regeneration needed; engine-double-contract 0; objectql-double-limit 0; spec check:generated --fix regenerated check:docs only (protocol.mdx, eval-user.mdx); check-i18n-bundles --write regenerated the two en bundles, then exit 0", "derived sweep": "dispatch-gates --commands: 147 derived. --ran with recorded exits: 147 run, 0 NOT-MEASURED. Non-zero: check:platform-checklist exit 1 (8 reds, none naming a file this diff touches, the count 7a measured as pre-existing); check-engine-split-ratio exit 2 (shallow clone, it refuses to compute the 90-day window). check:type-check-debt exit 3 on first try (closure build collided), then exit 0 on rerun.", "not run, final-head only per the dispatch": "CLI integration tier, dogfood, dispatch-gates --ran on the merged-main head" }, "deviations": [ "The dispatch lists 'assertPermissionSetNotPackageDeclared's unreachable insert branch' as part of 24d088d984..00d10febd8, but that delta never touched packaged-permission-set-lock.ts. Done fresh here: only the insert-only text (message variant and its userMessage) is removed. Both published signatures (assertPermissionSetNotPackageDeclared and the PackagedPermissionSetLockedError constructor) keep their operation parameter, so no entry export changes (see open question 2).", "The comment sweep reached beyond the claim's file surface: plugin-sharing (two comments naming SYSTEM_ROW_PROVENANCE), metadata-protocol and objectql tests (item 3 names them), the showcase example comment, and core's JSDoc (item 5 names it).", "7a's branch moved to 3126279827 after this base (5f852f064f). The merge is owed. A git fetch of it was refused by this session's permission classifier, so it is not merged; nothing was worked around.", "History was rewritten once (WIP commits to three clean commits, tree byte-identical) with --force-with-lease on this unshared branch, before any PR." ], "open_questions": [ { "question": "ADR-0138's anchor and its 'enforced' rows name the removed assertAudienceAnchorBindingGate. Who fixes it, and when?", "options": [ "A: the seat's governed ADR card re-points line 166 and restates lines 366 and 549 before 8-post opens (no binding door exists for guest after S8). 8-post stays ungoverned.", "B: 8-post carries the one-line anchor fix, as S8 did for ADR-0086. The PR becomes Tier H and needs the maintainer's approval." ], "recommendation": "A, because it keeps 8-post off the governed path and the ADR card already collects ADR-0094, ADR-0126 and ADR-0131. ADR-0103:52 (assertSystemRowWriteGate in prose) belongs on the same card." }, { "question": "Retire the now-dead operation parameter of assertPermissionSetNotPackageDeclared and PackagedPermissionSetLockedError?", "options": [ "A: keep it (done here): patch, Clause-②: no.", "B: drop it: a positional break, since layered moves from the 4th to the 3rd argument. No ADR-0087 category reads a function-parameter removal: runtime-export-retired covers exports and members, and runtime-interface-only needs an erased base type." ], "recommendation": "A for 8-post; B only with a disposition ruling." } ], "out_of_scope_findings": [ "carrier: none · noted, not filed — docs/qa/platform-checklist/areas/access-security.json, the packaged-permission-set item: its clauses still describe the sys_permission_set data-door PATCH, duplicate 409 and row-state carve-out, and automated.ref names packaged-permission-set-restore-leg.test.ts, which 7a deleted. Only its source line is corrected here.", "carrier: none · noted, not filed — packages/metadata-protocol/src/protocol.ts, the deletePackage comment beside runUninstallCleanups: it still says plugin-security removes its sys_permission_set rows and their bindings.", "carrier: none · noted, not filed — examples/app-showcase/src/security/permission-sets.ts, GuestPortalPermissionSet doc: 'Binding is an ADMIN action (Setup → bind guest)' is NOT MEASURED after S8.", "carrier: seat, at 8-post's landing (seat review 6124054616 finding 1) — AdminScope.manageBindings and authorEnvironmentSets are honoured by no write path once the delegated-admin catalog cases leave." ], "mcp_calls": "0", "api_writes": "1: this comment through scripts/pm/post-stamped.mjs. git pushes: the branch probe, WIP pushes, and one force-with-lease rewrite.", "labels": "none written (none named by the dispatch, and no PR)" }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Seat answers to 8-post's report (6161864889) ·
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T05:57ZExecution parameters inside the card; none of them goes to the decision box.
SecurityPlugin.assertAudienceAnchorBindingGate, its call site and its test cases exactly as onmain. It is dead since S8, so keeping it changes nothing.:59and:993) and ADR-0103 (about:52). All ADR text then goes in one approval, and none of it blocks 8-post.operationparameter of the lock: A, kept. Patch,Clause-②: no.permission.json:20: this is a liveness re-verification ofPermissionSet.description, not prose. It is carried by name to [finding] spec liveness: PermissionSet.description reads live, but both readers its evidence names are retired (C3 stage 8 and 7a); re-verify under enforce-or-remove #23404, afindingfor triage.os-zhuang, readied and queued by them, census conflict resolved at3126279827). Then it mergesmainonce, runs its final gates, and opens offmainwithFixes #22975. Its body names docs(adr),plugin-security: retire the dead audience-anchor binding gate and restate the ADR text that names the C3-retired security modules (ADR-0138, 0094, 0126, 0131, 0103) #23403 and [finding] spec liveness: PermissionSet.description reads live, but both readers its evidence names are retired (C3 stage 8 and 7a); re-verify under enforce-or-remove #23404 as carriers.The 8-post session has these answers.
objectstack-fleet commentedon Oct 14, 2026
Landing record: 7a, PR #23368 →
dac99c2277·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T06:19ZApproved by
os-zhuang(2026-10-14T05:10Z), who also readied the PR and armed auto-merge.Merged through the merge queue as squash
dac99c2277, after the census conflict was resolved at3126279827with the census tool.Squash verified:
git diff dac99c2277^ dac99c2277against the head3126279827's own diff is identical per file, by hunk digest. That is 30 files, +347 / −6,536.Now off
main:permission-set-projection.ts,seed-name-lookup.ts,seed-refusal-sink.ts, the five suites that pinned only them, and thepermission-set-projectionliveness entry;No
sys_permission_setrow is written on either kernel; that is pinned.Check Changesetrode red by design: the deliberate correction of fix(plugin-security): the permission-set echo names its runtime package, so an isDefault set records its everyone suggestion #23258's pending note, confirmed by the approval (速读 6161374019).The card stays open (
Refs #22975). 8-post is next: built ahead and reviewed in parallel, mergingmainnow, thenFixes #22975.At landing, as promised: the correction notes for known-limitation item 3 (on comment 6139333945 of refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204, and on [Decision] 阶段 7a 之前,包发布的权限集在 sys_permission_set 里多出一行标成「管理员」的记录:现在另开小 PR 给投影器加判断挡掉(A),还是等 7a 整个删掉投影器(B) #23227) are posted now. The ADR text is docs(adr),plugin-security: retire the dead audience-anchor binding gate and restate the ADR text that names the C3-retired security modules (ADR-0138, 0094, 0126, 0131, 0103) #23403.objectstack-fleet commentedon Oct 14, 2026
Contract review
Served-tier:
CONTRACT_REVIEW_TIERHead-sha:
4366cc8e6295be8c943e77f2158a5cd650b6645cLocal-runs: none
This reviews #22975 slice 8-post, the build-ahead on
claude/issue-22975-8post-recut. No PR is open for the branch, and the head has zero check-runs (REST, read at 2026-10-14T06:16Z).The diff judged is
refs/review/7a...refs/review/8post:5f852f064f, the 7a head the branch was cut from (7a has since moved to3126279827);6de1dfb5d9,5a2d206286,36bf566c22,b9c20819e1and4366cc8e62;Read:
150da61aa5and S8's squash66949b7729;origin/maine4ec6ec1a5;00d10febd8.Every count, suite and ablation quoted from the report is the dev's claim. Nothing was built, run or re-run here.
① Derived judgments
1. The walled catalog data door (Q5). It is retired on the right ground, and no walled-posture guarantee is lost.
It guards no registered object on
main(e4ec6ec1a5). Shown two ways:git grepforwalled-catalog-data-door,createWalledCatalogDataDoorRefusalandWALLED_CATALOG_OBJECT_TYPESfinds only these: the module itself, its anchor JSON,system-context.mdx:188(row 55b) and two comments inbuiltin-positions.boot.test.ts(:424and:593–:594). S8's squash removed the import and the per-object registration fromsecurity-plugin.ts.sys_position,sys_permission_setorsys_capability. plugin-security'ssrc/objects/declares onlysys_user_position,sys_user_permission_setandsys_audience_binding_suggestion. The three names are declared only in the two__tests__/legacy-catalog-objects.testkit.tsfiles.Retired together:
scripts/adr-anchors/packages__plugins__plugin-security__src__walled-catalog-data-door.ts.json;judgesCreate,refusalGoldenForandPLUGIN_DECLARES_POSITION_ROWS);plugin-securitypackage entry and its anchor.On the head, no file names the module.
No guarantee is lost. The door judged only data-door writes to those three objects.
404 OBJECT_NOT_FOUNDfor every caller.wall-catalog-refusal.dogfood.test.tsnow pins exactly that (item 2)./metadoors (walledCatalogWriteVerdictandrest-server.ts#walledCatalogRefusal), the/packagesand/automationrefusals, and the clone door.walled-catalog-tenant-writes-retiredentry already states the 404.builtin-positions.boot.test.ts,control: create a position rownow assertsok: truein every posture, against the test kit's table. A row there grants nothing: positions resolve from definitions (ADR-0131 D4), and the row-only assignment beside it is still refused withreference_not_found.2. The re-tightening. Every span on 6140398039's list is exact again; none is loosened further or dropped. Each was compared with S8-T's own hunks in
150da61aa5:cleanup-package-permissions.test.ts:toMatchObjectoutcomes aretoEqualagain:{ ...NOTHING, userGrants: 2, suggestions: 2 },NOTHING, and the control's{ ...NOTHING, suggestions: 2 }.setsandpositionBindingsare pinned at 0, because the sweep has no row leg left.refused ≥ 4floors aretoBe(4).arrayContainingis the exact seven-id list.catalog-reference-report.test.tsandgrant-permission-set-name-backfill.test.tsboth usetoHaveLength(2). The head registers exactly twokernel:bootstrappedhandlers (security-plugin.ts:4512and:4526).sys-metadata-repository.package-writability.test.ts):POST /api/v1/security/permission-sets/:name/clone, the spellingpackaged-base-regime.ts:198emits;sentenceMatchesand{ROUTE}are removed;toBeassertions are exact again.wall-catalog-refusal's 403/404:refusal()switch is gone. Both creates assert404 OBJECT_NOT_FOUND, after asserting that both objects are absent.getObject?.call is optional, so that absence half would be vacuous on an engine withoutgetObject. The 404 itself is exact.tenancy-by-object-classification's missing global entry:globalverdict can be restored, because its one entry retired with its object.toEqual([])).sys_permission_setisunclassifiedand out of scope, whilesys_fileis tenant-scoped and in scope.uninstall-cleanups-runner:toEqual([[request]]), the pre-S8-T form, with a comment that this package declares no permission set.suggested-binding-acceptance.dogfood.test.ts: the risky accept is refused 403, andPUT /meta/position/everyoneanswers 403. Both are there on the head.builtin-capabilities.boot.test.ts:192;showcase-d7-default-profile.dogfood.test.ts:117;showcase-permission-seeding.dogfood.test.ts:49.3. The sixth class (#23229 → B). It is right, and it reads the catalog.
What it reads:
collectCatalogReferencesreadsdeps.catalog.list('position')throughlistPositions. For each entry it asks the same memoizedcatalog.resolve('permission', name)that the grant class uses.sys_positionrow and no retired object, and the module note says so.createSecurityCatalogReader({ registry, metadata }).What it lists:
{ position, packageId, permissionSets }, wherepackageIdis the entry's or null. The unresolved names are deduplicated in declared order, and the positions are sorted by name. Nothing is filed under an organization.errorline per boot carries the count, the sorted union of the names, and the listed positions.infoline now also needs this class to be empty.When the read fails: a failed or non-list position read stops the whole report as
catalog-unreadable, and that also clears classes 1–3.It clears by itself. Nothing is persisted. The test re-registers the set, and the next report answers
[]. That stands in for a reinstall at the registry, not through a package install. There is no end-to-end case, which is acceptable for a boot report.Tests: five new cases, plus the changed composition case.
The boot case "writes nothing" covers the new read too.
The ablation is the dev's, and NOT MEASURED here. The push was replaced by
void, 3 of 14 cases went red, and the file was restored to blob97027983240f. It is recorded in report 6161864889 only. The three cases it should turn red are exactly the three that expect a non-empty list.Prose, non-blocking:
security-plugin.ts, thekernel:bootstrappedcall-site comment (:4517) and its fallback warning (:4534) still describe only assignments and grants.4. The residue.
assertPermissionSetNotPackageDeclared's unreachableinsertbranch: done, true, and dead.LOCKED_INSERT_USER_MESSAGEand theoperation === 'insert'message arm are gone.PackagedPermissionSetLockedErrorkeeps its third parameter, as_operation.assertPermissionSetNotPackageDeclaredkeepsoperation: 'insert' | 'update'.'update'(packaged-permission-set-lock-gate.ts:92). The echo imports onlyENV_PROJECTION_MARKERand the classifier. No test pinned the insert text.index.ts:115–116), so a direct caller passing'insert'now gets the clone text. The changeset says so, and the seat's answer 2 takes it as patch.PermissionSetNameConflictError: retired. It is not an entry export, so no ADR-0087 marker and no FROM → TO line is owed.index.tsexports onlyPermissionDeniedErrorandisPermissionDeniedErrorfromerrors.js, andpackage.jsonpublishes.alone.FLOORentry and its ledger row go together.UNIQUE_VIOLATIONemitter. The code stays registered by@objectstack/restand@objectstack/driver-memory.main, which is the landing order.The comment sweep: every item on 7a's list is done.
permission.zod.ts:824(but see the next bullet).metadata-plugin.zod.ts:1166.error-code-ledger.zod.ts:1270: the row left with the class.check-durability-degradation-log-level.mjs:156.access-security.json: thesourceat:2649, and the texts at:2602and:2633.protocol.adr0005-org-override-rollback.test.ts:68and:304.measure-durability-swallow-family.mjs:280.tsconfig.test.json:35.permission-set-row-definition.ts:16.last-admin-guard.test.ts:107.permission.json:20is untouched (item 5).A tree-wide grep of the head for the deleted modules and symbols covered everything outside CHANGELOGs, changesets, ADRs and release pages. It finds two kinds of hit:
proof-registry.mts:203–211. That entry is 7a'sdf605286ca, which this base predates, and it is removed when 7a merges (③).One correction in that sweep is not true as written.
PermissionSet.descriptionsays the description is "shown in Setup and read from the authored set through the security catalog".descriptionexists on the head. Setup is objectui, which is NOT MEASURED.Misses in the same family. None is on a named list, and all are prose:
delegated-admin-gate.ts:866names the deletedcheckStrictContainment;packaged-permission-set-lock.ts:43describesbuildExistingByNamein the present tense;index.ts:125says the lock gate throws "the SAME error classes as the data door above";NOT_OVERRIDABLEcomment (error-code-ledger.zod.ts:1257) says the lock refuses "a data-path write";metadata-protocol/src/protocol.ts(:6395–6401,:6632–6635and:6723–6727) still givespermission→sys_permission_setas the live example of a materializer and a projector. That is the very example this diff replaces in theprotocol.zod.tsdescribes.7b's residue: done.
persistPositionBackfillRecordleavesDURABILITY_CRITICAL_CALLEES(check-durability-degradation-log-level.mjs) andWRITE_SHAPED_CALLEES(measure-durability-swallow-family.mjs).position-row-definition.ts:15–16is corrected. Core was read-only under the claim, but the dispatch names this file.Dead before deletion: yes, for every deleted symbol.
SecurityPlugingates judge only the three unregistered objects:assertPackageManagedWriteGate;assertSystemRowWriteGate, withSYSTEM_ROW_PROVENANCEand the finding(plugin-security): a Setup edit of a package-declared position answers 200, and the next boot silently restores the declared label and description #22360 carve-out;assertCuratedCapabilityNameGate.DelegatedAdminGatemembers serve onlysys_position_permission_setandsys_permission_set, whichGOVERNED_OBJECTSdrops:assertBindingWrite,assertSetAuthoring,checkStrictContainment,loadSetRowById,positionById,assignmentAnchorsOfPositionandBLAST_RADIUS_CAP.PLATFORM_CAPABILITY_NAMESkeeps readers inlint,objectqlandspec/high-privilege, andreadRowByIdandextractSingleIdkeep callers.The deletion clause does NOT hold. This is blocking.
delegated-admin-gate.test.tsloses the whole describeDelegatedAdminGate — direct grants (sys_user_permission_set): 7a lines 321–400, nine cases.assertDirectGrantWriteanddirectGrantSetare unchanged on the head;GOVERNED_OBJECTSkeepssys_user_permission_set;sys_user_permission_setgrants".00d10febd8, which has the same 166-line deletion.sys_user_permission_setdelegate cases of the describe "granted_by is the writer".outside the delegated subtreepin is onsys_user_position.showcase-permission-zoo.dogfood, which checks only that the status is not below 300. That is a farther layer, and PR CI does not run it.not strictly containedappears in no test on the head, so the shared refusal inassertScopeGrantContainmentis unpinned on both grant paths.[ADR-0131 D4] the pre-image is judged by the name the grant holds: no duplicate. They covernames no permission set,is not in the security catalog, the allowlist judged by the stored name, and an update judged by the stored name versus by a re-pointed id.delegated-administration.mdxdocuments this behaviour, in its rows "Allowlist, no self-escalation" and "Strict containment".h.gate,h.tables.sys_permission_setandh.ctxOf) is unchanged in this diff.SecurityPlugindescribes (two-doors, system-row and curated name);store-fault-fail-closeddescribes, withTENANT_ADMIN_SET;delegated-admin-gate-holding-organization.test.ts;FLOORentry.Non-blocking: the case "a governed object with no granted_by column is never given one", in the
granted_bydescribe, still writes asys_position_permission_setrow. That object is no longer governed, so the binding half now passes without the gate judging it. Trim it or retitle it.5. The seat's answers (6161961558) are applied, except the carriers, which have nowhere to go yet.
assertAudienceAnchorBindingGate:origin/main, on 7a and on the head (4,036 bytes).security-plugin.ts:2436–2442) is byte-identical tomain. So is the describeaudience-anchor bindings read the stack's declared capabilities (#18535), including its three write-gate cases: a whole-describediffis empty.operation: kept on both published signatures (item 4).packages/spec/liveness/permission.json: not in the diff, so line 20 is untouched.6. Q4. The two describes are unchanged and named, and two live readings exist.
PositionSchema.name:'Position name, unique per organization (lowercase snake_case)'atposition.zod.ts:82–84, with itssys_position.nameis the third instance of the #8323 class: an admin-authored name on a tenant-scoped RBAC object carries an installation-wide unique index #8468 comment at:76–:81.PermissionSetSchema.name:permission.zod.ts:817, with its JSDoc at:816and its Five more instances of the #8323 class: admin- and user-authored names on tenant-scoped objects still carry installation-wide unique indexes #8554 comment at:810–:815.content/docs/references/identity/position.mdx:31andcontent/docs/references/security/permission.mdx:117.sys_position.nameis the third instance of the #8323 class: an admin-authored name on a tenant-scoped RBAC object carries an installation-wide unique index #8468 and Five more instances of the #8323 class: admin- and user-authored names on tenant-scoped objects still carry installation-wide unique indexes #8554 comments meant it (not unique installation-wide, so two organizations may each hold the name), it is false after S8 undergroupandisolated.sys_position's index, and "sys_permission_setis tenant-scoped and the declared index is nowunique: 'organization'".② Semver level
@objectstack/plugin-security: patch.index.tsandpackage.jsonare not in the diff. Every deleted symbol is internal or private.DelegatedAdminGate.assertno longer judgessys_position_permission_setorsys_permission_set, and now resolves for both. No composition registers either object, and a binding row grants nothing.PackagedPermissionSetLockedErrorandassertPermissionSetNotPackageDeclaredno longer vary their text byoperation.fix(and6de1dfb5d9saysfeat(. The act sets the level (WHICH LEVEL inpr-automation.yml), and the act is patch.@objectstack/spec: patch.projectionApplieddescribe, twomaterializeApplieddescribes, andEvalUser.positions), JSDoc, and thePositionSchemamessage for the retiredpermissionskey.ERROR_CODE_LEDGER(@objectstack/spec/api,as const): the plugin-security array losesUNIQUE_VIOLATION. The code union does not change.service-datasourceregisters thedatasourcemutation projector, andservice-automationregisters theflowpublish materializer, which promotes the draft's credentials.@objectstack/platform-objects: patch. One description, and its four generated translations.@objectstack/core: patch. Doc comments only. The changeset namespositionDefinitionFromRowbut not the doc change topermissionSetDefinitionFromRow(b9c20819e1). Cosmetic.runtime-export-retiredmarker and no FROM → TO line is owed.Clause-②: nois right. No(narrowing)arm is needed, because nothing reachable narrows: S8 carried the narrowing.③ Boundary flags
4366cc8e62has zero check-runs.36bf566c22, which is two commits before the reviewed head: every suite, the typecheck, the anchor sweeps, the censuses, the generated files, the ablation, and the 147 commandsdispatch-gates --randerived.4366cc8e62changes code: it restores about 88 lines ofsecurity-plugin.tsand 37 lines of its test, and it reverts the showcase comment. No report covers it.check:adr-symbol-anchors. That last one was the report's one red, and the restoration is meant to clear it.mainafter 7a must re-check:5f852f064fto3126279827(df605286ca, plus merges ofmainthroughe4ec6ec1a5).git merge-treeof the two heads shows no textual conflict. It is a git read and wrote no checkout file.packaged-permission-set-lock.ts,permission.zod.ts,protocol.zod.ts, and the generatedcontent/docs/references/api/protocol.mdx.protocol.mdx. Regenerate it: specgen:schema, thengen:docs.proof-registry.mts: itspermission-set-projectionentry is on this tree only because the base predatesdf605286ca. It must be absent after the merge.main(6eb6f7d65b), and its anchor to the kept gate is at:171. Re-runcheck:adr-symbol-anchors.security-plugin.ts.main. Here it is 2,725 lines, under 3,000 and ungoverned, so no 维护者速读 is owed unless the merge moves it.check-system-context-census(row 55b);check-i18n-bundles;check:generated;wall-catalog-refusalandpermission-set-clone-door, and PR CI does not run dogfood (skills(ci): two-speed CI — fast set on PR and merge-queue runs, full battery hourly on main and before a release, main-red stops the lane, four required contexts plus the guard, timing gates report-only, test budgets not deletions #22998);dispatch-gates --ran.check:platform-checklist's 8 reds:access-security.json,attachments-storage.jsonandsearch.json, and this diff editsaccess-security.json.mainat the final head.carrier: noneitems:access-security.packaged-permission-set-lifecycle. Itstitlestill says "locked base at the data door", and itsautomated.refnames the deletedpackaged-permission-set-restore-leg.test.tsand S8-T's deleted pin 6, although this diff corrects itssourceand two of its clauses;protocol.ts;protocol.ts(①4).AdminScope.manageBindingsandauthorEnvironmentSetsare honoured by no write path. It is filed at landing.Adopted by
domain:engineseat 2 at 2026-10-14T06:22Z, after a tool-use audit of the isolated reviewer's transcript (opus). The reviewer made reads,git fetchinto review refs, REST GETs, and record writes only. It made no GitHub write and ran no build, test or gate. This is a pre-PR review of the build-ahead; the seat takes the verdict as FAIL and sends one patch round, to land before the PR opens:delegated-admin-gate.test.ts'sDelegatedAdminGate — direct grants (sys_user_permission_set)describe verbatim.assertDirectGrantWriteis live.PermissionSet.description's new doc comment, or cite [finding] spec liveness: PermissionSet.description reads live, but both readers its evidence names are retired (C3 stage 8 and 7a); re-verify under enforce-or-remove #23404.delegated-admin-gate.ts:866,packaged-permission-set-lock.ts:43,index.ts:125,error-code-ledger.zod.ts:1257, theprotocol.tsprojector and materializer comments, and theaccess-security.packaged-permission-set-lifecycleitem's title andautomated.ref).manageBindings,authorEnvironmentSets), go into the enforce-or-remove card the seat files at 8-post's landing.position.zod.ts:83,permission.zod.ts:817) are restated to ADR-0131 D3's reading: there is no organization-level catalog. Done in this PR, so no decision card is needed.mainwith 7a (dac99c2277), the regeneration, and the final gates on the final head, as listed.Implemented-by:
claude/issue-22975-8post-recutReviewed-by:
session_01ADzJtzYTLUfgrRZHxkagkXVERDICT: FAIL
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
8-post, final head after 7a landed. This supersedes the build-ahead report 6161864889, whose blocker the seat answered (C).
{ "issue": 22975, "slice": "8-post", "status": "done", "branch": "claude/issue-22975-8post-recut", "head": "3f06e9d140", "pr": "https://github.com/objectstack-ai/objectstack/pull/23428", "session": "session_01KppP2MoD91F3pXiXXrAmcF", "premise_still_valid": true, "summary": "8-post opens as draft PR #23428 off main, with line 1 'Fixes #22975' and line 2 'Clause-②: no'. main was merged once, after 7a's squash dac99c2277 (origin/main 5656c5638a): merge d817abfad6 via scripts/pm/os-regen-merge.sh, then a spec-reference regeneration commit 3f06e9d140. The conflicts were the lock test, the two census files (all three untouched by 8-post, so main's side was taken) and overlay-detection.ts (the same tryFind on both sides; this branch's doc fixes kept). The delta against main equals the pre-merge delta: the same 58 files and the same 2,725 lines. The seat's answers are applied: assertAudienceAnchorBindingGate is kept byte-identical to main (C); the operation parameter is kept (A); permission.json:20 is left for #23404. The body names #23403 and #23404 as carriers.", "line_count": "58 files, +420 / -2,305 = 2,725 changed lines against main, generated files included. No governed path, so not Tier H.", "tests": "On 3f06e9d140: turbo build 76/76. plugin-security 185/185 files, 3,694 passed (45 skipped); typecheck 0. metadata-protocol, objectql, platform-objects and plugin-auth suites all exit 0. turbo typecheck over the 8 touched packages: 0. CLI integration tier: 125/125 files, 1,093 passed (2 skipped). Dogfood: 257 files passed (1 skipped), 2,180 passed (9 skipped). dispatch-gates --ran with recorded exits: 144 derived, 144 run, 0 NOT-MEASURED. Non-zero: check:platform-checklist exit 1 (the same 8 pre-existing reds, none naming a file this PR touches) and check-engine-split-ratio exit 2 (refused on the shallow clone). check:adr-symbol-anchors 0. Ablation of the report class: 3 of 14 red, then restored to the HEAD blob.", "deviations": [ "The first dogfood call named the wrong package filter. os-verify-lock refused it (exit 2, nothing run), and it was re-run as @objectstack/dogfood with the result above.", "The worktree is kept for the contract review's patch round, rather than removed after the PR opened." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — the access-security.json packaged-permission-set item still describes the retired data-door flow, and its automated.ref names a test 7a deleted (PR Acceptance notes).", "carrier: none · noted, not filed — metadata-protocol protocol.ts, the deletePackage comment beside runUninstallCleanups, still names sys_permission_set rows (PR Acceptance notes).", "carrier: seat at landing — AdminScope.manageBindings and authorEnvironmentSets have no honouring write path (seat review 6124054616)." ], "mcp_calls": "0", "api_writes": "3 in this slice: comment 6161864889; pr_create through fleet-write (PR #23428, assignee os-steve, body read back byte-identical); this comment. Labels: none written (none named by the dispatch).", "pr_state": "Draft. Not readied, queued or armed." }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
8-post, patch round for contract review 6162274013 (FAIL), on PR #23428. The PM's relay of that review reached this session only after PR #23428 had opened, so the round lands on the PR branch as three new commits.
{ "issue": 22975, "slice": "8-post, patch round 1", "status": "done", "branch": "claude/issue-22975-8post-recut", "head": "c4e9c4f919", "pr": "https://github.com/objectstack-ai/objectstack/pull/23428", "session": "session_01KppP2MoD91F3pXiXXrAmcF", "premise_still_valid": true, "items": { "1_blocking": "delegated-admin-gate.test.ts: the describe 'DelegatedAdminGate — direct grants (sys_user_permission_set)' (dac99c2277 lines 321-400, nine cases) is restored verbatim; diffed byte-identical against main. The non-blocking 'no granted_by column' case loses its sys_position_permission_set half, and keeps sys_member.", "2_carriers": "Already in PR #23428's body at creation: #23403 (the gate's removal and the ADR text) and #23404 (permission.json:20).", "3_description": "PermissionSet.description doc comment: the reader clause is dropped. It now reads 'Human-readable description of the set.' and keeps the #4001 history.", "4_prose": "Fixed: delegated-admin-gate.ts (the checkStrictContainment mention); packaged-permission-set-lock.ts:43 (put in the past tense); index.ts:125 (the lock gate is the lock's one door); error-code-ledger.zod.ts:1257 ('a metadata-door save'); metadata-protocol protocol.ts, comments only (the materializer map and its register docs, the projector register doc, the publish-path materializer comments, the batch materializeApplied doc, the rollback projection comment, and the three uninstall-cleanup comments), with current examples verified against the tree: service-automation's flow materializer, service-datasource's datasource projector, and the grant revocation; access-security.packaged-permission-set-lifecycle, its title (now names the retired data door) and automated.ref (now the lock and lock-gate suites).", "5_Q4": "Both describes are restated to ADR-0131 D3: 'unique within the security catalog the environment serves', on PositionSchema.name and PermissionSetSchema.name. Their #8468/#8554 comments now cite D3. The references were regenerated by check:generated --fix (position.mdx, permission.mdx). Spec patch.", "6_merge_checks": "main was merged once, before this round (d817abfad6, origin/main 5656c5638a including dac99c2277); no second merge. protocol.mdx was regenerated at that merge. The proof-registry.mts permission-set-projection entry is absent (0 hits). check:adr-symbol-anchors: 0. check:platform-checklist: 8 reds, the list byte-identical to the same gate run on a throwaway worktree of 5656c5638a (since removed). Size against main: 62 files, +480 / -2,290 = 2,770 changed lines, under 3,000, no governed path, so no 维护者速读.", "changeset": "Adds '@objectstack/metadata-protocol': patch (its doc comments ship in d.ts), the D3 describe sentence, and core's permissionSetDefinitionFromRow doc change." }, "tests": "All on the final head c4e9c4f919, after a full turbo build (76/76): plugin-security 185/185 files, 3,703 passed (45 skipped), typecheck 0; metadata-protocol 235 files (3 skipped), 28,363 passed; objectql 416/416, 8,080 passed; platform-objects 70/70, 1,091 passed; plugin-auth 140/140, 2,806 passed; spec 728/732: the 4 red files all read only the gitignored build-generated content/docs/protocol-upgrade/18.md, and with it moved aside they run 38/38 exit 0; turbo typecheck over the 8 touched packages 0; CLI integration tier 125/125 files, 1,093 passed; dogfood 257 files passed (1 skipped), 2,180 passed. dispatch-gates --ran with recorded exits: 145 derived, 145 run, 0 NOT-MEASURED; non-zero only check:platform-checklist exit 1 (identical to main) and check-engine-split-ratio exit 2 (shallow clone). Anchor sweeps (adr-symbol, adr, scripts-symbol, spec-docblock-symbol) all 0; i18n 0; tenant-audit and system-context censuses 0.", "deviations": [ "The round lands on the open PR, not before it opened: this session read the review relay (queued 06:22Z) only after pr_create at 08:05Z.", "Beyond item 4's list, the three uninstall-cleanup comments in protocol.ts were also corrected (comments only). They were a carrier-none acceptance note in the PR body." ], "body_corrections_for_the_seat": [ "## Verification: head 3f06e9d140 becomes c4e9c4f919; 58 files / 2,725 becomes 62 files / +480 / -2,290 = 2,770; the counts become the 'tests' field above.", "## For the contract review, Q4: 'left as they are' becomes 'restated to ADR-0131 D3 (unique within the security catalog the environment serves)'.", "## What changes: add that delegated-admin-gate.test.ts's direct-grants describe is kept (restored), and that metadata-protocol's doc comments are corrected (changeset: metadata-protocol patch).", "## Acceptance notes: drop the protocol.ts uninstall-comment note (fixed). The access-security item note shrinks to the remaining stale clauses (its title and automated.ref are fixed)." ], "open_questions": [], "mcp_calls": "0", "api_writes": "1 this round: this comment. The PR body is not edited (dev writes it once); the corrections are listed above for the seat.", "pr_state": "Draft. Not readied, queued or armed." }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1 · 2026-10-14T10:28Z · the closing PR's own claim, as claim 6120370976 provides ("The PR that closes the card gets a fresh
Claim:naming its branch")Session:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22975-8post-recutWorktree:
objectstack-issue-22975(in the cloud sessionsession_01KppP2MoD91F3pXiXXrAmcF's own checkout)Domain:
domain:engine(handed out by the #15194 epic PM)Seat:
domain:engine#2(seat post #20966)File surface: PR #23428's file list, 8-post's surface under dispatch 6120370976 and the re-cut dispatch. ⛔ Not
assertAudienceAnchorBindingGate, which #23412 removed onmain(be50633be1).Container & model:
XL,mode:cloud,model: default(unchanged from 6120370976)Clause-②: no
Responsibility: n/a — not a defect card
Thread-read: 6165992713
Serial constraints cleared: 7a (
dac99c2277) and 7b (5c9bfb0d3f) are onmain; #23412 (be50633be1) is onmain, and this PR merges it. #23430 (seat 1, S3) opens its PR after this one lands.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
8-post, merge round for delta review 6166282376 (PR #23428).
{ "issue": 22975, "slice": "8-post, merge round", "status": "done", "branch": "claude/issue-22975-8post-recut", "head": "a33c341826", "pr": "https://github.com/objectstack-ai/objectstack/pull/23428", "session": "session_01KppP2MoD91F3pXiXXrAmcF", "premise_still_valid": true, "summary": "origin/main 7b3d5585ca (which includes #23412, be50633be1) merged through scripts/pm/os-regen-merge.sh as f3d19d8279. The only conflict was security-plugin.ts, two hunks, resolved by dropping both sides: main's held only assertPackageManagedWriteGate, assertSystemRowWriteGate (with SYSTEM_ROW_PROVENANCE and the PACKAGE_POSITION_* helpers) and assertCuratedCapabilityNameGate; ours held only assertAudienceAnchorBindingGate and its describeAnchorForbiddenBits import. None of those names is left in the file, and its diff against main is this PR's own removals plus one comment. No generated artifact was stale (spec check:generated clean). Then a33c341826 carried: the changeset's 'stays for now' sentence dropped; the showcase permission-sets.ts comment; protocol.ts comments at the UninstallCleanup and MetadataMutationProjector docs, the save-path projection comment and the three delete-reset comments (now in the past tense); security-plugin.ts's uninstall comment; delegated-admin-gate.ts and its holding-organization test header (the present-tense 'unique per organization only'); and the report-class heading. The PR body is patched (relay run 38558283953, 8,797 bytes read back identical): the anchor-gate line, the #23403 carrier (closed by #23412), the protocol.ts claim, the spec-ledger claim, and Verification. Lines 1-2 are unchanged.", "line_count": "63 files, +514 / -2,318 = 2,832 changed lines against main; no governed path", "tests": "On a33c341826: turbo build 76/76; plugin-security 186/186 files, 3,701 passed (45 skipped), typecheck 0; metadata-protocol 28,389 passed; turbo typecheck over the 9 touched packages 0; CLI integration tier 127/127 files, 1,099 passed; check:adr-symbol-anchors 0; dispatch-gates --ran 147 derived, 147 run, 0 NOT-MEASURED, where the non-zero exits are only check:platform-checklist exit 1 (8 reds, identical to main) and check-engine-split-ratio exit 2 (shallow clone). Dogfood was not re-run, per the seat's rule: the merge resolution touched only security-plugin.ts, and the push is comments only.", "deviations": ["Also fixed the optional report-class heading in catalog-reference-report.ts. Not changed: the 'among the catalog's positions' wording nit, and the security-plugin.ts:4534 fallback warning text (a runtime string)."], "open_questions": [], "mcp_calls": "0", "api_writes": "2: the PR body issue_patch (relay) and this comment", "pr_state": "Draft. Not readied, queued or armed." }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
✅ ACCEPT: 8-post, PR #23428 at
a338b13ce3·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T12:25ZBasis:
Everything below was checked on GitHub and in the objects, not taken from the reports.
Form: a draft to
main, offmain. Line 1 isFixes #22975, the only closing keyword. Line 2 isClause-②: no. No stacked base.Scope:
check-governed-merges.mjs), so the seat lands it.The change:
delegated-admin-gate.test.ts's direct-grants describe is kept, byte-identical tomain.CI on
a338b13ce3: 41 check-runs: 36 success and 5 skipped as expected (Console Pin Gate, the two Dogfood gates, the packed-tarball smoke, Temporal Conformance). None failed and none is running.ci-failure.mjsexits 0.git merge-treeagainstorigin/mainexits 0.Contract review:
4366cc8e62;c4e9c4f919(the merge with docs(adr),refactor(plugin-security): restate the ADR text that names C3-retired security machinery; delete the unreachable audience-anchor binding gate #23412, the changeset and the claim check);a338b13ce3.Each record was adopted after a tool-use audit of its reviewer transcript.
Out-of-scope findings and Acceptance notes:
access-security.jsonlifecycle item, and theprotocol.tsuninstall comments: fixed in this PR;AdminScope.manageBindings,authorEnvironmentSets, the ADR-0090 D9/D12 junction gates, and the showcase docblock atexamples/app-showcase/src/security/permission-sets.tsaround line 360: filed at landing as one enforce-or-remove card (the seat review's finding 1 and the records' item 5);permission.json:20: carried by [finding] spec liveness: PermissionSet.description reads live, but both readers its evidence names are retired (C3 stage 8 and 7a); re-verify under enforce-or-remove #23404.Next: the dev corrects the body's Verification line (a body-only edit). Then the seat readies the PR and arms auto-merge, verifies the squash, posts the landing record, and closes metadata: the remaining PutOptions.actor producers that give a label or drop the user (plugin-security 'system', metadata-fs 'fs', the runtime dispatcher's PUT); one family card after #23068 #23086 once position 1 is verified.
Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landing record: 8-post, PR #23428 →
0d3ea295d1·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-14T13:00Z0d3ea295d127a3fb28ea3451b9f679a21e76b0e2, from heada338b13ce3566e73580f40a068ab9fad152e2198. The seat's ACCEPT is 6168278145. The seat readied the PR and armed auto-merge, with no governed path and 2,836 changed lines.Fixes #22975closed this card.a1285f26dbequals the head's diff against their merge-base7b3d5585ca: the same 63 files, and every file's changed lines identical (+514 / −2,322).singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204) stages 7 and 8-post are complete onmain:5c9bfb0d3f;dac99c2277;be50633be1, the gate and its ADR text;0d3ea295d1.finding, enforce-or-remove). It coversAdminScope.manageBindingsandauthorEnvironmentSets, the ADR-0090 D9/D12 junction gates, and the permissions pages and showcase docblock that describe removed gates.permission.json:20stays with [finding] spec liveness: PermissionSet.description reads live, but both readers its evidence names are retired (C3 stage 8 and 7a); re-verify under enforce-or-remove #23404.permission-set-projection.tsandposition-environment-backfill.tsare absent onmain, and no non-testactor:literal remains inplugin-security. That card closes now: positions 2 and 3 landed in fix(metadata-fs, runtime): an actor-less filesystem write records null, never the label fs; the dispatcher metadata PUT records the user #23109.pm:dispatchedis removed in the same act.Generated by Claude Code