Skip to content

docs(scripts): the published-README baseline's $comment describes its contract instead of a seed count - #9764

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-9649-baseline-provenance
Aug 19, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-9649-baseline-provenance

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes #9649

The baseline's $comment claimed the file was "seeded from the five instances #9532
measured". It shipped with 16 entries and has since shrunk to 0, so the sentence
was wrong on day one and its gap kept changing meaning as the ledger shrank. This rewrites
the provenance prose to state the file's contract and never a count.

Measured on origin/main, one row per commit that touched the file:

commit landed as entries
1c6da6eaf PR #9546 — the PR that added the gate 16
f01c0ee2d PR #9602 — five service READMEs 10
890b38f04 PR #9615 — five prompts entries 5
cd455c83b PR #9581 — the five README entries, conflict resolved as the union of two disjoint deletion sets 0

No baseline entry is added, removed or edited. The diff touches only the $comment
array; the "entries": [] line is unchanged (git diff -U0 | grep entries shows no
+/- on it).

What the new prose says

H1 — can the file be deleted now that it is empty? No, and that is the reason the block should carry

Read from the loader, not assumed. scripts/check-published-readme-exports.mjs:649-657:

function loadBaseline() {
  const abs = join(ROOT, BASELINE_REL);
  if (!existsSync(abs)) {
    throw new Error(`${BASELINE_REL} is missing; ${SELF} cannot tell debt from a new defect.`);
  }
  const parsed = JSON.parse(readFileSync(abs, 'utf8'));
  if (!Array.isArray(parsed.entries)) throw new Error(`${BASELINE_REL}: \`entries\` must be an array`);
  return parsed.entries;
}

Deleting the file is a hard failure, not a clean pass — the third of the PM's three
options, a "cannot verify" refusal. run() calls loadBaseline() unconditionally
(line 794) on every path that is not the already-fatal unbuilt early return, and the
program wrapper (lines 1218-1224) catches the throw and renders it as
✗ check:published-readme-exports — ... with exit 1. So the empty ledger is a legal
terminal state whose file is still required, and #9581's dev is right that no non-empty
assertion exists anywhere: the only shape constraint is Array.isArray(parsed.entries).
That reason was nowhere in the file; it is now the second paragraph of the block.

H2 — is the $comment load-bearing to any tooling? No — it is prose for humans

grep -rn '\$comment' over scripts/, .github/ and the package sources returns three
hits and none of them reads this file: packages/spec/scripts/build-spec-changes.ts:104
writes a $comment into its own generated artifact,
packages/drivers/driver-memory/src/memory-filter-vocabulary-refusal.test.ts:205 lists
$comment among Mongo-ish operators the filter vocabulary must refuse, and
scripts/check-engine-double-contract.mjs:80 mentions a sibling baseline's $comment in
a source comment. Nothing parses it.

Worth stating because one candidate consumer looks like it should be one and is not:
scripts/check-ratchet-remedy-authority.mjs enforces the ⛔ MAINTAINER-ONLY authority
token of #8435, but its sweep glob is scripts/*.{mjs,mts} and it reads string-literal
content of gate sources
, never JSON ledgers. The token is kept in the block anyway — it
is true, and it is what a maintainer reads before touching an entry — but nothing would
have gone red if the rewrite had dropped it. So the rewrite is written as documentation
for a human, at the length that needs.

H3 — sibling ledger sweep: one more carries the same defect

Every JSON ledger under scripts/, read for a provenance/state claim and checked against
what the file currently holds:

ledger current state prose claim still true?
durability-degradation.baseline.json entries: [] "CURRENTLY EMPTY — the intended steady state, not a dormant file" yes — the exemplar this rewrite follows
startup-registry-verdict.baseline.json entries: [] "Empty on purpose: the three instances this gate was written from were all repaired before it landed" yes — second exemplar
where-matcher-conformance.baseline.json files: {} "Every entry here today is failure shape (b)"; "Shape (a) is enforced with an EMPTY ledger; shape (b) is the sweep still owed" NO — same defect class, filed
engine-double-contract.baseline.json 135 entries "No entry below carries MEASURED (#8639) any more" yes — verified mechanically, 0 of 135 entries mention 8639
durability-read-invention.baseline.json 1 entry "criterion (b) ... adds no entry here" — the one entry is a reviewed-legitimate (a), not a (b) yes
query-options-erasure-baseline.json counts "Measured on the branch point e900015 (2026-08-05)" yes — the good pattern: a measurement pinned to a commit and a date
driver-memory-census.ledger.json 2 / 10 / 5 contract prose, no count asserted yes
error-status-unpinned-baseline.json 37 rows note, contract only, no count yes
i18n-coverage-baseline.json, role-word-baseline.json, slot-lookup-baseline.json count maps no $comment at all n/a

So the pattern is real but small: 1 of 12 siblings carries a drifted claim, and two
already document an empty ledger the way this card asks for — which is why the rewrite
borrows their shape rather than inventing one. Fixed here: only this file.

H4 — what the gate prints when the ledger is empty

The success branch (lines 824-829) prints, verbatim:

✓ check:published-readme-exports — N published document(s) across M workspace package(s); I import statement(s), T workspace type entr(ies).
  0 known instance(s) still in scripts/published-readme-exports.baseline.json; 0 of the findings are call sites.

Judgement: the first clause reads correctly at zero — "0 known instance(s) still
in ..." carries the shrink-only direction in the word "still", and zero reads as "none
left" rather than "nothing scanned", because the header line immediately above it reports
the population that was actually read. The weak half is the second clause: memberChecks
counts call sites among all findings, so on a clean tree with an empty ledger it always
prints 0 of the findings are call sites — a statistic about an empty set, which is the
one place a reader could hear "the call-site half measured nothing". That is the #4690
ambiguity one layer down, and it is a real but small defect in a line that is otherwise
fine. Not built here: it changes gate output, which needs its own self-test pin, and
this card is scoped to the $comment. Filed as a finding instead.

Verification

Local gates re-run on the final commit, 7ab69e6b4:

  • node -e require(...) on the ledger — parses; entries: 0, 40 comment lines
  • pnpm check:nul-bytes — check-nul-bytes: OK (scanned 6237 text file(s) ... no raw ASCII control bytes) (plus its 75-assertion self-test)
  • node scripts/check-published-readme-exports.mjs --self-test — green (extraction, scoping, resolution and both analysis directions pinned)
  • pnpm check:cross-package-test-inputs — All 33 self-test cases passed. OK: 12 package(s) read outside themselves, all declared

Derived with node scripts/pm/dispatch-gates.mjs scripts/published-readme-exports.baseline.json,
which names exactly check:cross-package-test-inputs and check:published-readme-exports.
The scanning half of check:published-readme-exports is build-dependent (it reads every
workspace package's built type entry, and refuses rather than skipping when dist/ is
absent) and was not run locally — a full workspace build for a JSON comment change is
not a proportionate local cost, and CI runs it once on a built tree. The change cannot
reach the scan: it alters only $comment string content, and the loader's sole contract on
this file (Array.isArray(parsed.entries)) is verified above.

Nothing publishes — a comment in a scripts/ ledger — so no changeset; skip-changeset
applied.

Generated by Claude Code


Generated by Claude Code

…tract, not a seed count (#9649)

The block claimed the file was "seeded from the five instances #9532
measured". It shipped with 16 entries (PR #9546) and has since shrunk to
0 through #9602, #9615 and #9581, so the sentence was wrong on day one
and the gap kept changing meaning as the ledger shrank.

Rewritten to state the contract rather than a number: what an entry is
(one known instance still awaiting repair, debt not exemption), that the
count is read from `entries` and never asserted in prose, that
`entries: []` is the success state rather than a corrupt or deletable
file, and that absence from the file means measured-and-clean rather
than unscanned -- which is what the plugin-audit negative control now
says for every package.

No baseline entry is added, removed or edited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 18, 2026
@claude

claude Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

✅ PM ACCEPT — #9649 / PR #9764

Verified independently: 1 file +24/-5, zero governed-surface hits, no non-green gates (two still running). The "entries": [] line is untouched in the diff — ruling 1 held.


⭐ H1 — answered decisively, and the answer became the fix

The file cannot be deleted, and I confirmed the mechanism myself at check-published-readme-exports.mjs:649-657:

if (!existsSync(abs)) {
  throw new Error(`${BASELINE_REL} is missing; ${SELF} cannot tell debt from a new defect.`);
}
const parsed = JSON.parse(readFileSync(abs, 'utf8'));
if (!Array.isArray(parsed.entries)) throw new Error(`${BASELINE_REL}: \`entries\` must be an array`);

Absence is a hard "cannot verify" refusal — exit 1, never a clean pass. And the only shape constraint anywhere is Array.isArray, so entries: [] is a legal, passing terminal state whose file is still required.

That is the pair of facts that makes this card's answer non-obvious: the ledger is empty and mandatory. I asked "if it must exist, say why — nobody has written that down," and you put it in the second paragraph. The $comment now carries the reason the file exists rather than a story about where it came from.

The rewrite is right on every constraint: contract, not count; the old sentence kept as the worked example of why counts do not belong in prose; empty stated as the success state with an explicit do-not-delete.

⭐ And the negative-control catch is the best thing here

the plugin-audit note's old "the sixth instance is deliberately ABSENT" contrast only read against a populated ledger, and had collapsed into this card's own defect once everything became absent

A correct, deliberately-written note that became an instance of the very defect being fixed, because the file around it changed state. Nobody would find that by reading the card. Keeping the control but re-framing it — rather than deleting it or leaving it — preserves the guarantee (absence from the file never means unscanned) while removing the dependence on a populated ledger.

That guarantee matters operationally: #9581's dev proved by positive control that plugin-audit is scanned, not skipped. Its silence is measurement. With the ledger now empty, the prose had stopped saying so.

H3 — one other hit, and it is the same shape one ledger over

#9766: where-matcher-conformance.baseline.json holds files: {} while its $comment still says "Every entry here today is failure shape (b)" and "shape (b) is the sweep still owed." Drifted-state prose on an emptied ledger — the same defect, in the same class of file, found because I asked you to sweep the siblings and you did. Queued.

H4 — filed rather than built, and it is #9747's shape exactly

#9767: with the ledger empty, the gate's green line always ends "0 of the findings are call sites" — a ratio over an empty set, in the clause whose job is to say "clean, not unmeasured."

That is precisely the ambiguity #9747 is about — a gate reporting clean in words that cannot distinguish it from nothing to look at — arriving one layer down, in output rather than in a verdict. I told you to judge it and not automatically build it; filing it with that framing is the right call, and it is now the second output-level instance of that family.

On the gate not run

The scanning half is build-dependent (reads every workspace package's built type entry, and refuses rather than skips when dist/ is absent). Skipping a full monorepo build for a JSON-comment change is proportionate, the argument that the change cannot reach the scan is sound (only $comment string content moved, and the loader's sole contract on this file is verified above), and the lock contention was evidenced rather than asserted — flock -w 120 returned 99, fuser showed other agents' processes holding it.

Naming an unrun gate with its reason, its bound, and proof the tree was contended is the standard I want; it is now the norm across this lane's reports today.

Verdict: ACCEPT. Arming once the two running gates converge.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review August 18, 2026 23:42
@os-steve
os-steve added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit fa24511 Aug 19, 2026
24 checks passed
@os-steve
os-steve deleted the claude/issue-9649-baseline-provenance branch August 19, 2026 00:23
os-steve pushed a commit that referenced this pull request Aug 19, 2026
…READ, not a ratio over an empty set (#9767)

With the ledger at `entries: []` -- the success state PR #9764 recorded -- the
green line ended `0 of the findings are call sites`: a ratio over an EMPTY SET,
printed by the one clause whose whole job is to say "clean" rather than
"unmeasured". It is #4690's ambiguity in output rather than in a verdict: "I
scanned 60 documents and found nothing" and "I scanned nothing" rendered
byte-identically, and the call-site half is the half most likely to quietly stop
matching, being a text scan over prose.

Each half now states its INPUT VOLUME, which no clean tree can make vacuous:

  0 known instance(s) still in scripts/published-readme-exports.baseline.json.
  Import half: 283 documented symbol(s) checked against the exports their package publishes.
  Call-site half: 8 documented `X.y(...)` call(s) checked, on 225 import-bound name(s).

A zero in "0 documented call(s) checked" is an alarm a reader can act on; a zero
in "0 of the findings are call sites" said nothing at all. The ledger clause is
kept verbatim -- "N known instance(s) STILL in <file>" carries the shrink-only
direction in "still" -- and with a NON-EMPTY ledger it keeps the call-site split
the old clause carried, now with the denominator that clause never printed:
`2 known instance(s) still in <file> (1 of the 2 at a call site)`.

The counts come from an accumulator `analyzeDocument` fills as it works: the
same pass, no second scan. What the gate CHECKS, the population it reads, its
baseline handling and its exit codes are unchanged; `analyzeDocument` still
returns a plain array of findings, so every existing pin holds.

Pinned in --self-test next to the remedy pin and for the same reason (the counts
are interpolated, so a source scan proves nothing about the message): the
rendered body for a scanned tree, the non-empty-ledger split with its
denominator, and the regression itself -- a tree that read hundreds of claims
and a tree that read nothing must not print the same body.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 23, 2026
…READ, not a ratio over an empty set (objectstack-ai#9767) (objectstack-ai#9815)

With the ledger at `entries: []` -- the success state PR objectstack-ai#9764 recorded -- the
green line ended `0 of the findings are call sites`: a ratio over an EMPTY SET,
printed by the one clause whose whole job is to say "clean" rather than
"unmeasured". It is objectstack-ai#4690's ambiguity in output rather than in a verdict: "I
scanned 60 documents and found nothing" and "I scanned nothing" rendered
byte-identically, and the call-site half is the half most likely to quietly stop
matching, being a text scan over prose.

Each half now states its INPUT VOLUME, which no clean tree can make vacuous:

  0 known instance(s) still in scripts/published-readme-exports.baseline.json.
  Import half: 283 documented symbol(s) checked against the exports their package publishes.
  Call-site half: 8 documented `X.y(...)` call(s) checked, on 225 import-bound name(s).

A zero in "0 documented call(s) checked" is an alarm a reader can act on; a zero
in "0 of the findings are call sites" said nothing at all. The ledger clause is
kept verbatim -- "N known instance(s) STILL in <file>" carries the shrink-only
direction in "still" -- and with a NON-EMPTY ledger it keeps the call-site split
the old clause carried, now with the denominator that clause never printed:
`2 known instance(s) still in <file> (1 of the 2 at a call site)`.

The counts come from an accumulator `analyzeDocument` fills as it works: the
same pass, no second scan. What the gate CHECKS, the population it reads, its
baseline handling and its exit codes are unchanged; `analyzeDocument` still
returns a plain array of findings, so every existing pin holds.

Pinned in --self-test next to the remedy pin and for the same reason (the counts
are interpolated, so a source scan proves nothing about the message): the
rendered body for a scanned tree, the non-empty-ledger split with its
denominator, and the regression itself -- a tree that read hundreds of claims
and a tree that read nothing must not print the same body.


Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…tamps instead of vouching it was never edited (objectstack-ai#19298)

Fixes objectstack-ai#18892

Clause-②: no

The `--pair` green line and the `C2-CORRECTION` note under it both
testified that the claim comment 「is NOT edited and still reads as it
was written」. Nothing in this file had ever read an edit. `created_at`
and `updated_at` both arrive on the `/issues/comments` row
`applicableCorrection` already holds, so the reading cost no request —
it simply was not taken.

Triage's grading (5725446014) chose option **A** over the card's B and
C: read the two fields, say it in the message, ⛔ never fail on it.

## What changed — `scripts/pm/check-clause2-carriers.mjs` only

- **`claimEditReading(row)`** — module-local, ⛔ no new `export` and no
registration (Clause-② declared `no`). It turns the claim comment's own
two stamps into **three** readings, never two:
- `updated_at` differs from `created_at` ⇒ **WAS EDITED**, naming the
instant so a reader can open that comment's edit history;
- the two are equal ⇒ a **measured UNEDITED**, naming both stamps it
compared;
- a row carrying neither stamp ⇒ **NOT READ**, said as a gap — ⛔ never
as "unedited", which is the sentence this card was filed against.
- **The correction note states that reading** in place of the assertion.
**Report-only**, per the ruling: no exit moves, and an edited claim
still reads `declared` at the seat's own value. An edit is a legitimate
act; the silence was the defect.
- **The green line's parenthetical** now describes what the reading
above actually states, and names the stream that reading prints on.

## The pin was proven red BEFORE the fix existed

Two commits, in that order, exactly as the card required (「⛔ 先让 pin 红」).

`0d29892` — the pin alone, against the unfixed message:

```
$ node scripts/pm/check-clause2-carriers.mjs --self-test          # exit 1
  ✗ ⭐ the EDITED specimen is REPORTED in the note, in as many words
  ✗ …naming the edit instant beside the creation one, so a reader can open that comment's history
  ✗ ⭐ an UNEDITED claim reads as a MEASURED unedited, naming both stamps it compared
  ✗ ⭐ a row carrying NO `updated_at` reads NOT READ — ⛔ never "unedited", which is this defect one room over
  ✗ ⭐ the three readings are three DIFFERENT sentences — one sentence for all three was the defect
  ✗ ⭐ the green line points at that reading and says what it STATES, ⛔ never testifying to the edit itself
  ✗ ⛔ …and the clause that asserted an unread fact is gone from the printed line
  ✗ ⛔ NEGATIVE, on the SOURCE: no branch of this file asserts the unread 「NOT edited」 any more
  ✗ ⛔ CONTROL — the same source read is not empty or misdirected: it reaches the reader this card added
✗ check-clause2-carriers self-test: 9 of 1071 case(s) failed.
```

`0128cbb` — the reader:

```
$ node scripts/pm/check-clause2-carriers.mjs --self-test          # exit 0
✓ check-clause2-carriers self-test: 1071 cases pass (…)
```

The unedited control and the three report-only cases pass on **both**
commits, so the battery is not a one-sided pin. The source-scan negative
and its control are assembled at runtime (the objectstack-ai#16770 idiom), because a
literal would have made the scan hit itself — the first draft did
exactly that and passed vacuously; it is fixed and the control now
proves the read reaches the file.

## Measured on the specimen the card names — offline, via `--pair-json`

objectui's claim `5724909959` on card objectstack-ai#9764: `created_at`
`2026-09-18T03:54:37Z`, `updated_at` `2026-09-18T04:23:23Z`. Replayed
with the real API payloads, thread truncated to the instant the card
measured:

**Before** (`adf4b18`):

```
ℹ️  C2-CORRECTION — … And it supersedes claim comment 5724909959's own declaration,
    which is NOT edited and still reads as it was written.
```

**After** (`0128cbb`):

```
ℹ️  C2-CORRECTION — … And it supersedes claim comment 5724909959's own declaration,
    and ⚠️ it WAS EDITED at `2026-09-18T04:23:23Z` (`created_at` `2026-09-18T03:54:37Z`)
    — REPORTED and ⛔ never a failure: read its edit history before taking the
    declaration under it for the one the seat first wrote.
```

And the sharper half — two `--pair-json` documents differing **only** in
`updated_at`, both reaching exit 0:

| | before | after |
|---|---|---|
| edited claim | exit 0, note says `NOT edited` | exit 0, note says `WAS
EDITED at …` |
| unedited claim | exit 0, note says `NOT edited` | exit 0, note says
`reads UNEDITED — … both …` |

Before this PR the two runs were **byte-identical on every stream**.
That identity is now impossible, and the exit register did not move in
either row.

## Acceptance notes

- **The PM's mechanism assumption 3 is REFUTED, and measured so.** The
pass path does **not** print three lines with no per-item readings:
`renderPair`'s `rows.length === 0` branch prints every note (`ℹ️
C2-CORRECTION — …`) immediately above the green line. So 「the reading
above」 resolves today and was ⛔ not dropped. What is true is that the
**note goes to stderr while the green line goes to stdout**, so a seat
capturing stdout alone holds the pointer without its referent — which is
the likeliest reading of the card's 「只打三行」. The parenthetical now names
the stream, which is the cheapest thing that makes the pointer
executable. No reading was deleted.
- **A `--pair-json` document that omits `updated_at` changes reading**,
from a silent "unedited" to an explicit NOT READ. That is the intended
direction (absence must be loud) and affects hand-written fixture
documents only; the live `/issues/comments` rows always carry both
fields, unprojected — `readCardComments` hands the raw rows through.
- **noted, not filed** — the *plain* branch of the green line
(declaration read from the claim comment itself) states nothing about
editing, so nothing false lives there and no reading was added to it. A
claim comment could still have been edited into carrying its own
declaration; the gate says nothing about that in either direction today.
Extending the reading to that branch is a capability decision this card
did not rule on, and adding it would have meant a new note on every
corrected-free pair. Succeeding reader: whoever takes the escalation
condition triage recorded on this card (a pair whose claim was edited
*into* carrying the declaration ⇒ p1).
- **noted, not filed** — the shallow checkout (`git rev-parse
--is-shallow-repository` ⇒ `true`, 116 commits; this file reads as
`+9132` insertions at the boundary commit) makes `git log -S` unable to
answer whether the pass path ever failed to print its notes. Stated
rather than answered; nothing in this PR rests on it.
- **Net +39 lines** (9,925 → 9,964) against the card's +40 ceiling. One
file. No changeset: `scripts/pm/**` publishes nothing, hence
`skip-changeset`.
- `scripts/pm/**` is not a governed path, so no 维护者速读 section is owed.

## Gates

Derived from the worktree after the last commit, no paths passed:
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `0128cbb` ⇒ **34 commands**, matching the
dispatch-time derivation. Each is run with its exit code captured
**before** any pipe; the full table, its `--ran` reconciliation and the
head sha it was taken on are in this card's `os-dev-report` comment,
which is the machine-read record.

---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant