docs(permissions): re-run the isSystem census — 101 of 111 anchors had rotted, and the page's "80 sites across 18 packages" was never true - #12969
Conversation
…opulation Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
|
ACCEPT — armed ( Entry qualification: every check. 36 runs at The census was re-run, not patched — and the page's headline was never trueThe grading demanded ⛔ "the fix is a re-census, not an anchor patch … report the current number; if it is no longer 80/18, that is part of the defect." Measured: the page claimed 80 sites across 18 packages while its own tables anchored 77, and the code held 83 across 18 at the census commit Reconciliation over the real population: 10 matched-and-correct · 101 matched-and-moved · 0 unmatched-on-page · 32 unmatched-in-code. Rot rate ≈ 101 anchors per 19 days. ⛔ And the population was 111, not the 64 my brief asserted. 64 was a The finding that decides the follow-up's shape⭐ Two sites were DELETED since the census — and both enclosing That is the page's worst failure mode — a row describing a protection that is gone, on the page someone consults when deciding whether elevation is safe — and it is exactly the case symbol anchors cannot catch. It is why the ruling on #12802 is option C: the gate lands first with the population check, and the symbol conversion happens inside that PR so it is verified rather than asserted. Enforcement filed as #12962. Instrument discipline worth copying⭐ The AST census is itself a correction. Two earlier regex passes each silently lost real sites — 6 in ⭐ The resolver was falsified in both directions in-run: ⭐ The card's own defect reproduced live mid-run — a rebase moved six Three gates first returned Also fixed, and neither the card nor my brief named it: 41 of the 111 anchors used a bare basename matching two files ( Two prose claims the re-census falsified are corrected on the page it owns: #6783's INFO notice has shipped, and Repo-wide
Generated by Claude Code |
Fixes #12802
The reporter checked 3 rows of
content/docs/permissions/system-context.mdxand found all 3 drifted, then explicitly did not audit the rest. Three-for-three on a page that claims "built by census over the whole repo, not by recall" means the census is stale wholesale, so this re-runs it rather than patching the sampled rows.Measured against
origin/mainatb1a987e4a(the branch point). Every number below is from a script in the worktree, not by hand.The four reconciliation buckets
Over all 111 anchors of the previous edition — not 64. A
grep -cfor anchor-shaped text answers 64 because it counts lines carrying an anchor; continuation anchors (the backticked:1409form) and range ends bring the real population to 111.ExecutionContext.isSystemread site with no row on the pageA fifth number the buckets do not capture: 41 of the 111 named a bare basename that matches two files (
engine.ts,sharing-service.ts,report-service.ts,seed-loader.tsand four more), so they could not be resolved at all without reading the row's Package column. This edition spells an ambiguous basename far enough to be unique —objectql/src/engine.ts, notengine.ts.The page's own claims, re-measured
The page asserted "a single boolean read at 80 distinct sites across 18 packages".
ExecutionContext.isSystemread sites (non-test sources)plugin-sharingsites ("19 of the 80")The headline was never true. The page's own tables anchored 77 read sites while its prose said 80 — a page that contradicted itself on the day it was written. Independently: measured at the census's own commit
ece8730(2026-08-09,docs(permissions): isSystem 行为全集权威表), the code held 83 sites in 18 packages. So 80 was wrong in both directions available to it — 3 short of the code, 3 over its own table.Rotted vs deleted vs newly-arrived
Populations measured by AST at
ece8730(83 sites) and atb1a987e4a(109 sites), aligned by file and enclosing scope:attachment-access-hooks.ts:79andcomment-access-hooks.ts:192, both theisSystem: exec.isSystempropagation inside acallerContext()helper. Both helpers still exist under the same name; only the read inside them is gone.ece8730and were never documented — the 32 unmatched-in-code above.The deletions change the answer to the card's open fork. #12802 offered symbol-name anchors or a resolving gate, and the dispatch asked for a measured view of the trade. A symbol anchor pointed at
callerContextwould still resolve today and would still be green — the symbol survived, the elevation read did not. On this page that is the failure that matters most, because the page's value is that it enumerates all elevated write sites for someone deciding whether elevation is safe. Symbol anchors stop the rot; only a population check catches a row describing a protection that no longer exists. Filed with that measurement as #12962.What the diff changes
isSystem: truehas at least three distinct, undocumented side effects across three packages — each one has cost an app-side bug #4707 ruling" recital moved with the measurement.ScopedContext.isSystem, the hook-session propagation, and two envelope builders) — they are not behaviours and are marked as such rather than being silently absent.rule-hooks.ts:274,:293callnoteSystemWriteSkipped); and row 33 (grant()) no longer merely skips its assertions, it asserts the grant is not inert instead.Maintaining this tablesection now states the census method, the measurement commit, and the full decomposition, so the numbers are re-derivable rather than assertable.Verification
Two throwaway instruments, both in the worktree and quoted in #12962, neither committed:
report-service.tsto a string-quoting desync, and a second regex pass lost 11 different ones to(ctx?.session as any)?.isSystemcasts. The AST census is exactly the union of both regex passes plus what each missed.git ls-files, refuses on ambiguity, and checks the resolved line against an expected fragment.Instrument checks, since a clean result is only a reading if the instrument can also come back dirty:
resolved 70 failures 41resolved 146 failures 0FAILED 110 of 110— the fragment check is not vacuousproblems 7, thenproblems 0after re-anchoringelevation reads 109 · without an anchor 0The rot reproduced during this run. Rebasing onto
b1a987e4apulled in one commit touchingsecurity-plugin.ts, and 6 of this page's anchors moved in that single merge (:3749to:3800,:4236to:4287,:4387to:4438,:4465to:4516, and both ends of the step-3.5 guard range). They are corrected here. That is the card's own point, observed live, and it is the argument for #12962.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackfrom the actual diff (1 path), re-derived after the rebase cleared its STALE TREE warning. All 23, exit code captured before any pipe:Three of them (
check:doc-formula-expressions,check:doc-security-posture,check:skill-examples) first returned exit 1 withPREREQUISITE NOT MET — the workspace package is not built. That is not a red gate and is not recorded as one: nothing was measured. They were re-run green afterturbo run build --filter=@objectstack/lint --filter=@objectstack/client-react --filter=@objectstack/client. The same run therefore contains both non-zero and zero rows, which is what makes the zeros readings.Verdict lines quoted from the gates themselves rather than from
$?:Heavy steps ran through
scripts/pm/os-verify-lock.shwithOS_VERIFY_LOCK_SLOT=issue-12802; both holds reportedVERDICT command-exit 0.Repo-wide lint: measured out of scope, not skipped
pnpm lintiseslint . --no-inline-config, and eslint's own configuration excludes this diff. Read from the instrument, not assumed:ESLint#isPathIgnored('content/docs/permissions/system-context.mdx')returns true, while the same call onpackages/objectql/src/engine.tsreturns false — so the predicate discriminates. The diff's linted-file count is therefore 0, and the diff touches no eslint config and no TypeScript, so no untouched file's verdict can move.Changeset: derived, none written
content/docs/**is documentation content in no published package, and the repo's practice is unambiguous on two direct precedents:ece8730(this very page's creating commit, docs-content only) andb1581b04(docs(content): one h1 per docs page, 137 deletions acrosscontent/docs/**) both landed with zero.changeset/files.changeset-checkinpr-automation.ymlhas no path-based exemption, soskip-changesetis the only way either could have landed.dispatch-gates.mjssays the same in its own words: "write one unless this card is docs-only". This PR carriesskip-changesetand no changeset.Scope
Per the dispatch ruling, this round is the census correction only. The enforcement mechanism is #12962 —
.github/workflows/lint.ymland the rootpackage.jsonwere both held by open PR #12942 this round, so a new gate could not land here.Generated by Claude Code