Skip to content

fix(devx): classify the tree-measurement claims under scripts/ instead of sweeping them - #19220

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-17797-measured-on-this-tree-classifier
Sep 20, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-17797-measured-on-this-tree-classifier

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Fixes #17797

The deliverable is a classifier, not a sweep. Three kinds of sentence live under one
phrase and take different repairs, and only one of them is a defect.

⭐ The card's own headline number had decayed — which is the card's best self-evidence

The card states that scripts/pm/dispatch-gates.mjs "alone carries 40 sentences
containing measured on this tree". Re-measured at 0046a41b4, 2026-09-20T00:30Z, with
the card's own case-sensitive probe: 14, of which 3 carry a revision by the card's
own rev probe. A card about bare magnitudes decaying in silence had its own bare magnitude
decay by 65% before anyone read it. ⛔ The 40 is not carried anywhere in this PR.

1. The declared population — which files, which phrase forms

All readings below are mine, taken at 0046a41b4 (this branch's merge base),
2026-09-20T00:30Z. ⚠️ Every one of them decays; the tool added here re-derives them.

probe occurrences files
the card's probe — measured on this tree, case-sensitive, over scripts/ 46 25
all three spellings that actually occur, case-insensitive — measured on this tree, re-measured on this tree, measured against this tree 121 47
the same, excluding the two files scoped out below 74 45

⚠️ That is an upper bound on a population, ⛔ not a count of defects. The card says so
in its own words and this PR does not contradict it.

Three findings about the population itself, each of which says a phrase probe is not a
population:

  • The card's probe is case-folded shut. Lower-case-only reaches 46 of the 121 sentences
    that carry the phrase in some spelling. The gap is not rounding.
  • A line-based probe cannot see a sentence that wraps. The phrase itself straddles a
    line break in five files, so no grep of it lists them at all:
    scripts/check-examples-live-imports.mjs, scripts/check-parse-guard.mjs,
    scripts/check-self-test-wired.mjs, scripts/eslint-fatal-guard.mjs,
    scripts/i18n-bundle-surface.mjs. The tool reads sentences, so it holds them.
  • ⭐ And the card's own named instance carries no phrase at all. It is a bare corpus
    size in the present tense. A population defined by the phrase would have reported the
    tree clean at the one site everybody already agreed was broken — so the population is
    declared in two forms, FORM A (the phrase) and FORM B (declared sites the phrase cannot
    reach, currently the hand-written-corpus size in scripts/docs-audit/README.md).

2. The classifier

scripts/pm/measurement-claim-triage.mjs:

node scripts/pm/measurement-claim-triage.mjs              the population + every verdict
node scripts/pm/measurement-claim-triage.mjs --review     the kind-3 residue alone
node scripts/pm/measurement-claim-triage.mjs --self-test  the controls, both directions

It records no number about its own population — the scope line it prints is the number,
re-derived on the tree it runs against. That is the durable half of the fix: the reason the
card's 40 went stale is that it was written down instead of re-derivable.

Four tests, applied in that order. Each can only move a hit out of the residue, and each
prints the cue that moved it, so every verdict is auditable against the sentence.

  • T1 FRAME — is the magnitude scoped to a moment that has passed, or to a counterfactual
    condition? (before this gate was written, at the commit that took it, an earlier revision, with the reservation removed, was auditing) ⇒ KIND 1.
  • T2 ANCHOR — does the sentence carry a revision or a date? ⇒ KIND 1.
    ⛔ A bare card number is deliberately not an anchor: #NNNN occurs in every kind of
    sentence here, and admitting it would clear the residue by matching everything.
  • T3 LOUDNESS — would the drift announce itself? Three ways: a named failure direction
    (a zero whose falsifier is spelled out is the commonest), a pointer at the instrument that
    reprints the value, or a live assertion that reds on drift. ⇒ KIND 2.
  • T0 MAGNITUDE — last, and weakest: nothing decays if nothing is counted. A ZERO counts,
    because kind 2 is defined on one.
  • Everything else is REVIEW, a candidate bucket. ⛔ Reading its size as a finding count
    is the error the card exists to prevent.

T4 — level or relation — is a judgement and no regex decides it. Does a reader act on
the magnitude's level, or on a relation (a ratio, an ordering, an existence claim, a set
equality) that the level's drift survives? A level is kind 3; a relation is an
ILLUSTRATION, and rewriting it buys nothing. T4 is recorded per site in the tool's TRIAGE
table with its reason, and a REVIEW hit with no row prints UNTRIAGED and reds the self-test.

Every TRIAGE row is keyed by an excerpt, never by a line number — the card cited its
own known instance at :493 and it was at :555 by the time anyone read it.

The window, and a bug worth recording

The first build read a fixed ±6-line block and cleared the one site everybody had agreed
was broken: six lines above it an unrelated sentence cites a revision, and a block window
handed that anchor to a claim that has none. T2 and T3 now read the sentence; T1 also
sees the sentence before (a narrative frame leads), T3 also the sentence after (a named
failure direction trails — the card's own kind-2 exemplar spells the zero in one sentence
and names its falsifier in the next); ⛔ T2 sees neither. That control is pinned in the
self-test.

3. ⭐ Controls, both directions

node scripts/pm/measurement-claim-triage.mjs --self-testgreen, six controls:

control site expects
kind 1 — a citation carrying its revision, left alone scripts/check-tier-file-adoption.mjs ("Measured on this tree at d03c3c96d6 …") KIND-1
kind 2 — a zero whose failure direction is named, left alone scripts/docs-audit/affected-docs.mjs ("zero commands declare static topic …" + "The failure direction if that ever changes …") KIND-2
kind 2 — a refusal a live assertion holds, left alone scripts/check-skill-compatibility-version.mjs ("the refusal is pinned in the self-test …") KIND-2
kind 3 — the card's named instance, CAUGHT scripts/docs-audit/README.md (pre-repair text) REVIEW
kind 3 repaired — the same site now points at the gate scripts/docs-audit/README.md (post-repair text) KIND-2
⛔ the one-sentence anchor rule — a neighbour's revision does not clear a bare magnitude synthetic REVIEW

Each control carries a liveness key that must still be present in the file it was quoted
from (and the pre-repair one carries an absent key instead — if that sentence comes back,
so has the defect). ⛔ A control quoting a sentence the tree no longer holds passes in
silence, which is the failure this whole PR is about. The self-test also reds on a dead
cue
: every cue must still match something in the population or the controls — nine that
matched nothing were deleted rather than left as decoration.

4. The kind-3 hits and their repairs

Five, judged out of a pre-repair review residue of 27. After the repairs the tool reports
87 claim(s) over 48 file(s) — KIND-1 35 · KIND-2 11 · NO-FIGURE 19 · REVIEW 22, and all 22
survivors are recorded ILLUSTRATION. ⛔ No fresh bare number is written anywhere in this diff.

Repaired by pointing at the live instrument (#16200's preferred shape):

  • scripts/docs-audit/README.md — "the anchor derivation reads the same 178-page corpus
    the old one did". Present tense, and wrong today: pnpm check:docs-audit-scope printed
    195 hand-written doc(s) at 2026-09-20T00:11:30Z, my own reading. Repaired to name the
    corpus without sizing it and to send the reader to that gate, and it says out loud that
    the figure is deliberately absent.

Repaired by pinning the reading to the commit that recorded it — the historical figure
does work a live reading cannot (it justifies a decision taken at that moment) and no gate
reprints it. Each carries a deliberately-absent note, so the next author does not helpfully
restore a present-tense figure:

  • scripts/check-pnpm-filter-targets.mjs — the scripts/** declaration-honesty ratio, now
    Measured at 52a41b72e (2026-08-23). The counts move with every file added under
    scripts/; the SHARE is what the paragraph argues.
  • scripts/check-published-files.mjs — the same shape over the whole publishable workspace,
    now Measured at 52a41b72e (2026-08-23).
  • scripts/check-skill-compatibility-version.mjs — the four precision ratios deciding which
    roots are declared, now measured at f29e89717 (2026-08-22), with a pointer to
    scripts/pm/bare-root-worklist.mjs, which carries this gate's package-root rows with
    their own dates.
  • scripts/check-slot-lookup-ratchet.mjs46s, the worst-ageing kind of figure: a
    wall-clock reading is a reading of one box as much as of one tree, so it decays without
    the tree moving at all. Now Measured at 46s when this was recorded (99ca6623f, 2026-08-19), with the order (seconds against a CI round) left as the load-bearing claim.

Each repair's excerpt is recorded REPAIRED in TRIAGE, and the self-test reds if it
returns to the population.

⛔ What the classifier deliberately did NOT touch

The 22 remaining REVIEW hits are recorded ILLUSTRATION with a reason each. Two worth naming,
because they are the shape a sweep would have destroyed:

  • scripts/docs-audit/README.md lines carrying 178 in the historical narrative — the card
    predicted these were kind 1 and judging each one agrees. Two more, at the --all backstop
    and the cost note, already point at check-audit-scope.mjs in the same sentence and
    classify KIND-2 mechanically: already repaired in [finding] the docs-audit union-read prose hard-codes the anchor lag as "532 keys" in two places — measured 604 four days later #16200's shape, so ⛔ this PR leaves
    them exactly as they are.
  • scripts/check-dispatcher-error-vocabulary.mjs's per-glob member counts: kind 2, not
    kind 3 — the docblock names what would falsify them and PUBLISHED_SOURCE_FACE_FLOOR
    plus the per-glob presence pin red in that direction.

⛔ Two files are outside the file surface, for two independent reasons

scripts/pm/dispatch-gates.mjs and scripts/pm/check-widening-tells.mjs are not edited
here
, and both reasons are carried as data in the tool's EXCLUDED table so every run
prints them rather than leaving them in prose:

  1. Live conflict. dispatch-gates.mjs is being edited by open PRs ci: publish the platform checklist status pages to the repository wiki on a schedule #19162 and
    revert(spec): take back the declaration-text snapshot, restore the 27 signature hashes #19024; check-widening-tells.mjs by fix(pm): check-widening-tells reads the member’s PRIOR schema — a bound inside a previously-z.unknown() bag is not a new key #19153 and revert(spec): take back the declaration-text snapshot, restore the 27 signature hashes #19024. Editing underneath
    them is a conflict, not duplicated work.
  2. The card's own verification constraint: scripts/pm/dispatch-gates.mjs is enormous
    and its --self-test exceeds the agent container's foreground cap (recorded on [finding] dispatch-gates.mjs --self-test asserts an empty child stderr too, so it reds under --use-env-proxy exactly as #15234 did #17765),
    so the card required whoever took this to say how they verified a change to that file
    or scope it out and say so. This is the saying-so.

⇒ The residue those two hold is un-swept, and the tool's scope line says so on every run
instead of reading as complete.

Also untouched, and reported rather than edited: .claude/**, skills/**, docs/adr/**,
AGENTS.md, CLAUDE.md (governed surfaces) and #16200's three carriers, settled by #17795.

Verification

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
at 60f9b648a — 6 paths, 722 changed lines. 35 derived families, 35 run, all exit 0;
reconciled with --ran: 35 derived famil(ies) accounted for — 35 run, 0 UNRUN.

  • node scripts/pm/measurement-claim-triage.mjs --self-test✓ controls hold in BOTH directions (6 controls, 27 recorded judgements).
  • pnpm check:pm-dispatch-gates✓ dispatch-gates self-test: 1866 cases pass,
    593.2s on this box, VERDICT command-exit 0, run detached under
    scripts/pm/os-verify-lock.sh (held 594s, waited 0s), 2026-09-20T00:23:16Z–00:33:10Z.
    ⚠️ The reference line at content/docs/qa/platform-readings.md:432 records 430–450s; this
    container reads well above that band, and this run is one more point in it.
  • ESLint, narrowed and the narrowing measured: npx eslint --no-inline-config --format json
    over the five changed .mjs files at 60f9b648a5 files linted, 0 errors, 0
    warnings
    (counts read from the JSON reporter). The narrowing excludes nothing:
    eslint.config.mjs enables type-aware linting for no configuration in this repo (no
    parserOptions.project, no typed rules), so this diff cannot move the verdict on a file
    it does not touch. The repo-wide eslint . run is CI's.
  • NOT MEASUREDpnpm check:published-readme-exports and pnpm check:dts-closure
    both exited 3, PREREQUISITE NOT MET (46 packages' dist/ not built). Neither is in
    the derived family; both are artifact-roster families whose roster sits under scripts/,
    run here only because silence there is not evidence. This diff changes no package source,
    so neither could be moved by it. ⛔ Recorded as not measured, not as a pass.
  • No changeset: measured, not assumed. The root manifest is private: true and no package's
    files[] names the repo-root scripts/ tree, so nothing published moves. Labelled
    skip-changeset.

Acceptance notes (out of scope, noted and not filed)


Generated by Claude Code

…d of sweeping them

Three kinds of sentence live under one phrase and take different repairs: a
citation of a past measurement (anchored, stays true), a claim whose failure
direction is named (loud when it moves), and a bare magnitude in the present
tense (decays in silence). Only the third is a defect.

Adds scripts/pm/measurement-claim-triage.mjs: it re-derives the population
rather than recording its size, applies T1-T3 mechanically, records the T4
judgement (level or relation) per site, and carries controls in BOTH
directions. Repairs the five sites judged kind 3 -- one by pointing at the
gate that prints the value, four by pinning the reading to the commit that
recorded it and saying out loud that the figure is deliberately not refreshed.

Co-Authored-By: Claude <noreply@anthropic.com>
@os-try-charles os-try-charles added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 20, 2026 — with Claude
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation labels Sep 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 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 0046a41b43da8e7d2db9d7f926cc0518a357c379packageMentionDocs.

@os-try-charles
os-try-charles marked this pull request as ready for review September 20, 2026 01:05
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 20, 2026
Merged via the queue into main with commit 805811e Sep 20, 2026
38 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-17797-measured-on-this-tree-classifier branch September 20, 2026 01:34
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/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants