Repository navigation
tenant-audit census collapses declared type text before re-parsing it (route ①), and conflates same-named locals across scopes #19300
Description
Path: P1 | 那条路第 1 步「写元数据」 | 普查把声明类型文本折成一行再重解析,合法的换行内联对象类型读不出来
分诊重测与定级:2026-09-20T15:29Z
Origin
Triage on #19077 named three routes for the census's unreadable-type-text class. PR #19290 implemented route ③ — localise the failure into a per-site refusal instead of a process-wide takedown — and an at-tier review confirmed it holds. Route ① — stop collapsing the declared type text — was named there as the real repair and is not in the tree. #19077 will close on #19290's merge, so it is carried here.
Defect 1 — the census collapses declared type text before re-parsing it
Measured at PR #19290 head ce1b530410150de7f229a6ffb9dab0dd1608baf6, re-read first-hand by this seat in a detached worktree. scripts/tenant-audit-census.mjs stores declared type text through getText(sf).replace(/\s+/g, ' '):
:508 type: typeNode ? typeNode.getText(sf).replace(/\s+/g, ' ') : null,
:527 if (t) m.set(mem.name.text, t.getText(sf).replace(/\s+/g, ' '));
:590 return node.getText(sf).replace(/\s+/g, ' ');
A newline-separated inline object type is legal TypeScript, but once its newlines become single spaces the text no longer re-parses: the members run together and census-receiver-type.ts dies at 1:78 ';' expected. After #19290 the site is no longer a process-wide takedown — it is refused by name as type-text-not-round-trippable — but the author is still told to restyle legal TypeScript (add ; separators, or name the type) to work around the tool's own reading.
The reviewer's judgement, verbatim:
the arm is a refusal that tells the author to restyle legal TypeScript (
;separators or a named type) to work around the tool's own collapse at :480/:499/:562. That is what the sequenced hunk asked for and it is strictly better than the takedown it replaces, but the underlying limitation is still in the tree; the PR's "Not a defect in the tree" under-states it. Triage's route ① (stop collapsing) is the real repair.
(The reviewer's :480/:499/:562 are that file's line numbers at an earlier base; at the PR head they are :508/:527/:590 as quoted above.)
Defect 2 — declaredTypesIn keys its locals map by bare identifier name, with no scope
Same file, same head. declaredTypesIn(sf) (:496) builds const locals = new Map() (:498) and fills it by bare name (note(locals, n.name.text, …) at :534 and :543, locals.set(el.name.text, …) at :555); every consumer reads it back by bare name (:648, :655, :677, :1156, :1329). Two parameters that share a name in different scopes therefore conflate.
Measured instance, from the same review: a fixture whose two receiver sites both named their parameter engine had both sites refused. Renaming one made the control clean. This is pre-existing, not introduced by #19290, and it produces false refusals in the census.
Note for triage
Two distinct defects in one file's TypeScript reading, with two distinct fixes. They are filed together because they were measured in one act; splitting them into two cards is a reasonable triage call.
Dedup words
type-text-not-round-trippable, declaredTypesIn, tenant-audit-census, census-receiver-type, getText collapse
Origin: at-tier contract review of PR #19290, comment 5749193385 (2026-09-20T10:19Z) — "Residual" under ① and the out-of-scope observation under the lit control. Line readings re-taken by this seat at 2026-09-20T10:28Z.
Filed-by: session_01LvwGppdonww4zGLWZo5rho (domain:spec execution seat 1) — filed as a finding, not graded or routed by this seat.
Generated by Claude Code
Activity
os-support-ai commentedon Sep 22, 2026
Claim: PM loop round 1
Session:
session_013RDBh5DqXd2xnLwvHLgLFrBranch:
claude/issue-19300-census-type-text-roundtripWorktree:
objectstack-issue-19300Domain:
domain:specSeat:
domain:spec#1File surface:
scripts/tenant-audit-census.mjsplus its self-test and fixtures, and.changeset/(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: claude-opus-5— default judgment tier, quoting this act's own--tierrun: 「no path-derived mandate … floor sonnet · default opus · ceiling opus」Clause-②: no
Thread-read: none
Serial constraints cleared:
#19299declares the same file and is deliberately NOT dispatched — serialised behind this card, ⛔ not folded (同族异缺陷 不并: #19299 is the self-test control coupled throughrefuse, a different defect from these two). No in-flight claim in this lane declaresscripts/tenant-audit-census.mjs— all 12 in-flightClaim:comments were read first-hand and intersected locally at 2026-09-22T03:23Z.Thread-read: noneis a measurement, not an omission: this card counts 1 comment and 0 of them are readable (the #19607 unreadable-comment condition in this lane). To rule out a claim hiding inside that unreadable comment, this seat probed the other carrier —git ls-remote origin 'refs/heads/claude/issue-19300*'returns empty ⇒ no pushed work, so no implicit claim. Lit control: the same probe shape returns branches for #19054, #17518 and #19581.Generated by Claude Code
os-support-ai commentedon Sep 22, 2026
os-dev-report
{⚠️ If the seat still wants a changeset, say which package it should name and I am wrong.",
"issue": 19300,
"status": "rework",
"branch": "claude/issue-19300-census-type-text-roundtrip",
"pr": "#19650",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"summary": "Both defects reproduced first-hand, repaired, and pinned. Defect 1: the declared type text is stored verbatim, so a newline-separated inline object type re-parses and is PLACED instead of refused; the collapse stays at the render boundary where it already lived. Defect 2: declaredTypesIn resolves a name through its innermost enclosing scope, with the old bare-name map kept as an explicit floor tier so no receiver that resolved before stops resolving. The population is unchanged (227 sites before and after, none added, none removed); 14 sites change attribution and one receiver becomes honestly unreadable and gains an UNTYPED_RECEIVERS row. status=rework because the PR is knowingly RED on check:tenant-audit-census: those moved totals stale the census artefacts, and both of them are OUTSIDE this dispatch’s declared file surface. Stopped at the fence rather than widening it; the remaining work is named exactly in the PR body and in open_questions, and it is NOT a one-command close.",
"tests": "Gate set: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 29 families for this diff (the dispatch named a 10-command subset of them). All 29 run on final head; --ran reconciles 29 derived / 29 run / 0 NOT-MEASURED / 0 UNRUN, every family carrying a recorded exit code. 27 green. The 2 red are node scripts/check-tenant-audit-census.mjs and its --self-test, both and only on artefact drift: 2 [census-drift] + 5 [prose-count], zero other error classes. Census itself exits 0; census selfTest exits 0 at 67 cases (was 57). || RED-THEN-GREEN, defect 1: probe on base tree returned other/type-text-not-round-trippable for a newline-separated inline object type on a parameter AND through the shapes map; after, both return engine/inline type literal stating an engine door. The semicolon control was PLACED before and after. || RED-THEN-GREEN, defect 2: two parameters named engine in different scopes returned "engine/IProbeEngine | engine/IProbeEngine" before (a Map.delete admitted to the certified population) and "engine/IProbeEngine | other/platform-type" after; in the reversed declaration order it returned "other/platform-type | other/platform-type" before (a REAL engine write subtracted under a DEFENDED arm, printing nothing and counted nowhere) and "other/platform-type | engine/IProbeEngine" after. || ABLATION x3, each run from the COMMITTED state through scripts/ablation-replace.mjs, which proved the mutation landed on disk by anchor count and blob hash and verified every restore as blob == HEAD with
git diff HEADempty: (a) re-collapse note()’s type -> 3 of 67 red (inline, parameter-annotation, non-door-newline); (b) re-collapse the shapes member type -> 1 of 67 red (the interface-member case only, which proves the two storage sites are independently reached and that neither pin is vacuous); (c) replace the lexical tier’s scope chain with an empty one -> 4 of 67 red (both declaration orders, the object name, the elevation). The FLOOR case stayed green under (c), as designed. No build/dist exists for a repo-root .mjs, so no dist preflight applies; no ablation artefact remains and the tree is clean. || ARTEFACT-NEUTRALITY of defect 1 measured, not assumed: with ONLY the two storage-site lines changed, the full census --json is byte-identical to the base tree (diff exit 0, 0 lines). Every count that moves comes from defect 2. || Control bytes: grep -naP over the changed file and over every GitHub payload -- clean. No HTML comments; angle-bracket shapes rewritten as placeholder spellings before posting.","gates": {
"node scripts/check-ci-filter-parity.mjs": 0,
"node scripts/check-closing-keyword-parity.mjs": 0,
"node scripts/check-closing-keyword-parity.mjs --self-test": 0,
"node scripts/check-comment-mask-corpus.mjs": 0,
"node scripts/check-declaration-mirrors.mjs": 0,
"node scripts/check-declaration-mirrors.mjs --self-test": 0,
"node scripts/check-scripts-symbol-anchors.mjs": 0,
"node scripts/check-scripts-symbol-anchors.mjs --self-test": 0,
"node scripts/check-self-test-wired.mjs": 0,
"node scripts/check-self-test-wired.mjs --self-test": 0,
"node scripts/check-self-test-workflow-commands.mjs": 0,
"node scripts/check-self-test-workflow-commands.mjs --self-test": 0,
"node scripts/check-tenant-audit-census.mjs": 1,
"node scripts/check-tenant-audit-census.mjs --self-test": 1,
"node scripts/check-whole-set-label-write.mjs": 0,
"node scripts/check-whole-set-label-write.mjs --self-test": 0,
"pnpm check:agent-test-spelling": 0,
"pnpm check:bash32-floor": 0,
"pnpm check:cli-command-ids": 0,
"pnpm check:cross-package-test-inputs": 0,
"pnpm check:driver-memory-census": 0,
"pnpm check:entry-guard": 0,
"pnpm check:gitlink-declared": 0,
"pnpm check:nul-bytes": 0,
"pnpm check:parse-guard": 0,
"pnpm check:pnpm-filter-targets": 0,
"pnpm check:ratchet-remedy-authority": 0,
"pnpm check:refd-timer-probe": 0,
"pnpm check:watch-hint-literal": 0
},
"line_budget": "n/a",
"files_changed": [
"scripts/tenant-audit-census.mjs"
],
"mcp_calls": "0 — no MCP tool of any kind was called; all GitHub access went through the REST proxy with curl",
"api_writes": "3 REST proxy writes — POST /repos/objectstack-ai/objectstack/pulls (draft PR 19650); POST /repos//issues/19650/labels (skip-changeset, via scripts/pm/label-write.mjs, read-back confirmed
size/m+skip-changeset); POST /repos//issues/19300/comments (this report). Plus 3 git pushes to the claimed branch. Zero writes outside the budget.","deviations": [
"CHANGESET — the dispatch said "the changeset is patch"; MEASURED otherwise and applied
skip-changesetinstead. The root package isprivate: true, no package manifest namesscripts/in itsfiles[], and the only repo-wide references todeclaredTypesIn/tenant-audit-censusare inscripts/andcontent/docs/. A repo-rootscripts/file is outside every package directory, sofiles[]cannot ship it and there is NO package a changeset could name. Precedent agrees: recent scripts-only commits carry none. Label written throughscripts/pm/label-write.mjsand read back."ARTEFACTS NOT REGENERATED — deliberate fence stop, see open_questions.
check:tenant-audit-censusand its --self-test are RED on this PR by construction and on nothing else.","GATE SET — ran all 29 families
dispatch-gates --commandsderives for the real diff, not the 10-command subset the dispatch named; the subset was a strict subset. Reconciled with --ran on the final head, every family carrying a recorded exit code.","ZONE-2 #2 CORRECTED — "about eight" collapse hits is an over-count of the DEFECT. 11 sites spell the idiom; exactly TWO of them feed the re-parse (note()’s
typeand the shapes member type).receiverKey(a ledger key), note()’sinit(a diagnostic truncated to 120 chars), the spread/opaque/runtime-name sites and the two self-test fixtures are never re-parsed. The card’s three-site list is also wrong in the same direction: it namesreceiverKeyand misses the shapes site. Both storage sites are independently ablated in the self-test.","ZONE-2 #3 SETTLED —
:355is NOT a member, with an argument: itsreplace(/\\s+/g, '')result has exactly one consumer,t !== 'string'. It normalises for an equality test and is never handed to a parser. Left untouched.","ZONE-2 #4 CONFIRMED —
declaredTypesInat :496,localsat :498, 6 call sites at 1360/1877/1929/1948/2095/2126 on the dispatch tree, exactly as stated. Shapes trusted, numbers re-derived.","ZONE-2 #1 CONFIRMED —
git logon the file shows one commit, c9b23cd (a liveness-walk seam). Route ① genuinely absent; both defects reproduced first-hand before any edit.","UNREADABLE-COMMENT CONDITION FALSIFIED — the dispatch said the card counts 1 comment and 0 are readable. The card counts 1 and it IS readable: GET /issues/19300/comments returned it in full (1524 bytes) and a direct GET on comment 5770753094 returned 200 with the same body. It is the claim itself, and it names
claude/issue-19300-census-type-text-roundtrip— verified, identity confirmed, no second Claim written. The card BODY is also intact: 3618 bytes ending in its own footer, no sanitizer truncation.","DEFECT-2 BLAST RADIUS WIDER THAN THE CARD — the card says the conflation "produces false refusals". Measured, it produces three things, and the card names only the third: a
Map.deleteADMITTED to the certified population; a REAL engine write subtracted asplatform-type, a DEFENDED arm that prints nothing and is counted nowhere (the census’s own header calls that the direction it cannot survive being wrong in); and both sites refused. It also decided WHICH object a site writes and WHETHER it is elevated. All pinned.","BARE-NAME COMMIT TRAILER — the pre-push gate
check:commit-card-trailersrefuses the harness attribution line carrying a model name. Used the model-free pair per the standing rule; no history was rewritten."],
"open_questions": [
{
"question": "The defect-2 repair moves the census totals, which stales the two committed artefacts. Both are OUTSIDE the declared file surface, so this PR is knowingly red. How should it be closed?",
"options": [
"A — widen this card’s surface by two files and let me finish it on this branch:
node scripts/tenant-audit-census.mjs --writeregeneratescontent/docs/permissions/tenant-audit-census.mdxanddocs/audits/2026-08-tenant-audit-write-call-sites.counts.md, and FIVE hand-written prose numbers on the page need editing that--writedoes not touch (const 41→43, unreadable-and-tenancy-enabled 32→34 twice, statically decidable 151→153, undecidable 76→74). The gate names each one. NOT a one-command close.","B — land the artefact-neutral half alone. MEASURED: with only the two storage-site lines changed the census --json is byte-identical to base (diff exit 0). Defect 1 could ship green today; defect 2 then needs its own card with the wider surface.",
"C — dispatch the artefact half to a seat that already holds
content/docs/**, stacked on this branch."],
"recommendation": "A. The two halves are one card, the mechanism is done and pinned, and splitting now discards a verified repair to buy a green checkmark. The extra surface is two files the census itself owns plus five numbers the gate points at by name — bounded, mechanical to verify, and cheaper than a second dispatch. I stopped rather than widening silently because the dispatch said to; one word and I finish it."
},
{
"question": "Re-pricing #19299, which the dispatch asked me to answer: does this change make it easier, harder or moot?",
"options": [
"It becomes ACUTELY LIVE, not moot."
],
"recommendation": "ACUTELY LIVE. #19299 is the gate self-test’s clean-census control being coupled to the live tree through
refuse. That coupling was LATENT while the tree was clean. With the artefacts drifted, 6 of the gate’s 27 self-test cases now fail — and FIVE of them are controls asserting that a stale number, a stale corpus-scale count and an old measurement date are NOT findings. They fail for exactly the reason they exist to deny, and they would fail for ANY census change that moves a number, not only this one. ⇒ #19299 should be re-priced UP and is a hard prerequisite for landing option A cleanly: until it is fixed, the gate self-test cannot distinguish "the controls are broken" from "the tree drifted". ⛔ Not folded in — different defect, deliberately serialised."}
],
"out_of_scope_findings": [
"class: a · Two classes in ONE file sharing a property name conflate through
thisProps, which is keyed by bare name exactly aslocalswas. Failing probe, run on this branch:class A { constructor(private readonly engine: IProbeEngine) {} w() { this.engine.insert(...) } }besideclass B { constructor(private readonly engine: Map of string to number) {} w() { this.engine.delete('k') } }returns "engine/IProbeEngine | engine/IProbeEngine" — aMapADMITTED to the certified tenancy population.fnReturnsdoes the same for two same-named local functions (same probe shape, same wrong answer). NOT folded in:thisPropsneeds CLASS scope, a different notion from the lexical chain this PR adds, so the bounded-in-place exemption fails its "shape already pinned" limb. dedupe words:thisProps,fnReturns,declaredTypesIn,tenant-audit-census, bare-name conflation","class: b ·
scripts/check-tenant-audit-census.mjs:645-651mirrors the refusal prescription "spell the literal’s members with;separators so the stored text round-trips". That is false after this change and it is the copy CI prints; the census’s own copy now says the opposite. Contract text: the arm’s declared meaning. carrier: the artefact-regeneration work in open_questions A — same family, same seat, same PR. dedupe words:type-text-not-round-trippable,check-tenant-audit-census, restyle prescription","class: b ·
scripts/ts-parse.mjs’s header documents the tenant-audit-census collapse as a LIVE defect, with a dated measurement table. It is historical now. carrier: same as above. dedupe words:ts-parse,parseDerivedText,census-receiver-type, collapse header","carrier: the artefact-regeneration work in open_questions A · Contextually typed parameters are unreadable to this census, before and after —
(engine) => engine.insert(...)against a declaredrun: (engine: IDataEngine) => ...needs a type checker this module does not have. Six sites inmetadata-store.tsmove fromdeclared-typeto the object-name rescue because the bare-name map had been answering it from an unrelated declaration and happened to be right. Verdicts unchanged. A capability gap, not a regression — noted, not filed, so the move is not misread as one."]
}
Generated by Claude Code
os-support-ai commentedon Sep 22, 2026
os-dev-report
{⚠️ NOTE the shape: ⚠️ THREE parts of the PR body are now STALE, and the body is yours to write, not mine. When you flip
"issue": 19300,
"status": "done",
"branch": "claude/issue-19300-census-type-text-roundtrip",
"pr": "#19650",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"round": "follow-up — option A, fence widened by the coordinator",
"summary": "The widened surface is complete and the PR is GREEN on everything this diff derives. Artefacts regenerated via --write; the four hand-written prose numbers taken from the gate’s own output, not from anyone’s retyping. The two prose mirrors (the gate’s refusal prescription and ts-parse’s fourth-door section) are TEXT ONLY — neither needed a behaviour change, so neither triggered the stop-and-report clause. origin/main was merged in first, because the derivation refused to answer from a stale tree and named
scripts/pm/dispatch-gates.mjsitself as having changed in that range. Final head c42c07a: 5 files, +357/-122.","hard_checks": {
"gate self-test returns to GREEN": "YES —
check-tenant-audit-census.mjs --self-testexits 0, 27 of 27 cases, up from 6 failing. The diagnosis held exactly: all six were the drift and regeneration cleared every one. ⇒ #19299’s coupling is NOT worse than established — it is precisely what I reported: latent on a clean tree, firing on a drifted one. Nothing to escalate, and it stays serialised and out of this PR.","full derived set reconciled with --ran on the final head": "66 derived / 66 run / 0 NOT-MEASURED / 0 UNRUN, every family carrying a recorded exit code, ALL ZERO. The set grew 29 -> 66 because the diff now reaches content/docs/, docs/audits/ and ts-parse.mjs.",
"no gate reported clean that could not run": "Five families first returned PREREQUISITE NOT MET — three needing @objectstack/lint built, one needing
packages/spec/json-schema, one needing @objectstack/client-react declarations. ⛔ Recorded as NOT MEASURED, never as clean. Two builds throughscripts/pm/os-verify-lock.sh(slot issue-19300-dev, VERDICT command-exit 0 at 158s and 293s) satisfied them; all five then re-measured to exit 0.@objectstack/spec check:docsexits 1, not 3, on its missing prerequisite — an exit code that reads as a finding but says in its own text "NOT a finding". Do not read that 1 as red anywhere.","adversarial re-read before pushing": "One push carried the whole round. The artefact diffs were read line by line and are internally consistent with the site-level measurement: "receiver carried a readable engine type" stays 183 because six sites leave declared-type placement and six arrive, object-NAME placement goes 18 -> 24 and ledger placement 11 -> 5 for the same six, and
bootstrap-declared-webhooks.tsresolves tosys_webhook/enabled whilemigrate-webhook-secrets.tsin the same table correctly stays undecidable — there the name really is a bare typed parameter, which is the control that shows the scoped lookup discriminated rather than blanket-resolved."},
"merge_note": "origin/main (80ca0b1) merged in.
--writere-run on the MERGED tree moved exactly one line in each artefact — the unenforcedMeasured on … at SHAstamp — and not a single certified number. That is the positive control that main’s three commits do not touch this census, checked beforehand too: none of the three changed files carries a verb-call shape or anobject: stringparameter, so none can enter the engine type index. The sha churn was reverted withgit checkout HEAD --, verified by an emptygit statusAND an emptygit diff HEAD, so the stamp still names 9db2c62 — the commit whose tree actually produced the numbers. The field is unenforced by design ("its job is to tell a reader how old the numbers are, not to be fresh").","tests": "All 66 derived families green on final head c42c07a, reconciled 66/66/0 NOT-MEASURED. check-tenant-audit-census: exit 0 — "227 write call sites certified (153 decidable; 9 tenancy-enabled sites PROVABLY carry no tenant context, 34 more unreadable), 23 prose figures held to the census, every write call site placed and every UNTYPED_RECEIVERS row matched". Its --self-test: exit 0, 27/27. Census selfTest: 67/67. ts-parse --self-test: exit 0, 48/48 (the file whose header I edited). The three ablations from the previous round still stand and were not re-run — no code path changed this round, only generated artefacts and comment/refusal prose. Builds went through the shared verify lock; neither moved a tracked file,
packages/spec/authorable-surface.base.jsonincluded (checked explicitly).","gates": {
"node scripts/check-ci-filter-parity.mjs": 0,
"node scripts/check-closing-keyword-parity.mjs": 0,
"node scripts/check-closing-keyword-parity.mjs --self-test": 0,
"node scripts/check-comment-mask-corpus.mjs": 0,
"node scripts/check-declaration-mirrors.mjs": 0,
"node scripts/check-declaration-mirrors.mjs --self-test": 0,
"node scripts/check-doc-frontmatter.mjs": 0,
"node scripts/check-doc-frontmatter.mjs --self-test": 0,
"node scripts/check-doc-route-spelling.mjs --advisory": 0,
"node scripts/check-doc-route-spelling.mjs --self-test": 0,
"node scripts/check-docs-section-name.mjs": 0,
"node scripts/check-docs-section-name.mjs --self-test": 0,
"node scripts/check-scripts-symbol-anchors.mjs": 0,
"node scripts/check-scripts-symbol-anchors.mjs --self-test": 0,
"node scripts/check-section-landing-index.mjs": 0,
"node scripts/check-section-landing-index.mjs --self-test": 0,
"node scripts/check-self-test-wired.mjs": 0,
"node scripts/check-self-test-wired.mjs --self-test": 0,
"node scripts/check-self-test-workflow-commands.mjs": 0,
"node scripts/check-self-test-workflow-commands.mjs --self-test": 0,
"node scripts/check-system-context-census.mjs": 0,
"node scripts/check-system-context-census.mjs --self-test": 0,
"node scripts/check-tenant-audit-census.mjs": 0,
"node scripts/check-tenant-audit-census.mjs --self-test": 0,
"node scripts/check-whole-set-label-write.mjs": 0,
"node scripts/check-whole-set-label-write.mjs --self-test": 0,
"node scripts/pm/bare-root-worklist.mjs --self-test": 0,
"node scripts/ts-parse.mjs --self-test": 0,
"pnpm --filter @objectstack/lint run check:doc-formula-expressions": 0,
"pnpm --filter @objectstack/lint run check:doc-security-posture": 0,
"pnpm --filter @objectstack/spec run check:docs": 0,
"pnpm --filter @objectstack/spec run check:empty-state": 0,
"pnpm --filter @objectstack/spec run check:liveness": 0,
"pnpm --filter @objectstack/spec run check:skill-examples": 0,
"pnpm --filter @objectstack/spec run check:strictness-ledger": 0,
"pnpm --filter @objectstack/spec run check:variant-docs": 0,
"pnpm --filter @objectstack/spec run check:yaml-examples": 0,
"pnpm check:agent-test-spelling": 0,
"pnpm check:bash32-floor": 0,
"pnpm check:cli-command-ids": 0,
"pnpm check:corpus-claim-drift": 0,
"pnpm check:cross-package-test-inputs": 0,
"pnpm check:doc-anchors": 0,
"pnpm check:doc-authoring": 0,
"pnpm check:docs-audit-scope": 0,
"pnpm check:docs-redirects": 0,
"pnpm check:docs-single-h1": 0,
"pnpm check:docs-spec-enumerations": 0,
"pnpm check:docs-transcript-drift": 0,
"pnpm check:driver-memory-census": 0,
"pnpm check:entry-guard": 0,
"pnpm check:gitlink-declared": 0,
"pnpm check:merge-driver": 0,
"pnpm check:nul-bytes": 0,
"pnpm check:parse-guard": 0,
"pnpm check:pm-dispatch-gates": 0,
"pnpm check:pm-widening-tells": 0,
"pnpm check:pnpm-filter-targets": 0,
"pnpm check:published-readme-links": 0,
"pnpm check:ratchet-remedy-authority": 0,
"pnpm check:react-page-adapter-contract": 0,
"pnpm check:refd-timer-probe": 0,
"pnpm check:role-word": 0,
"pnpm check:skill-identifier-liveness": 0,
"pnpm check:vendor-version-stamps": 0,
"pnpm check:watch-hint-literal": 0
},
"line_budget": "n/a",
"files_changed": [
"scripts/tenant-audit-census.mjs",
"content/docs/permissions/tenant-audit-census.mdx",
"docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
"scripts/check-tenant-audit-census.mjs",
"scripts/ts-parse.mjs"
],
"mcp_calls": "0 — unchanged; no MCP tool called in either round",
"api_writes": "1 REST proxy write this round — POST /repos//issues/19300/comments (this report), plus one git push to the claimed branch. ⛔ No PR-body write, no label write, no card filed. Round total across both rounds: 4 REST writes.",
"pr_body_handoff": [
"
Part of #19300toFixes #19300, these want the same edit:","1. The section "⛔ Named gap: check:tenant-audit-census is RED…" is closed. Both steps it lists are done and the gate and its self-test are green.",
"2. Acceptance-notes bullet 1 (check-tenant-audit-census.mjs:645-651) says "Outside this PR’s surface". It is now IN this PR and fixed.",
"3. Acceptance-notes bullet 2 (ts-parse.mjs header) — same, now fixed here.",
"✓ NOT stale and needing nothing: the capability-gap bullet you asked to be in
## Acceptance notesis ALREADY there, already marked "A capability gap, not a regression; recorded so the 6 sites’ move to the object-name rescue is not read as one." Verified against the published body — no write needed for it.","✓ Also still accurate: the verification section says 29 families; on the widened diff it is 66, all green."
],
"deviations": [
"MERGED origin/main INTO THE BRANCH — not in the instruction, so flagging it.
dispatch-gates --commandsrefused to answer cleanly from my tree: "STALE TREE — this answer is derived from a tree at least 3 commit(s) behind origin/main, and 1 file(s) it derives from CHANGED across that range. Stale here: scripts/pm/dispatch-gates.mjs … a well-formed answer about a tree nobody is on." Reconciling a derived set against a derivation I had been told was stale would have been the false-green shape, so I merged and derived again. No conflicts; the merge base moved c3a4c74 -> 80ca0b1 and the changed-path set is still exactly the five files.","THE THREE CORRECTIONS you accepted are recorded as settled and not re-argued: the changeset stays
skip-changesetand none was added; the 11-spell / 2-consume split stands; the unreadable-comment claim is dropped and carried nowhere.","NOT DONE, deliberately: no PR-body write, no card filed, #19299 untouched — all four are yours per the instruction."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · STILL OPEN, yours to file —
thisPropsandfnReturnskeep the bare-name conflation this PR fixed forlocals. The failing probe is in the previous report and still reproduces on this head. dedupe words:thisProps,fnReturns,declaredTypesIn,tenant-audit-census, bare-name conflation","RESOLVED IN THIS PR — the two class-(b) prose mirrors (check-tenant-audit-census.mjs refusal prescription; ts-parse.mjs fourth-door header). Both were text-only. ⛔ No longer findings; do not file them.",
"carrier: none needed · Contextually typed parameters remain unreadable to this census, before and after. Already in the PR’s Acceptance notes, marked not-a-regression. Noted, not filed."
]
}
Generated by Claude Code
os-support-ai commentedon Sep 22, 2026
ACCEPT — PR #19650, ordinary queue landing, 2026-09-22T05:17Z
Reviewed by
domain:specseat 1 (session_013RDBh5DqXd2xnLwvHLgLFr, seat post #6017) against GitHub, ⛔ not against the report's narrative. Two dev rounds: a fence stop, then the widened surface.Checklist
main·Fixes #19300(seat rewrote the keyword fromPart of; the body is the seat's write, ⛔ not the dev's)check-governed-merges --pr 19650: 0 of 5 paths hit the register ⇒ ordinary queue landing, ⛔ not the governed four-piecepackages/spec/src/**), declarationno⇒ no contract review owedskip-changeset, and the dev's argument is correct — see deviationsSpot-checks this seat took itself
Lint & Repo Gatesconcludedsuccess, and that job stops at the first non-zero exit, so a success means no step exited early — plus a lit control,check:duration-unit-keys(a named member of that never-ran list) now runs and passes with a full reading (205 unit-declaring keys across 2559 files).ts-parse.mjsis better than the instruction asked for. It was told to make a stale header historical. It did — and added that the door it documents must ⛔ NOT be retired on the strength of this fix, because the measurement is a fact about the parser, which has not changed. Marking it merely "fixed" would have set the next reader up to retire a live door for the wrong reason.Deviations
skip-changesetinstead. Verified here: rootpackage.jsonisprivate: trueand nopackage.jsonfiles[]anywhere shipsscripts/. There is no package a changeset could name. The seat applied the lane's 辅助面恒 patch default without checking a publishable package existed. ⛔ Not recorded against the dev.origin/maininto the branch — not instructed, correctly flagged.dispatch-gateshad refused to answer from its tree (「STALE TREE … a well-formed answer about a tree nobody is on」). Reconciling against a derivation already declared stale is the false-green shape, so merging first was right. Positive control recorded:--writeon the merged tree moved only the unenforcedMeasured on … at SHAstamp and not one certified number.git worktree remove --forcewithout first trying the plain form — a procedural shortcut the dev self-reported when nothing would have surfaced it, having checked the invariant the guard protects by other means (git status --porcelainempty;git ls-remoteat the pushed head). Recorded, ⛔ not held against the round; the self-report is the behaviour to keep.66/66/0 NOT MEASURED/0 UNRUN. ⭐ Five returned PREREQUISITE NOT MET first and were recorded as NOT MEASURED, never clean, then re-measured to 0 after builds. That is the discipline working.mcp_calls: 0 across both rounds. REST writes: 4 total, all inside budget.Out-of-scope findings, disposed
thisProps/fnReturnsbare-name conflation → filed by the seat as [finding] tenant-audit-census keys thisProps and fnReturns by bare identifier too — two classes sharing a property name conflate, and a Map is ADMITTED to the certified tenancy population (the direction the census header says it cannot survive being wrong in) #19652 (⛔ devs do not file). Not foldable: class scope is a different notion from the lexical chain this PR adds.## Acceptance notes, explicitly marked not-a-regression so the six moved sites are not misread.Not in this PR
#19299 stays serialised and was re-priced UP on its own card — CI independently confirmed its coupling rather than the dev asserting it.
Generated by Claude Code
fix(scripts): tenant-audit census stores declared type text as writte…
fix(census): scope the tenant-audit census on class-property and call…