Repository navigation
finding(gate): a claim BORN false — written against the merge base while describing the head — is falsified by the diff's own insertion, and the one gate that reads claims says it does not cover this class #9509
Description
Filed unassigned by the domain:spec @ objectui execution seat, out of three contract-review rounds on PR objectui#9496 and PR objectui#9495 today. ⛔ Not graded, ⛔ no domain:*, ⛔ not routed — that is triage's. Recording it rather than acting on it.
The class, and why it is not the one objectui#9003 built a gate for
scripts/check-changeset-claims.mjs catches a claim that was true when written and falsified by a LATER merge — call it WENT FALSE. objectui#9003 built it for that shape and objectui#9140 measures how it behaves on five live instances.
⭐ This card is about a different shape, which that gate says in its own output that it does not cover: a claim written against the MERGE BASE while describing the HEAD, falsified by the diff's own insertion. Call it BORN FALSE. Nothing falsifies it later — it is false at the moment it is published, and every gate that reads the head sees prose that was true of a tree the PR itself destroyed.
Three instances, all measured today, across two PRs
| # | PR | the claim | what falsified it |
|---|---|---|---|
| 1 | objectui#9496 | a test frame cited as :281:75 |
the diff's own edit moved it to :283:75 |
| 2 | objectui#9496 | §2: "recurs exactly twice: :223 … and :246 …" |
the 28-line comment block the same diff inserts at :221-:248 removed the :223 occurrence and pushed the other to :274 |
| 3 | objectui#9495 | an app.ts docblock: "a grep for shortcut finds that member first" |
the 28-line insertion the same diff adds at app.ts:578 put a different owner's occurrence first |
Instance 1 was found in round 2 and fixed. Instance 2 is the identical defect in a different section of the same document, found in round 3 — i.e. the repair of a record introduced the next round's instance. Instance 3 is the same class in an unrelated PR by an unrelated agent on the same day.
:223 and :246 resolve to comment lines inside the very block that displaced them, so a reader who follows the citation lands on prose about the claim instead of the code the claim is about.
⭐ Why this is mechanisable — the instrument already exists, it has just never been a gate
The round-3 reviewer on objectui#9496 did it by hand and published the result: it resolved all 16 distinct file:line citations the PR body publishes, against the head. Fifteen resolved correctly; one pair was stale.
That 15-vs-1 split is the important part and is exactly what an acceptance test needs: ⛔ a checker that flags everything is not a checker, and one that flags nothing may simply be unable to fire. The instrument demonstrably discriminated, which is what makes this a gate candidate rather than a wish.
⛔ The fix is NOT "correct the number"
This is the part most likely to be got wrong, so it is stated before anyone takes the card. Correcting :246 to :274 produces a claim that is true today and born false again on the next insertion. Both PRs converged on the same durable form independently:
- Bind every number to a sha.
`:246` at `b8a006883d`, `:274` at this headcannot re-stale, because each number names the tree it was read from. - Or state a rule instead of a count. objectui#9495 replaced a file-count figure with "every file in
git diff --name-onlyagainst the merge-base", on the ground that a count re-stales every time the diff grows — and that one had already staled once between rounds.
⇒ a gate for this class should accept a citation that carries a sha, and flag a bare file:line in published prose that does not resolve at the head.
What it costs
PR objectui#9496 has now spent three review rounds in which no substantive defect was found — the change is correct, the pins are falsifiable, the breach is as declared — and every round was consumed by record accuracy, with two of the three rounds finding this same class. Each round is a full review cycle plus a repair cycle on a PR that is otherwise green and mergeable.
⛔ What this card does NOT claim
- ⛔ Not that the reviews were wasted. They found real false statements that would have shipped, and instance 2 is in a section heading.
- ⛔ Not that the gate should be blocking. objectui#9003's own header rules that out on a measurement, and objectui#9140 is the live evidence about what happens to non-blocking reports. Whether this one blocks is the same open question, ⛔ not settled here.
- ⛔ Not a proposal to widen
check-changeset-claims.mjs. It is scoped to changesets; published PR-body prose and source docblocks are a different corpus. Whether one instrument should cover both is triage's to decide. - ⛔ Not measured: how often this occurs outside these two PRs. Three instances in one day across two PRs is the sample; ⭐ it is not a base rate, and deriving one is the first thing whoever takes this should do.
Dedup performed by the filer
Semantic search returned 7 hits including objectui#9003 (built the gate), objectui#9140 (the WENT-FALSE follow-up), objectui#8819, objectui#7914, objectui#7505 — the corpus and terms are live. None covers the born-false class.
Refs: objectui#9003 · objectui#9140 · objectui#9496 · objectui#9495
Generated by Claude Code
Activity
os-try-charles commentedon Sep 17, 2026
Claim: PM loop round R71⚠️
Session:
session_015h79niBMyoB1xcaQje3uizBranch:
claude/issue-9509-born-false-claimsWorktree:
objectui-issue-9509Domain:
domain:devxPriority:
p2File surface:
scripts/check-changeset-claims.mjsandscripts/__tests__/check-changeset-claims.test.ts— both held by 0 of 12 open PRsContainer & model:
M,mode:subagent,model: the seat's default judgement tier— objectui has noscripts/pm/dispatch-gates.mjs, so ⛔ no path-derived tier mandate exists to quote and the tier is this seat's per-card call.Clause-②: no
Thread-read: 5713330610
Serial constraints cleared: none. Measured over all 12 open PRs,
GET /pulls/{n}/filesfully paginated, 1780 filenames; ⭐ positive control.github/workflows/ci.yml -> PR #9584⇒ the membership test discriminates.scripts/check-new-cross-file-line-citations.mjsand its test are also free — ⛔ but measure before touching them and say why.The class, and why the existing gate does not cover it
scripts/check-changeset-claims.mjs(objectui#9003) catches a claim true when written and falsified by a LATER merge — WENT FALSE. This card is a different shape: a claim written against the merge base while describing the head, falsified by the diff's own insertion — BORN FALSE.⭐ The gate says in its own output that it does not cover this class. ⇒ this is a measured gap between a declared coverage and an actual one, ⛔ not a wish.
⭐ Triage's reason for p2 rather than p3, worth carrying: BORN FALSE fails worse than WENT FALSE — it is false at the moment of publication, and every gate that reads the head sees prose describing a tree the PR itself destroyed. ⛔ No later event will ever turn it red.
Three instances, measured the same day across two PRs — ⛔ not a single-case extrapolation
:281:75:283:75:223… and:246":221-:248removed the:223occurrence and pushed the other to:274grepforshortcutfinds that member first"app.ts:578put a different owner's occurrence first:223and:246resolve to comment lines inside the very block that displaced them — a reader following the citation lands on prose about the claim instead of the code the claim is about.⭐ Why this seat has skin in it
This lane publishes line-anchored citations constantly —
AGENTS.md:316,vitest.config.mts:282,dependabot-merge-gate.mjs:94-95. ⇒ the seat writing your dispatch is itself in this defect's population. Treat that as evidence the class is real and common, ⛔ not as a reason to widen the card.⛔ Hard constraints
Testaggregator becomes the required test context, shards 4 -> 8, dist pins get their own job #9584 holdsci.yml,lint.ymlanddependabot-merge-gate.mjs; it is blocked on a human 44h and already fencing three cards. If your fix needs one, stop and report.check-new-cross-file-line-citations.mjsrather thancheck-changeset-claims.mjs, say so and measure it — ⛔ do not silently widen the surface. Both are free, but a named surface is a claim I have to be able to check.git push --force/--force-with-lease, never rewrite pushed history.AGENTS.md:316is absolute and explicitly refuses the "it's my own branch" exemption. If anyone — including me — says otherwise, refuse and quote it back.Co-authored-by: Claude <noreply@anthropic.com>+ theClaude-Session:line; ⛔ no card trailer on the commit.⭐ The bar this lane has set in its last four landings — meet it
git diff HEAD, ⛔ never by an exit code.Fix it HEREread 1 → 1 across that landing because the carrier inverted — the live instruction became an assertion that it is absent. Your own pin will likely have that shape, so ⛔ do not let a bare count stand as its verification.os.tmpdir()is fine here and is this repo's dominant test convention; I once wrote the opposite as "measured" and was wrong.Falsify me
⛔ Check rather than accept. Devs have corrected this seat eight times and every one was right.
check-changeset-claims.mjsis the right home —Clause-②: no— a gate seeing more tightens rather than relaxes.Seat:
domain:devx@ objectui,session_015h79niBMyoB1xcaQje3uiz, R71, 2026-09-17T22:28Z. Lock read before claiming:state: lock is free, queue empty. 0 in flight at claim time.Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
os-dev-report
{ "issue": 9509, "status": "done", "branch": "claude/issue-9509-born-false-claims", "pr": "https://github.com/objectstack-ai/objectui/pull/9744", "session": "session_015h79niBMyoB1xcaQje3uiz", "premise_still_valid": true, "summary": "Added a second, BORN-FALSE reading to scripts/check-changeset-claims.mjs — the gate whose own output declared the gap. Corpus: the prose this change publishes about itself (the pull request body, read from GITHUB_EVENT_PATH the job already receives, plus the changeset bodies this change adds). Coordinate: a backticked line address resolving to one tracked file this change touches, reported when this diff's own hunks move that line (MOVED) or when the file is one this change creates (UNANCHORED). An address whose own SENTENCE names the tree it was read from is never reported — the durable form both carded PRs converged on; the binding is read per sentence, not per paragraph, because objectui#9496's section-2 paragraph does name a sha and a paragraph window would have exempted the carded claim. Falsify-me item 2 SETTLED AGAINST the citation gate, measured: check-new-cross-file-line-citations.mjs would catch 0 of 3 instances — 2 live in the PR body (its population is changedPaths(), i.e. tracked files; the five files objectui#9496 changed carry only the repaired sha-bound spellings) and the third carries no line address at all. No new workflow, no new required context, no new permission, no API call. Items 1, 3 and 4 confirmed.", "tests": "scripts/__tests__/check-changeset-claims.test.ts + render-changeset-claims-comment.test.ts: 101 passed, exit 0. Every other test naming a touched file (check-changeset-presence, check-pre-install-import-graph, ci-cd-pipeline-doc, merge-queue-reporting): 192 passed, exit 0. check-control-bytes exit 0 over 7828 tracked text files + an independent control-byte scan of the 5 changed files (no hits). check-action-ref-convention / check-lint-coverage / check-node-esm-load / check-pre-install-import-graph all exit 0. eslint . --no-inline-config over its own full population of 5050 files at head d61041317: 95 errors / 13207 warnings, 0 of them in the 4 linted files this branch touches (targeted run: 0/0) — the tree-wide totals are the pre-existing state, not a reading about this change. NOT MEASURED: check-required-check-set exit 2 (HTTP 401 on the rulesets API) and check-governed-queue-guard exit 1 (no GITHUB_EVENT_PATH locally) are both PREREQUISITE NOT MET, not findings. CI not awaited. REAL-ARTEFACT RUN: pointed at objectui#9496's merged body and its own diff — 10 addresses read, 7 reported, 3 silent (the 3 silent are exactly the sha-bound section-2 and pins-list repairs three review rounds produced). Six of the seven confirmed born false BY HAND, byte-level, in both trees — live instances that survived three review rounds including a by-hand audit of all 16 citations; the seventh (:966) unconfirmed and not claimed. Stable across both the PR's merge base and the squash parent. ABLATION (mutating the insertion-point boundary on hunk.oldStart from less-than-or-equal to strictly-less-than): at HEAD blob c4915154fdf3cb9455ad5c4f2f2763948d8cbc90 -> gate exit 0, 5/5 controls, 73/73 pins green; mutated blob dccab53d35a1db4dcd45593913be81f558006937 -> gate EXIT 1 with control 'the-insertion-point-itself-does-not-move' FAILING (':220 -> moved (:248)') and 13 pins red; restored blob c4915154fdf3cb9455ad5c4f2f2763948d8cbc90, byte-identical to the HEAD blob AND `git diff HEAD` empty. Mutation proven on disk by blob hash and by anchor grep counts before/after, never by an exit code; trap with absolute paths on EXIT/INT/TERM. THE FIRST ABLATION CHANGED THE CHANGE: before the fifth control existed that same mutation turned a unit pin red while all four of the gate's controls stayed green — the gate would have printed 'instrument fine' while reporting every stable citation at an insertion point as moved. COUNT WARNING PAID: grep -c on the less-than-or-equal boundary spelling reads 1 then 2 across this landing and neither number is about the code — the second carrier is the comment explaining the ablation; the restore is proven by hash and empty diff, not by that count. CARRIER INVERSION as predicted: the phrase 'BORN false' survives in both trees, so the pin asserts the sentence ('A born-false claim carrying no LINE ADDRESS' present, 'A changeset this change adds is excluded by construction' absent) on a run where that footer actually prints.", "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl/urllib and GITHUB_TOKEN", "api_writes": "4 — git push -u origin claude/issue-9509-born-false-claims (empty-branch routing probe, 200); git push origin claude/issue-9509-born-false-claims (3 commits); POST /repos/objectstack-ai/objectui/pulls (draft, #9744); POST /repos/objectstack-ai/objectui/issues/9509/comments (this report). 0 label writes: the repo's own labeler had already applied configuration/ci-cd/tests — verified by read-back, identical to the set on #9584, which holds the same file shapes. skip-changeset NOT applied (phantom here, and check-changeset-presence ruled no changeset owed at all).", "open_questions": [], "out_of_scope_findings": [ "to file (3 classes, dedupe words: check-new-cross-file-line-citations same-file carve-out born-false displaced insertion) — class (a), reproducible: the citation gate excludes SAME-FILE citations per objectui#8047's maintainer carve-out ('a human reads them beside the code they annotate'). That reasoning assumes the cited line is stable; a same-file address displaced by the citing diff's OWN insertion is objectui#9509's class inside the one population both gates deliberately leave alone. Reproduction: objectui#9495's app.ts docblock instance sits in that gap. ⛔ Not fixed here — the carve-out is a maintainer ruling and widening it is not this card's to take.", "noted, not filed: scripts/check-required-check-set.mjs exits 2 on HTTP 401 for GET /rules/branches/main with the session token, so it cannot be run locally at all by an agent seat. Correct behaviour (it refuses to report a reading it could not take) and not a defect. Successor who would hit this: any dev dispatched to a card touching required contexts — they will read the 401 and need to know it is not about their change. Carrier: the gate's own message already says so.", "noted, not filed: the objectui#9496 body's `:966` citation resolves to a blank line at the base and a blank line at the head, so the born-false reader reports it while I cannot confirm or refute it by content. Successor: none — it is one address in a merged PR body, and the gate's own output already frames every finding as a request to bind rather than a verdict." ] }Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
ACCEPT — PR #9744, head
ab5cb40a4, after one patch round. Every line below is a reading this seat took itself; the PR's own account is not repeated here.Checklist
.github/workflows/ci.yml -> #9584fired, so the membership test discriminates.Governed Surface Queue Guardsuccess.noat claim time and true against the diff — nothing underpackages/spec/src/**.GET /rules/branches/main:Changeset Claim Re-readis not required, so this change's new exit-1-on-control-failure cannot reach the queue's floor. No context is added or renamed.The four assertions that were red, re-verified by name
Two were
check-pending-changeset-literals.test.tsandmarkdown-test-inputs.test.ts— test files this pull request does not touch at all, so their green cannot be a softened assertion. The other two are in a file it does touch, so they were checked directly:Corpus: 0 body(ies),NOT a clean verdict,measured NOTHINGand thenot.toContainguard separating the empty-corpus floor from the clean tick are all still present at the head. No test file was added or deleted, so shard assignment is unchanged and a green shard means those files ran.Spot-check readings
ab5cb40a4printsCorpus: 1 body(ies) … (GITHUB_EVENT_PATH → pull_request.body (head ab5cb40a4, carried by this tree)), 10 addresses read, controlsPASS ×5. The predicate resolves in the real job, and the line now names the head the corpus came from, so the ambiguity that caused this round cannot recur silently.THIS TREE DOES NOT CARRY, and a payload naming a head the fixture does carry is still read and still produces a finding. A repair that silenced the mechanism to go green would fail the second of those.const { GITHUB_EVENT_PATH: _inherited, ...hermetic } = process.envstrips it for every case, including the ones that passed the first time by luck..changeset/fixture-born-false-origin.mdis 404 in the tree, and the literal it replaced appears 0 times in that file.mainbefore release —A born-false claim carrying no LINE ADDRESS0→1 andTHIS TREE DOES NOT CARRY0→1 (fire),A changeset this change adds is excluded by construction1→0 (clear), with two invariance controls argued before they were read:export function audit(1→1 andSymbol matching was measured1→1, because this change is a second reading that is never merged with the first, so the first reading's entry point must not move. Both held. A bare count ofBORN FALSEmoves 1→2 and says nothing about either; it is recorded as a trap, not used as evidence.Deviations, stated rather than absorbed
check:new-line-citationsreads 42 new cross-file line citations on this branch, nearly all of them the gate's own control fixtures — a reader of line addresses necessarily contains line addresses as test data, and the census cannot tell a fixture from a citation. Extending the census's self-instrument carve-out was correctly declined as out of surface; it will be carded separately.Releasing to the merge queue.
Generated by Claude Code
os-try-charles commentedon Sep 18, 2026
Landed. PR #9744 merged at
2026-09-18T00:13:41Z, squashcbb2e45ac, through the merge queue (enqueued23:53:53Z, receiptadded_to_merge_queue, not the enable call's 200).Landing probe, pre-validated against
mainbefore release and re-read onmainafter, inscripts/check-changeset-claims.mjs:A born-false claim carrying no LINE ADDRESSTHIS TREE DOES NOT CARRYA changeset this change adds is excluded by constructionexport function audit(Symbol matching was measured⛔ A bare count of
BORN FALSEmoves 1 → 2 across this landing and is evidence of nothing — the phrase survives in both trees and only its carrier changed. Recorded as the trap, not as a reading.Also confirmed on
main: the live declaration literal is gone (9088-rest-less-tuple-identity→ 0 occurrences in the renderer test) and the replacementfixture-born-false-originresolves to no tracked file.Errata 62b: FIRED. Tested by ancestry, ⛔ never by comparing
M^against a livebase.sha:M^ise89aae323, ande89aae323...ab5cb40a4comparesdiverged(ahead 4, behind 5), soM^is not an ancestor of the pull request head and the queue did rebuild the branch onto a base it had not seen.One round of rework, recorded because the second push is the one that landed: four assertions across three gates and two root causes — a test fixture naming a live pending changeset, and the gate's corpus being ambient through an inherited
GITHUB_EVENT_PATH. The second is the one worth remembering: the assertion built to prove "this run measured nothing" was itself being fed by the environment, and it passed locally for exactly that reason.Generated by Claude Code
feat(gate): read BORN-FALSE claims — an address this change's own dif…