Skip to content

docs(adr): qualify the pre-repo ADR-0081 citations as cloud ADR-0081, letter-checked per site - #15612

Draft
claude[bot] wants to merge 2 commits into
mainfrom
claude/issue-9072-adr-0081-cloud-qualification
Draft

docs(adr): qualify the pre-repo ADR-0081 citations as cloud ADR-0081, letter-checked per site#15612
claude[bot] wants to merge 2 commits into
mainfrom
claude/issue-9072-adr-0081-cloud-qualification

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #9072

⚠️ Governed surface (docs/adr/**): draft for human merge — review recorded on the issue.

What this settles

The cloud-side reading delivered on 2026-08-20 (issue comment 5350230356, objectstack-ai/cloud origin/main @ 5f1bf23f) identified the pre-repo ADR-0081 as cloud ADR-0081Organization Management — Open Basics, Enterprise @objectstack/organizations, Accepted 2026-07-09 — with D1 = the default-org bootstrap (ensureDefaultOrganization, slug='default' reuse-or-create, owner binding, kernel:ready, the !resolveMultiOrgEnabled() gate) and D2 = the multi-org machinery closing into cloud/packages/organizations. The 2026-09-04 re-triage ruled: requalify, letter-check every site, do not prefix blind, and record the identification in ADR-0093's Relates to line.

This PR does exactly that. It changes citations only — no decision text, no behaviour, no test assertion, no changeset-bearing surface.

Why no gate could have caught this. This repo owns its own docs/adr/0081-trusted-react-page-tier.md (the kind:'react' page tier), so a bare ADR-0081 here resolves — to the wrong record. check-adr-anchors.mjs only fails a number that names no record; a number that names the wrong record is invisible to it. That gate does, however, already recognise cloud ADR-0081 structurally (CROSS_REPO_QUALIFIERS), so the repaired spelling is the one the tooling was built for.

No site carried D4. D4 is the SCOPE_RULES.sys_member change from {field:'user_id', from:'user'} to {field:'organization_id', from:'org'}. git grep -n "SCOPE_RULES" -- packages returns nothing in this repo — the surface left with plugin-org-scoping under D2 — so there was no D4 site to mislabel. Likewise the kernel service name 'org-scoping' is untouched (setup-nav.contributions.ts still spells requiresService: 'org-scoping').

Per-site classification

Every one of the 72 non-CHANGELOG ADR-0081 occurrences on origin/main was classified before anything was edited.

cloud D1 — 18 citations requalified (letter kept, verified)

site what it says
content/docs/permissions/sharing-rules.mdx:179 "before its default organization is bootstrapped"
docs/qa/platform-checklist/areas/identity-auth.json:757 org capability "always mounted"; default-org bootstrap guarantees an org
docs/qa/platform-checklist/areas/identity-auth.json:824 (2nd citation on the line) "Teams/Invitations always mounted"
packages/platform-objects/src/apps/setup-nav.contributions.ts:79 Teams / Invitations no longer gate on org-scoping — the OPEN basics
packages/platform-objects/src/identity/sys-user.object.ts:89 gated on the org CAPABILITY, not multi-org
packages/plugins/plugin-auth/src/auth-plugin.test.ts:1259 single-org default-organization bootstrap
packages/plugins/plugin-auth/src/ensure-default-organization.test.ts:3 the bootstrap helper
packages/plugins/plugin-auth/src/ensure-default-organization.ts:4 the helper's own header
packages/plugins/plugin-auth/src/ensure-default-organization.ts:12 "the gap … closes" — bare on main, letter supplied
packages/plugins/plugin-auth/src/ensure-default-organization.ts:354 runtime durability-failure log string
packages/spec/src/kernel/public-auth-features.ts:125 "Org CAPABILITY gate, not multi-org"
packages/verify/src/harness.org-context.test.ts:183 bootstrap abstains under a walled posture
packages/verify/src/harness.ts:181, :238, :418 the autoDefaultOrganization flip and its posture abstention
packages/verify/src/harness.ts:337, :656 runtime error strings raised by the harness
scripts/publish-smoke.sh:890 "bootstraps that org" — bare on main, letter supplied

cloud D3 — 7 citations requalified (nav deep-link; 6 were bare on main)

D3 is the nav deep-link, per the reading's own bounds note. Each of these describes the active-org record page reached from nav_organization with recordId: '{current_org_id}', or that token's resolution.

site what it says
docs/qa/platform-checklist/areas/identity-auth.json:762 the nav entry and its {current_org_id} recordId
docs/qa/platform-checklist/areas/identity-auth.json:774 "the active-org token is wired"
docs/qa/platform-checklist/areas/identity-auth.json:820 landing on the raw list is a FAIL of that wiring
docs/qa/platform-checklist/areas/identity-auth.json:824 (1st citation on the line) the nav_organization source pin
packages/platform-objects/src/apps/setup-nav.contributions.ts:74 the ACTIVE organization's record page
packages/platform-objects/src/identity/invite-entry-toolbar.test.ts:4 "the org record page … opens on tab-0 Members"
packages/platform-objects/src/identity/sys-member.object.ts:47 same page, same tab-0 reasoning

wrong letter — 1 site corrected

docs/adr/0093-tenancy-mode-and-membership-lifecycle.md:388 (D8 non-goal 2) called the features.organization vs features.multiOrgEnabled split "a deliberate ADR-0081-D1 distinction". Only the open half is D1's ("basic add-a-teammate stays OPEN"); the enterprise half — org management available — is squarely D2's ("multi-org machinery closes into @objectstack/organizations"). Corrected to cloud ADR-0081 D1/D2, with one clause naming which letter draws which half. The decision itself is untouched.

cloud D2 — 0 live sites

No live citation in this tree carried a D2 label. ADR-0105's Builds on line at :5 already spelled it cloud ADR-0081 (@objectstack/organizations) — that was the clue the finding was filed on — and its :345 citation note quotes "ADR-0081 D2" only as the superseded label it is describing.

identification prose — 5 blocks (they name the record rather than carrying a live label)

site change
docs/adr/0093:7 (Relates to) "that decision record predates this repo's ADR series" replaced by the identification: cloud ADR-0081, its title, its Accepted date, and that D1 is this bootstrap. It still says it predates this series — now with the reason (it lives in cloud's, where it is current).
docs/adr/0093:69 (D9 summary bullet) names the record; the collision is now stated as a property of writing the number unqualified
docs/adr/0093:404 (D9 recording preamble) same, plus one clause noting the surviving citations now carry the qualifier
docs/adr/0105:345 (Citation note) names the record and points at this ADR's own Builds on line, which already used the qualified spelling; states that its D2 is the entitlement decision. D12 stays the anchor — untouched.
docs/adr/0131:828-830 (census note) already said "the '0081' is cloud's numbering"; now names the record, and its quoted label is the qualified one

react (ours, untouched) — 39 occurrences across 20 files

docs/adr/0081-trusted-react-page-tier.md, docs/adr/0082:5,:8, docs/adr/0084:5, the two react-tier links inside the ADRs edited above (0093:409, 0105:352), content/docs/protocol/objectui/layout-dsl.mdx, content/docs/references/ui/page.mdx, content/docs/ui/pages.mdx, docs/audits/2026-06-react-tier-authoring-dogfood.md (x5), docs/audits/2026-07-unknown-key-strictness-ledger.md:676, docs/qa/platform-checklist/areas/studio-authoring.json:1052,:1088, the three examples/app-showcase react pages, packages/lint (x7), packages/spec/scripts (x3), packages/spec/src/ui/chart.zod.ts (x2), page.zod.ts:685, react-blocks.ts:3, scripts/gen-sdui-manifest.sh:650, scripts/regen-artifacts.mjs:327, skills/objectstack-ui/references/react-blocks.md (x2). None touched — see the control below.

left verbatim and reported — 5 occurrences

Not ambiguous: each is deliberate, and each is why the branch's "unqualified org-meaning" count is 5 rather than 0.

  • docs/adr/0093:68, :403 and docs/adr/0105:344, :348 — these quote the superseded label ("ADR-0081 D1" / "ADR-0081 D2") inside the very sentence that identifies it. Requalifying a quotation would erase the thing the prose is about.
  • docs/qa/platform-checklist/areas/identity-auth.json:833 — the append-only history row for revision 1, a record of what a past edit did. Item revision was deliberately not bumped and no history row added: a citation repair changes nothing a runner does, and bumping would invalidate run results pinned to revision 2. The gate's revision == last history revision invariant still holds (both 2).

ambiguous → left, reported — 0

Every site's letter was determinable from its own surrounding text.

Grep controls

Occurrence counts, git grep -o, excluding CHANGELOG.md at every depth.

reading origin/main this branch
cloud ADR-0081 (qualified) 1 34
ADR-0081 not preceded by cloud 72 44
— of those: org-meaning, live citation 28 0
— of those: org-meaning, quoted label or history row 5 5 (enumerated above)
— of those: react-tier 39 39

React-tier byte-identity control. The sorted multiset of every ADR-0081-bearing line was taken on both sides. comm -23 (present on main, absent on the branch) is 31 lines, and grep -cE "react|REACT|kind:'react'|PageSchema|ObjectChart|OS_PAGE_REACT|trusted-react-page-tier" over those 31 rewritten lines returns 0 — no react-tier line was rewritten. The react-marker subset itself is 29 lines on both sides, diff empty, sha256sum identical on both:

03ed1c3c42640387f6ba685d357773f0f621c39b9d6ce49b7e440da836845170  (main)
03ed1c3c42640387f6ba685d357773f0f621c39b9d6ce49b7e440da836845170  (branch)

D4 control. git grep -n "SCOPE_RULES" -- packages → no output, exit 1. There is no sys_member scope-rule surface in this repo to have mislabelled.

Verification

Gate family derived mechanically, not from a hand-written list:

node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack

Derived at HEAD 6e019fa0a against merge base 900334a56 — 16 changed paths, 106 commands. The first derivation ran on a stale tree (it warned that scripts/pm/dispatch-gates.mjs itself had moved on origin/main); origin/main was merged into this branch and the family re-derived clean before anything was run. Exit codes were captured before any pipe, into per-command log files. Every run reported below — the gate union, the builds, the typechecks, the tests and the grep controls — was taken on that same tree: git rev-parse --short HEAD = 6e019fa0a, which is the tip this PR pushes.

result count notes
exit 0 first run 95 / 106 includes check:adr-anchors, check-adr-links, check-adr-symbol-anchors, check:doc-anchors, check:nul-bytes, check:role-word, check:docs-single-h1, check:org-identifier, check:cross-package-test-inputs, check:type-check-coverage
NOT MEASURED, then green after the prerequisite build 11 / 106 listed below
red 0

The 11 that first refused for a missing build — 2 with exit 3, 6 with exit 1 whose text says "Build first, then re-run", 3 with PREREQUISITE NOT MET:

@objectstack/lint check:doc-formula-expressions, @objectstack/lint check:doc-security-posture, @objectstack/spec check:api-surface, check:browser-reachable-entries, check:dual-source-exports, check:entry-nameability, check:exported-any, check:skill-examples, check:dual-build-cjs-loads, check:i18n, check:type-check-debt.

Builds and every heavy run went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-9072. One acquisition returned 99 (never got a turn, slot parked); the interval was spent on lock-free work and the same slot was resumed rather than re-queued.

run verdict
turbo run build --filter='@objectstack/spec...' --filter='@objectstack/formula...' --filter='@objectstack/lint...' VERDICT command-exit 0 · held the lock 165s
turbo run build --filter='./packages/*' --filter='./packages/*/*' VERDICT command-exit 0 · held the lock 235sTasks: 71 successful, 71 total
re-run of all 11 all exit 0
pnpm check:type-check-debt check-type-check-coverage --re-measure: OK — 13 ledger entr(ies) re-measured in 118.6s, 143 raw tsc error(s) total, none above its recorded number.
typecheck for @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/spec, @objectstack/verify exit 0; check:test-typecheck: OK for spec (54 files / 261 errors / 145 pinned signatures held) and plugin-auth (10 / 94 / 23) — both at their recorded numbers
pnpm check:pm-dispatch-gates — named by the dispatch; scripts/pm/** is untouched by this branch, so it is outside the derived family VERDICT command-exit 0 · held the lock 418sdispatch-gates self-test: 1445 cases pass (1445, not the 1415 the dispatch quoted: the tool moved on main. No case was edited)
vitest run on the three edited test files Test Files 2 passed (2) · Tests 122 passed (122) (plugin-auth) and Test Files 1 passed (1) · Tests 21 passed (21) (platform-objects)

check:platform-checklist is not CI-wired (#11730), so it was run by hand, as the ruling requires:

check-platform-checklist: OK — 15 areas, 264 items (264 active); coverage: 35 kinds mapped,
1 waived; traps: 19 documented, 19 in use; provisioning: 5 area recipes, 8 item references
resolved (1 area-qualified), 5/5 recipes referenced; meta-URL spelling: 19 `call` strings
scanned against 34 folded spellings; source citations: 20 family files carry no `file:line`
pin; symbol anchors: 624/624 resolved against 306 cited sources, 17 file floors held

Exit 0. Coverage derives inside this same gate — there is no separate check:platform-checklist-coverage script in this tree.

Declared narrowing — whole-repo pnpm lint. It is not in the derived family and CI runs it on this PR regardless. Locally, eslint was run over the 10 changed TypeScript files with the same flags CI uses: eslint --no-inline-config --format json, 10 files linted, 0 errors, 0 warnings (counts read from the JSON output, not from the console). The narrowing is safe to state as a measurement rather than a gap because this config is not type-aware — it declares no parserOptions.project and no projectService, and eslint.config.mjs:328 says so in its own words — so a file's verdict is a function of that file plus the config, and this diff can move no untouched file's result.

No test pins any of the edited comment strings. git grep -n "ADR-0081" -- "*.test.ts" returns 6 hits on main, all of them comments or describe() titles; none is an assertion argument. The two runtime strings that changed (ensure-default-organization.ts:354, harness.ts:337/:656) are matched by tests only on other substrings (/orgContext:true does not compose with multiTenant/, /walled posture/), which are unchanged.

Scope

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/spec, @objectstack/verify, touching 4 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/ui/setup-app.mdx (via SETUP_NAV_CONTRIBUTIONS (symbol, a top-level const object))

2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via BootOptions (symbol, a top-level interface))
  • content/docs/releases/v17.mdx (via bootStack (symbol, a top-level function))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 134 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 4444885271c4fec39672a892d5189d6905a65b2cpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 34acf5f0574d1118d0b6dcf237b66eb9501ed677 — the merge of head 6e019fa0add1a4b7a8a23e7826d776ac024536fc into base 4444885271c4fec39672a892d5189d6905a65b2c, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 34acf5f0574d1118d0b6dcf237b66eb9501ed677 && git checkout 34acf5f0574d1118d0b6dcf237b66eb9501ed677
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4444885271c4fec39672a892d5189d6905a65b2c 6e019fa0add1a4b7a8a23e7826d776ac024536fc && git checkout -B drift-repro 4444885271c4fec39672a892d5189d6905a65b2c && git merge --no-ff 6e019fa0add1a4b7a8a23e7826d776ac024536fc

node scripts/docs-audit/affected-docs.mjs --json 4444885271c4fec39672a892d5189d6905a65b2c

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 4444885271c4fec39672a892d5189d6905a65b2c → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

REVIEW (mirror of the record on #9072; governed surface — docs/adr/**; draft PR #15612 for HUMAN MERGE, ⛔ not flipped, not armed) — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

Reviewed against the three-dot diff origin/main...claude/issue-9072-adr-0081-cloud-qualification (head 6e019fa0a; 16 files, +54/−41), not the self-report. Every changed line read.

  • Citations requalified, letter-checked against the cloud reading (5350230356): 18 sites → cloud ADR-0081 D1 (default-org bootstrap: ensure-default-organization.ts header/docblock/error string and its test, auth-plugin.test.ts, harness.ts ×4 + its test, public-auth-features.ts, sys-member.object.ts, sys-user.object.ts, setup-nav.contributions.ts Teams/Invitations gate, sharing-rules.mdx:179, publish-smoke.sh, checklist rows); 7 sites → cloud ADR-0081 D3 (the {current_org_id} active-org nav deep-link — 6 were bare ADR-0081 on main, so the letter was supplied, matching the reading's D3 = nav deep-link); 1 letter CORRECTED — ADR-0093 D8 non-goal 2 called the features.organization / multiOrgEnabled split a "D1 distinction"; only the open half is D1, the enterprise half is D2 — now cloud ADR-0081 D1/D2 with the clause naming which half each letter draws. 0 D2 live sites (ADR-0105 :5 already qualified), 0 D4 sites (SCOPE_RULES left with plugin-org-scoping), 0 unclassifiable.
  • ADR prose now names the record instead of declining to: ADR-0093 Relates to :7, D9 summary :69, D9 preamble :404; ADR-0105 citation note :345; ADR-0131 census note :828–830 — each states cloud ADR-0081 — Organization Management — Open Basics, Enterprise @objectstack/organizations, Accepted 2026-07-09, identified 2026-09-04. ⛔ No decision text rewritten: D12 stays ADR-0105's anchor, ADR-0093 D9 stays the local anchor, the kernel service name 'org-scoping' untouched. The 5 remaining unqualified spellings are quotations of the superseded label inside the sentences that identify it (ADR-0093 :68/:403, ADR-0105 :344/:348) and the append-only checklist history row (identity-auth.json:833) — correct to leave.
  • This repo's own react-tier ADR-0081 untouched: the 29-line react-marker subset is sha256-identical on both sides; none of the 31 changed lines matches a react marker.

Dev's verification quoted (on 6e019fa0a): derived family 106 commands, 106/106 exit 0 after building the closure (11 first answered NOT MEASURED for a missing build, then green); typecheck of the four changed packages exit 0 with check:test-typecheck: OK at recorded numbers; the three edited test files 122 passed / 21 passed, no assertion pins an edited string; check-platform-checklist run BY HAND (not CI-wired, #11730): OK — 15 areas, 264 items … symbol anchors: 624/624 resolved, item revision deliberately not bumped (citation repair); check:pm-dispatch-gates 1445 cases pass; grep controls: cloud ADR-0081 1 → 34, unqualified org-meaning live sites 28 → 0.

Disposition: review recorded here per the standing ADR rule; the PR stays a draft for an authorized human to approve and merge. On merge this seat probes ADR-0093 :7 on main and strips pm:dispatched + assignee. #8531's remaining claims B/C are sequenced after this and should drop the mint-new-owning-record assumption.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] The repo never resolved whether the pre-repo ADR-0081 is cloud ADR-0081 — and ADR-0105 cites both spellings in one document

1 participant