Repository navigation
platform-admin re-anchor follow-up (Choice 4B): config-anchor the single posture — first-user promotion becomes development-only fallback #11979
Description
Sequenced follow-up ruled, not optional, in #11663's acceptance (Choice 4: 「4A for the first landing, with 4B filed as the sequenced follow-up」). Provenance: design document = #11663 comment 5394453215 (§4 Choice 4, migration step 8); maintainer acceptance = #11663 comment 5404675670 (2026-08-25, verbatim 「接受你的建议,继续」). Filed by PM session session_01KWRU3s15AJz7PGW7a7wdCh.
Re-derived by the epic seat (epic:#15194): the Blocked-by: #15204 line that stood here is removed. C3's code this card depends on has landed, and the one C3 item left for it, the Default-Organization ownership of the promotion grant, is this card's own acceptance. It is dispatched as C8 stage 8b-0a (plan 6251466182 on #15212).
⛔ Blocked-by: #11974 was struck 2026-09-01 — that leg is SPENT. #11974 closed 2026-08-31T01:36:53Z, so the edge could never fire again while it sat here advertising an unmet dependency. Struck by the domain:engine seat (session session_01Q5WBDtaUnoz5XuJ6jk8pQ5) on the half-state patrol's H19 row, which reads a partial discharge and reports it rather than deciding it.
pm:blocked — on #11975, which is in turn the sound half of a mutual-Blocked-by deadlock with #13515 that was repaired on #13515 on 2026-09-01. ⇒ This card waits on a card that is waiting on a card. A single-level unlock predicate cannot see past one hop, so re-derive this blocker when the #11978 → #11975 → #13515 chain clears — ⛔ do not read #11978's closure alone as this card's release without re-reading the chain.
Content: single posture keeps its zero-config first-user promotion. What changes is the grant row's owner, ⛔ not its existence: the admin_full_access row that promotion writes becomes owned by the Default Organization instead of carrying a NULL organization. That ownership change is C3's, on the v18 line. OS_PLATFORM_OWNER_EMAIL remains the walled-posture channel and is ⛔ not required for a single deployment to have an administrator.
⭐ The previous Content — 「first-user promotion survives in development only; production single deployments derive platform admin from OS_PLATFORM_OWNER_EMAIL like walled ones」 — was #11663 Choice 4B as accepted 2026-08-25. That acceptance is reversed on this point by the ruling.
Constraints: the posture branch stays inside the one derivation site (the 4A mitigation is absolute — if it cannot be held, this card's priority rises); zero-config pnpm dev:crm / packages/verify harness flows keep working via the development-only fallback; the product promise change for production single (config now required for admin) gets its own loud migration note, same discipline as L5.
Discipline: Clause-② expected yes; needs:contract-review at review.
Acceptance criterion: single boot with no config still promotes the first user, and the admin_full_access grant row it writes is owned by the Default Organization — ⛔ never a zero-admin boot. The walled/single derivation stays verifiably one code path with a posture parameter, ⛔ not two sites.
⭐⭐ The timing qualifier is load-bearing and is ADR-0131 D5's own, taken verbatim from origin/main 031e5fbfa3 (docs/adr/0131-total-organization-ownership-no-null-organization-id.md:363-364), ⛔ not from the ruling's quotation of it:
…so no NULL grant row is ever produced once C3 has landed; until then the
singlerow carries the NULL organization it carries today, and D10's migration is what clears it.
⇒ ⛔ 「No NULL-organization grant row exists」 is NOT a test that can pass before C3 lands. A taker asserting it on today's tree will be asserting something D5 says is false until C3. The acceptance test before C3 is that the row is written and owned as D5 prescribes once C3 has landed, with D10's migration clearing the pre-C3 rows — ⛔ not that no NULL row is present.
⏹️ DISCHARGED 2026-09-18 05:39 UTC — the letter arrived. The maintainer ruled A on #18707 (2026-09-18 05:13 UTC, director seat summon #24, maintainer 「同意」) and the Content and Acceptance criterion above have been rewritten accordingly by the domain:engine execution seat. ⛔ The note below is kept verbatim as the audit trail of why this seat declined to edit them earlier; ⛔ it is no longer an instruction. single (config now required for admin) gets its own loud migration note」 — that clause is premised on the reading the ruling just reversed. ⛔ This seat did not edit it, because the ruling names exactly two sections and widening it is the maintainer's call, ⛔ not a PM's. ⇒ A taker must read that clause as superseded, and it is flagged here rather than silently corrected.
domain:engine execution seat (session_01CqmCgU5RGDoJYhHUMVp2af) out of #18707. #18411 (filed at the maintainer's direction) rules that two cards state their goal as 「config-derived standing is the only channel」, which is wider than ADR-0131 requires, and directs that both bodies be corrected — ⛔ 「wording only, no scope change」. Its sibling half landed cleanly: #18336 carried that sentence literally and one clause was swapped. This card never carried it. Measured: the phrase occurs 0 times in this body, against a firing control of 1 occurrence in #18336 on the same instrument — so the zero is a reading, ⛔ not a dead grep. What stands here instead is the Content sentence (「production single deployments derive platform admin from OS_PLATFORM_OWNER_EMAIL like walled ones」, first-user promotion 「in development only」) and the Acceptance criterion (「a production-mode single boot with no config has zero platform admins」). ⭐ Those say the same thing #18411 objects to — and they are this card's scope, ⛔ not its phrasing. Rewriting them would reverse a deliverable the maintainer accepted on 2026-08-25 (#11663 Choice 4, comment 5404675670) in favour of a later record, ADR-0131 D5, which keeps the single-posture first-user promotion and only changes the row's owner (「No NULL grant row is ever produced」). ⇒ ⛔ This seat did NOT edit the Content or Acceptance criterion, because choosing between two governing records is the maintainer's call and ⛔ never a PM's. The question is routed on #18707. ⇒ A taker must not read the Content and Acceptance criterion above as settled until that letter arrives.
Generated by Claude Code
Activity
admin_full_accessbecomes a kernel metadata declaration; WHO holds it comes from env-configured verified emails — retiring the org-less row anchor #11663baozhoutao commentedon Sep 3, 2026
Cross-lane pointer from the
repo:cloudseat (sessionsession_017Wu48ZSjk7HJjyJmGNBtUk, 2026-09-03) — record lives elsewhere, this is the accelerator: the cloud seat's review of L8 (objectstack#11977, now aneeds-user-decisioncard; fork on #11663 comment 5521187539) measured that landing this card (Choice 4B) before the hosted tenant runtime's admin anchor moves silently locks every cloud tenant owner out of their own environment — cloud confers standing today by writing the legacy unscopedadmin_full_accessrow (env-owner-admin-grant.ts:67/:91), the write keeps succeeding after 4B and simply stops conferring, and the writer swallows its own errors. ⛔ Not a label change from this seat; the sequencing rider is put to the maintainer on #11977. Suggest this card's lane reads that decision before dispatching.Generated by Claude Code
hotlong commentedon Sep 4, 2026
Pointer, and a correction to an easy misreading: ADR-0131 does NOT decide this card. Reading it as decided would land the opposite of what its C3 card builds.
ADR-0131 D5 rules that platform standing is configuration — which sounds like this card's Choice 4B. It is not the same question, and on this card's actual question the record leans the other way:
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 (C3)'s acceptance criterion, verbatim from the card: "PLATFORM_ADMINstill derives for the config-anchored owner and, undersingle, for the first user." That is Choice 4A preserved, not 4B. ADR-0131 keeps first-user promotion undersinglebecause nothing in the ownership model needed it removed — the record changes who owns the grant row (the Default Organization, D5), not who becomes platform admin.singleshould requireOS_PLATFORM_OWNER_EMAILand demote first-user promotion to a development-only fallback. That is a product-promise change with its own migration note, and it stays open.⛔ So: do not close this card as absorbed, and do not treat C3's landing as 4B being done. Conversely, whoever dispatches #15204 should not quietly implement 4B on the strength of D5 — if they think D5 forces it, that is a
needs-user-decisionmoment, not a judgement call inside a refactor.State: unchanged —
pm:blockedon its existing chain (the transitive wait through #11978 → #11975 → #13515 still needs re-deriving; ⛔ #11978's closure alone is not this card's release). Not moved behind the v18 gate: it is not ADR-0131 work.Refs: ADR-0131 D5 (platform standing is configuration; the
singlegrant row is owned by the Default Organization) · #15204 (C3, preserves 4A) · #11663 Choice 4.docs(adr-0131): amend D13's reach — the legacy-anchor retirement leav…
huangyiirene commentedon Sep 18, 2026
Ruling quoted here so the reversal is findable — the Content and Acceptance criterion above were rewritten under it 2026-09-18T05:39Z.
domain:engineexecution seat ·session_01CqmCgU5RGDoJYhHUMVp2af·Seat: domain:engine#1· R5 · executing #18707.The ruling
Source: #18707 comment
5725504264— director seat, summon #24,session_01Wj1HUjzyeiBQ8atRf1ZhaL; maintainer 「同意」 2026-09-18T05:13Z, batch #155 item 5, letter A.Governing text:ADR-0131 D5.What this seat changed, and what it did ⛔ not
<sub>noteBlocked-by: #11978pm:blocked,domain:engine, open, no assignee⭐⭐ One completion of the ruling's quotation, ⛔ not a re-ruling
The ruling renders D5's clause as 「⛔ no NULL-organization grant row is produced」. Re-measured verbatim on
origin/main031e5fbfa3,docs/adr/0131-total-organization-ownership-no-null-organization-id.md:363-364 — ⛔ not copied from the ruling:⇒ The rewritten Acceptance criterion carries 「once C3 has landed」. Without it, the criterion would be false on today's tree, and a dev implementing #11979 would assert a state D5 itself says does not hold before C3. ⛔ The ruling's direction is unchanged; only its quotation is completed. (Charter basis for re-measuring rather than copying: SKILL.md 「搬自任何工件(含己文)本轮未亲测…重测或注「未验证」」 and the newly landed 「裁决点名文件/符号/行/调用形状的条款,逐条带读数或注「未验证」」.)
The Constraints paragraph still reads 「the product promise change for production
single(config now required for admin) gets its own loud migration note」. That clause is premised on exactly the reading this ruling reverses.⛔ This seat did not edit it: the ruling names two sections, and widening a ruling is the maintainer's call, ⛔ never a PM's. ⇒ It is flagged in the body's discharged note and here, so a taker reads it as superseded and the maintainer can settle it in one line if they wish.
⛔ All readings at
origin/main031e5fbfa3, 2026-09-18T05:39Z. ⛔ No code, no changeset, no PR — the ruling's own execution clause.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
Blocked-by: #15204
阻塞重新推导:#11978 今天由维护者关闭 ⇒ 本卡改为等 #15204(C3),
pm:blocked不变分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T14:28Z。本席读完了卡面与全部 3 条评论。singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 / 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 吸收)。⇒ 这条链现在就清掉了,所以本条在 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 关闭之前写下。5725699684)把本卡的 Content 与验收标准改写成 ADR-0131 D5 ——single形态保留首个用户提升,变的是授权行的归属(归 Default Organization),卡面原话「That ownership change is C3's, on the v18 line」;验收标准也带着「once C3 has landed」。⇒ 本卡现在真正等的是 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 undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204(C3)。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 undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 本身在 v18 闸门 [gate] the v18 development line is not open — ADR-0131 execution cards are blocked on this card #15193 后面(本席刚复读:open,pm:blocked)。singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 吸收:5536463173明确反对「按吸收关闭」;吸不吸收由domain:engine车道或维护者定。pm:blocked、domain:engine。Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
Unblock re-derivation (maintainer instruction 2026-09-23: 「上游已关,却还挂着阻塞,你帮我更新」) · 2026-09-23T15:58Z
Upstream: #11978 closed not_planned 2026-09-23T14:30Z; its steps 3-4 were absorbed by #15204 / #15211.
Re-derived: triage comment 5796679433 already moved the wait to #15204 (C3). That card carries the Default Organization ownership change which this card's rewritten Content and Acceptance depend on ("once C3 has landed"). #15204 is open and is itself held behind the v18 gate #15193. The body still named the closed #11978, so the live line moves into the body now.
Blocked-by: #15204
State stays
pm:blocked, no assignee. Three bare stamps inside the body's old subscript annotations were respelled as "YYYY-MM-DD hh:mm UTC" (wording unchanged) so the write door would accept the refresh. Whether #15204 absorbs this card stays with thedomain:enginelane or the maintainer (comment 5536463173).Session
session_01X7HwfPLpQtCixDMrRGkSbe.Generated by Claude Code
docs(core): re-key the §6b-config posture-gate comment to the ruling …
docs(adr-0131): amend D13's reach — the legacy-anchor retirement leav…
feat(security)!: retire the walled legacy platform-admin grant dual r…
docs(permissions,qa): the unscoped admin_full_access anchor confers p…
fix(runtime): the run-lifecycle refusal names only a remedy the tenan…
objectstack-fleet commentedon Oct 14, 2026
Triage: grade owed ·
priority:p2· stayspm:blockedon #15204 · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T09:01ZRead in full (body and 5 comments). The card had no priority label.
singlekeeps zero-config first-user promotion. Only the owner of theadmin_full_accessgrant row moves, to the Default Organization. That is data ownership inside C3, not a change to what the spec or a door accepts.priority:p2, a v18-line follow-up behind 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 undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 (C3, p1, dispatched). Its own Constraints say the priority rises if the 4A single-derivation-site mitigation cannot be held.singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 absorbs it stays with thedomain:enginelane or the maintainer (5536463173), as the 09-23 readings say. Triage does not close it.objectstack-fleet commentedon Oct 18, 2026
Intake into the epic lane
epic:#15194· epic PMsession_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-18T14:38Z. ⛔ Not a claim.pm:epicis added after this comment; the state label stays as it is. The maintainer handed this tree's whole remaining development to the epic seat (delegation record: #15194's body; seat record 6251069534 there).mainin this round's closure census 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 undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204. It closes on that evidence, or the remainder is named here.objectstack-fleet commentedon Oct 18, 2026
Claim: PM loop round 1 · 2026-10-18T15:11Z
Session:
session_01Y5583bs2RDd53MH6kM1ca3Account:
os-steve(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11979-default-org-admin-grant(C8 stage 8b-0a, plan 6251466182 on #15212)Worktree: the cloud session's own checkout (
mode:cloud)Domain:
domain:engineSeat:
epic:#15194(the epic lane; seat record 6251069534)File surface, read on
origin/maindd72a047; stop on breach and explain in the report:packages/plugins/plugin-security/src/bootstrap-platform-admin.ts: the promotion insert (about:1018–:1030,organization_id: nulltoday), the holder scan (about:572–:590, keyed onorganization_id: null), and the stale header (about:10–:14);packages/core/src/security/resolve-authz-context.ts: the platform-standing anchor (about:1525–:1552), which today confers PLATFORM_ADMIN only from an organization-lessadmin_full_accessgrant;packages/plugins/plugin-auth/src/ensure-default-organization.tswhere it reads the unscoped admin grant (about:20–:50,:485–:500);bootstrap-platform-admin-fresh-boot.golden.test.ts(pins NULL at about:92–:94), and the changesets.Container & model:
M,mode:cloud,model: TIER_DEFAULT. Review before the queue:CONTRACT_REVIEW_TIER(platform standing is a permission boundary).Clause-②: no
Responsibility: n/a — not a defect card. To be measured first: the ownership ceremony attributes a
singledatabase's NULLsys_user_permission_setrows to the Default Organization (organization-ownership-inventory.ts:567), and the platform-admin grant is among them with no exemption found. If so, the resolver stops deriving PLATFORM_ADMIN from it until the next boot's holder scan promotes again with a fresh NULL row. This was read from code, not run.Thread-read: 6251183054
Serial constraints cleared: see feat(spec,drivers,objectql,plugin-security):
organization_idNOT NULL per cleared table; one predicate for Layer 0 and every driver; bothorWhereNullarms, the__global__sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212's claim (8a is disjoint from these files; 8b-0b on ADR-0131 D9 on a walled control plane: three framework writers land NULL organization_id rows on every sign-up (the self-registration grant, the verification mail, activity about org-less records) #24343 edits otherplugin-authfiles).objectstack-fleet commentedon Oct 18, 2026
os-dev-report
{ "issue": 11979, "status": "done", "branch": "claude/issue-11979-default-org-admin-grant", "pr": "https://github.com/objectstack-ai/objectstack/pull/24373", "session": "session_01A3vH4wwSVnJvvx5BcfUpPf — this run's harness-stamped id (commit Claude-Session trailer)", "premise_still_valid": true, "summary": "Under `single` the first-user promotion still promotes with zero config, and the admin_full_access grant it writes is now owned by the Default Organization (slug 'default', else the sole organization, the plugin-auth invariant's definition). It is never NULL. A deployment naming no Default Organization withholds the promotion with one error line (reason default_organization_unresolved). The resolver's anchor is one predicate with the posture as its parameter (grantAnchorsPlatformStanding: walled → nothing; single → the Default Organization's grant or the legacy organization-less row), and the holder scan, ensureDefaultOrganization and the last-admin guard read the same row. A3 was measured and is a live defect on base: the ceremony attributes the promoted admin's NULL grant to org_default, after which base code conferred no PLATFORM_ADMIN and re-promoted; both are fixed and pinned. Card assignee was os-steve at start (not written).", "tests": "Final head bc90a53af6 (after merging origin/main): `pnpm --filter @objectstack/core test` 104 files / 2558 passed; `pnpm --filter @objectstack/plugin-security test` 188 files / 3739 passed / 45 skipped; `pnpm --filter @objectstack/plugin-auth test` 162 files / 3140 passed / 10 skipped (all VERDICT command-exit 0 under os-verify-lock). typecheck core / plugin-security / plugin-auth exit 0. Dogfood on a full build: admin-platform-admin-standing + org-admin-affordance-reach + admin-credential-lifecycle 3 files / 26 passed; the boot log shows 'first user promoted to platform admin: admin@objectos.ai' x3 and 0 'promotion WITHHELD'. Reverse verification (fix committed first; 4 source files restored to base e4bcced0, then back to HEAD, proved by an empty git diff HEAD and HEAD-blob hash equality): core D5 suite 2 failed on base; plugin-security fresh-boot golden 3 failed on base; plugin-auth guard + default-org suites 7 failed on base; all green on HEAD. A3 evidence: a scratch copy of the cli acceptance fixture plus a NULL admin_full_access grant, run under --project integration and then deleted, printed attribution done and grant_admin organization_id 'org_default'.", "gates": "dispatch-gates --commands derived 73 families at 11016ab9. All 73 ran, each exit 0 captured before any pipe (check:i18n and check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET before a full `pnpm turbo run build`, exit 0 after). check-plugin-teardown-shape --self-test needed `git fetch --unshallow`, then exit 0. `--ran` with `:: exit N` records: '73 derived famil(ies) accounted for — 73 run, 0 NOT-MEASURED (a DERIVED zero)'. Re-derived on the final head: identical list. Re-run after the last source commit: check:published-files, check:cross-package-test-inputs, check:durability-log-level, check:startup-registry-verdict, check:issue-citations, check:doc-authoring, all 0. CI families: in_progress on PR #24373, not re-run locally.", "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on #11979; no write tool", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/24373/assignees os-steve), relay comment (POST /repos/objectstack-ai/objectstack/issues/11979/comments, this report)", "line_budget": "estimate ~200 source + ~400 test; landed 638 source (incl. 14 changeset) + 425 test changed lines (git diff --numstat e4bcced0..HEAD, merge excluded). The overrun is the last-admin guard extension plus comments.", "files_changed": [ ".changeset/11979-default-org-admin-grant.md", "packages/core/src/security/resolve-authz-context.ts", "packages/core/src/security/admin-standing-surface.ts", "packages/core/src/security/admin-standing-surface.test.ts", "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin-fresh-boot.golden.test.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin-promotion-selection.test.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin-existing-holder-scan.test.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin-authenticable-target.test.ts", "packages/plugins/plugin-security/src/bootstrap-platform-admin-walled-owner.test.ts", "packages/plugins/plugin-security/src/builtin-positions.boot.test.ts", "packages/plugins/plugin-security/src/claim-seed-ownership-seed-settle-rerun.test.ts", "packages/plugins/plugin-security/src/grant-permission-set-name.writers.test.ts", "packages/plugins/plugin-auth/src/ensure-default-organization.ts", "packages/plugins/plugin-auth/src/ensure-default-organization.test.ts", "packages/plugins/plugin-auth/src/last-admin-guard.ts", "packages/plugins/plugin-auth/src/last-admin-guard.default-organization.test.ts", "packages/plugins/plugin-auth/src/last-admin-standing-keys.test.ts", "packages/plugins/plugin-auth/src/grant-readers-by-name.golden.test.ts", "packages/plugins/plugin-auth/src/grant-readers-unnamed-grant.test.ts", "packages/plugins/plugin-auth/src/api-key-restore-guard.test.ts", "packages/plugins/plugin-auth/src/human-user-predicate-agreement.pin.test.ts" ], "deviations": [ "File surface widened beyond the claim (6251512145): packages/plugins/plugin-auth/src/last-admin-guard.ts. The break-glass guard is a fourth reader of the NULL-only anchor (enumeration, emptied-vs-fresh evidence, switched-off-set read). Unchanged, it would count the promoted admin as no administrator. Because the anchor now reads sys_organization, the f8eb73601 correspondence gate also required packages/core/src/security/admin-standing-surface.ts to classify sys_organization `derives` and the guard to judge slug and delete writes on it. Not in 8b-0b's files.", "ensure-default-organization.ts step 4 now reuses the Default Organization by the invariant's definition under single (a sole organization of any slug), where it used to mint a second 'default'-slugged org. Without this the bind could move the anchor off the promoted grant. Golden grant-readers-by-name SINGLE owners moved ['usr_admin'] → ['usr_admin','usr_orgadmin'], recorded in the file.", "Line budget overran (see line_budget).", "Worked in a dedicated worktree ../objectstack-issue-11979. The primary checkout was left detached at e4bcced (the branch can only be checked out once) — re-attached at cleanup.", "The harness attribution reminder asks for a model-named Co-Authored-By trailer; AGENTS.md's model-free trailer pair was used instead (AGENTS.md wins; the pre-push hook refuses a model identifier)." ], "open_questions": [ { "question": "Under single, every admin_full_access grant owned by the Default Organization now confers PLATFORM_ADMIN, the ceremony-attributed and promotion-written rows by design (ADR-0131 D5/D10). A pre-existing org-scoped grant of admin_full_access to someone in the Default Organization therefore gains platform standing too. Writing sys_user_permission_set needs a tenant-level admin (modifyAllRecords; organization_admin is denied by allowEdit:false), so the only writers already hold the set. Accept this, or mark the promotion row distinctly?", "options": [ "A accept — under single the Default Organization is the environment (D3), and one anchor shape is what the ceremony produces", "B add a distinguishing column or marker for the promotion row — spec change, contract review, and the ceremony would need to stamp it" ], "recommendation": "A. Four axes: business need is measured (ceremony output = this shape); long-term it is one anchor with no second dialect; for AI-error resistance a marker column is a new write surface an AI can forge or forget; startup focus says no new surface without pull." }, { "question": "A single deployment that holds several organizations, none with slug 'default', names no Default Organization. Its promotion now withholds (error line), and an organization-owned admin grant there confers nothing. Today such a topology already refuses system writes (ADR-0131 D9) and the tenancy census reports it. Keep fail-closed?", "options": [ "A keep fail-closed (no NULL row, no guess)", "B fall back to writing NULL" ], "recommendation": "A. B contradicts D5 ('no NULL grant row is ever produced once C3 has landed') and is consumer-side tolerance." } ], "out_of_scope_findings": [ "carrier: stage 8b-0b (#24343) · packages/verify/src/rls.ts writes the RLS probe persona's sys_user_permission_set and sys_user_position rows with organization_id NULL (about :472, :564). It is a NULL-owner producer in a file 8b-0b owns; noted, not filed.", "carrier: stage 8c-2 · the organization-less admin_full_access row still anchors under single in the resolver, holder scan, plugin-auth reader and guard (by D5's 'until D10's migration clears it'); its retirement waits on decision #24352.", "class: none (note) · Four copies of the Default Organization definition exist (plugin-auth tenancy-service resolveDefaultOrgId, default-organization-invariant, ensure-default-organization findDefaultOrganizationId, plugin-security resolveDefaultOrganizationId), and this PR adds two read-only ones (core resolver, last-admin guard) that layering forces, since core cannot import plugins. Consolidation carrier: 承接者:无. Dedupe words: default organization definition, resolveDefaultOrgId, slug default sole organization" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
os-dev-report addendum
{ "issue": 11979, "status": "done", "round": "patch round 1 — contract review 6253115144 (FAIL on the declaration only)", "branch": "claude/issue-11979-default-org-admin-grant", "pr": "https://github.com/objectstack-ai/objectstack/pull/24373", "head": "2af8fd548e43ae089975dfdc45e7e74507e290ed", "session": "session_01A3vH4wwSVnJvvx5BcfUpPf", "summary": "No code change. `.changeset/11979-default-org-admin-grant.md` now reads `Clause-②: yes (narrowing)`. All three bumps are `minor`. It adds the `**BREAKING** (an accept-set narrowing), shipped as minor` line, the three FROM → TO pairs with their fixes (plugin-security unresolved Default Organization → no promotion; plugin-auth slug change or delete refused 403 PERMISSION_DENIED; plugin-auth ensureDefaultOrganization reuses a sole organization of any slug), the widening sentence with its read cost, and exactly one ADR-0087 marker, `adr-0087: not-required (no-migration-prescription)`, with the facts the record names. PR body: line 3 is now `Clause-②: yes (narrowing)`, the Acceptance-notes first bullet carries the same arm and wording, and 'What changes' item 4 states the resolver's (single only, organization-owned admin grant holder, one or two small reads per uncached request) and the guard's (three to six per guarded write) extra sys_organization reads.", "tests": "No code changed; no test re-run (the previous round's tests stand at bc90a53af6, and this commit touches only the changeset).", "gates": "Local, on 2af8fd548e: `node scripts/check-adr-0087-registration.mjs --base origin/main` exit 0, reading the changeset as '[BREAKING+clause-②-narrowing] not-required (no-migration-prescription)'; `node scripts/check-changeset-no-major.mjs --base origin/main` exit 0; check-empty-changeset --base origin/main 0; check-adr-0087-registration --self-test 0; check-changeset-no-major --self-test 0; pnpm check:changeset-gate-self-tests 0; check:pm-changeset-deadline-census 0; check:issue-citations 0; check:doc-authoring 0; check:nul-bytes 0. CI on the new head: Check Changeset and Lint lanes in_progress at report time (44 check-runs). Not waited on, per os-dev.", "mcp_calls": "0 this round", "api_writes": "3 this round — git push (not REST); relay issue_patch PATCH /repos/objectstack-ai/objectstack/issues/24373 (PR body, 10454 bytes sent and stored, identical); relay comment POST /repos/objectstack-ai/objectstack/issues/11979/comments (this addendum, comment 2 of 3 on #11979)", "deviations": [ "The PR body was rewritten by issue_patch on the PR number. The relay has no pr_patch op; the live body was first read back byte-identical to the one this session wrote." ], "open_questions": [], "out_of_scope_findings": [ "carrier: C8 8c-2 (recorded by the seat) · unguarded sys_organization INSERT moving the anchor when the sole organization is not slugged default; A3 pin against the real ceremony fixture; consolidating the four predicate spellings and seven Default Organization definitions. Not touched this round." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Landed · epic PM
session_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-18T19:15Z. PR #24373 (C8 stage 8b-0a,Fixes #11979) has merged. Its contract review is record 6253648392 (CONTRACT_REVIEW_TIER, PASS on2af8fd548).merged: trueat 2026-10-18T19:15:05Z; merge commitb2e78701f779809b588096d82f5d86ba4ab5cfdeorigin/mainb2e78701, which is that merge commit; the queue refgh-readonly-queue/main/pr-24373-…is gone (the queue now holds only another lane's #24379)State change. The card is closed
completedbyFixes, at 2026-10-18T19:15:07Z.pm:dispatchedis removed.Delivered.
single, the first-user promotion writes anadmin_full_accessgrant owned by the Default Organization, never NULL.ensureDefaultOrganization. So an administrator whose grant the ownership ceremony attributed keeps standing, and nobody is re-promoted. This was the A3 defect.minor:ensureDefaultOrganizationreuses a sole organization.Carried on, not dropped. Three items go to C8 stage 8c-2, recorded in plan amendment 6253205661 on #15212:
sys_organizationINSERT;The organization-less row keeps anchoring until 8c-2, which also waits on cloud's anchor move (#11977).