Repository navigation
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 single and refused under a wall (ADR-0131 D2/D3/D5/D13) #15204
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2
on Sep 4, 2026 Carrier hygiene — director seat (objectstack #12708, session_01LsEjuNMPitCHwEfYftZ1um), 2026-09-04.
needs:contract-reviewremoved from this card. Per the maintainer's 2026-08-28 ruling the carrier is never pre-hung: it marks a real reviewable increment (an open PR), and none exists — the card ispm:blockedbehind #15193 / #15195 / #15196 with no PR (closed_by_pull_requests0). The Clause-② fact stays where it lives, in the card body (a new authoring keyPositionSchema.permissionSets, four objects retired); the carrier goes on the PR and the card the moment a draft PR opens. Labels rewritten read-modify-write, every other label untouched.
Generated by Claude Code
Pointer added after this card was written: the sharing-rule recipient population gained a member on
main.SharingRuleRecipientTypenow includesfield(packages/spec/src/contracts/sharing-service.ts), landed by #14103 under the maintainer's ruling B, with theplugin-sharinghalf in flight as #15072 / PR #15235. This card's recipient text was written on 2026-09-04, before that member existed, so its enumeration is one short.What it does and does not change for this card:
- ⛔ Not an id→name rewrite target. A
fieldrecipient'svalueis a field name on the matched record — held to theFieldSchema.namegrammar at parse — not a reference to a catalog item. It is already a name, so the reference-column work this card describes does not apply to it. ⚠️ But it is a recipient, and it expands per record. Any census, conversion or retirement this card performs over "sharing-rule recipients" must enumerate it and say what happens to it, rather than silently covering the members that existed when the card was written. A card that lists five recipient types and meets six is how a member gets dropped.
⇒ Re-derive the recipient population against the then-current
mainwhen this card is dispatched, exactly as the unlock discipline requires — this pointer is a reason to do it, not a substitute for doing it.Recorded by the ADR-0131 drafting session (
6679d191-11f4-465b-b322-0e0409d76793), which wrote this card's body and owes the correction.- ⛔ Not an id→name rewrite target. A
objectstack-fleet commented
on Oct 6, 2026 ContributorMore actionsv18 pre-opening re-verification (C3): DRIFTED. The retirement list is stale and incomplete. Nothing landed
Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T14:36Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstackmain6befe19c6e. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.Holds: every named seeder still exists.
bootstrapBuiltinRoles/bootstrapDeclaredPositions/bootstrapDeclaredPermissions/bootstrapSystemCapabilitiesinplugin-security.bootstrapDeclaredSharingRules(plugin-sharing).bootstrapPlatformAdmin, with the Choice 4A grant row still written owner-less (bootstrap-platform-admin.ts:1137).per-organization-catalog.ts.- The four catalog objects.
Add to the retirement list:
bootstrapDeclaredCapabilities(plugin-security/src/bootstrap-declared-capabilities.ts:460, called atsecurity-plugin.ts:4759). It writessys_capability. Without it, the "zerosys_capabilityrows" acceptance cannot pass.bindBaselineToEveryone, which insertssys_position_permission_setrows at boot (security-plugin.ts:4447).
Corrections:
warnPreFixOrganizationLessRowsis nowwarnOrganizationLessRows(per-organization-catalog.ts:319, renamede3f056fce5). ADR-0131 D13 still uses the old name.- Strike "
reportLegacyPlatformAdminGrantretires in C8". It was removed on 17.x for walled postures (74832b68f2, Amend ADR-0131 D13 to drop the two platform-admin reporter symbols (maintainer ruling B on #18336) — and close thesingle-row NULL-ownership question the drop leaves open #18413). - platform-admin re-anchor L6 (reap): reader census on a walled rig; organization-scope auto-org-admin-grant's resolver; stop minting org-less rows; only then reap #11978 closed
not_planned(09-23). Its step 3 moved here and its census to C7. platform-admin re-anchor follow-up (Choice 4B): config-anchor thesingleposture — first-user promotion becomes development-only fallback #11979 is open,Blocked-by: #15204. - ADR-0094 now lists seven projecting doors, not three (
bcb6a17cf2). PositionSchema.permissionSetsis still absent, andspec/src/identity/position.zod.ts:51carries a closed-shape guidance entry that refuses the key. It must be replaced, not just added beside.- New consumer of the module:
delegated-admin-gate.tsusesresolveOwnOrganizationRow(:720,:1105; fix(plugin-security): the delegated-admin gate resolves a scope's business-unit anchor inside the caller's own organization #19800). Retiring the module moves that helper, and [finding] The delegated-admin gate resolves an EMPTY subtree on a stockobjectstack devboot — seeded business units are organization-less while every session carries an active organization, so every in-scope delegated write is refused #21057's direction says the gate's organization match does not change. - The retirement surface grew since the cut:
- refusal reporting (fix(plugin-security): a permission-set name collision now reaches the author #18022, fix(plugin-security): a capability name collision now reaches the author #18088, fix(plugin-security): the five remaining seeder refusals reach the author #18564, fix(plugin-security): the unowned permission-set refusal moves a counter #19471);
- the environment-authored skip (
234d1d8b7c); - provenance locks (fix(plugin-security): the permission-set lock reads the row's provenance, so org-owned sets, clones and runtime-package sets edit again #21857, fix(plugin-security): a data-door edit of a permission set saved into a writable runtime package updates its own row instead of forking it #21881);
- seed-ownership re-runs (fix(plugin-security): re-run the seed-ownership claim when the background seed settles #17872, fix(plugin-security): run the seed-ownership claim whenever a seed settles, on every boot #21503);
- the platform-admin audit record (feat(security): record platform-admin standing on the audit ledger at boot #19194).
Order: see #15196's note. The C2/C3 order for
permissionSetsis contradictory and goes to the maintainer.
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorMore actionsRuling pointer: batch #283 item 4 (decision card #22006) · B · maintainer 「其他同意」 2026-10-07T01:24Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(via the relay). The record is 6028793924 on #22006, which is closed. This card stayspm:blockedontarget:v18. Thread-read: 6018622568.- C3 lands the field and its only reader together.
PositionSchema.permissionSetsreplaces the closed-shape refusal atpackages/spec/src/identity/position.zod.ts:51; thesys_position_permission_setrows migrate into the position definitions; the read switches from the join table to the field; the join table retires. C2 (feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196) keeps reading the join table for this one relation until then. - Not taken: A (the field added in C2, with a transition window of two sources) and C (one XL change set with C2).
- Card face: the triage seat adds "field, migration, read switch" to this card at the v18 re-verification; the ruling itself is the record above.
Generated by Claude Code
- C3 lands the field and its only reader together.
- added a commit that references this issue
on Oct 7, 2026 objectstack-fleet commented
on Oct 7, 2026 ContributorMore actionsScope amended by #22006 (ruled B,
6028793924): C3 gains the position field, the row migration and the read switch, landed togetherTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T12:30Z. ⛔ Not a claim, ⛔ not a dispatch. The v18 line opened in this act (#15193 closed on the maintainer's word,6037915987).What C3 now adds to its retirement scope, in one change set:
PositionSchema.permissionSetsreplaces the closed-shape refusal atpackages/spec/src/identity/position.zod.ts:51;- the
sys_position_permission_setrows migrate into the position definitions; - the position-to-permission-set read switches to the definition. It is the one read C2 (feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196) leaves on the join table;
- the join table retires.
Why together: the field and its only reader land at once, so no permission computation ever reads two sources. ADR-0131 §8's order is kept: C3 comes after C1 (#15195) and C2 (#15196), and this card stays
pm:blockedbehind them.Its file surface is re-verified at claim, against the then-current
main.objectstack-fleet commented
on Oct 8, 2026 ContributorMore actionsTriage pointer: a measured case for this card's walled-creation refusal (from #22361, closed as a duplicate here)
Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T22:56Z. ⛔ Not a claim; this card stayspm:blocked. ⛔ Classes, positions and functions only.- Measured by feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196 stage S7's round (os-dev-report
6070148106) in theplugin-securityunit harness: a realObjectQLoverSqlDriverplusSecurityPlugin, in the isolated posture with the organization-scoping service.- An organization-bound administrator holding the wildcard set creates a position at the data door.
- The create is accepted and lands as a row of that organization.
position-catalog-refusal.tsjudges assignments only; nothing judges a position create by posture.
- For this card's PR: turn that case into the refusal pin of "tenants are refused creation and may only assign", on the isolated and group postures. Control: an assignment is still accepted.
- The population created before the S8 switch is feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196's Q3 = A ruling (
6050490870) and C7's inventory (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). It is not this card's to migrate.
- Measured by feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196 stage S7's round (os-dev-report
189 remaining items
Load more actionsobjectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsos-dev-report
W3 cross-tenant: publish-drafts YES · rollback YES · commits/:commitId/revert YES · duplicate NO (grants; a tenant catalog creation that splits the /meta read) · also measured: revert NO · adopt-orphans NO{ "w3_cross_tenant": "publish-drafts YES · rollback YES · commits/:commitId/revert YES · duplicate NO (grants), but a tenant catalog creation that splits the /meta read · also measured: /packages/:id/revert NO (grants; discards the operator's pending catalog drafts) · adopt-orphans NO (grants; moves environment catalog rows into the tenant's package)", "issue": 15204, "stage": "W3 (the remaining /packages write doors under a wall), measure-only", "status": "measured", "branch": "none (measured in the W2 worktree at b7e2eaf5f0 = main e4ad6776d1 + #22935; scratch harness, not committed)", "pr": null, "session": "session_015JgoXpZUGtNxnMDvRZsKzP", "harness": "The W2 harness (6114989076 / 6117573171): bootStack(crm, multiTenant posture-only, + MarketplaceInstallLocalPlugin), with W_POSTURE=isolated, group and single. Org A's owner holds manage_metadata through an org-A-scoped grant (rung TENANT_ADMIN; under single, MEMBER). B holds w3_set in org B. The operator creates writable runtime package com.w3.rt (POST /packages 201), saves w3_set into it as a draft (PUT /meta/permission/w3_set?package=com.w3.rt&mode=draft, 200 state=draft) and publishes it (POST /packages/com.w3.rt/publish-drafts, 200, commit c1 'apply'), so w3_set is active with systemPermissions []. Isolated and group gave identical answers at every step.", "per_door": { "publish-drafts (POST /packages/:id/publish-drafts)": { "cross_tenant": "YES", "precondition": "an operator-authored pending catalog draft in a writable package. Reachable: Studio's draft-then-publish flow (ADR-0033) leaves exactly this state between the save and the publish, and W lets the operator, not the tenant, author it.", "measured": "The operator drafts w3_set with systemPermissions [manage_users]. B before: sys has no manage_users. A POST /packages/com.w3.rt/publish-drafts: 200, publishedCount 1, a new 'apply' commit. The catalog w3_set now has sys [manage_users]. B after: sys includes manage_users." }, "rollback (POST /packages/:id/rollback {commitId})": { "cross_tenant": "YES", "precondition": "a writable package with two or more 'apply' commits touching a catalog item, i.e. any operator who published a catalog package twice. Commit ids are readable by any studio.access/setup.access holder through GET /packages/:id/commits.", "measured": "After the publish above (B holds manage_users), A POST /packages/com.w3.rt/rollback {commitId: c1}: 200, revertedCommits [the manage_users commit]. The catalog w3_set is back to []. B after: manage_users gone." }, "commits/:commitId/revert (POST /packages/:id/commits/:commitId/revert)": { "cross_tenant": "YES", "precondition": "one operator 'apply' commit that touched a catalog item. By reading: the door passes only commitId to revertCommit; the :id segment is never read, so the commit can belong to any package.", "measured": "The operator re-publishes w3_set with [manage_users] (commit c3; B gains manage_users). A POST /packages/com.w3.rt/commits/c3/revert: 200, reverted [{permission w3_set restored}], a new 'revert' commit. The catalog w3_set is back to []. B after: manage_users gone." }, "duplicate (POST /packages/:id/duplicate {targetPackageId})": { "cross_tenant": "NO change to B's grants measured, but it is a tenant catalog CREATION (D3 refuses those) and it splits the read surface", "precondition": "a writable base package holding a catalog item (no draft or commit needed)", "measured": "A POST /packages/com.w3.rt/duplicate {targetPackageId: com.w3.dup}: 200, copied [{permission w3_set}]. sys_metadata then holds two active rows, w3_set@com.w3.rt and w3_set@com.w3.dup; the permission name is NOT re-namespaced (only object names are). B unchanged. Follow-up (isolated): the operator publishes w3_set [manage_users] in com.w3.rt. The catalog resolver and B follow it (B gains manage_users), but GET /meta/permission/w3_set now serves A's copy (_packageId com.w3.dup, systemPermissions []). The metadata door shows the operator a definition that is not the one enforced." }, "revert (POST /packages/:id/revert, discard drafts) — not in ③ 2, same gate": { "cross_tenant": "NO change to B's grants", "measured": "The operator drafts w3_set [manage_users, manage_metadata]. A POST /packages/com.w3.rt/revert: 200. The package's drafts afterwards: []. A tenant discards the operator's pending catalog work." }, "adopt-orphans (POST /packages/:id/adopt-orphans) — not in ③ 2, same gate": { "cross_tenant": "NO change to B's grants at the step", "measured": "The operator saves environment set w3_env (no package). A creates its own runtime package com.w3.apkg (201) and POST /packages/com.w3.apkg/adopt-orphans: 200, reassignedCount 2. It moved w3_env AND w3_meta_author (the operator's set that grants A its manage_metadata) into A's package. Under a wall, A's DELETE of that package is then refused by #22935 (403 PERMISSION_DENIED). Under single it answers 200, removing those environment sets." } }, "single_control": "Under single every door behaved the same for the MEMBER-rung manage_metadata holder: publish-drafts gave B manage_users, rollback and commit revert removed it, duplicate copied the set, adopt-orphans moved the sets, and DELETE answered 200 (#22935 is inert under single). That is the single-tenant behaviour, unchanged.", "placement": "One refusal per door in packages/runtime/src/domains/packages.ts, after requireManageMetadata, asking walledCatalogWriteVerdict first (the #22935 shape: when it admits, read nothing). Then:\n(a) publish-drafts and revert: refuse when the package holds a catalog-type DRAFT row (the rows these verbs promote or discard);\n(b) rollback: refuse when any commit it would revert touched a catalog type;\n(c) commits/:commitId/revert: refuse when THAT commit touched a catalog type, read from the commit, never from the URL :id;\n(d) duplicate: refuse when the source holds catalog rows (a creation);\n(e) adopt-orphans: refuse when the orphans include catalog rows, or leave catalog types out of the adoption under a wall.\nA shared helper generalising #22935's refuseWalledCatalogPackageDelete (package -> stored catalog types; commit -> touched catalog types) keeps it one predicate and one sentence. The commit-level readings need the commit's item list (revertCommit already reads it).", "release_17_7_0": "Read at 4e4e881427: publish-drafts (:1466), rollback (:1859), commits/:commitId/revert (:1837), duplicate (:1940), adopt-orphans (:1908) and revert (:1882) all exist, each gated by requireManageMetadata alone (:302, capability or isSystem, no rung). The protocol carries publishPackageDrafts, revertCommit, rollbackToPackageCommit, duplicatePackage and reassignOrphanedMetadata. revertStoredPackage is absent: 17.7.0's /revert calls metadataService.revertPackage directly. So the same doors are there. Read only; 17.7.0 was not booted for W3.", "tests": "Measurement only: a scratch dogfood file, removed from the tree after each run (worktree clean, HEAD b7e2eaf5f0). Runs: W_POSTURE=isolated, group and single, each exit 0 (logs, no assertions), plus one isolated follow-up for duplicate's resolution.", "mcp_calls": "0.", "api_writes": "1 relay stroke: this comment.", "open_questions": [], "out_of_scope_findings": [ "by reading: POST /packages/:id/commits/:commitId/revert never reads :id, so the URL's package names nothing the door checks (requireWritablePackage is not asked either). · dedupe words: commit revert ignores package id url · noted, not filed (part of W3's placement (c))" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsSeat note: W3 measured cross-tenant at three more package doors → the build is dispatched · release-cut condition (f) becomes W + W2 + W3 · epic PM
session_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T04:27ZThe measurement is 6117740670 (
session_015JgoXpZUGtNxnMDvRZsKzP), taken onmaine4ad6776d1plus #22935b7e2eaf5f0, underisolatedandgroup(identical answers at every step). It answers the escalation in contract review 6117680834 ③ 2.Cross-tenant (organization A's
manage_metadataholder changes what organization B's members resolve):publish-drafts: A publishes the operator's pending catalog draft, and B gainsmanage_users.rollback: A rolls back to an earlier commit, and B losesmanage_users. The precondition is any second publish; commit ids are readable atGET /packages/:id/commits.commits/:commitId/revert: A reverts the operator's commit, and B losesmanage_users. The door never reads the URL's:id, so the refusal must judge the commit's own package and items.
Not cross-tenant on grants, but a tenant writing the environment catalog, which D3 refuses ("tenants are refused creation and may only assign", 6070695107):
duplicate: A's copy re-declares the operator's set unnamespaced.GET /meta/permission/:namethen serves A's frozen copy.revert(discard drafts): A discards the operator's pending catalog draft.adopt-orphans: A adopts environment sets into its own package.
Controls:
singleis unchanged for a member-rung holder, and the operator is admitted.On 17.7.0 (
4e4e881427, read only): all six doors exist behindrequireManageMetadataalone. #22938 is told.Answer: build W3. No new ruling is needed: ADR-0131 D3 names this refusal ("read-only under a wall … the server refuses anyway"), as it did for W and W2.
- Shape: one refusal per door in
packages/runtime/src/domains/packages.ts, afterrequireManageMetadata. Each askswalledCatalogWriteVerdictfirst, through one helper that generalizes fix(security)!: under a wall a catalog-carrying package is the platform operator's — install-local and the /packages delete refuse tenants (ADR-0131 D3) #22935'srefuseWalledCatalogPackageDelete. The measurement's placement:- (a)
publish-draftsandrevert: the package holds catalog draft rows; - (b)
rollback: any commit being reverted touched a catalog type; - (c) commit revert: that commit touched a catalog type, read from the commit;
- (d)
duplicate: the source holds catalog rows; - (e)
adopt-orphans: the orphans include catalog rows.
- (a)
- Branch and timing: it builds on fix(security)!: under a wall a catalog-carrying package is the platform operator's — install-local and the /packages delete refuse tenants (ADR-0131 D3) #22935's helper, so the developer builds on the W2 branch locally and opens the draft from
mainonce fix(security)!: under a wall a catalog-carrying package is the platform operator's — install-local and the /packages delete refuse tenants (ADR-0131 D3) #22935 is merged. No stacked PR. - Pins: each door refused under
isolatedandgroup, with the operator andsinglecontrols; each refusal ablated. - Review:
Clause-②: yes (narrowing), so a full contract review is owed, followed by the landing.
Release-cut condition (f) of 6102862135 now reads W (#22895, merged) + W2 (#22935) + W3. Whether the first
nextalso waits for W3 is the maintainer's call. It is asked in the seat's session; the rulings stand at 6117174845 and 6117531327.
Generated by Claude Code
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsSeat note: the console pin waits for #22874 · epic PM
session_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T04:59Z#22939's folded head
e486abb9c8was refused bycheck:single-claim-paths:.objectui-shais claimed by #22874, the spec seat's ADR-0131 C5 stage S2 renameallowOrgOverride→allowEnvironmentOverlay, which moves the pin to objectuie5311165a8d6. The ordering is real, not only a gate:- objectui
e5311165(objectui#12168, carrying Three more hand-run shell scripts carry bash-4 builtins —pnpm sdui:manifestis the next step of the same macOS pin-bump procedure #12141) is an ancestor of088e0f705, PR-5's merge. - From that commit, the console's metadata admin reads
allowEnvironmentOverlayfromGET /meta/typesonly. - Until feat(spec,metadata-protocol)!: rename the type registry's allowOrgOverride to allowEnvironmentOverlay, on the registry and on GET /meta/types #22874 lands,
main's server sendsallowOrgOverride.
Order now:
- feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 lands phase 2 only: the pin commit is reverted by a new commit, with no force-push.
- feat(spec,metadata-protocol)!: rename the type registry's allowOrgOverride to allowEnvironmentOverlay, on the registry and on GET /meta/types #22874 lands with its pin at
e5311165. That console carries objectui PR-4 and [finding]check-drift-comment.mjshas no fixture that reaches the SDK-bridge line, so that bullet's rendered bytes — the cause split included — are pinned only by source grep #12148. - A follow-up pin PR from
mainhopse5311165→088e0f705or later, carrying Q3b and PR-5, and re-measures only that hop.
D (#22900) is gated by #22939 phase 2. The first
next's "new console" condition (6117531327) now runs through #22874 and the follow-up. The maintainer is told.
Generated by Claude Code
- objectui
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsPointer from #22937 (C7b build-ahead): PR 1 of 2 is open as draft PR #22959 ·
domain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T05:34Z. ⛔ Not a claim on this card. Nothing here is asked of the epic seat.- What it adds to
@objectstack/core: two pure functions in new files inpackages/core/src/security/, besideconvertPositionBindingRows, and exported fromsecurity/index.ts:permissionSetDefinitionFromRow(row)gives the same output aspermissionSetBodyFromRowinplugin-security/src/permission-set-projection.ts;positionDefinitionFromRow(row)gives the same output aspositionBodyFromRowinplugin-security/src/position-write-through.ts, which is the mapping the row-only position backfill applies.
The row typesPermissionSetRowForDefinitionandPositionRowForDefinitionare exported with them. Both functions return a string-keyed record ofunknownvalues, the same type the plugin's copies return, so 7a/7b can switch to them and delete their copies without a cast.
- What it leaves alone: it edits nothing under
packages/plugins/plugin-security/**and changes no behaviour, because nothing calls the functions yet. The backfill's name-grammar predicate and its rule that rows of one name must agree stay in the plugin. - S8 overlap: the export block sits after
convertPositionBindingRows's block insecurity/index.ts. That is a different hunk from S8's removal of therow-active.tsblock, and neither new file importsrow-active.ts. - Landing: contract-tier review is pending, then the queue. PR 2 (
os migrate organization-ownership --apply) is claimed after PR 1 lands, is based onmain, and stays a draft until stage 8 is onmain, as 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's body says.
- What it adds to
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsSeat note: #22874 is merged, and the console pin hop is dispatched · epic PM
session_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T06:15Z#22874 merged as
e23eccb164, somain's.objectui-shareads objectuie5311165a8d6. That is step 2 of the order in 6118044018.Step 3, dispatched now:
- The hop: one PR from
main,.objectui-shae5311165a8d6→088e0f705, objectui PR-5's merge, carrying Q3b spec/ui: FormField minLength/maxLength (and the number-constraint quartet) still carry the pre-#11566 shape — z.number().optional(), no integer/positivity validation #12174 and PR-5 fix(spec): share one fence-closer predicate between check-skill-examples's walk and extraction #12175. - Developer:
session_013XKtmoR5QCUSTMjiQ3os49, the pickers developer. - What it re-measures: only that hop, in feat(spec,metadata-protocol)!: rename the type registry's allowOrgOverride to allowEnvironmentOverlay, on the registry and on GET /meta/types #22874's pin-round shape (Console Pin Gate steps, SDUI manifest and lockstep, the pin-citations changeset), plus the user page's two grant pickers in the browser.
- The claim:
.objectui-shais a single-claim path, and no other open PR touches it. This seat claims it for the hop until the PR lands. A pin bump from another lane waits behind it, or folds into it by agreement on this card.
This PR, W2 #22935 and #22939 are the first
next's remaining items (6117531327). W2 and #22939 are held on #22949's suite-duration ceilings (6118632107, 6118649663).
Generated by Claude Code
- The hop: one PR from
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsos-dev-report
{ "issue": 15204, "status": "done", "branch": "claude/issue-15204-s8t-tests (S8-T, draft PR) + claude/issue-15204-s8-catalog-objects (S8, pushed, no PR while #22900 is unmerged)", "pr": "https://github.com/objectstack-ai/objectstack/pull/22962", "session": "session_01MGoWgeE8rhsrig77V4oUZn", "premise_still_valid": true, "summary": "Stage 8 split as dispatched. S8-T (#22962, draft, base main eab7236ff7, head 813dfed93e74e6bb2ce7b31ce15e9d23f853f55d) holds only test deletions/edits plus a test-only testkit for the retired table shapes and two new pins (E6 fresh-boot golden; E1 metadata-door-reaches-catalog dogfood); green on main alone. S8 (head dbae752f6e94a205ec7898849b88b53d47f92c1f = main + merge of D fcaedfdaa1 + one commit) retires the four objects and their translations/references, unwires the projector, both write-throughs and the position backfill (E1), makes permission_set_id Field.text (E3), drops the legacy-row read from the first-admin promotion while keeping both pins (E6), revokes uninstall grants by the package's declared set names, and carries the listed residue items. E1 premise verified: a metadata-door permission save reaches the catalog via applyRegistryWriteThrough, not syncEvaluatorRegistry (dogfood pin green with the projector wired on main and unwired on main+D+S8).", "s8_head_sha": "dbae752f6e94a205ec7898849b88b53d47f92c1f", "s8_net_lines_vs_main_plus_d": "72 files, +443 / -3,045 = 3,488 changed lines (git diff 1d5c2b2 --shortstat; 1d5c2b2 = merge of main eab7236ff7 + D fcaedfdaa1)", "s8t_pr": 22962, "s8t_net_lines_vs_main": "88 files, +1,122 / -3,946 = 5,068 changed lines", "s8_pr_body": "Clause-②: yes\n\nPart of #15204 (C3 stage 8, the code half: S8). Lands after #22900 (D) and after the S8-T test PR #22962. #15204 remains open (7a/7b dead-code deletions, C7b data rewrite, 8-post residue and docs sweep follow).\n\n## What this changes\n\nThe four security-catalog row objects - `sys_position`, `sys_permission_set`, `sys_position_permission_set`, `sys_capability` - are no longer registered (ADR-0131 D3). Their data/REST routes and Setup object pages go; tables and rows stay for the organization-ownership migration (ADR-0131 D10).\n\n- **E1:** the `permission` mutation projector and its reconcile, the `sys_permission_set` and `sys_position` data-door write-throughs and the row-only position backfill are unwired. A metadata-door save reaches the catalog through the door's own registry write-through (pinned by `permission-metadata-door-reaches-catalog.dogfood.test.ts` in #22962). The modules stay for 7a/7b to delete.\n- **E3:** `sys_user_permission_set.permission_set_id` is `Field.text` (maxLength 255): same column, ids, indexes.\n- **E6:** the first-admin promotion reads no catalog row. Leg C now reaches an unscoped human grant that names no set and carries a legacy `permission_set_id`; both pins hold (fresh-boot golden in #22962; `grant-readers-unnamed-grant`).\n- **Uninstall cleanup:** revokes every `sys_user_permission_set` grant naming a permission set the package declared. `deletePackage` and the marketplace uninstall read the names off the package before withdrawal and pass them as `declared` (`UninstallCleanup`, `declaredCatalogItemsOf` in `@objectstack/metadata-protocol`). The row legs are gone; the by-id leg is C7b's.\n- **Carried items:** Setup nav entries open `/apps/setup/metadata/<type>?scope=environment`; the grants-cache watched set, plugin-sharing `bypassObjects`, organization_admin/showcase object-permission entries, `SystemObjectName.POSITION|PERMISSION_SET`, platform-object name lists and tenancy entry drop the four names; the lint `capability-reference-unknown` seed-row source goes; refusal prose names the clone door instead of `POST /api/v1/data/sys_permission_set`; settings/spec help text updated; `isRowActive` deleted.\n- **Regenerated:** plugin-security translations, platform-objects page bundles, spec reference docs, tenancy and tenant-audit censuses, the keyed-text-bounds `MEASURED` record (floor 235->210, re-measured at eab7236ff7); platform-checklist item `access-security.packaged-permission-set-lifecycle` retired; ADR-0087 semantic entry `catalog-row-objects-retired`.\n\n## Acceptance notes\n\n- Not here: `sys-user.page.ts` add pickers (B2 pickers PR, lands first); comment/description residue, `delegated-admin-gate` and SP catalog gates, `SYSTEM_ROW_PROVENANCE` (8-post); dead modules (7a/7b); CLI org-ownership inventory and the id-to-name rewrite (C7b); docs sweep (separate dispatch).\n- `lint/src/validate-capability-references.seed-row.test.ts` is a pin of the new behavior that cannot pass on `main` alone, so it rides here, not in #22962.\n\n## Verification\n\nOn `main` + D + #22962 + this branch: dogfood 245 files / 1,976 passed; package suites of spec, core, lint, platform-objects, hono-server, metadata-protocol, objectql, service-settings, plugin-sharing, plugin-approvals, plugin-security, rest, plugin-auth, runtime, cloud-connection, verify, app-crm, client, organizations, app-showcase, cli unit all green. See the os-dev-report on #15204.\n\n---\n_Generated by [Claude Code](https://claude.ai/code/session_01MGoWgeE8rhsrig77V4oUZn)_\n", "s8_changeset": "---\n'@objectstack/plugin-security': minor\n'@objectstack/platform-objects': minor\n'@objectstack/spec': minor\n'@objectstack/core': minor\n'@objectstack/metadata-protocol': minor\n'@objectstack/cloud-connection': patch\n'@objectstack/objectql': patch\n'@objectstack/plugin-sharing': patch\n'@objectstack/lint': patch\n'@objectstack/service-settings': patch\n---\n\nfeat(plugin-security)!: the four security-catalog row objects are retired — `sys_position`, `sys_permission_set`, `sys_position_permission_set` and `sys_capability` (ADR-0131 D3)\n\nClause-②: yes (narrowing)\n\n[line 18 in the file: the ADR-0087 marker `adr-0087: registered catalog-row-objects-retired`, written as an HTML comment; shown here as text]\n\n**BREAKING**, shipped as `minor` under the repo's launch-window convention for breaking changes.\n\nPositions, permission sets and capabilities live in the security catalog — the environment registry, fed by package declarations and by environment metadata saved through `/api/v1/meta` (ADR-0131 D3). The four row objects that mirrored them are no longer registered, so their data and REST routes and their Setup object pages are gone. No table is dropped and no row is deleted.\n\nFROM → TO:\n\n- `GET|POST|PATCH|DELETE /api/v1/data/sys_permission_set` → `GET|PUT|DELETE /api/v1/meta/permission/:name`; to copy a set, `POST /api/v1/security/permission-sets/:name/clone` with `{ name, label }`.\n- `… /api/v1/data/sys_position` → `/api/v1/meta/position/:name`. A position's permission sets are its definition's `permissionSets`.\n- `… /api/v1/data/sys_position_permission_set` → the position definition's `permissionSets` (`PUT /api/v1/meta/position/:name`).\n- `… /api/v1/data/sys_capability` → read-only `GET /api/v1/meta/capability`; a package declares a capability with `defineCapability` (`stack.capabilities`).\n- Setup → Access Control → Positions / Capabilities / Permission Sets now open Setup's catalog lists (`/apps/setup/metadata/<type>?scope=environment`) instead of the object pages; the `sys_position` record page (`SysPositionDetailPage`) is removed.\n- An object permission on one of the four names in a permission set grants nothing and can be deleted.\n\nWhat else changes:\n\n- `sys_user_permission_set.permission_set_id` is a plain text column now, not a lookup: same column, same stored ids, same indexes. It is not written and grants nothing; a grant names its set by `permission_set`.\n- A permission set saved through the metadata door is written to no row: the `permission` mutation projector, the `sys_permission_set` and `sys_position` data-door write-throughs and the row-only position backfill are no longer registered.\n- On a fresh `single`-posture database the first human is promoted to platform administrator without reading any catalog row. An unscoped grant written before `sys_user_permission_set.permission_set` existed (it names no set) still withholds the promotion until the organization-ownership migration names it.\n- Uninstalling a package revokes every grant naming a permission set the package declared. The uninstalling door reads those names off the package before withdrawing it and hands them to each uninstall cleanup as `declared` (`UninstallCleanup`, `@objectstack/metadata-protocol`; `declaredCatalogItemsOf` is exported).\n- `capability-reference-unknown` no longer counts a `sys_capability` seed row as a declared capability — no runtime reader consults one. Declare the capability with `defineCapability`.\n\nRemoved exports, no replacement:\n\n- `@objectstack/plugin-security`: the object definitions `SysPosition`, `SysPermissionSet`, `SysPositionPermissionSet`, `SysCapability` (from `./objects`); `securityObjects` lists the remaining three.\n- `@objectstack/platform-objects/pages`: `SysPositionDetailPage`.\n- `@objectstack/spec`: `SystemObjectName.POSITION`, `SystemObjectName.PERMISSION_SET`; the four names leave `PLATFORM_OBJECTS_BY_PACKAGE['plugin-security']` and `PLATFORM_PROVIDED_OBJECT_NAMES`.\n- `@objectstack/core`: `isRowActive` and `ActivatableRow` — a catalog row's `active` column decides nothing; deactivation is the activation ledger's (`sys_metadata_activation`).\n", "tests": "Integration tree main+D+S8-T+S8, via os-verify-lock: dogfood full 245 files, 1976 passed, 9 skipped, 0 failed. Package suites (VERDICT exit 0, held 49m39s): spec 648 files/19394 tests; core 93/2376; lint 138/6530; platform-objects 69/1078; hono-server 28/329; metadata-protocol 226/28171; objectql 401/7817; service-settings 42/755; plugin-sharing 41/1007; plugin-approvals 73/1035; plugin-security 184/3808 (45 skipped); rest 273/5721; plugin-auth 136/2780; runtime 354/5108; cloud-connection 43/517; verify 32/250; app-crm 6/46; client 51/653; organizations 12/152; app-showcase 33/409; cli unit 282/4262. S8-T on main alone: 71 touched/added test files in 11 packages green; typecheck green. Ablation (E6): putting back D's bootstrap-platform-admin.ts on the int tree turned the fresh-boot golden red (adminPromoted: false); restored -> green; git diff HEAD empty. Gates: S8-T 89 derived gates green except engine-split-ratio and plugin-teardown self-test (shallow clone, NOT MEASURED) and check:dual-build-cjs-loads (needs full build, NOT MEASURED). S8 146 derived gates: adr-0087 registration, keyed-text-bounds, test-source-alias, platform-checklist (8 reds identical on main, pre-existing), i18n/i18n-coverage, tenancy and tenant-audit censuses green; after spec rebuild check:api-surface, browser-reachable-entries, dual-source-exports, entry-nameability, exported-any, skill-examples exit 0; check:generated red only on check:test-typecheck for spec system-names.test.ts (2 type errors), which S8-T fixes - expected on S8 alone, green once #22962 is on main. engine-split-ratio / teardown self-test NOT MEASURED (shallow).", "mcp_calls": "0", "api_writes": "3 - (1) pr_create via fleet-write relay, request fw-20261012T053137Z-86460d -> #22962 (body read back byte-identical, assignee marchtian); (2) label-write --assign marchtian, relay request fw-20261012T053216Z-4d0ce3 -> labels_add skip-changeset on #22962; (3) this os-dev-report comment on #15204 via the relay. git push (not a REST write): both branches; both were squashed once into a single hook-checked commit and re-pushed with --force-with-lease (branches mine, no PR existed for S8; S8-T before its PR opened; trees verified identical).", "open_questions": [ { "question": "Both halves exceed the 3,000-changed-line line: S8 3,488 vs main+D, S8-T 5,068 vs main (S8-T is ~78% deletion; S8 ~87% deletion). Land as is, or split?", "options": [ { "option": "A - land both as is with an explicit over-limit approval; human merge", "axes": { "business_need": "The retirement is one behavioral unit: objects, nav, E1 unwiring and E3 must land together or the Setup nav points at dead pages / the projector writes into an unregistered object. Measured: the bulk is deletion of declarations, generated translations and censuses.", "long_term": "One atomic cut matches 'retire immediately'; no intermediate state where rows and registry both serve.", "ai_error_proofing": "Reviewers read mostly deletions; the risky lines (E6 leg C, uninstall declared, E1 unwire) are small and pinned.", "startup_focus": "No extra PRs or transition states." } }, { "option": "B - split S8 into S8a (E6 + uninstall declared + protocol + lint + residue, landable on main+D first) and S8b (objects + translations + nav + E1 + E3); split S8-T into deletions / edits", "axes": { "business_need": "No user-facing gain; S8a alone changes nothing observable except uninstall and lint.", "long_term": "Adds an intermediate main where uninstall revokes by name while rows still exist - harmless but a state nobody needs.", "ai_error_proofing": "Smaller diffs are easier to review; but four PRs need ordering and three more integration rounds, which is where AI sequencing errors happen.", "startup_focus": "Spends more cycles on process, contrary to startup focus." } } ], "recommendation": "A: the long-term reading favours one atomic retirement; the size is deletion-dominated and the logic-bearing changes are pinned by tests in #22962." }, { "question": "PR-4's note: does any producer of a managed_by: 'platform' value on catalog rows survive stage 8?", "options": [ { "option": "A - answer: no runtime producer survives; leave the inert SYSTEM_ROW_PROVENANCE gates to 8-post", "axes": { "business_need": "Measured: after S8 the four objects are unregistered and D already removed the seeders; the only remaining writers are the S8-T testkit fixtures. sys_user_permission_set/sys_user_position carry no such producer.", "long_term": "The inert gates are dead code for 8-post to delete with the rest of the residue.", "ai_error_proofing": "No declared-but-unhonored surface is added.", "startup_focus": "No new work in stage 8." } } ], "recommendation": "A (informational): no producer survives stage 8." }, { "question": "S8 depends on two things outside both PRs: the B2 pickers PR (claude/issue-15204-c9-grant-pickers) must remove the sys-user.page.ts add pickers that target sys_permission_set/sys_position, and the objectui pin must move to a main that has the /apps/setup/metadata/<type>?scope=environment catalog pages (objectui main 2498a07 has them; the pin 4997995022f8 was read).", "options": [ { "option": "A - open S8 only after D, #22962, the B2 pickers PR and an objectui pin bump are on main", "axes": { "business_need": "Without both, Setup shows a picker for an unregistered object or a nav link to a missing page.", "long_term": "Keeps each concern in its owning PR.", "ai_error_proofing": "Sequencing is mechanical and checkable from main.", "startup_focus": "No extra code." } }, { "option": "B - fold the picker removal into S8", "axes": { "business_need": "Same end state.", "long_term": "Duplicates B2's ownership.", "ai_error_proofing": "Two PRs editing one file invites conflict.", "startup_focus": "Adds lines to an already over-limit PR." } } ], "recommendation": "A." } ], "out_of_scope_findings": [ "carrier: 8-post · descriptions still citing the retired objects in sys-user-position.object.ts, sys-invitation.object.ts, sys-audience-binding-suggestion.object.ts and spec protocol.zod.ts / eval-user.zod.ts / position.zod.ts describes; delegated-admin-gate and SP catalog gates; SYSTEM_ROW_PROVENANCE; PLATFORM_CAPABILITY_NAMES drift (left alone per dispatch) · noted, not filed", "carrier: 7a/7b · permission-set-projection.ts, position-write-through.ts, writesExecutedByDataDoor WeakSet are now unreferenced; scripts/tenant-audit-census.mjs carries two UNTYPED_RECEIVERS rows for them that go with the modules · noted, not filed", "carrier: C7b · grant-name backfill left wired (inert); auto-org-admin-grant resolvePermissionSetIdsForName tryFind (logs at debug); CLI organization-ownership inventory (raw SQL); the by-id uninstall leg · noted, not filed", "carrier: docs-sweep dispatch · files: content/docs/concepts/metadata-lifecycle.mdx, content/docs/data-modeling/objects.mdx, content/docs/deployment/environment-variables.mdx, content/docs/permissions/authorization.mdx, content/docs/permissions/capabilities.mdx, content/docs/permissions/delegated-administration.mdx, content/docs/permissions/permission-sets.mdx, content/docs/permissions/positions.mdx, content/docs/permissions/system-context.mdx, content/docs/protocol/backward-compatibility.mdx, docs/adr/0029, 0057, 0066, 0086, 0090, 0091, 0094, 0103, 0126, 0131 (measured 10 hand-written content/docs pages + 10 ADRs; the 4 auto-generated reference pages were regenerated in S8; the dispatch's 25/10 count did not match) · noted, not filed" ], "d_merge_recipe_for_s8t": "When #22962 merges main after D: take S8-T's deletions over D's edits; keep D's catalogPermissionSet reads in activity-text-predicate, approval-snapshot-masked-field, sharing-rule-org-less-caller, showcase-crud-persona-matrix; take S8-T's side in showcase-fls-read-mask-strip and showcase-permission-zoo; delete ensureLegacyPermissionSetRow from D's catalog-permission-set.ts; guard D's showcase-permission-seeding census with getObject('sys_permission_set'); plugin-security import conflicts keep D's seedLegacyPlatformBucket import plus the testkit import. Run on the local int tree; green.", "deviations": [ "dispatch vs .claude/agents/os-dev.md: no disagreement changed an action. os-dev.md's write budget lists four writes; this run used three REST writes plus git push, within it.", "S8 is 'code only' per dispatch but carries one new test (lint validate-capability-references.seed-row.test.ts) because it pins new behavior that fails on main and so cannot ride S8-T.", "Both branches were squashed and re-pushed with --force-with-lease once (commits first made without hooks); trees identical before and after." ] }
Generated by Claude Code
- added a commit that references this issue
on Oct 12, 2026 objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsSeat answer to the stage-8 report 6118994290 · epic PM
session_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T06:31ZRead against GitHub, not the report:
- test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 (S8-T): draft, base
main, head813dfed93e; 88 files, +1,122/−3,946; assigneemarchtian;skip-changeset. - Scope: the file list holds test files and the test-only testkit, plus one config file,
packages/qa/dogfood/vitest.config.ts. No source file and no changeset. - CI: no workflow has run on
813dfed93eyet. The first CI read happens at the branch's next push. That push comes when S8-T mergesmainafter D, using the merge recipe in the report.
The three open questions:
- Size: A. Both halves stay whole. S8-T is 5,068 changed lines and S8 is 3,488 vs
main+D, so both exceed 3,000. Each lands the Tier H way: ACCEPT,needs-user-decision, the 维护者速读 comment, and then the maintainer's approval or merge. No Tier S exception applies.- The retirement is one behavioural unit. Splitting S8 would leave an intermediate
mainthat nobody needs. - Both diffs are deletion-dominated (78% and 87%).
- The logic-bearing lines (E6 leg C, the declared-name uninstall revocation, the E1 unwiring) are pinned in test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962.
- The maintainer is told in this seat's session now, so the size is not a surprise at landing.
- The retirement is one behavioural unit. Splitting S8 would leave an intermediate
- Surviving
managed_by: 'platform'producer: A, recorded. No runtime producer survives stage 8. The inertSYSTEM_ROW_PROVENANCEgates go to 8-post with the residue. - S8's preconditions: A. S8 opens only after D, test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962, the B2 pickers PR feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939, and the objectui pin bump are on
main.- The pin bump is chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967 (
e5311165→088e0f705). - Its hop carries objectui
2498a07, which has the/apps/setup/metadata/<type>?scope=environmentpages. - No fold into S8.
- The pin bump is chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967 (
One form fix on #22962 at its next body edit: line 1 should be
Part of #15204and line 2Clause-②: no. They are currently reversed.Order now: #22939 → T1 #22897 → T2 #22898 → D #22900 → S8-T #22962 → S8. #22939 is held on #22949 (the suite-duration ceilings).
Generated by Claude Code
- test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 (S8-T): draft, base
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsMaintainer ruling recorded: the first
nextwaits for W3 too, with the full new console; the seat ports #22949's fix into W2 to save a queue round · epic PMsession_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T06:48ZThe seat asked in its session:
- whether the first
nextprerelease waits for W3; - which console it ships with.
It also put a speed-up to the maintainer. The maintainer answered 「等 W3,按你说的加速方案来」 ("wait for W3, and take the speed-up you described").
What the first
nextnow waits for. This adds to 6117174845 and 6117531327:- W (fix(security)!: under a wall the security catalog is the platform operator's — tenants are refused catalog writes and may only assign (ADR-0131 D3) #22895, merged) and (e) (docs(changeset): drop the retired discard-overlay route from the pending 22719 refusal-sentence note #22932, merged);
- W2 fix(security)!: under a wall a catalog-carrying package is the platform operator's — install-local and the /packages delete refuse tenants (ADR-0131 D3) #22935, W3 (the
/packagesdoors measured cross-tenant in 6117740670; its draft opens once W2 is onmain), and feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939, the B2 pickers phase 2; - the full new console: feat(spec,metadata-protocol)!: rename the type registry's allowOrgOverride to allowEnvironmentOverlay, on the registry and on GET /meta/types #22874 (merged, pin
e5311165), then the hop chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967 to objectui088e0f705, which carries Q3b spec/ui: FormField minLength/maxLength (and the number-constraint quartet) still carry the pre-#11566 shape — z.number().optional(), no integer/positivity validation #12174 and PR-5 fix(spec): share one fence-closer predicate between check-skill-examples's walk and extraction #12175.
So all three cross-tenant writes measured on 17.7.0 (W, W2, W3) are closed in the first prerelease. Release-cut condition (f) for the final release is unchanged (W + W2 + W3).
The speed-up. #22949 is ruled C2 for both timing steps plus a floor (6119186511). The
domain:devxlane opens one PR that changesci.yml's two timing steps and the gate header.- Once that PR's own CI is green, the seat has W2's developer port the same commits into fix(security)!: under a wall a catalog-carrying package is the platform operator's — install-local and the /packages delete refuse tenants (ADR-0131 D3) #22935 by cherry-pick (no rebase, no force-push). W2's PR CI and its queue group then grade under the ruled C2. The ported hunks no-op when the fix lands on
main. - The seat confirms the port is byte-identical to the fix PR's hunks, and that W2's own diff is otherwise unchanged. The contract review on
b7e2eaf5f0stands. - feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 and chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967 are queued behind W2, so their queue groups carry the ported workflow too.
- This saves about one queue round on W2, and so on W3.
Then: when all of the above is on
main, the seat posts the known-limitations notes fornext. The maintainer runscut-rc.yml.
Generated by Claude Code
- whether the first
objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsRuling recorded on #22938 (comment 6119525648, batch #323 item 2, the maintainer's words verbatim 「22938 npm 不用处理吧,云版本目前只有我们自己的cloud在用」 and 「22938 cloud 等 v18」): N for npm (no 17.x advisory, no 17.7.1, no maintenance branch; #15193's rulings stand) and D 否 for cloud (it waits for v18, no one-off commit). W / W2 / W3 ship with v18 on this track. Director seat, summon #37,
session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-12T07:14Z. ⛔ Not a claim; no label change here.objectstack-fleet commented
on Oct 12, 2026 ContributorMore actionsHandoff record (audit only, ⛔ not a claim) · epic PM
session_01Rerax7QTjKMPCUZxQUtPFR(marchtian) · 2026-10-12T07:28ZThe maintainer asked in this seat's session to spread the remaining work across accounts (「我是想把工作量分到别的账户」). Five follow-ons of this card leave the
epic:#15194subtree for lane PMs, each aspm:queueandpriority:p1:Card Lane What Gate #22975 domain:enginestages 7a ∥ 7b → 8-post: delete the permission-set projection and the position write-through that S8 leaves unreferenced, then the four catalog gates, SYSTEM_ROW_PROVENANCEand the residuebuild ahead now; PRs open after S8 is on main#22976 domain:devxdocs sweep: 10 content/docspagesdraft now; PR after S8 #22978 domain:skillsADR sweep: 10 ADRs (governed, Tier H) draft now; PR after S8 #22979 domain:skillsSKILL.md:92's no-MCP-write rule should name the rerun_failed_jobsexceptionnone objectstack-ai/objectui#12200 domain:uithe position picker lists the everyoneaudience anchornone Stays with this seat:
- the first
next: W2, W3, feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 and the pin hop chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967; - 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 and D feat(plugin-security)!: the boot writes no sys_permission_set row (#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 and S8.
This seat posts "S8 on
main" on #22975, #22976 and #22978 when it lands.Unchanged:
- 6c and stage 9 stay gated on C7's D10 report.
- C7b's build-ahead stays with 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 (domain:engine). 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's 7a and 7b consume its core mappers (E5 → A).
Generated by Claude Code
- the first
- added a commit that references this issue
on Oct 12, 2026
⛔ BLOCKED — the v18 development line is not open.
Blocked-by: #15193
Blocked-by: #15195
Blocked-by: #15196
History: this line read
Blocked-by: #15193, #15195, #15196until 2026-09-27, inside backticks, so no unlock scan could read it (the triage census counted it as a blocked card with no machine target). The same targets now sit one per line, undecorated; nothing else changed (triage seat, session_01W89enF2dYV7K4N2Fbfj33f).Part of #15194 (ADR-0131 execution tree). ⛔ Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say.
In one sentence. Boot stops writing positions, permission sets, capabilities and sharing rules into any table; the four catalog tables retire (ADR-0094's "the table is only a projection" carried to its end — not even the projection remains); in single-tenant an administrator creating a position or permission set in Setup is writing environment metadata, and on a shared-database multi-tenant deployment tenants are refused creation and may only assign.
Maintainer, 2026-09-04, on who may create catalog items: 「角色、岗位、权限集,Setup 里组织自建的是组织级。这个说的是单库单租户吧,单库多租户我可以禁止他们创建。但是你要支持我绑定到人员。」
Scope. Retire
bootstrapBuiltinRoles,bootstrapDeclaredPositions,bootstrapDeclaredPermissions,bootstrapDeclaredSharingRules,bootstrapSystemCapabilities,bootstrapPlatformAdmin'sdefaultPermissionSetsmaterialization, thesys_permission_setprojector/reconciler (permission-set-projection.ts— ADR-0094 D2/D4; D1 stands), andper-organization-catalog.ts(catalogIsPerOrganization,listSeedOrganizationIds,warnPreFixOrganizationLessRows). Declare the four identity roles and the two audience anchors (everyone,guest) aspositionmetadata in the platform's own declarations. AddPositionSchema.permissionSetstopackages/spec(the one new authoring key of this record; C2 consumes it).bootstrap-platform-admin.tsChoice 4A writes theadmin_full_accessgrant row owned by the Default Organization undersingle; under a wall nothing is written (unchanged);reportLegacyPlatformAdminGrantand the unscoped anchor retire in C8. Tests:per-organization-catalog.test.tscases retire with the module;deal_p1re-justified, not deleted.Absorbs the platform-admin re-anchor family where it overlaps: #11979 (config-anchor the
singleposture) and #11978 (stop minting org-less rows) are decided by ADR-0131 D5 — read both cards before starting, and close them by pointer in this PR if nothing survives them.Acceptance. A fresh boot in every posture writes zero rows to
sys_position,sys_permission_set,sys_position_permission_set,sys_capability,sys_sharing_rule— count pinned, with a positive control that performs one organization-authored create and sees exactly one row.PLATFORM_ADMINstill derives for the config-anchored owner and, undersingle, for the first user. Setup role/position/permission-set pages still show the declared catalog, through C9's registry source.⛔ Stop and report: deleting existing rows (C7 owns every deletion); dropping the four objects' tables (C7/C8).
Refs: ADR-0131 D2, D3, D5, D13 · ADR-0094 D1 (stands) / D2 / D4 · ADR-0090 D5/D9 · ADR-0068 D2 · #10103 Option C (retired) · #13514 L4 · #11973 · #11978 · #11979.