Skip to content

Amend ADR-0131 D13 to drop the two platform-admin reporter symbols (maintainer ruling B on #18336) — and close the single-row NULL-ownership question the drop leaves open #18413

Description

@os-project-manager

ADR-0131 D13 lists reportLegacyPlatformAdminGrant and resetLegacyPlatformAdminGrantReport among the retirements it assigns to the v18 line. A maintainer ruling in session session_01LmoCFLwGkcAGefVf7jryEV (2026-09-16T09:54Z) decided option B on #18336: #11663's design governs this leg, the work stays on the 17.x line, and ADR-0131 D13 is to be amended to drop those two symbols.

⇒ This card is that amendment. It is a governed-surface change (docs/adr/**) ⇒ single PR, maintainer-merged, ⛔ never a rider on a code PR.

Why it must land BEFORE the code

ADR-0131 is Accepted and on main today. Landing #18336's removal while D13 still names these symbols puts the code in direct contradiction with an accepted ADR. ⇒ ordering is fixed: this card → then #18336. #18336 is pm:blocked on this one.

What the amendment must say

  1. Drop the two symbols from D13's retirement list, recording the ruling (platform-admin re-anchor L5 EXIT (re-file of the unreadable #13515): retire the legacy row-id grant dual read and its deprecation log — the 17.4.0 boundary is measured MET #18336, option B) as the authority.
  2. ⚠️ Resolve the scope, because the ruling narrowed it. Two standing constraints the ruling did NOT touch:

🔴 The open question this amendment MUST close, ⛔ not defer

ADR-0131's core rule is 「no NULL organization_id」. If single keeps writing its grant row, and that row's organization is NULL today, then dropping two symbols from D13 does not address the NULL ownership at all.

ADR-0131 already states an answer for this, :360–363 verbatim:

single-posture first-user promotion (Choice 4A), which today writes an admin_full_access grant row with a NULL organization, writes it owned by the Default Organization instead … No NULL grant row is ever produced.

⇒ The amendment must say explicitly whether the single row still becomes Default-Organization-owned (ADR-0131's own answer, untouched by the ruling) or stays NULL for now. The two have materially different consequences for D1 (the constraint) and D10 (the zero-NULL migration that D13's other retirements are gated on).

⚠️ ⛔ This is not a re-litigation of the B ruling — B decided which record governs the two SYMBOLS. It did not decide the row's ownership, and the ADR cannot be left self-contradictory on that point.

Also reconcile

Dedup words: ADR-0131 D13 amendment · reportLegacyPlatformAdminGrant retire 17.x · #18336 option B ruling · D14 v18 line half record · single posture NULL organization grant row


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 17, 2026
  2. os-justin commented on Sep 17, 2026

    @os-justin
    Collaborator

    Claim: PM loop round 1
    Session: session_01Gqi43smmqjJ5sUrhfoPeKu
    Branch: claude/issue-18413-adr-0131-d13-drop-reporter-symbols
    Worktree: objectstack-issue-18413
    Domain: domain:skills
    Seat: domain:skills#1
    File surface: docs/adr/0131-total-organization-ownership-no-null-organization-id.md only (D13's retirement list loses reportLegacyPlatformAdminGrant + resetLegacyPlatformAdminGrantReport with the ruling recorded; the single-row NULL-ownership question CLOSED in text, ⛔ not deferred; the two standing constraints — Choice 4A 5587754690 and the zero-config constraint — honoured verbatim); ⛔ no code, ⛔ no other ADR; governed docs/adr/** ⇒ draft, four-piece, the maintainer's approval lands it (stop on breach; explain in the report)
    Container & model: M(ADR 修订,规则层;含一个必须在文本里关掉的开口), mode:subagent, model: claude-opus-5 — node scripts/pm/dispatch-gates.mjs --tier --repo objectstack-ai/objectstack <surface> at 2026-09-17T11:43Z on the fast-forwarded tree: 「Model tier — no path-derived mandate … floor sonnet · default opus · ceiling fable」; default tier taken; the seat's contract-tier review at delivery
    Clause-②: no
    Thread-read: 5713104256
    Serial constraints cleared: pm:blocking — #18336 (services) is pm:blocked on this card and lands after it; the ADR file is FREE; 12 open PRs' file lists read at 2026-09-17T11:43Z — none touches this surface; os-verify-lock.sh --status at 2026-09-17T11:43Z: free, queue empty; shared checkout fast-forwarded to origin/main 32be735e5 before this dispatch. Batch of 3 this round: #18413 (pm:blocking, first in the total order) · #18343 · #18379 (p2 Bugs by card age); #18422, #18636, #18372, #18426 queue behind (SKILL.md and check-half-states.mjs serial where they share a file).
    Ruling-ref: 5713104256


    Generated by Claude Code

  3. os-justin commented on Sep 17, 2026

    @os-justin
    Collaborator

    os-dev-report

    {
      "issue": 18413,
      "status": "done",
      "branch": "claude/issue-18413-adr-0131-d13-drop-reporter-symbols",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18646",
      "head_sha": "ef300b6864eb049ae1879aca388c9cb046cffe1c",
      "files": [
        "docs/adr/0131-total-organization-ownership-no-null-organization-id.md (+129 / -4)"
      ],
      "session": "session_01Gqi43smmqjJ5sUrhfoPeKu",
      "premise_still_valid": true,
      "premise_note": "SURVIVES in substance, with one reading correction the card got wrong. The card says D13's retirement list names both symbols. Measured on origin/main 32be735e5: D13's own list (:641-659) names NEITHER. `reportLegacyPlatformAdminGrant` occurs exactly ONCE in docs/adr/ - ADR-0131 :362, inside D5, in the sentence that ASSIGNS its retirement to D13. `resetLegacyPlatformAdminGrantReport` occurs ZERO times in docs/ at all. Counts by `grep -ro`: docs/adr/ 1 and 0; docs/ 3 and 0; positive control packages/ 15 and 17; negative control (a nonexistent symbol over docs/adr/) 0. The ASSIGNMENT is what the ruling reaches, so the amendment edits D5, D14 and section 7 and leaves D13's list unchanged. Before: the retirement was D13's and therefore v18's. After: it is #11663's and 17.x's. No PR premise died.",
      "summary": "Amended ADR-0131 to carry the maintainer's option-B ruling on #18336 (session session_01LmoCFLwGkcAGefVf7jryEV, 2026-09-16T09:54Z): D5's assignment of `reportLegacyPlatformAdminGrant` and `resetLegacyPlatformAdminGrantReport` to D13 is withdrawn; those symbols retire on the 17.x line under #11663's design, WALLED POSTURE ONLY. Five text sites: the Status line gains an `**Amended** (2026-09-17, #18413 ...)` clause; D5's sentence is rewritten; D14 gains one named, exhausted exception; section 7's post-17.2 audit line gains the same exception; a full `## Amendment (2026-09-17, #18413)` record is added at the end of the file carrying the authority, both standing constraints verbatim and untranslated, the closed question and the D14 reconciliation. The corpus's own revision convention was followed (status-line note + in-place correction + a named end-of-file Amendment section, as ADR-0045 / ADR-0049 / ADR-0055 do; ADR-0090's #17189 block read for the inline form). The NULL-ownership question is CLOSED in the text, not deferred: the STOP condition did not trigger. NO code, NO other ADR, NO packages/** path.",
      "decision_sentence_that_closes_the_open_question": "Decision (2026-09-17, #18413). The `single`-posture first-user grant row STILL BECOMES OWNED BY THE DEFAULT ORGANIZATION. That is D5's own answer, accepted by the maintainer on 2026-09-04 (ADR-0131 section 6, one of the four open questions answered 'jie shou ni de jian yi' - the verbatim text in the ADR is unchanged and untranslated), and the option-B ruling does not touch it. It still lands ON THE V18 LINE, UNDER C3 (section 8), exactly where it was before this amendment. UNTIL C3 LANDS, THE ROW KEEPS THE NULL ORGANIZATION IT CARRIES TODAY - the state D10's migration exists to clear - and D1's NOT NULL constraint still reaches that table only when D10 reports zero for it.",
      "why_no_stop": "The STOP condition asked for a fork if the two standing constraints conflict with the D13 change in a way the ruled texts do not settle. They do not conflict. (1) Choice 4A ('retiring the walled write must not retire the `single` one') - the D13 change REDUCES what retires, and a reduction cannot retire the `single` write. (2) The zero-config constraint - the zero-config channel is the unscoped-grant read at resolve-authz-context.ts:839 / :928, which is NOT the reporter and is untouched. The closure needs no new maintainer decision: it is D5 (ruled 2026-09-04) plus the option-B ruling's own explicit statement of what it did NOT decide. MEASURED, not argued, that the drop moves no row: reportLegacyPlatformAdminGrant (platform-admin.ts:351) is a once-per-process warn naming one holder and pointing at OS_PLATFORM_OWNER_EMAIL; resetLegacyPlatformAdminGrantReport (:371) drops that latch for tests. Neither writes the grant row, neither reads its `organization`, neither participates in the PLATFORM_ADMIN derivation. So the 17.x retirement adds no NULL row, removes none, re-owns none => D1 and D10 are unaffected. Also mechanically decisive: the deprecation pointer is ALREADY posture-keyed (postureEnforcesWall(resolveTenancyPosture()) at the 6b-config arm), so under `single` there is no pointer behaviour to retire at all - the all-postures reading was never available for this leg.",
      "d13_text_before_after": {
        "site": "D5, ADR-0131 :358-363 on origin/main 32be735e5 (D13's own list is NOT edited - see premise_note)",
        "before": "`PLATFORM_ADMIN` derives from `OS_PLATFORM_OWNER_EMAIL` (#13514 L4) - configuration, not a row. The `single`-posture first-user promotion (Choice 4A), which today writes an `admin_full_access` grant row with a NULL organization, writes it **owned by the Default Organization** instead; under a walled posture no grant row is written (unchanged). `reportLegacyPlatformAdminGrant` and the legacy unscoped anchor retire with D13. No NULL grant row is ever produced.",
        "after": "... under a walled posture no grant row is written (unchanged). That ownership change is C3's, on the v18 line, and it is **unchanged by the 2026-09-16 ruling** - so **no NULL grant row is ever produced once C3 has landed**; until then the `single` row carries the NULL organization it carries today, and D10's migration is what clears it. The legacy unscoped anchor retires with D13 **for the `single` posture only**: its **walled** half, together with the two symbols that carry the migration window - `reportLegacyPlatformAdminGrant` and `resetLegacyPlatformAdminGrantReport` - **left D13 on 2026-09-16** and retire on the **17.x** line under #11663's design instead (#18336; see the Amendment at the end). The `single` anchor's own disposition is #11979's (Choice 4B), which this record does not pre-empt."
      },
      "standing_constraints_honoured": [
        "Choice 4A (maintainer 2026-09-08, #16682 comment 5587754690), quoted verbatim in the ADR: 'The rest of Choice 4A (#11974, 2026-08-25) stands: retiring the walled write must not retire the `single` one'. Honoured: every site that names the retirement says WALLED - D5, D14's exception, the section 7 line. The `single` write, its row and its zero-config promotion are stated as surviving until #11979 (Choice 4B). Nothing in the diff removes or narrows the `single` half.",
        "The zero-config constraint (maintainer 2026-09-16, same session as the ruling), quoted verbatim and untranslated in the ADR (the original Chinese sentence about a development environment started for a moment not being configurable). Honoured: the amendment states `single` keeps its zero-config first-user promotion and touches no part of the derivation that delivers it; it also records that the pointer is already posture-keyed, so `single` has no pointer behaviour to retire."
      ],
      "d14_and_15193": "D14 gains ONE named exception, written into D14 itself, with two independent sufficient reasons: (1) the leg is not 'a half of this record' - the ruling put it under #11663's design, so this record no longer governs it; (2) it narrows no ARM - the arms D14 fences are the drivers' orWhereNull arms inside applyTenantScope (this record's own vocabulary: D13 :641, D14 :674, section 7 :836 'the arms are inside applyTenantScope ... there are two'; the reads in resolve-authz-context.ts are called 'NULL readings', never arms). The exception is written as EXHAUSTED by that leg and those two symbols; every other D13 retirement keeps D14's fence and stays gated on D10's zero-NULL report. #15193: CONFIRMED it no longer gates #18336 under this ruling - #15193 binds 'every ADR-0131 execution card' and option B took this leg out of that set; the ruling comment states it directly. NO label or body of #15193 was touched - that re-pointing is #18336's, out of scope here.",
      "tests": "No tests owed and none written: the diff is one markdown file under docs/adr/, no packages/** path, no code. GATES (derived, not hand-listed): `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` from the worktree, change set taken three-dot vs merge base 32be735e5 -> 18 commands. All 18 run, exit captured BEFORE any pipe (redirect-then-$?), all exit 0: check-adr-links (+--self-test), check-adr-symbol-anchors (+--self-test), check-ci-filter-parity, check-closing-keyword-parity (+--self-test), check-comment-mask-corpus, @objectstack/lint check:doc-formula-expressions, check:adr-anchors, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal. RECONCILED: `dispatch-gates --ran` -> '18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN' and 'a DERIVED zero - all 18 recorded an exit code and none of them is 3'. ONE non-measurement, declared: check:doc-formula-expressions exited 3 on the first attempt = PREREQUISITE NOT MET, its own text 'Nothing was measured: this gate exited before running a single check'; its prescribed remedy was run (turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under scripts/pm/os-verify-lock.sh, OS_VERIFY_LOCK_SLOT=issue-18413, VERDICT command-exit 0, held 134s, waited 0s) and the gate re-run to a real exit 0. The 3 is recorded as a non-measurement, NOT as a failed gate. GOVERNED CHECK: `node scripts/pm/check-governed-merges.mjs --test docs/adr/0131-...md` -> GOVERNED, 1 of 1 path hit the register, exit 3 (the GOVERNED verdict code, as the dispatch expected). ESLINT - a PROVEN narrowing, three pieces: (1) population read from eslint's own config - every `files:` entry in eslint.config.mjs names only {ts,tsx,mts,cts,js,jsx,mjs,cjs}, including COMMENT_SWALLOW_FILES, and `grep -c '\\.md' eslint.config.mjs` returns 0; (2) `pnpm exec eslint --no-inline-config --format json` over the one changed path -> 1 result, errorCount 0, single message 'File ignored because no matching configuration was supplied.'; (3) invariance - the diff is one .md file and touches no eslint config and no TS/JS source, so no untouched file's verdict can move, and type-aware linting does not enter into it because the file is not in the population at all. Measured against final head ef300b686. NO ABLATION and no reverse verification: there is no executable assertion in this diff to ablate - it is a governance record, and the corresponding claim is proved instead by the mechanical reading of the two symbols' definitions (platform-admin.ts:351/:371) quoted in the PR body. CI CONVERGENCE: not waited on, per the report-on-local-completion rule.",
      "mcp_calls": "0 - no MCP GitHub tool was called, read or write, at any point.",
      "api_writes": "3 REST proxy writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18646, HTTP 201); POST /repos/objectstack-ai/objectstack/issues/18646/labels (skip-changeset, via scripts/pm/label-write.mjs, HTTP 200, four-step with read-back: target {size/m, skip-changeset} == read-back {size/m, skip-changeset}; size/m was the size-labeler's and was not touched); POST /repos/objectstack-ai/objectstack/issues/18413/comments (this report). Plus 2 git pushes (the mandated empty-branch routing probe, then the commit). PR body read back after create: byte-identical to what was sent apart from the trailing newline GitHub strips (md5 compared; footer present exactly once, session-URL form, under the rule line).",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: docs/qa/platform-checklist/areas/access-security.json :2462 / :2492 describe the legacy-anchor deprecation pointer as live behaviour and name reportLegacyPlatformAdminGrant. Those two clauses go stale for walled rigs the moment #18336 lands. Not one of the three filing classes (not a reproducible defect, not a declared-contract violation, not a metadata-authoring trap), and it has a named taker: #18336 itself, whose diff removes the symbol those clauses name. Out of this PR's declared file surface (one ADR).",
        "noted, not filed: the card's claim that D13's LIST names the two symbols is a reading error, not a defect in the tree - it is reported as premise_note above and corrected in the ADR's own Amendment section so the next reader does not repeat it. Taker: this PR."
      ]
    }

    Generated by Claude Code

  4. os-justin commented on Sep 17, 2026

    @os-justin
    Collaborator

    ACCEPT — in-seat contract-tier review of PR #18646 (head ef300b686, report 5714035120) by the skills seat, 2026-09-17T12:21Z. Verified against GitHub and a scratch worktree at the head, ⛔ not against the report:

    Rules layer ⇒ the four-piece is hung on PR #18646 in the same act: 维护者速读(终稿) on the PR, needs-user-decision, review requested from os-zhuang and hotlong. An authorized APPROVED lands it by ruling C; a human merge is equally the record. #18336 (services) stays pm:blocked on this card until the merge.


    Generated by Claude Code

  5. os-justin commented on Sep 18, 2026

    @os-justin
    Collaborator

    LANDED — PR #18646 (#18413 pm:blocking: ADR-0131 amended under ruling B on #18336 — D5's assignment of the two platform-admin reporter symbols to D13 withdrawn, walled-only, 17.x under #11663; the single-row NULL-ownership question closed in text by D5's own answer under C3 / v18) merged through the queue at 2026-09-18T01:44:29Z (merged_at), squash 0b271e2e16b338ee70bee65623ee6a775da7990d (single parent c7dc0895fa3c312bff1199df81d2e396f78fd501, an ancestor of origin/main; docs/adr/0131-total-organization-ownership-no-null-organization-id.md +129 / −4, the Amendment 2026-09-17 on main). Governed surface (docs/adr/**): the seat's four-piece was ACCEPT 5714248975 here, ## 维护者速读(终稿) 5714246119 on the PR, needs-user-decision + reviewers os-zhuang / hotlong at 2026-09-17T12:21Z; os-zhuang APPROVED at 2026-09-18T01:11:16Z (review 5243100378 on the ACCEPT head ef300b6864), marked ready and enqueued by hand at 2026-09-18T01:11:21Z; the seat stripped needs-user-decision at 2026-09-18T01:12:46Z per ruling C (--pair 18646 0, check-governed-merges --pr 18646 GOVERNED, harness CURRENT at 88aa326deb). The card auto-closed completed at 2026-09-18T01:44:30Z on the PR's Fixes; pm:dispatched and the assignee are stripped in the same act. Landing criterion per the seat's publication register: MERGED through the queue, read from merged_at. ⇒ #18336 (domain:services, pm:blocked on this PR) is unblocked by this landing — that lane's card, reported here only.


    Generated by Claude Code

  6. removed their assignment
    on Sep 18, 2026
  7. github-actions commented on Sep 18, 2026

    @github-actions
    Contributor

    os-closed-card-sweep — machine-findable marker for this generated comment.

    Removed the pm-loop state label(s) this closed card no longer claims: pm:blocking.

    A state label claims work is in flight. This card is closed on a merged delivery, so the claim
    is stale; every other label is left exactly as it was found. Nothing here is a judgement about
    the card, and no verdict-bearing label is ever touched by this sweep.

    posted by half-state-patrol run 35297049699 · trigger schedule

    Generated by Claude Code

  8. added 2 commits that reference this issue on Sep 28, 2026
    0b271e2
    74832b6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions