Skip to content

docs(organizations): state ADR-0132's entitlement boundary as the reason the cross-tenant proofs stand in - #17910

Merged
claude[bot] merged 2 commits into
mainfrom
claude/issue-17369-organizations-stale-cause-prose
Sep 13, 2026
Merged

claude[bot] merged 2 commits into
mainfrom
claude/issue-17369-organizations-stale-cause-prose

Conversation

@claude

@claude claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #17369

Clause-②: no

Re-written by the domain:cli seat (#6024) at 2026-09-13T01:17Z after a body rewrite dropped it. The declaration is the seat's, ⛔ not the implementer's, and it is re-measured on this head 7990da9233af387b15acd8c5e8e748855087d450 (unchanged since 00:38Z) against merge base a9c64779046facc1b0b2e74f71a9441b0f5b7fb8: added exported declarations in packages/verify/src/harness.ts — the diff's only non-test source file — 0, control lit (export occurs 5 times there); non-comment added lines in that file: 0, so 「comment-only」 is measured rather than asserted; whole-diff added export const|function|class|interface|type|default: 0; package.json files touched: 0, so no dependency moved and ADR-0132's entitlement-boundary pin keeps its premise. ⇒ the axis stands down and @objectstack/verify: patch stands.

⚠️ Please leave these four lines in place. scripts/check-changeset-no-major.mjs reads this declaration out of the PR body; removing it re-reds Check Changeset with no push involved, which is what happened at 01:15:13Z. The seat's process fault, owned on the card at the record below: the gate was cleared at 00:40Z and the author was never told, so a later body rewrite clobbered it.

Option 3, as ruled (director batch #114 item 3, carried by the maintainer's 「其他同意」 at 5629544916): the prose moves, the behaviour does not. Zero dependency changes, zero behaviour changes, no-framework-dependents.pin.test.ts untouched and green.

Acceptance is triage's rewritten one (5649534177 §③), not the ruling's execution line: class (i) reaches zero, never "a phrase reaches zero".

  1. 永远不要求 git grep -nF "not installable" 归零

That grep still reads 5 hits / 5 files, and it is supposed to.

The enumeration — method, then membership

Subject + cause, with context, exactly as triage prescribed after breaking the single-line form on this very card:

git grep -nE -C2 "cloud-private|not installable|closed-source"

On the merge base a9c64779046facc1b0b2e74f71a9441b0f5b7fb8 (non-shallow): 60 hits / 36 files, minus published CHANGELOG.md and .changeset/**47 hits / 30 files. Every hit was then read in context and classified by hand — ⛔ no single-line | grep -i organizations filter, which is what hides a site whose subject and cause sit on different lines (harness.posture.test.ts is one: the subject is on line 9, the cause on line 10).

Membership proof against the claim's 30-file set (5649601883) — ⛔ not a count agreeing with a count:

check reading
files in my enumeration 30
files in the seat's table 30
in mine, not in the seat's 0
in the seat's, not in mine 0
symmetric difference 0
intersection (the instrument firing) 30

The two sets are equal by membership, and the intersection is non-empty, so the comparison instrument is live rather than silently matching nothing.

Per-site classification — all 47 in-scope hits

(i) still states the stale reason as currently true = MUST-FIX · (ii) already past tense / already recorded as "no longer cloud-private" = not touched · (iii) the subject is another package = not touched

Counts: (i) 21 hits / 13 files — all fixed · (ii) 19 hits / 13 files · (iii) 7 hits / 5 files.

Class (i) — fixed (21 hits, 13 files)

site what it said why (i)
packages/verify/src/harness.ts:45 "Stand-in for the cloud-private @objectstack/organizations runtime" the epithet is the justification for the stand-in, present tense
packages/verify/src/harness.ts:159 "instead of requiring the cloud-private enterprise package" same, in the BootOptions.multiTenant TSDoc
packages/verify/src/harness.ts:513 "is cloud-private and only ever lives in the host app's node_modules, so the import could never succeed" explicit causal so
packages/verify/src/harness.ts:534 "is cloud-private and resolves from nowhere in the framework workspace" present-tense cause
packages/verify/src/harness.posture.test.ts:10 "The enterprise package is not installable in this workspace, so a fake stands in for it" explicit causal so — the card's headline site
packages/verify/src/harness.posture-only.test.ts:4 "without the cloud-private enterprise runtime" epithet justifying the stand-in
packages/verify/src/harness.posture-only.test.ts:12 "is not installable in this workspace, so the fixture needed an honest way…" explicit causal so
packages/verify/src/harness.host-resolution.test.ts:9 "is cloud-private and only ever lives in the verified app's node_modules, so the import could never succeed" explicit causal so
packages/verify/src/harness.host-resolution.test.ts:24 "(it is not installable in this workspace — that is the whole point)" states the stale cause as the point of the fixture
packages/cli/test/serve-organizations-host-resolution.e2e.test.ts:9 "is cloud-private and only ever lives in the served app's node_modules, so the import could never succeed" explicit causal so
packages/cli/test/serve-organizations-host-resolution.e2e.test.ts:24 "(it is not installable in this workspace — that is the whole point)" as above
packages/types/src/node.test.ts:10 "while the package is cloud-private and only ever exists in the host app's node_modules. It could therefore never resolve" present-tense cause inside a past-defect narrative
packages/qa/dogfood/test/automation-toggle-tenant-scope.dogfood.test.ts:41 "runtime is cloud-private and genuinely absent from this workspace" both halves false — the package IS a workspace member now
packages/qa/dogfood/test/showcase-external-autoconnect.dogfood.test.ts:78 "the single honest walled harness is multiTenant: true with the cloud-private @objectstack/organizations" the epithet is why feasibility is in doubt
packages/plugins/plugin-dev/src/dev-plugin-tenancy-failfast.test.ts:22 "is a cloud-private enterprise package genuinely absent from this workspace, so the dynamic import genuinely fails" explicit causal so, and "absent from this workspace" is false
packages/plugins/plugin-dev/src/dev-plugin-tenancy-mount-refusal.test.ts:23 "off the genuinely-absent cloud-private package" / "the thing the open-source workspace cannot have" same premise, restated
packages/plugins/plugin-dev/src/dev-plugin-tenancy-posture.test.ts:23 "is a cloud-private enterprise package that is genuinely absent from this workspace, so the dynamic import genuinely fails" explicit causal so
docs/qa/platform-checklist/areas/attachments-storage.json:189 MARKER: "@objectstack/organizations is cloud-private, so the dogfood matrix's cross-tenant block is gated behind describe.skipIf(...)" explicit causal so
docs/qa/platform-checklist/areas/attachments-storage.json:277 same MARKER string, second carried copy as above
docs/qa/platform-checklist/areas/attachments-storage.json:358 same MARKER string, third carried copy as above
content/docs/plugins/packages.mdx:331 "Ships as a separate, closed-source enterprise package — it is not part of the open framework repo" ⭐ named by neither the card, the objection nor triage; the most customer-visible site in the set, and flatly false

The attachments-storage.json cluster is the one the order singled out, and the effect survives verbatim. The three copies carry the same MARKER string; only the cause clause changed. The sentences that carry the effect — "skips BY DESIGN here. That is blocked(dependency), never a pass and never a defect. A run that is supposed to ship the package sets OS_TEST_MULTI_ORG_ENABLED=1, which turns the skip into a hard failure instead of a silent one." — are byte-identical to before, and all three copies stay identical to each other (verified: 3 occurrences before, 3 after, and the file still parses as JSON).

Class (ii) — already past tense or already self-correcting (19 hits, not touched)

site why (ii)
packages/cli/src/commands/serve.ts:1107 already past-tensed: "the then-cloud-private package". ⚠️ triage cited this as :820; on a9c64779 it sits at :1107 — the only §1/§3 figure that moved
packages/rest/src/rest-api-plugin.ts:300 record of a cloud-side measurement ("cloud#1982 reproduced it … mounted")
packages/rest/src/single-kernel-isolated-api-key-matrix.test.ts:21 same: "cloud#1982 reproduced it on apps/objectos-ee"
packages/rest/src/single-kernel-isolated-session-org-claim-matrix.test.ts:11 same: "On a real objectstack serve of cloud's apps/objectos-ee"
packages/core/src/security/resolve-authz-context.ts:483 same incident, past tense ("measured on a live isolated boot")
packages/core/src/security/resolve-authz-context.test.ts:1604 under the heading "## What was measured, before the guard existed"
packages/qa/dogfood/test/enterprise-organizations.ts:26 "while the package was cloud-private and lived in the host app's node_modules"
packages/qa/dogfood/test/enterprise-organizations.ts:59 quotes prose it says the file "used to" carry
packages/qa/dogfood/test/enterprise-organizations.ts:101 "⚠️ #16539: no longer cloud-private — ADR-0132 / #16215 brought it back to open core"
packages/qa/dogfood/test/enterprise-organizations.ts:152 "the clause that used to close this comment … died with #16215"
packages/qa/dogfood/test/enterprise-organizations.test.ts:7 "The old probe answered 'unavailable' … because it resolved a cloud-private package"
packages/qa/dogfood/test/enterprise-organizations.test.ts:20 "@objectstack/organizations was cloud-private"
packages/qa/dogfood/test/enterprise-organizations.test.ts:53 "(… was cloud-private when these cases were written)"
packages/types/src/node.test.ts:50 "a real cloud-private package at the time", then records #16215 explicitly
packages/plugins/organizations/src/open-only-wall-acceptance.test.ts:20 "Until ADR-0132 moved this package into the open core that was unavoidable — the only registrar was cloud-private"
packages/services/service-cluster/src/multi-node-gate-mount.ts:61 the same doc block corrects itself eight lines later: "⚠️ @objectstack/organizations is ONE NAME over TWO packages since ADR-0132"
docs/adr/0132-…:35 history: records what cloud ADR-0081 D2 did. ⛔ ADRs are a maintainer floor and out of scope
docs/adr/0132-…:218 ADR-0132 stating its own consequence. ⛔ out of scope
docs/adr/0105-…:357 already carries an editorial note saying those sentences 「read as history」. ⛔ out of scope

⚠️ The five cloud-measurement rows are the one judgement call in this table a reviewer might reasonably take the other way, so the reasoning is stated rather than implied. Each records a measurement performed in the commercial repository, on cloud's apps/objectos-ee, with the copy that app declares. ADR-0132 split one package name across two packages, and this repository says so in its own words at multi-node-gate-mount.ts: "the framework publishes an Apache-2.0 package of that name and the commercial repo keeps a private licence-gated subclass of it". The copy those five sentences name is therefore still cloud-private, and the sentences are still true. serve.ts:1107 — which triage excluded by name — is the same shape with an explicit then- marker; these five are the same shape without one.

Class (iii) — the subject is another package (7 hits, not touched)

site subject
content/docs/kernel/services-checklist.mdx:74 @objectstack/service-ai — and true as written. This is the hit that makes the ruling's grep-to-zero a wrong edit
packages/types/src/node.ts:34 the epithet attaches to @objectstack/service-ai-studio, not to organizations. The claim it does make about organizations — host-supplied, invisible to a bare import — is still true (measured below)
packages/types/src/node.test.ts:74 "none of them can see a cloud-private package" — the class of such packages generically, and true
packages/spec/src/kernel/platform-capabilities.ts:204 closed-source @objectstack/ packages in general
packages/spec/src/kernel/platform-capabilities.ts:252 the roster row for @objectstack/security-enterprise (ADR-0057)
packages/spec/src/api/error-code-ledger.zod.ts:43 a closed-source product's error states
content/docs/references/api/error-code-ledger.mdx:47 generated from the row above — and content/docs/references/ is ⛔ never hand-edited

⇒ The order's packages/spec reading is confirmed independently: neither spec hit names @objectstack/organizations, so nothing here routes to the domain:spec seat and no file under packages/spec/** is touched.

The two controls, printed

control before after expected
must FIREentitlement boundary 2 files 15 files fires; it grew because every corrected site now cites the real cause
must say NOnot installable in this galaxy 0 0 still says no, so a zero here is a reading and not a dead instrument
must NOT be driven to zerogit grep -nF "not installable" 5 hits / 5 files 5 hits / 5 files unchanged on purpose (services-checklist.mdx:74 is true)

Class (i) after the change: 0. Remaining in-scope hits: 32 — every one of them class (ii) or (iii), including five new ones created by the corrections themselves, which say in so many words that being closed-source is not the reason.

The pin, and the boundary it defends

Zero dependency changes. git grep -l '"@objectstack/organizations"' -- '*package.json' returns exactly one file before and after — packages/plugins/organizations/package.json, the package's own manifest. no-framework-dependents.pin.test.ts is not in this diff and is green.

Measured while classifying — the plugin-dev premise holds, and is not a function of build state

Three plugin-dev sites said the dynamic import fails because the package is "genuinely absent from this workspace". Since ADR-0132 it is a workspace member, so before rewriting the cause I had to know whether the effect is still true — the order's STOP rule covers exactly this ("if a class-(i) site cannot be made to tell the truth without a behaviour change — STOP and report"). It is true, and for the entitlement-boundary reason:

  • A bare ESM import('@objectstack/organizations') from packages/plugins/plugin-dev, run on this file's own vitest runner, answers ERR_MODULE_NOT_FOUND "Cannot find package" — the package directory is never found.
  • Ablation, with packages/plugins/organizations/dist stubbed present: same answer, ERR_MODULE_NOT_FOUND "Cannot find package". So the signal is not a function of build state.
  • Discriminating control, same moment, same tree: a require-shaped resolve with the pnpm bin shim's NODE_PATH did resolve, to packages/plugins/organizations/dist/index.js — so the hoisted store copy is genuinely reachable that way, and the instrument can say "found". Node's ESM resolver does not consult NODE_PATH, which is why the two differ.
  • The stub was removed and the removal proven by git status --porcelain on that path being empty; the throwaway probe test was deleted before the first commit.

⇒ No behaviour change is needed anywhere in class (i), so the STOP rule did not fire. That measurement is recorded in dev-plugin-tenancy-failfast.test.ts itself, because it is the reason that file may keep reading a real failure rather than a stubbed one — and it is the same build-state trap #16539 had to move a require-shaped probe off a workspace name to escape.

Changeset

The gate's own words, from pr-automation.yml's "Require a changeset (or the skip-changeset label)" step:

  1. It releases nothing (.github/, .claude/, skills/, docs/, content/, examples/, tests-only, and the like)
    -> apply the 'skip-changeset' label. (the workflow marks this route PREFERRED)

This PR is not tests-only, so route 2 does not apply and the label would be wrong. Measured rather than assumed: packages/verify/src/harness.ts is source, its TSDoc is carried into dist/index.d.ts, and dist is in that package's files[]. After a real build of @objectstack/verify and its closure, the corrected sentence is present in packages/verify/dist/index.d.ts, with a positive control (untouched TSDoc prose from the same block: HIT) and a stale-cache probe (cloud-private in that .d.ts: absent, so the artifact is fresh rather than a turbo cache hit).

⚠️ The first attempt at that measurement read zero for the subject and zero for the control — a single-line grep for a phrase the formatter had wrapped across two lines. A zero against a dead instrument is not a reading; the figures above come from the whitespace-normalised re-measurement.

⇒ Route 1, patch, @objectstack/verify only. The other three touched published packages (cli, plugin-dev, types) changed only *.test.ts files, which the shared tsup entry (entry: ['src/index.ts']) never reaches and which CI's "No compiled test files in any dist" step forbids in dist anyway; packages/qa/dogfood is private: true. ⛔ No package is named whose published bytes do not move, and no level is raised: no behaviour and no public surface moves, so patch.

Verification

Everything below was run on this branch. Exit codes captured before any pipe; every heavy run went through scripts/pm/os-verify-lock.sh (slot issue-17369-cli-seat).

what command reading
derived gate set node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack 92 families (85 before the changeset existed; the changeset added 7)
all 92 each run individually 92 green
reconciliation node scripts/pm/dispatch-gates.mjs --ran … --repo … 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN — a derived zero: every family carries a recorded exit code and none is 3
repo lint pnpm lint exit 0, whole repo, unnarrowed (eslint . --no-inline-config)
⭐ the pin pnpm --filter @objectstack/organizations test exit 0no-framework-dependents.pin.test.ts green, and not in this diff
the pin's package typecheck pnpm --filter @objectstack/organizations typecheck exit 0
plugin-dev test · typecheck exit 0 · exit 0
types test · typecheck exit 0 · exit 0
verify typecheck pnpm --filter @objectstack/verify typecheck exit 0
the touched cli test OS_TEST_TIERS=nightly … vitest run test/serve-organizations-host-resolution.e2e.test.ts 3 passed (3)
the touched dogfood tests … vitest run test/automation-toggle-tenant-scope.dogfood.test.ts test/showcase-external-autoconnect.dogfood.test.ts 2 files, 11 passed (11)
full package build turbo run build --filter='./packages/*' --filter='./packages/*/*' 72 successful, 72 total

Three gates first read non-zero and are recorded twice on purpose, because a prerequisite failure is neither a pass nor a finding:

gate first reading after the prerequisite existed
pnpm --filter @objectstack/spec run check:skill-examples exit 1 — its own text: "packages/client-react/dist holds no .d.ts declarations — the package is not built" exit 0, 258 prose examples type-check
pnpm check:dual-build-cjs-loads exit 3 — "PREREQUISITE NOT MET … Run pnpm build first. ⛔ This is NOT a pass: nothing was measured." exit 0
pnpm check:type-check-debt exit 3 — PREREQUISITE NOT MET (unbuilt closure), then exit 3 again on a tsc OOM under my own --max-old-space-size cap, which the gate names as the binding constraint exit 0 — "5 ledger entr(ies) re-measured in 72.1s, 55 raw tsc error(s) total, none above its recorded number"

⚠️ pnpm --filter @objectstack/cli exec vitest run --project integration … returned exit 1 reading "No test files found" — recorded as NOT MEASURED, ⛔ not as a red. I had assumed "spawns the CLI ⇒ integration tier" and that was wrong twice over: packages/cli/vitest-tiers.ts classifies *.e2e.test.* as a nightly tier, so with OS_TEST_TIERS unset the file is outside both projects' population by design. The passing reading in the table above is the one taken under the switch the file actually runs in. test/vitest-tiers-partition.test.ts is green (22 passed), so the partition itself is intact.

⛔ One pre-existing failure in packages/verify, proven not to be this diff — filed as #17911

pnpm --filter @objectstack/verify test reads Tests 1 failed | 102 passed (103). The failure is harness.host-resolution.test.ts → "CONTROL — the declared-unresolvable remedy is unchanged: declared, not installed (#4719)", and it is #16539's defect in a file that card's fix did not reach:

  • My delta to that file is comment-only — the failing assertion is at line 299, untouched; the diff is a doc-block header.
  • Ablation, same built tree: the file was restored from its origin/main blob c89a1c1b1 and re-run — same single failure, same case. Restore proven by git diff HEAD empty, git status --porcelain empty, and the blob back to HEAD's e4ea9ed7e.
  • Cause, two-legged on one tree: packages/plugins/organizations/dist present → 1 failed | 6 passed (7); the same directory moved aside → 7 passed (7). So the control's verdict is a function of whether a sibling package has been built.

⇒ Not fixed here — it is a behaviour change to a test fixture, which this prose-only card may not make. Filed unassigned and bare as #17911.

Acceptance notes

Measured in passing, in scope for nothing here:


Generated by Claude Code

… cross-tenant proofs stand in

ADR-0132 brought the multi-organization runtime back to open core
(Apache-2.0, published on npm), which falsified the reason thirteen files
gave for standing in for it: "the enterprise package is cloud-private /
not installable in this workspace".

The EFFECT those files describe is unchanged and every behaviour, every
dependency and the pin stay exactly as they were. Only the stated cause
moves, to the true one: ADR-0132's entitlement boundary forbids any
framework package DECLARING `@objectstack/organizations`, pinned by
`no-framework-dependents.pin.test.ts` ("Apps declare it; packages do
not"), so a framework package cannot depend on it and cannot resolve it;
the proof that the real plugin walls tenants lives in cloud's
`security-enterprise` multi-org integration test.

Sites were enumerated by subject + cause with context
(`git grep -nE -C2 "cloud-private|not installable|closed-source"`) and
classified per site; only the class that still stated the stale reason as
currently true was edited. Measured while classifying: a bare ESM
`import()` of the package from a framework package answers
ERR_MODULE_NOT_FOUND "Cannot find package" with its `dist` built and
unbuilt alike, so the plugin-dev fail-fast signal is not a function of
build state.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
Co-authored-by: Claude <noreply@anthropic.com>
…e correction

`packages/verify/src/harness.ts` is the one touched file inside a published
`files[]` path whose bytes move: its TSDoc is carried into `dist/index.d.ts`
(measured after a real build, with a positive control and a stale-cache probe).
The other touched published packages — cli, plugin-dev, types — changed only
`*.test.ts` files, which the shared tsup entry (`src/index.ts`) never reaches.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/verify, touching 2 documentable anchor(s).

2 release-owned page(s) 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/17-0.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
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 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 — 2 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 a9c64779046facc1b0b2e74f71a9441b0f5b7fb8packageMentionDocs.

Which tree this was computed on

This run read content/docs from 59d2f7ffd95eaf30920d9e5e4284587f55b74db7 — the merge of head 7990da9233af387b15acd8c5e8e748855087d450 into base a9c64779046facc1b0b2e74f71a9441b0f5b7fb8, 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 59d2f7ffd95eaf30920d9e5e4284587f55b74db7 && git checkout 59d2f7ffd95eaf30920d9e5e4284587f55b74db7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a9c64779046facc1b0b2e74f71a9441b0f5b7fb8 7990da9233af387b15acd8c5e8e748855087d450 && git checkout -B drift-repro a9c64779046facc1b0b2e74f71a9441b0f5b7fb8 && git merge --no-ff 7990da9233af387b15acd8c5e8e748855087d450

node scripts/docs-audit/affected-docs.mjs --json a9c64779046facc1b0b2e74f71a9441b0f5b7fb8

⚠️ 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 a9c64779046facc1b0b2e74f71a9441b0f5b7fb8 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Contract review — PR #17910 (card #17369)

Head reviewed: 7990da9233af387b15acd8c5e8e748855087d450. 14 paths, +87/−44. Readings taken 2026-09-13T01:20–01:22Z against origin/* refs and merge base a9c64779046facc1b0b2e74f71a9441b0f5b7fb8.

⚠️ Independence: the implementer is a mode:subagent dev of this same PM session; ⛔ not an arm's-length second opinion.

① Derived judgments — measured here, ⛔ not ratified from the report

1. The acceptance is met in the form triage rewrote it: class (i) → zero, ⛔ not a phrase → zero. Every class-(i) site now states ADR-0132's entitlement boundary as the reason, and ⭐ the EFFECT survived where it had to: the three attachments-storage.json MARKER copies (:189, :277, :358) still read 「the dogfood matrix's cross-tenant block is gated behind describe.skipIf(!organizationsAvailable) and skips BY DESIGN here. That is blocked(dependency), never a pass and never a defect」 — the only thing that moved is the cause, which is exactly what option 3 authorised.

2. ⭐ A class-(i) site that NOBODY named, and it is the most customer-visible of the whole set. content/docs/plugins/packages.mdx:331 told readers the package 「Ships as a separate, closed-source enterprise package — it is not part of the open framework repo」. The card's nine sites did not name it; the objection's ledger did not; triage's ~27-line enumeration did not. The ruled instrument found it. ⇒ the rewritten acceptance criterion earned its keep on its first use, ⛔ not just as a correction of a broken one.

3. Two survivors this seat DOUBTED, and reading settled both against the doubt. packages/types/src/node.test.ts:50 reads 「a real cloud-private package」 — present tense at a glance, and class (i) if judged from that line. In context it is 「…was written against @objectstack/organizations, a real cloud-private package at the time」, and the next sentence is 「#16215 brought that package into this workspace」 ⇒ history, class (ii). :74's 「none of them can see a cloud-private package」 has a generic subject, not this package ⇒ class (iii). ⭐ Judged from the single line, this seat would have called two correct decisions wrong — which is precisely the instrument fault triage recorded on this card, arriving on the review side this time.

4. ⛔ Every banned path is clean, measured on the delivered head: packages/spec/ 0 · docs/adr/ 0 · CHANGELOG.md 0 · content/docs/releases/ 0 · package.json 0 · no-framework-dependents.pin.test.ts not in the diff. ⇒ no dependency moved, ADR-0132's entitlement-boundary premise is intact, and the two floors this card could have touched — the domain:spec seat's package and the ADR record — were not.

5. Clause-② re-measured on this head (twice tonight, the second time after the line was clobbered): added exported declarations in packages/verify/src/harness.ts, the diff's only non-test source file: 0, control lit (export ×5); non-comment added lines in that file: 0, so 「comment-only」 is measured, ⛔ not read off the title; whole-diff added export const|function|class|interface|type|default: 0. ⇒ Clause-②: no; @objectstack/verify: patch stands, and --pair 17910 returns exit 0.

② ⛔ Two figures in the report that measurement CONTRADICTS — both named, neither a defect

a. 「Still 5/5 after the change, deliberately」 is WRONG. Measured: git grep -nF "not installable" returns 3, not 5 — four class-(i) sites correctly stopped carrying the phrase. ⭐ The property it was asserting nevertheless holds, and holds where it matters: the grep did not reach zero, and content/docs/kernel/services-checklist.mdx:74 — the true sentence about @objectstack/service-ai, the entire reason triage forbade requiring that grep to zero — is byte-intact. ⇒ a correct act described by an incorrect figure. ⛔ The figure is not a reading and is retracted here.

b. The entitlement boundary control reads 16 files, not the 15 reported. The sixteenth is .changeset/17369-organizations-entitlement-boundary-prose.md, the PR's own changeset. Same set minus one identifiable member — before: 2, after: 16, so the control fires either way. ⭐ Same species as this round's standing lesson: two counts of one control can differ with neither being wrong, and only membership says which; naming the extra member is the whole repair.

③ Boundary flags

a. ⚠️ One site was fixed that the RULED INSTRUMENT COULD NOT SEE, and that is a scope question, not a nit. dev-plugin-tenancy-failfast.test.ts said the package 「is really absent」 — the same falsified premise as the class-(i) hit eleven lines above it, carrying none of the three enumerated phrases, so the acceptance's own enumeration is blind to it. The acceptance is defined by that instrument, so this is strictly outside it. ⇒ Accepted as in scope: same file, same sentence, same defect class, zero behaviour, and leaving it would have made the file contradict its own corrected paragraph three lines up. ⭐ It was disclosed by the dev in its acceptance notes, ⛔ not discovered at review — which is the difference between a judgement call and a widening.

b. The judgement call the dev flagged as reasonably-other-way — this seat read it and agrees, without overturning the flag. Five cloud-measurement sites (rest ×3, core ×2) are class (ii). Read at source: rest-api-plugin.ts:300 says 「cloud#1982 reproduced it with the real, cloud-private @objectstack/organizations mounted」 — a statement about what was mounted in the commercial repo, where the licence-gated subclass genuinely is private, and this repository says so itself at multi-node-gate-mount.ts. resolve-authz-context.ts:483 has the same shape. ⇒ (ii) is right. ⚠️ The other reading — that a reader may not notice the cloud#1982 scoping and take the adjective as current — is real, and is recorded rather than dismissed.

c. ⭐ A ruling's line numbers went stale mid-card and the dev located from TEXT. Triage excluded packages/cli/src/commands/serve.ts:820 for its past-tense 「then-cloud-private」; on this base that text sits at :1107. Same text, same class (ii), same exclusion — only the coordinate moved. This lane has now paid for that three times in a week.

d. #17911 was filed BARE and UNASSIGNED, explicitly ungraded — no domain:*, no type, no priority — for a pre-existing failure the dev proved is not this PR's (comment-only delta to the file; restored from origin/main's blob and re-run → same single failure; cause isolated by a two-leg ablation on organizations/dist present vs moved aside). ⛔ Grading is the triage seat's and the dev did not usurp it. ⇒ correct on both halves.

e. The clobber was this seat's fault, and the dev's diagnosis is better than the one this seat published. Check Changeset went red a second time at 01:15:20Z because the seat's clause-② line was gone — the dev had rewritten the body from a locally composed copy made at 00:33Z, so the 00:40Z line was never in the bytes it edited. ⇒ the failure mode is compose-then-overwrite, ⛔ not 「the author was not warned」; a read-modify-write of the live body cannot drop a line it has read. Owned at 5649903910, restored 01:17Z, generation 103651341925 success. ⭐ The restored block now carries its own notice in the body, so the next author learns it from the artefact instead of from a message.

f. ③ is met: 35 check names, all terminal — 31 success / 4 skipped / zero failures; mergeable_state: clean.

Independence pair

Implemented-by: claude/issue-17369-organizations-stale-cause-prose (mode:subagent)
Reviewed-by: os-sales — domain:cli execution seat, issue #6024, session_01TSf4DV7ziu4V5j73e46b7c
Independence: SELF-REVIEW — the implementer is a subagent of the reviewing seat's own session

Tier: default judgment — 「余席条款②复核 = 默认判断档自审加门禁」.

Verdict

PASS. ⛔ No carrier to clear — the claim declared the axis no, the delivered diff agrees, and --pair 17910 is exit 0. The two contradicted figures in ② are corrections to the report, ⛔ not to the change: the acts they described are right, and the acceptance — class (i) → zero with services-checklist.mdx:74 intact and both controls behaving — is satisfied on measurement rather than on assertion. ⇒ landing pre-check reduces to ③, which this head already meets.


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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

verify's cross-tenant proofs are skipped for a reason ADR-0132 falsified — but the obvious fix is pinned shut by the entitlement boundary

1 participant