Conversation
Records the design before the code, and splits build path A in two on the strength of what the write path actually does. `compile.py` has three write paths, not two: `merge→create` composes an article from scratch, while `merge` and `merge-batch` run against existing article text through prompts whose only actions are `append_to_section` and `new_section`. Carrying the document date and one block per source lets the create path state the newer version, and cannot help the merge paths at all — there is no action that retracts. So the ordering signal and the replace primitive fix different paths, and only the second can destroy correct content. A1 is the signal half: an optional `date` on submit written as frontmatter, the date read from raw frontmatter at write time, per-source blocks instead of one flattened bag, and newest-first budget allocation so truncation drops the oldest source rather than the newest. A2 adds the replace primitive and is bought only if A1 fails the fixture positives. A1 therefore does not satisfy D1 — its best output is latest-wins, with no superseded trail — and the spec says so, so a clean A1 score is not mistaken for the trail landing. Settles what design-options.md left open. The trigger is explicit contradiction only: under A1 the writer sees extractions rather than raw text, so a claim absent from a later source is indistinguishable from one the summarizer dropped, and triggering on absence would turn every lossy extraction into a false supersession. Dropped claims escalate to a report instead — already shipped for revised documents, new for two documents whose titles differ only by a version marker. D3 exposes the date on submit rather than inferring it, because ingest time is not authorship time and backfilling an older version would otherwise invert the order. D4 reads raw frontmatter at write time, a deliberate exception to the extraction layer's write-phase boundary, taken because a provenance field costs a `schema_version` bump and that refuses every existing file. D5 keeps `write_prompt_version` reported and never gated. Also flags that the fixture cannot yet score any of this: 38 documents in one compile routes each version chain into a single `merge→create` call, so it measures the path A1 can fix and never exercises the merge paths. It needs one compile per version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…depend on Re-reading the spec against the code turned up four citations that do not match what is there, three of which change what A1 has to touch. The Background enumerated three write paths in compile.py and missed the create-ops loop at :492/:495, which calls create_new_article while the article file is absent and merge_into_article once it exists -- exactly what a version chain hits when its members arrive as separate create ops. The single-source merge pointer named :553, the branch head, rather than :558, the call. WP4 counted four call sites. Both writers take (extraction: ExtractionResult, source_path: str), so changing that signature reaches the three single-source callers too: compile.py:492, :495 and :558. Seven sites move, not four. WP1 named merge.py:95 as the only place the "- Source:" prefix is rendered. _estimate_full_extraction_size at merge.py:72 spells it out a second time, and BG3's truncation notice fires on the two disagreeing, so both sites gain the "- Date:" line together. The single renderer does serve both writers (merge.py:320, :596), so no write path is missed there. RT6 cited design-options.md:57-60 for the shared-helper argument; the passage is at :60-63.
A1 step 1 of the supersession spec: the write phase needs to know when each source was written, and no ingest route recorded it. The submit handler now writes a `date` into the document's YAML frontmatter, and the reader that parses it back is shared rather than duplicated. The two ends share no definition of the format, so the Go writer's rules are pinned against the real PyYAML reader from both sides. The scan is textual and answers "may this already be dated" rather than "is it": it errs towards yes, so a block it cannot read is left alone instead of having the ingest clock stamped over a date the document authored -- which is the corpus defect A1 exists to fix. Unreadable means flow syntax, a sequence, tab indentation, a colon without the space YAML needs, a top-level value the reader refuses, a `date` whose value is on the lines below it, or a character the reader breaks a line on. An explicit caller date outranks the document's own, so it is written even there, as a stacked block: inserting into frontmatter that does not parse would cost the document every label it had. `read_document_frontmatter` moves out of storage.index into _frontmatter so the write phase can share it (RT6), and widens two guards a raw document can actually trip: a date no calendar accepts, which took the whole document catalog down for every document beside it, and a leading BOM, which made a document read as having no frontmatter at all. `ContentHash` and `FileTitle` are still computed over the content as submitted, before anything is prepended -- hashing the written bytes would put the stamp time inside the hash and leave the 409 duplicate path unreachable. Verified by a round-trip differential over 68 shapes through both implementations: the clock never replaces a date the reader can see, every stamp reads back as a date, an explicit date always survives, and no input line is lost. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A1 step 2 of the supersession spec. The write phase received one flattened extraction and one comma-joined source string, so two things were unrecoverable from its payload: which document made a given claim, and which document is the later one. An article composed from a plan and its revision could state both. `create_new_article` and `merge_into_article` now take `Sequence[SourceBlock]`, one block per source, each carrying the day the document dates itself. All seven call sites move together -- the create-op pair, merge->create, single merge and merge-batch in compile.py, and both branches of the pipeline's write phase, which build the payload once for whichever runs. `_combine_extractions` had no callers left and is deleted with its test file; the enumeration guarantee it carried (#41) is re-pinned as a block-rendering test, where per-source blocks keep it structurally rather than by field priority alone. Blocks come back oldest to newest, undated last, both orders path-derived so the payload is reproducible across a 16-worker run whose raw-scan order is not. Duplicates collapse on checksum (WP7), the survivor being first in path order; the collapsed path is then absent from the article's `sources:`, which costs the derived KB no content -- the bytes are identical to the survivor's -- only the second path's name. The ops bookkeeping still reads every merge's rel rather than the surviving blocks, or a collapsed duplicate would stay uncompiled and be retried forever. The date is read from raw frontmatter at write time (D4), a deliberate exception to the extraction layer's write-phase boundary: the alternative costs a `schema_version` bump, which refuses every existing extraction file. A document that cannot be read degrades to undated rather than failing the write. Stamps are narrowed to their day, because `datetime` is a subclass of `date` that refuses to be compared with one, and the corpus holds both. Budget allocation across blocks is interim and says so: every block is rendered whole when they all fit, and only otherwise is the budget split evenly with the unused share carried forward. BG1's newest-first priority replaces it in step 3. The first version split unconditionally and truncated an 11-member enumeration out of a payload with 10,560 characters of budget unspent. Two of the three write paths already guaranteed in code that every source reaches the article's `sources:` key. The full rewrite did not, and a source missing from that key is a document `derive` refuses to copy, so its user message now renders the same list. No `write_prompt_version` churn: user messages are outside that hash by design, and the prompt file's singular wording is step 4's. Verified by 26 mutations of the new rules. Three survivors were adjudicated, not waved through: two are equivalent given the path pre-sort and a stable sort, and the third does not overrun the budget because the separators are deducted before any share is computed. Three real survivors were closed with tests -- both bookkeeping paths, and the two single-source sites building blocks without reading the date at all. Plus a both-routes parity test (VF6) comparing whole blocks from the CLI and the worker in one process, over documents dated against their path order. Rebased onto #45, which landed the grounding constraint on the same three write prompts. Its three new prompt-parity tests called the flattened signatures this commit replaces, so they now pass one block each; the constraint they assert is untouched. And `_sources` in the new grounding checker documented its comma-splitting as covering the `", ".join(rels)` that `create_new_article` used to be handed, which no longer happens -- the splitting stays, because the rewrite path's frontmatter is model-authored and articles compiled before this change carry that joined string, but the docstring now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A1 step 3 of the supersession spec. Step 2 split the block budget evenly between sources with the unused share carried forward, which is the wrong policy for the thing this increment exists to fix: whether a claim has been superseded is a question about what the latest document says, and an even split cuts the newest source to fit the oldest. Budget is now claimed in `_budget_priority`'s order -- dated blocks newest first, then undated ones in path order -- while blocks still render oldest to newest (WP5). A block is kept only if it fits whole in what is left, separator included, and the first one that does not ends the walk, so what is dropped is whole blocks from the bottom of the queue (BG2). A block cut to its header and a halved list is worse than an absent one: the writer cannot tell a thin source from a truncated one, and a partial enumeration is what it turns into a confident wrong list (#41, #42). A budget too small for even the first block is spent truncating that one by field priority rather than sending the article and no new information (BG4), and every source that contributed nothing is named on stderr (BG3). The queue is deliberately not the render order reversed. `build_source_blocks` emits dated blocks then undated ones, so reversing hands the highest priority to the sources that make no recency claim: measured on two 3,050-char blocks against a 3,123 budget, the undated block survived and the 2021 document was dropped -- BG1 inverted on a guess, on a shape the spec provisions in three places (RT12 leaves the files route undated, WP8 makes an unparseable date undated, and a raw file that cannot be read degrades to undated). The spec said it too, so BG1 now states the queue, BG2 stops calling the dropped blocks "trailing" -- true only while every block is dated -- and BG4 names the first block in that order rather than "the newest". Sources sharing a day break to path order, the same direction the undated ones take, and both keys are read off the blocks rather than inherited from the order they arrive in: 160 of the reference KB's 395 multi-source articles have two sources dated the same day, so that tiebreak decides real drops. `_fit_block_to_budget` rejected a budget of exactly its header, which this step's own arithmetic is what made reachable: an extraction whose eight priority fields are all empty estimates at its header, so a block measured as fitting whole came back without its `- Date:` line, silently, with the rest of the budget unspent. WP6 reads an absent date as "makes no ordering claim", which is the opposite of what that document says about itself. One character, and a test on the boundary. A dropped source is still named under the article's `sources:`, now pinned rather than only described. `derive` reads that key to decide which raw documents reach a derived KB, so dropping the name would cost the document its only route into one. The price is an article naming a source the writer was shown nothing from, and on the reference corpus that is not rare: modelling a full compile through the real budget arithmetic, 152 of 577 measurable articles (46.6% of the multi-source ones) drop at least one whole block and 29 hit BG4. That is BG2 working as specified -- the relief is fewer sources per write op or a larger prompt budget, neither of which is A1 -- but the figures belong on the record before FX4 scores anything. Verified by 19 mutations of the new rules, 18 caught. The survivor -- clamping a whole-fitting block to the budget minus its separator -- is equivalent because that line is only reached when the block already fits, which is a claim the header-sized-budget fix above is what makes true: 4,000 random block shapes at six budgets from the estimate upward, 0 that did not render whole. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 2 gave the payload one dated block per source, oldest to newest with the undated last, and step 3 made the newest one survive a tight budget. Nothing said so to the model. A sequence whose meaning is never stated is one it may read either way, and the undated tail is the trap: those blocks sort last for reproducibility, not recency, so an unexplained order invites reading the sources that make no recency claim as the newest material (spec WP6, S5, Q2). _SOURCE_ORDER states the direction, what a `- Date:` line dates, and that an undated block's position carries no ordering claim. In the system prompt because that is where an instruction is applied reliably, and a code constant appended to all three write-stage prompts for the reasons _GROUNDING already carries: one of the three is built in code, and a fourth prompt file would fail an operator's existing KAAS_PROMPTS_DIR on the first write after upgrade. It states facts and asks for nothing. A1 carries the ordering signal and adds no action: the merge paths cannot retract, and the rewrite path must not start, since it returns a whole article and is the one place A1 could destroy correct content (NG1, G4). What to *do* about a contradiction is A2's replace primitive, and saying it here would also spend the fixture arm that exists to decide whether A2 is needed at all (FX7). Two approximations in what the statement asserts are recorded rather than closed: BG2 drops whole blocks the `Sources:` list still names, and the bare-source-line branch can emit a dated block's header without its date -- which now reads as a claim rather than as missing text. Editing every write-stage system prompt moves write_prompt_version, so the first report after this names every article (PV1). It gates nothing per D5, and the argument for keeping it ungated is unchanged: an article that exists is re-composed through the merge paths, which are still the additive ones. Both copies of that reasoning are updated -- write_prompt_version's docstring (PV2) and storage/lag.py's, which ended on the same pre-A1 sentence. Also corrects the singular-source wording both writers inherited from the flattened payload. merge-rewrite.md asked for "source" where the payload now lists N of them, and the create prompt's frontmatter template shows one `sources:` item; neither path repairs that list in code, so a source missing from it is a document derive will not copy into a derived KB. py 1661 passed, core/merge.py 100%.
Shape A is already reported: a re-fetched document is marked revised and its articles named. Shape B -- v1 and v2 ingested as two documents, which no `id` connects and only the title betrays -- was not reported at all, so an article holding both versions looked like an article holding one document twice. The rule is the one test-set.md validated on 996 documents: same title after a trailing version marker is stripped, same `source`, different `id`. Its two exclusions come from that corpus rather than from taste. Cross-source collisions are excluded by making `source` part of the grouping key, so a design document and the recording of the meeting about it are not paired while two recordings of one meeting still are. A title that is a person's name groups with nothing, because a recurring one-to-one is titled that way; the names come from the KB's person pages and from the configured allowlist, since the pages are stubs a later phase writes and a first compile has none. RP3's stated trigger is dropped, and the spec now says why. "The earlier member asserts something the later one does not" selects nothing: over the corpus's stored extractions a claim-text comparison fires on 35 of the 35 checkable pairs at every threshold from 0.55 up, and the similarity distributions do not separate real version pairs from recurring meeting series (median 0.47 against 0.36). Claims get restated in new words between versions, so absence is the normal case. The cheap proxy fails the other way: "the later member asserts fewer claims" holds for 14 of 35 and excludes P6, the one adjudicated success, whose claim count grows. An LLM judge would settle it and RP5 forbids one, so the report names the group and leaves the reading to a human. A recurring series satisfies any title rule -- 37 of the 41 (article, group) pairs on the corpus are one, against 4 real chains -- so the version marker is reported as a triage key and marked groups are listed first. It is not a filter: P7, P8 and P9 are positives whose two versions share a title verbatim. Nothing here reaches a prompt (RP5), and that is structural rather than reviewed: the rule lives in storage/, core/merge.py is asserted over its imports not to reach it, the writer's entry points take source blocks and nothing else, and the report is built after the last write op. "Share an article" spans this run's ops and the paths already under the article's `sources:`, because the staged fixture compiles version N into the wiki version N-1 produced, and a report built from one run would be silent on exactly the merge paths A1 is measured on. Moves the date narrowing out of core/merge.py into the shared frontmatter reader. The report orders a group's members by the same dates the writer's blocks use, and two narrowings that disagreed would order them opposite ways. Also corrects what the corpus actually says. Reconstructing the rule showed the throwaway script that measured it missed a three-part `v1.0.0` marker and compared titles case-sensitively, so shape B has 42 matching titles rather than 40, leaving 38 groups after the cross-source rule and 37 after the person rule. And the migrated extractions are schema_version 1 where the loader now reads 2, so FX3's label drafting needs them re-serialized first -- free, but not free of work. py 1701 passed, storage/lineage.py 100%, commands/compile.py 99%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rsion FX1 asked for the /tmp/supersession/ scripts with tests. Two of the three were one-shot migrations that already ran against a gitignored KB with absolute paths baked in, and have since been deleted; porting them would mean owning tests for code that cannot run again. What lands is the two that do run again: select_cases.py finds the lineage chains and stratifies them, stage_fixture.py builds FX2's stages. test-set.md's Regenerating section says the conversion is not reproducible instead of pointing at /tmp paths that will vanish. The selector had to be rebuilt rather than moved. The script that measured the corpus is gone and only cases.json survived, so each rule was reconstructed against that file: all 79 non-identical chains' diffstats and all 134 strata now reproduce exactly. Getting there recovered four things the numbers in test-set.md depended on and did not state. The diff runs over the body, never the frontmatter -- every version differs in date, id and checksum, which is three changed lines between two files whose prose is identical, enough to move a group out of the noise stratum. The line counts include the break that ended the closing delimiter, because the original split on the delimiter rather than on lines. The append-only test runs before the similarity test, since a large enough append drives similarity below 0.55 on its own and testing similarity first put two negative controls in the positive set. And `sources:` entries holding a comma-joined batch are split apart, which is what the shared-article column had been undercounting: 43 duplicate-stratum groups against the 34 recorded, 6 append-only against 4, on a corpus where 46 articles carry such an entry. Shape B goes through storage.lineage, exclusions included, so the selector reports 131 chains where the old file has 134: it drops three cross-source pairs and a set of one-to-ones, and adds the v1.0.0 chain the original's marker missed. Corrects the strata table, and 101 of 675 articles at 15% becomes 123 of 682 at 18%. Staging is what puts the merge paths under test. One version per stage, materialised into the KB the previous stage wrote, so from stage 2 onward every write is a merge into an article an earlier version composed -- on the fixture that plans four stages of 18, 18, 1 and 1 documents, the last two being P4's four-version chain. The script prints the compiles rather than running them: a pass costs about 10 USD and each arm pays it again, so spending stays the operator's decision. FX4's baseline arm needs the pre-A1 code, which is no longer checked out, and both the script and the spec now say it runs from a worktree at bd8252e. Verified without spending: the selector finds exactly 18 chains in the fixture, which is its 10 positives, 4 negative controls and 4 duplicate controls; two staged materialisations then pass `kb-ai check` with 36 match, 0 missing, 0 mismatched. py 1740 passed, scripts/ 99% and 98%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ontradiction and drop The test set's single `superseded` list conflated two failures that A1 is not equally responsible for. Q1 scopes A1's trigger to explicit contradiction and sends dropped claims to the RP1-RP3 report, so a single list would have judged A1 against work it does not contain. Split it into `superseded-contradiction`, which gates FX7, and `superseded-drop`, which is measured on the same runs and gates nothing. Draft the labels for P2-P5 and P7-P10 in labels.md: 58 contradictions, 36 drops, 48 controls, of which 38 contradictions are still stated as current today. Two consequences are recorded rather than buried. P1, the one adjudicated failure, is a drop case and no longer gates the work it motivated. And the fixture needs no re-serialization: the schema check lives inside `parse`, which only `extraction.load` calls.
Both blocking rulings from FX3's label drafting are settled, so the labels are down to item-by-item confirmation. P2 is withdrawn from the positives and kept as the documented wrong-date counter-case. Its file dated 2026-04-14 is a rolling document carrying a `# 2026-05-04` body section and an `extracted_at` three weeks after the file it supposedly precedes, so the chain runs backwards relative to its content. Scoring it would credit A1 for asserting an order that is wrong -- the direction that flatters the work. The drafted label is retained verbatim, in the fixture's direction, along with the inversion to apply if the case is revived, because P2 is the corpus's only inverted chain. P7 keeps its 8 contradictions: the measurement-time reading is accepted, decided on the article's own behaviour rather than on a preference between two defensible readings, since the article flattens the weekly table into undated current-state prose and that is exactly where v1's figures become wrong. The scoring set is therefore seven drafted cases plus P6, carrying 50 contradictions, 31 drops and 42 controls, with 31 contradictions stated as current today. Records the design gap P2 exposed as an A2 question rather than leaving it in the label file: a frontmatter date can be wrong and not merely missing, which is a case Q2 and D3 did not provision for, and A1 has no way to notice because the writer is told a date and never the text it came from.
Subtracting P2 left the drop count at 31 where the seven remaining cases carry 30 (5+4+5+0+6+5+5). The contradiction, control and staleness totals were right.
…cation Objective corrections only; the disputes those audits raised are recorded separately once every case has reported. P3: D5's quote is at v1 L1113, not L1114, which is a closing tag. K3's v2 cite moves to L97/L109, because L28 asserts source-to-structured-docs without the AI authorship the control is about. D1 is narrowed to the repository count -- v2 restates the multi-team half at L20, so the original compound row was half not a drop -- and its stray fifth cell is removed so the row renders. P8: the relocated-list cites for MCP and AI Coding adoption are v2 L291 and L311, eight lines off as drafted. The intro said four rows move to `架构` when two move to `架构 / api 团队` and `架构 / 效能`, so it now says they replace named individuals with team names. And the drop table claimed all six drops are stated as current when D3's headcount is absent from the article -- only its 25%/two-month clause survives.
K2's v2 range is L53-62; L54-63 as drafted started one line late and omitted the `Fee Conversion` label cell. C5's replacement said "5 capital-protected Earn products" when v2's own table at L333-384 spans Earn, Margin Staked SOL and Spot X, so it overstated the narrowing -- v1's spot leg is partly retained and only RWA and the horizontal-comparison framing are genuinely gone. Neither change touches a classification or an article verdict.
P7's verification found that the article's fifth source, the 04-14 infra biweekly that is also P2's v1, asserts v1's entire 0430 column verbatim. So 7 of P7's 8 staleness observations have a second possible cause, and its headline was wrong on both halves: C4's and C6's replacements are in the article, so 5 of 8 corrections were lost rather than 8 of 8. Generalised into a note, because P10's judgement call 5 had already caught the same shape for one case. Only P3 and P8 compile from their chain alone; P5's article merges 16 sources, which is the strongest reason not to read its 0-of-5 pass as evidence about the pipeline. The bound matters as much as the finding: FX4 already re-runs the compile over the staged fixture rather than trusting the existing wiki, and only P5 and P7 carry a co-source into that run. So the 62% figure is motivation, not measurement, and FX5 needs staleness defined against the newest source in the compile set. Also corrects C2's article evidence (L57 sits under a `Completed (Apr 30)` header, so the row rests on L480 alone), C3's (v1's 13.3% is absent, not present -- the article recomputes ~27-34%), and C6's (L192 is explicitly `as of April 30` and carries the replacement scope in the same sentence).
…ruling queue All 128 drafted items across the seven scoring cases were re-derived from the sources in fresh contexts, one per case, with no access to the drafting reasoning. Result: 111 verified, 4 line-corrected, 13 disputed, 0 unverifiable. The quoting held up well -- only four cites had drifted and no quote was invented -- and the findings concentrate in classification and in the `Article today` column, which is the one that scores. labels.md gains a verification section with two tables: 15 objective corrections already applied in place, and a queue of 17 items needing a Captain ruling, ordered by how much each moves the measurement and each carrying its own location, finding, recommendation and consequence. Three would move the totals -- P8's four contradictions collapsing as de-specifications rather than contradictions, P9-C1 being preserved by v2 rather than superseded, and P10-C6 comparing a mean against a median -- taking the set to 44 contradictions with 27 stale and six gating cases instead of seven. test-set.md and spec.md now point at that queue instead of implying 122 unchecked rows, and FX3 records that FX5 needs staleness defined against the newest source in the compile set.
系統户 for 系统户; the traditional form appears nowhere in the fixture.
The P10 verifier's full report flagged that C5's delta is largely a basis artifact, and I confirmed it by comparing all 24 monthly values: v2 L378 declares its median series >120-filtered, but its twelve monthly medians (L51-62) are identical in all twelve months to the full report's UNFILTERED column (L89-100), not its filtered one. So C5 compares v1's <=90-filtered 13.8/17.8 against v2's unfiltered 15.3/19.8. The row survives -- v2 declares the same span and statistic, so it contradicts on its face -- but it must stop being cited as evidence of real slowdown, and it strengthens the case that FX5 has to state measurement basis. Queue is now 18 items, 13 of them disputes; the rest are corrections and one spec change. Also records A16, a quote boundary in P10-C4.
…t finding The P4 verifier's full report surfaced one thing I had not captured: v1 asserts both the monthly fund-flow table and its replacement, two lines apart (L1761 uta_liq_trans_log_202605, L1763 translog_realtime). Confirmed independently -- the measured token is clean, 1 hit in v1 and 0 in v2-v4, but translog_realtime already has 2 hits in v1. L1763 is also the line control K4 scores on. Queued as V18. That makes four instances of one shape, so it is now a note rather than a per-case remark: P4-C3 in v1, P4-C8 and P4-C7 in v4, and P2's rolling file asserting both 100% and 90%. Only C7's was documented when drafted. Every contradiction row is phrased 'the earlier version asserts X, the later asserts incompatible Y', and that is stronger than these documents support. The practical consequence is for FX5: an extractor reading the later version alone can legitimately emit the older claim, because the later version still makes it. P4-C8 is the sharp case -- grading the article stale would fail a pipeline for repeating what v4 itself says in five places. So a stale verdict needs the later version to be unambiguous, not merely to contain the correction somewhere.
…ass did not cover The 128-item pass covered only the seven drafted positives. The controls and the adjudicated cases were never checked, and the controls are what protects A1 from being wrongly FAILED: if a chain labelled purely additive actually contains a contradiction, A1 reporting it correctly scores as a false positive. All eight hold. N1's only non-carried body line is its own H1 (a retitle, not a contradicted claim), N2 is an append-at-top rolling log whose shared 0428 section is unedited apart from extraction artifacts, N3 and N4 differ by one blank line. U1-U4 all confirmed: bodies byte-identical after stripping frontmatter and checksum fields matching exactly, with only date differing; U1 spans a six-week gap. P1 verified exactly as written -- v2 has 0 hits for both 现有情况 and 140, and the article has precisely four occurrences at L39, L44, L241 and L702 with both quoted strings verbatim. Notably P1 is NOT confounded: none of its nine co-sources asserts the ~140 figure, the only other hit being a substring of a numeric id. So the motivating case's evidence is cleaner on that axis than the drafted positives'. Two new findings. N2 carries P2's wrong-date pathology -- a file dated 04-17 holding 0422 and 0428 sections -- making it a second named fixture instance, though it does not break the control because the pair still orders correctly. And corpus-wide, 91 sources entries comma-pack multiple paths into one YAML item while 22 articles duplicate a source path; recorded against FX4 as a check for both arms, since G2 is the claim that a source is an attributable unit. The seven scoring cases contain none, so the co-source table stands.
P6 is the only adjudicated success in the set, and its explanation is load-bearing for the build decision: if the failures cluster on documents lacking an internal version marker, path A is the whole fix and paths B and C are over-buying. It holds as written. Both framing quotes are where the doc says, the article leads with the v1.7 framing and names v1.5-v1.7, and the superseded framing is absent in both languages -- 0 hits for 重量级 and 0 for `heavyweight`, which matters because grepping Chinese against an English article would otherwise have passed vacuously. Two precision fixes: the v2 quote drops the source's own bold markers, and the scope widening has a cleaner second location the adjudication never cited (the 定位 line, where v2 adds 整合 bgw / bgwg / bgwtp / LiteLLM). Also checked the one thing that could have read as stale -- the article repeats BGW's problem list, but v1.7 keeps that six-row table under a new per-gateway subheading, so v1.7 subordinates v1.5's framing rather than retracting its detail. P6 is not confounded, like P1: three sources rather than the chain's two, and the third asserts none of the framing and carries no version or date marker at all. It is not staged in the fixture, so FX4's re-compile sees two of three sources and cannot reproduce §14 -- score P6 on the framing, not on completeness. The finding lands on the design lesson rather than on the case. P6's v1 contradicts itself about its own version: title and H1 say v1.5, the body marker says v1.6. The accidental ordering signal the success is credited to is present in both documents but self-inconsistent in the earlier one, so a reader taking the title sees v1.5->v1.7 where a reader taking the marker sees v1.6->v1.7. The case stands, and the finding argues for path A rather than against it. Recorded as a fifth instance of within-version ambiguity, the first about a version rather than a claim. Verification coverage is now complete: every case, control and adjudicated case has been re-derived from the sources. Also fixed a dead anchor left when the section was renamed to three adjudicated cases.
…rulings V16 asked whether the compile read a source P5's article does not declare, or whether the article's source list is incomplete. No artifact answers it: the compile state records no target article, no classify cache survives, and the list itself is model-written on the rewrite path. Resolved on content instead. None of the 68 lines the hardening plan alone asserts reaches the article, and two residues at issue are single corpus hits in v1 -- including D5's own dropped clause -- so D2-D5 score as lost drops and the fixture has no provenance gap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rontmatter Re-measuring the source-list defect for V16 found a worse one beside it: seven of the 682 articles do not open with a frontmatter delimiter, because the writer's preamble prose stands above it, so no key reaches any reader -- no title, no date for WP2's signal, and no sources for derive to copy, which fails G2 outright rather than mis-shaping it. Nothing catches it today: check counts documents against extractions and skipped all 682 on the schema-version gate. Also withdraws the 22 duplicated-path articles figure, which reproduces under no reading tried, for 21 literal and 30 after splitting comma-packed items, with the definitions attached. The 91 comma-packed entries reproduces exactly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ions Captain accepted V1, so P8 contributes no contradictions and leaves the gating set: six drafted cases plus P6, totals 46/30/42 with 29 stale. Two arguments the queue row did not have decided it. v2 asserts the mapping the rows read as a substitution -- it writes Lucas (架构) and hangs @lucas.wan on the whole infrastructure heading -- and the article writes both sides anyway, so under either staleness rule it is not asserting a superseded value. v2 also keeps person names in its own team column and still names Victor / Lucas elsewhere. The rows stay as a re-attribution list with their evidence and their IDs retired, because they are the set's clearest instance of a change that reads like supersession and is not one. P8 keeps its 6 drops and 6 controls, which is worth having: it is the one case with no accidental ordering cue at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Captain accepted V2. v2 keeps both halves of v1's two-part end state, at L175-178 and L184, and L184 is already the line control K1 is scored on -- so the label set had one passage both preserved and superseded. Checked at ruling time that the stale verdict was wrong on the facts too: the article's two-component framing is what v2 asserts as well. The substance goes into K1's evidence rather than a new control, since K1 already covers the second half, and the three-pillar restructure joins call 7's additive list as a taxonomy on another axis. Totals 45/30/42 with 28 stale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…diction C6 paired v1's mean development duration against v2's median 研发周期, which v2 defines as development plus test: different statistic, different span. Two checks at ruling time closed the alternatives. v2 does carry a same-scope development duration as a median (1-3 to 4-7 days), compatible with v1's mean and predicted by v2's own note that the mean runs high on a long tail. And v1 reports that duration only as a mean, so there is no same-basis pair to re-cut the row onto. Recorded as drop D6 and as a lost drop, since the article still carries the mean framing. V12 lands in the same item: v2 does report means elsewhere, so that claim is now restricted to development duration. Totals 44/31/42 with 27 stale, which is the arithmetic verification predicted for V1 through V3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five of the nineteen items are settled -- V1, V2, V3 and V12 ruled, V16 resolved by investigation -- so the queue heading and preamble now say 14 open rather than 18, and name which five of those still move a scored number. Also corrects the staleness rate to 61%, which is what 27 of 44 reads after V3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…urces V19 asked for staleness to be restated against "the newest source in the compile set". Ruled accepted, tightened to the newest source *that speaks to the item*: read per document the criterion clears an item whenever the latest source is merely silent on it, which is the common case. Ruling it established two things the item did not claim. Its own rationale does not hold. V19 invokes V4, but the wording only clears an observation where a co-source is newer than the chain head, and in the fixture none is except P5's -- P7's is 2026-04-14 against a chain head of 2026-05-14, P10's 2026-03-05 against 2026-03-06. So it answers V4 in no case, and the co-source note no longer implies a definition can repair that confound. P5 cannot be scored on the column at all yet, which is now V20. Both of its versions carry date: 2026-03-13; build_source_blocks breaks the tie on the path while _SOURCE_ORDER states "blocks run oldest to newest" caveated for undated blocks only, and since "-" sorts before "." the payload renders the v3 file first and thereby asserts that v1 is the newest source. The article carries v3's figures, so against the stated order P5 reads 5 of 5 stale rather than 0 of 5. It is held out of the gating count until V20 is ruled, and V20 is recorded as WP9 because the fix belongs in the payload, not in the scoring. Scope of V20, measured: 159 of 397 multi-source articles in the reference KB carry two or more same-day sources (411 pairs), of which only 8 have a version-suffix shape -- so the tie-break is mostly uninformative rather than inverted. Three cases render a source after their own chain head, but only P5's is a chain member; the same-day co-sources P7 and P10 render last assert none of the superseded values. No total moved: 44 contradictions, 31 drops, 42 controls, 27 stale.
… the score V4 found that P7's article merges the 04-14 infra biweekly (P2's v1), which asserts v1's entire 0430 column, and recommended scoring only C8. The finding is accepted and verified exactly; the scoring restriction is rejected. Premise verified with fixed-string counts and the lines read in context: L898 40.95/24.57, L904 13.3, L911 3000C, L916 合同已提交, L919 117.3, L921 3300/83.1, L925 7197, L928 17054 -- one hit each except 7197 with two. The restriction was rejected because it attributes staleness to a document pair, while supersession is a property of the compile set. The set holds 04-14 asserting the old value and v2 asserting otherwise, so a writer that emits it undated mishandled ordering whichever document supplied it -- and 04-14 is itself superseded inside the fixture by P2's v2, so A1 orders it too. Under V19's ruled criterion every stale row holds, the newest source speaking to each being v2. For FX7 the confound cancels, the co-source sitting in both arms. So P7 keeps all 8 rows at 6 of 8 stale, and only the causal claim narrows to C8. Two repairs came out of ruling it. C8's test is now the full phrase 识别—分析—跟踪—复盘, which is 0 hits in all three non-chain sources, because the bare token 闭环 has 7 hits in the 双周会 alone on a different loop -- the same string-matching hazard already recorded on C2. And C6 gains a residual: the newest source in the set restates 3000C at 05-20 L374, six days after v2 reported that gap closed to 7C, with the scope unstated. That is the one row where the newest source speaking may assert the superseded value. Also recorded: 3,864 carries a comma in the 05-14 meeting, so a scorer searching 3864 misses it, and the corrections absent from every co-source are C1's 95.18, C2's 44.4/41.13, C3's 41.5/8.3, C5's 25046, C6's 7C and C7's ES outcome. No total moved: 44 contradictions, 31 drops, 42 controls, 27 stale.
…rong V5 found that v4 still names 系统户 as the settling counterparty in five places, none in a 待决策 block, and offered either an open call or dropping the row. The residual is recorded and the row stands. It survives because the replacement is the cleanest in the chain: v2 L5447-5453 and v3 L5697-5703 are the same table row replaced cell for cell -- subject 交易系统户 to 交易系统内的差额账户, role 作为事故用户的对手方 in both, and detail 1 from 资金都和系统户结算,允许透支 to 资金都和差额账户结算,允许透支. The five residual mentions are weaker than C7's rather than stronger, because they describe a different level than the counterparty role the row scores: three are transType accounting directions in §3.3 engine (which ledger account moves per transType), one is hedged with 可以考虑, and one is a worked example that three lines later says 差额公司出, sitting under an open question highlighted light-yellow. Scored on the table row, the basis call 2 already uses for C7, and written up as call 8. Two line-level corrections came out of ruling it. The cited pair is v2 to v3, not v2 to v4. Term counts across the chain are 0/0 at v1, 7/0 at v2, 5/2 at v3 and 5/2 at v4 for 系统户 and 差额账户, and v4 only shifts the two lines by one. This confirms V15's "rewrite X1 as v2->v3" from a second direction, so V15's row and X1's cites are updated too. And 允许透支 is not part of the change: it already stands in v2's cell, so the row wrongly implied overdraft arrived with the replacement. X1's entry had this right, which is internal corroboration. No total moved: P4 stays 9 of 10 stale, and the set is 44 contradictions, 31 drops, 42 controls, 27 stale.
V20 asked what to do about two source blocks that share a date: WP5 breaks the tie on the path and WP6 then tells the writer that blocks run oldest to newest without qualification, so the pair gets a positive ordering claim resting on a filename. The fix is to withdraw the claim rather than state a better one. WP6's undated caveat now covers same-day blocks, they keep rendering in path order for reproducibility, and BG1 restates its own basis as newest known day first with ties broken on path for stability. Both candidate tie-breakers were rejected on measurement. Of 384 same-day pairs on the reference KB a filename version marker appears in 9, names a document revision in 2, and survives inspection in 1 -- the other of the two, the testnet report marked v100, carries the tested skill's version 1.0.0 against a sibling reporting 3.1.0. A body-stated date is present in both members of 9 pairs, unambiguous and differing in 5, a revision pair in 1. A rule in the system prompt applies to every payload, so a signal worth 1 pair in 384 cannot be it. Reading body dates is also A2's deferred question and the corpus does not settle it: of the 10 same-day sources whose body date contradicts their frontmatter, 7 point earlier and 2 later. Ruling it reversed the item's own consequence. P5 does not become gate-scoreable, because withdrawing the claim leaves its chain unordered rather than ordered, so its 0 of 5 would be luck instead of evidence. P5 stays out of the gating column for good, and the reason underneath is new: v3's body dates itself 2026-03-19 against a frontmatter date of 2026-03-13, six days apart, so the shared date is an error in the metadata rather than a property of the corpus. That is raised as V21. Two numbers were corrected on the way. The population figure recorded for this item counted byte-identical duplicates as two blocks, which WP7 collapses into one, so the basis is 156 articles and 384 pairs rather than 159 and 411. And BG1 needs no change of tie-break direction: it already breaks path-ascending exactly as the render does, so the conflict was never between two orders, only between WP6 calling a block older while BG1 called it newer. P5's five contradictions stay in the set totals while P5 is not judged on the staleness column, so the stale rate now has two readings -- 27 of 44 (61%) over all cases carrying contradictions, 27 of 39 (69%) over the five that gate. V21 picks the published one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… a chain P4-X1's third step lands at v3, confirmed three ways: fixed-string counts (差额账户 0/0/2/2, TRW 0/0/1/1, 交易系统户 only in v2), v3's own lines L5697/L5703/L5705, and a whole-file v3->v4 diff that is four changes -- date, checksum and three 进展 cells -- so v4 only shifts this material by one line. The v1->v2 step supersedes nothing: v1 asserts no counterparty at all, its two 对手方 hits being opponent_user_id field descriptions, and v2's §5 table is material v1 does not have. So the chain holds one same-predicate replacement, already scored as C8 and C9, with v1's line scored as D3. The entry is relabelled rather than deleted, on a fixture-level measurement: intersecting the v1->v2 and v2->v3 diffs leaves 34 v2-side lines, all either v2-introduced or unchanged in value until v3, and P4 is the only staged chain longer than a pair (38 files checked), so this fixture cannot carry a nested supersession at all. What X1 does show is that the article asserts v1's dropped state and v2's superseded state as one current section while carrying neither 差额账户 nor TRW. Ruling it raises V22: of C9's three article residues only L667's "(discuss with TR)" discriminates a version, since L425-426 trace to the 待决策 block v4 keeps verbatim -- the one open item that could still move a total. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…three The item's line-by-line premise holds and generalises to the whole block. From v2's 待决策和讨论项 marker (L5531) to end of file, v2 and v4 differ by two deletions only -- 仓位强增操作,经过撮合? and 现货兑币: TR还回来? -- and v3's tail is byte-identical to v4's, so item 5's two bullets stand unchanged in all three versions. The article's L425-426 therefore discriminate nothing and leave C9's staleness evidence; they are recorded as a presentation defect instead, in P10-C2's shape, since the article states v4's pending options as settled characteristics while filing the junk-coin question from the same block as an open item (L685). What keeps the row a contradiction rather than a drop is that v3 answered the TR question rather than falling silent on it: the edit that first writes 给到TRW处置 (TRW 0/0/1/1) also deletes both of v2's TR markers -- the cell's own 这里还需要和TR讨论下 and 现货兑币: TR还回来?, 1 hit each in v2 and 0 elsewhere -- and folds 现货 into the disposal item. So the article's L667 repeats a question v3 closed, and TRW appears nowhere in it. The article exhibits the append that produced it: its action items are partitioned by source, and the "from 2026-06-04 TRD" block picks up the line v3 added to §5 (财务资金处置, article L688) while missing the line v3 changed. That also bounds the dated-label defence -- the labels name which document a block was read from, not when its content entered, since 财务资金处置 is v3's and is filed under 06-04. Two further corrections: the pair is v2 -> v3, not v2 -> v4, the same line-level fix V5 made for C8; and the article's overdraft bullet is L424, not L423. P4's one co-source is silent on the row (处置, 甩卖, 保险池, TRW, 系统户, 差额, TR讨论 all 0 hits), so unlike P7 and P10 this row carries no co-source confound. Tests pinned: C9 on 这里还需要和TR讨论下 / "discuss with TR", not on PM接管户, 等交割, twap, 保险池, 盘口, 甩卖 or 移仓, all of which survive into v4 -- a count discriminates where a presence test does not. R9 on TRW, clean at 0/0/1/1 with 0 in the co-source and 0 in the article. No total moves: 44/32/42 with 27 of 39 stale (69%), P4 at 9 of 10. The queue closes at 22 items, 20 settled and 2 open, and neither of the two can move a number. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…down P10-C5 stands as a superseded-contradiction, on level and not on trend. v2's twelve monthly overall-cycle medians are the 2026-03-05 companion volume's unfiltered column in 12 of 12 months, and the 17,777-item >120 population v2 declares for efficiency produces no figure anywhere in the document, so the row compares v1's <=90 series against an unfiltered one. On the same twelve cells the basis change alone accounts for all of H2's +2.0 days and 0.92 of H1's +1.5, so C5 is not evidence of real slowdown. The artifact stops before the on-time rows: filtering moves an on-time rate by 0.4-1.6pp while v2's monthly rates sit 7.4-13.9pp below the unfiltered column and match neither column in any month, so C3, C4 and C8 rest on a measurement v2 made rather than a column it re-based. No total moves -- 44/32/42 with 27 of 39 stale, P10 at 3 of 7. The queue closes at 22 items, 21 settled and 1 open (V18). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…string P4-C3 stands, on four v1-exclusive strings instead of one. v1's L1761 heading names the monthly uta_liq_trans_log_202605, and across the 774 lines of the section it opens that name never occurs again, while the body specifies translog_realtime from its first line. So v1's ambiguity is a heading against its own section body, and being the earlier version's it does not reach the stale verdict under V19's and V22's test -- v2, v3 and v4 name the replacement in the heading, the body, the DDL and six queries. What it costs is R3. translog_realtime is v1's own string and is control K4's line, so a presence test on it reads the control rather than the replacement; only the count (2 -> 11) and one attachment discriminate, and on that attachment the article sides with v1, leaving R3 not carried. The transition is corrected to v1 -> v2 as V5 did for C8 and V22 for C9. No total moves -- 44/32/42 with 27 of 39 stale, P4 at 9 of 10. The queue is closed: 22 items, 21 ruled and V16 settled by evidence, none open, no total moved since V8. The confirm pass is untouched: 118 rows still read `to confirm`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…g headline The header claimed "every item below is `to confirm`" while seven scoring rows had lost the marker entirely -- their Status cells were overwritten with ruling text (P3-D3, P4-C3, P10-C2/C4/C5/C7/C8). That made the doc's own "118 rows still read `to confirm`" false by seven and let those rows pass the done-test at L30, which fires on the absence of the marker. Restore `to confirm --` in front of the seven rulings, matching the convention the other eleven ruled rows already use, and reword L3 onto today's state: the confirm pass has not started, the verification queue is closed at 22 of 22, and settled is not confirmed. P4-X1 and P2-C7/C8 keep no marker, since neither scores. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
First case through the confirm pass, which is a different act from the closed verification queue: a ruling settles what a row means, confirmation decides whether it scores. All 19 P3 rows are settled, 99 of 118 remain. Re-derived every row from the fixture rather than from the drafted quote -- all 8 C/R pairs, 5 drops and 6 controls check out against v1, v2 and the article. Both "not stale" verdicts survive a counter-check: the article has no project-level knowledge path (L66 names it only to reject it) and no 6-agent or 6-dimension claim anywhere. Five rows are amended on evidence with no verdict moved, and four of those are the same defect -- article residue cited short. C2 was cited at three lines and has six, C5 at the heading alone while the claim survives in prose at L264 and L22, C8 at the file tree while v1's filenames also sit at L38 and L174, and C3 gains the two lines carrying the every-session half. Under-cited residue is a scoring hole: a fix reaching only the cited lines would have read as complete. K4 is amended for the opposite reason -- its v2 side was cited on the MR half only, and registry.mjs is v2 L742, so a control that both versions assert was recorded looking like half a drop. Calls 1, 4 and 7 are answered at the drafted position, each on evidence rather than on the default: the article asserts D1's two counts in one coherent sentence, v2's command table never declares itself complete, and C2/C3 overlap partially rather than totally. Call 3 is left open and its "low consequence" framing withdrawn -- v1's repo-URL form is 12 hits in v1 and 0 in v2, v2's is 3 in v2 and 0 in both v1 and the article, so both sides have exclusive strings. It stays out pending Captain because promotion is the one move in P3 that shifts published totals, to 45 contradictions and 28 of 40 stale. P3 holds at 8C / 5D / 6K with 6 of 8 stale; set totals unmoved at 44/32/42. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ty claim fixed P2's 18 marked rows are settled; C7 and C8 were already settled by V10 and keep no marker. The label stays in the fixture's stated direction as counter-case evidence, so none of this scores and the 118 scoring rows are untouched at 99 still to confirm. The correction is in the prose the inversion rests on. "v1 L1776-1786 and v2 L819-829 are byte-identical apart from three lines" is false as written: the rolling file re-indents with tabs where v2 uses spaces, so a plain diff of those eleven lines reports nine changed and only three survive whitespace normalisation. The same applies to V10's seven verbatim pairs -- only v2 L953 / v1 L1910 is byte-identical, the other six match on content. This matters because the pair's whole argument is re-derivable identity, and anyone re-deriving it with diff would conclude the rows are wrong. Recorded as the third form of one hazard, after C8's split colour spans and K2's bold markers, and the image lines are noted as differing in pixel dimensions too, not only in token. Three rows amended on evidence, no verdict moved. D3 and D5 stand as drops with their false positives recorded: v2 has seven ABF hits belonging to that team's own work items and five openclaw hits on other subjects, so a presence test on either token fails to detect the drop -- the propositions themselves are 0 hits (disk encryption, slow-progress reason, the three pending-improvement items). K2 stands as a control whose two lines differ only in bold markers around 57. Verified independently: both dated body headings, both extraction timestamps, all eight contradiction cites, all six drops, all six control pairs line by line, and every article residue including C8's absence -- the article's four 56 hits are alert-RCA coverage, and L707 pairs 56% with P0/P-1, the same token v1's own 56% line carries. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…acements land mid-chain
Third case through the confirm pass, and the first whose amendments generalise.
All 20 rows settled, 39 of 118 done and 79 to confirm. No verdict moved: P4 holds
at 10C / 4D / 6K with 9 of 10 stale, and no published total changes.
The systematic correction: nine of the ten replacements first appear at v2 or v3,
not at v4. V18, V5 and V22 had each found that for one row (C3, C8, C9); C1, C2,
C4 and C5 land at v2 and C6 and C7 at v3, leaving C10 the only contradiction v4
introduces. Verified by fixed-string counts across the chain -- 在TiDB中建立单表,
不按月分 0/1/1/1, 改造为按月分表 1/0/0/0 against 从mysql迁移过来 0/1/1/1, 设置时间(纳秒)
7/7/0/0 against 设置时间(ms) 0/0/13/13, and the three _{yyyyMM} table names each
1/0/0/0. The version a reader is handed is not the version that made the change,
which is the case for NG3's trail measured on the only staged chain longer than a
pair. The contradictions table now says so above the rows, since the verdict is
still v1 against v4 while the cite is where the edit happened.
Open call 9 answered yes -- a heading asserts -- at the drafted position, on
evidence V18 did not have. C2 is the same defect mirrored: the article's heading
is current (L485 uta_exchange_record) where the body under it is stale (L487's
monthly name), while in C3 v1's heading is the stale side and its own 774-line
body specifies the replacement. Headings and bodies drift both ways here and the
compile reads each as an assertion. v2 rewrites both headings in one edit at the
same offset (both shifted 223 lines), which is how an author treats a claim, not
an inert label. Declining would have read 9C, 8 of 9 stale and 26 of 38.
Ten amendments, none moving a verdict. One residue reassigned: article L508 and
L642 are v1 L3653's, which is C4's third cite, not C5's -- the article files both
leverage tables together where v1 files that one under 用户行为记录表. Two residues
were under-cited (C1's open actions are L634 and L636; D1's article hits are five,
the fifth a bare Related-Concepts link with no predicate). C1's replacement is
stronger than drafted -- v2 strikes the three field rows in the table itself, not
just the prose rule. Three string hazards recorded, the P7-C2 class:
service_action is 2 hits in v1 and 3 in v2 as the translog tables' own column, so
C7's test needs the uta_auto_add_margin_log DDL; the article writes D2's row count
with commas; and D4's task is 兑币的流水回滚, where the form used in the transition
table and the X1 write-up was 0 hits in all four versions. Two cite-grain fixes:
C1 pointed at a description cell instead of its field name, and K3 was cited on
bare 10000 and 90 cells that locate nothing.
Calls 1 and 7 re-verified. exec_time_e9 is still nanoseconds at v4 L1976, so the
article's L490 is current -- but the unstruck bullets call 1 listed are C1's
residual, not C6's, and moved there. Adding call 7's MarginDB cell would read not
stale too, so it doubles the v3-to-v4 evidence without adding a gating row.
All six controls re-checked in the article with lines now cited, which
substantiates a claim that carried none.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rop arm is structural Fourth case through the confirm pass. 14 rows settled, no verdict moved, so P7 holds at 8C / 0D / 6K with 6 of 8 stale and no published total changes. What the pass settles is the case's structure rather than its rows. v1 sits inside v2 byte-identical across all ten shared table cells, so the empty drop arm is a property of the pair -- and it rests on call 4, now answered on arithmetic, because strikethrough is the one deletion an additions-only diff still allows. Five of six controls are re-asserted in v2's own newest column; only K1 holds by construction. V4's confound is narrowed from the inside: the co-source copies only the Q2 half of v1's newest column and carries the three landed corrections without their units, which is where C1's replacement figure became a percentage in four places. Also: C5's correction only half landed, C8's and C5's residues were under-cited, C3's superseded rate is stale inside v1 and on a different basis than its replacement, and four string hazards are recorded. 53 of 118 scoring rows settled, 65 to confirm. P3 call 3 stays the only open call in the pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…op arm is short by five All 17 scoring rows settle with no verdict moved: P9 holds at 6C / 5D / 6K with 3 of 6 stale. Calls 1, 2, 4 and 5 are answered at their drafted position, and the mechanism question the case turns on is settled with them -- colour markup asserts a phase where the document declares a legend (v2 L124), which is not the same as reading a phase off an absent highlight, C6's weaker half. Two calls are left with Captain, both with a branch that moves published totals. Call 3: v2 restates v1's offer nowhere and re-terms the same capability as a paid tier, yet demotion still turns on reading v2's tier table as exhaustive, which P3 call 4 declined to do for command tables. Call 9 is new -- 126 of v1's 208 non-blank body lines survive in v2 byte-identical, and re-testing the other 82 against V8's standard finds five unrestated propositions the drop arm does not carry, three of them stated as current in the article. Row-level corrections: C7's hybrid residue is four article lines and not two (L298 and L448 added); C4's phase move is asserted at v2 L156 alone, since L307 restates the item unphased; K1 holds on content and not on bytes; K2's figures reach the article carrying a currency neither source states; K5 has the case's thinnest carriage. Also fixes a stale headline claiming three rulings still open. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…19 lines survive the rewrite All 19 scoring rows settle with no verdict moved: P10 holds at 7C / 6D / 6K with 3 of 7 stale. Calls 2 and 3 are answered at their drafted position, call 1 is recorded as settled by V3 rather than as an open question, and calls 4 and 5 keep their lists. The case is where the pass measured the rewrite. Only 19 of v1's 171 non-blank body lines survive in v2 byte-identical, and seventeen of them are separators, headings and table rules -- the two that carry anything are §1.1's column header and K5's own heading. No row here can be scored on a shared string, which is why every one is measured on figures and prose. Two findings land off the gating column. The drop arm reads 4 of 6 stated as current, and the two that are not show where a compile loses things quietly: D2's whole residue is the frontmatter tag `wip-limits` with no body line behind it, and D3's is a link to a page the KB does not contain. K2 is an over-deletion hit -- v1, v2 and the co-source all state the on-time rule and the article writes "on-time" 39 times without defining it once -- while three of the six controls are co-asserted by the never-superseded full-data report and so cannot score alone, which is recorded on the co-source note too. One call is left with Captain. Call 6 is new: all 152 of v1's non-surviving lines were classified and 93 re-tested against V8's standard, turning up six unrestated propositions the drop arm does not carry, three of them stated as current, plus two excluded on V9's ground. One of the six has a contradiction reading that would gate. Row-level corrections: C7's 43% is v1's arithmetic and not the framing V6 left unscored; C1 holds on the rule because v1's 6.3% never reaches the article; C3's replacement reaches two lines beyond its cite; K1 holds on content and not on bytes; and seven cites were short of their own item. Also fixes the pre-V3 arithmetic in calls 2 and 3, which both read a denominator of nine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…atus cell is not the status Seventh case through the confirm pass, and the one that could be measured end to end instead of argued. Parsing both files into endpoint rows gives 278 rows in v1 and 299 in v3, 273 shared, with name and method identical in every one -- the case's central claim turned into a count. Two measurements under it were wrong: the status cell differs on 22 of the 273, always by the removal glyph v3 drops, so a field-equality test reads 22 changed rows where a decision test reads none; and the warning-glyph rise is +6, not +8, eight added in the new modules against two lost with the leverage tokens. The 280-against-278 basis reconciles on two untabled WebSocket endpoints both documents count. The case gains a notation finding. The removal glyph is 24 rows in v1 and 0 in v3, v1 is the only one of the article's 16 declared sources that marks removals with it, and it survives into the article -- while in the other direction v3's own rewritten P2P wording reaches two article lines. So the compiled output took its notation from the superseded version and all five figure pairs from v3. The glyph asserts no proposition, so call 4 still keeps it out of the score. Row-level: four of the five contradictions had their article side cited one line short, two of the six controls sit on cells v3 abridged so a byte test reads over-deletion while the control holds, both of those dropped clauses reach the article on the control's own line, K1 holds on content rather than bytes, and D6's two arms cannot be cited at one grain. Five of the 17 abridgements are not the trailing-clause deletions the blurb claimed, one of them a rewrite. No verdict moved: P5 holds at 5C / 6D / 6K, 0 of 5 stale, totals unchanged at 44/32/42 with 27 of 39 stale. All five calls answered, so P5 leaves nothing with Captain. 106 of 118 rows settled; P8's 12 are what is left. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ference set is fully labelled Last case through the confirm pass, and the only one it could close completely. 71 of 88 table rows are byte-identical, and the 17 that are not decompose into two table headers, the four owner rows V1 struck plus one scope expansion, the four rows of the deleted resource-constraint table, the three deleted milestone rows, and three items the calls had already set aside. Nothing in this pair is unlabelled -- the sweep that found five unrestated propositions in P9 and six in P10 finds none here -- so P8's drop arm is complete at 6 rather than capped at 6. The 212-line figure is reproducible once its basis is named: diff reports 155 changed lines on v1's side and 65 on v2's, 8 of them frontmatter. Two tighter figures sit beside it, because 212 counts reserialisation: 40 of v1's 1,665 non-blank body lines have no counterpart in v2, 22 of v2's are new, and all eight surviving table tags were rewritten with header-row and column widths. Two evidentiary points are stronger than drafted. The article declares only the two chain versions, so with P3 this is one of the only two cases free of a co-source confound. And v2 deletes the only two in-body dates later than v1's own frontmatter -- they are D4 and D5 -- so the newer body is dated less than the older one, which pushes a body-reading ordering heuristic the wrong way. Call 3 is escalated and left with Captain: V1 ruled a de-specification is not a contradiction and said nothing about drops, and V8's test, the one that promoted P5-D6, is satisfied by v1's week-level MCP commitment becoming a bare quarter. On that reading it is a seventh drop with three article residues and the published drop total moves 32 to 33. An undeclared same-day sibling document asserts the same schedule, which is the V16 shape that kept P5's residues with the chain. Row-level: K3's cite was one cell of three and the whole summary table turns out to be a control, though the article never states its category split; K4 holds on content rather than bytes; D1's residue is three lines and loses its scope clause; D2 shares one of them; D6's second residue was uncited; and one absence test had to be re-based off a string with a hit in v2. Calls 1 and 5 are corrected on their own evidence. No verdict moved: P8 holds at 0C / 6D / 6K, totals unchanged at 44/32/42 with 27 of 39 stale. All 118 scoring rows are now settled. What "done" still needs is test-set.md's Status block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…h defect was never one The confirm pass finished on the rows in the previous commit; this is the last of the three conditions "done" required. test-set.md's Status block now reads confirmed rather than awaiting-confirmation, its Label column carries each case's pass result and its open calls, labels.md records all three conditions met, and spec.md's FX3 criterion carries the closing line -- with the historical blocker-2 paragraph annotated rather than rewritten, since it is quoted there as the reasoning A1's criteria were written from. One deferred item dissolves on inspection. The note carried since P7's pass said test-set.md's article paths use plural wiki directories where the corpus is singular, wrong on all ten rows. The section's own preamble already says the paths are given as they stand in ~/.knowledge and that corpus copies sit under the singular names, and both trees check out: ~/.knowledge/wiki is plural, the corpus is singular, and all fourteen paths resolve as written. The caveat now records the re-check instead of the table being rewritten. Aggregate, cross-checked by counting status cells rather than by adding up the commit messages: 118 scoring rows, 64 confirmed and 54 amended, none rejected, plus P2's 18 counter-case rows. No pass moved a total, so the set still publishes 44 contradictions, 32 drops and 42 controls with 27 of 39 stale. Five judgement calls stay open with Captain -- P3 call 3, P8 call 3, P9 calls 3 and 9, P10 call 6 -- each a promotion whose other branch moves one of those numbers up. FX5 can now score against these labels, which unblocks the FX4 baseline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FX4 asks both arms to check two defects nothing in the pipeline catches, and a note in the spec is not a check. This is the script. Comma-packed and duplicated `sources` entries are the first: G2's claim is that a source is an attributable unit, and an entry holding `raw/a.md, raw/b.md` is not one, while a path listed twice is the double-count the U1-U4 controls exist to catch. Frontmatter that does not start at byte 0 is the sharper one, because for those articles every key is invisible to every reader -- `split_frontmatter` returns None for content that does not open with a delimiter line, so there is no title for the catalog, no date for WP2 and no sources for `derive` to copy. The walk goes over the filesystem rather than `existing_articles()` on purpose: the index is built from the very frontmatter the second defect hides, so an article with an unreachable block is invisible to every reader that goes through it. A BOM is reported apart from those articles rather than with them, since every reader here strips it and no key is lost. On `data/kb-knowledge` it reproduces the spec's figures exactly -- 682 articles, 91 packed entries in 46, 47 duplicated paths in 30, 7 unreachable -- which is what qualifies it to be believed on a fresh run. It adds one datum the spec did not have: 8 articles carry readable frontmatter with no `sources` key at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The confirm pass settled 118 rows and moved no total, leaving five judgement calls open because each had one branch that moves a published figure. All five are ruled, and ten rows arrive with them: one contradiction and nine drops. V23 promotes P3's knowledge-repo naming row to C9 -- both sides carry exclusive strings, which is what P4-R3 was found to lack, and only one of its three article residues falls under the one-defect-counted-once precedent. It is the only ruling that touches the gate: 44C to 45C, and the headline 27 of 39 to 28 of 40 (70%). V24 promotes P8's `Q2 W6` to `Q2` de-specification to drop D7, not to a contradiction, which V1 already closed. V9's exclusion does not fire because the sibling carrying the same string is undeclared -- the V16 shape, which leaves the residue with the chain. V25 keeps P9-C6 and re-grounds it: read on the tier table being exhaustive it collides with P3 call 4, so it is ruled on v2's own re-terming of the same capability instead. Nothing moves; what changes is what the row is tested on. V26 takes three of P9's five unrestated propositions as D6-D8, and V27 five of P10's six as D7-D11. Both hold back the item that would gate on an absence -- P9's answer-card componentisation, which v2 answers with A2UI, and P10's ToB volatility, declined on V3's and V17's different-statistics ground -- and both leave a dimension as a note rather than a row. Two principles decided the branches, and they are recorded as such: V8's standard is applied uniformly, so "the diff did not show it" is no longer a reason a proposition stays unlabelled; and the gate may only grow on affirmative evidence, never on an absence. Also here, from starting the FX4 baseline arm: the two article-shape checks are a script now, both arms re-extract because the cached extractions predate the schema the code reads, and the cost estimate's "one merge op per document" is not an upper bound -- 18 documents fan out into 26 articles, so an arm lands near 14-15 USD. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…the prediction was wrong FX4 predicted that comma-packed and unreachable-frontmatter `sources` were old-writer residue a fresh run would not reproduce. The finished pre-A1 baseline arm reproduces both, at rates no better than the corpus they were found in: 2/27 (7.4%) comma-packed against 46/682 (6.7%), and 1/27 (3.7%) unreachable against 7/682 (1.0%). Small denominators, so the sign is the finding. The mechanism implicates both arms. `_apply_diff` appends one list item per path and cannot pack; the full-rewrite path has the model re-emit the article's frontmatter, and every packed entry sits in an article that took a merge-batch write. Step 2's rendered `sources:` list tells the model what to emit without constraining it. So the A1 arm gets audited on the same checks rather than assumed clean, and serializing `sources` in code is a fix outside A1. FX5 gains three scoring rules the arm exposed: - Cases resolve to an arm's article by its `sources` set, not by the name test-set.md cites. N2 landed as zero-trust-security-initiative.md, not the platform slug in the table; classification picks the slug, so the arms can diverge from each other too. - infra-team-h1-2026-decisions.md is excluded by name: it wrote in stage 1 and then lost every later merge to a write timeout, so it carries v1 of both its chains and would read as a supersession failure. Exposure is near nil (P2 scores nothing under V10, N2's scoring article wrote with both versions). - That exclusion is not assumed symmetric. The timeout constant is 300.0 in both arms, but three other groups timed out and then landed, and this one failed 21% under MAX_PROMPT_CHARS. If the A1 arm writes it, the exclusion is one-armed.
…solves to two articles FX5 is measured against the finished FX4 baseline arm (27 articles, 17.99 USD, code at bd8252e). The gating column -- Staleness over superseded-contradiction -- reads 24 of 40 (60%) against the 28 of 40 (70%) the label pass published for the historical articles, so the arm is better than the artifact it replaces. Band 21-25 on the four queued rulings that move the column. The reason nothing on this branch predicted: the pre-A1 writer already performs supersession unprompted on 18 of 45 rows, in four distinct styles -- explicit wording, version-labelled parallel presentation, as-of snapshot dating, and coequal presentation that names the conflict and refuses to order it, which the D1 option list has no name for. It is unreliable rather than absent: P9's article compared one of three phase deadlines stated on a single v2 legend line and kept v1 for the other two. Two findings changed the criterion before a row was scored. A case resolves to two articles rather than one (10 of 18 chains split across decision/ and project/, both carrying the whole chain), so scoring is the union over a case's articles -- arm-independent, unlike designating a primary, and on P3 the two articles are stale on almost disjoint rows, 5 of 9 each and 8 of 9 unioned. And one article carrying a whole chain is invisible to source-based resolution because FX4's frontmatter defect hides its sources; it is the article carrying P10's trails, so it was resolved by hand. Three spec clauses were checked rather than assumed and did not hold: the frozen article needs no by-name exclusion, V9's co-source exclusion changed no verdict anywhere on this fixture, and Size is unmeasurable on both arms as scripted. test-set.md's Trail and Size rows now say what is open and what is unavailable, NG3 no longer expects Trail 0 on P4, and labels.md's closed queue points at V31, which questions P3-C7's own scope. Seven rulings are open with Captain (V28-V34); the drafted position on each is what these numbers use, so none of them blocks the A1 arm. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
V28 is the only one of the seven that moves a number, and it is ruled against its drafted position: a Trail requires a directional statement about which value is dead. Version- or basis-labelled parallel presentation and as-of date stamps do not count, because P5 reads (Staleness 0 of 5, Trail 4 of 5) -- forging the current-plus-trail signature while deciding nothing -- and P7 reads (5 of 8, 6 of 8), a pair no D1 option produces. The three tiers decompose as 7 directional + 4 basis-labelled + 7 as-of = the 18 the rubric counted, and the two excluded tiers stay on the record so FX7 cannot claim the baseline performs no supersession. V31 and V34 are ruled at the draft on evidence that still exists. V29, V30, V32 and V33 close permanently at the draft, with a dissent recorded on V33: they are reads of lines in baseline-arm articles, and /tmp was cleared, so no baseline-arm article survives. scoring.md is now the arm's only record, which is also why FX7 compares against a written baseline rather than a readable tree. The gating column keeps 24 of 40 (60%) and the 21-25 band closes onto the point estimate. D1's option list gains coequal presentation, the shape the baseline produces most often and the one it never named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The baseline arm ran from four shell scripts under /tmp that were never committed. /tmp was cleared on 2026-08-19 and took them, the 27 scored articles and the logs, so the arm can only be re-quoted from scoring.md. This is their replacement, versioned and under test. It carries their policy, all of it paid for by 2026-08-18's two outages: wait for the endpoint before every compile (one outage lasted ten minutes and the driver that gave up into it scored the wrong thing), one retry per stage taken in place (staging the next version first would compile a leftover against an article that version had already moved), and a residual recorded rather than raised (stage 2 finished 16 of 18 and the arm is still the measurement). Plus the two things their absence cost. --out may not be under /tmp, and wiki/ is copied per stage, which is what Size was never measurable without. cases.json is rebuilt rather than shipped: select_cases against the fixture emits the curated 18 chains over all 38 documents -- the 131 candidates on record is its count against data/kb-knowledge, a different KB -- so the driver regenerates it and proves the coverage every run. 35 tests, 99% coverage, 10 of 10 mutations of the new rules caught. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sioned The 2026-08-19 entry recorded cases.json as unrecoverable on the ground that select_cases.py emits 131 candidates rather than the curated 18. That count is against data/kb-knowledge. Against the fixture the same script emits exactly 18 chains over all 38 documents, no orphan and no missing member, and the stage plan comes back 18/18/1/1 -- the split stage_fixture.py and the baseline arm both used. test-set.md L764 already published that count on this branch, so the claim contradicted a document beside it. So the file is derived, deterministic and free, and run_fx4_arm.py rebuilds it per run with the coverage proved by a test against the real fixture. FX1 now covers the thing that spends the money too, not only the things that prepare it, and Size is recorded per stage on the A1 arm while staying unavailable on the comparison -- the baseline is unrecoverable, not merely expensive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Found in review. The completion test read data["compiled"] from the compile response, but that count is KB-wide: gate 2 (compile.py:312-317) re-queues every document whose state carries no compiled_at, so a later stage's compile also recomposes an earlier stage's residual. Stages 3 and 4 stage one document each and the baseline left two residual in stage 2, so stage 3 would have reported compiled=3 against staged=1 and been declared done even when its own document failed -- no retry, nothing in the report, and the chain collapsed onto the single-run merge->create path FX2 exists to avoid. An 18 USD arm mis-measured silently. Stage completion is now by name: stage_shortfall requires compiled_at for every member of that stage, read fresh from .compile-state.json after each attempt, and the residual names the documents. A per-document compile error is deliberately not a retry trigger -- those errors can be entirely about documents this stage never staged, while an error on a member of this stage leaves it missing, which is the trigger. Also from the round: --attempts, defaulting to 3 rather than 2 because the baseline got three passes at stage 2 by hand and an arm with fewer attempts than the arm it is compared against confounds FX7; a config block in the report (repo SHA, models, workers, extract strategy) plus the per-document errors, since the baseline's write history had to be rebuilt by hand from log lines; the report checkpointed after every stage instead of once at the end; --out refused when it *resolves* into a volatile directory, the relative spelling having passed the prefix check; --out refused when non-empty unless --resume, staging being additive; and a real --execute integration test, without which an argument swapped between fixture and kb would have copied an empty KB over the fixture with every test still green. Docs: scoring.md's Size section still said "unmeasurable on both arms" and cited a deleted /tmp script; spec.md FX1 said "only the two" and named four; test-set.md's Regenerating block showed only the corpus-scoped select_cases invocation, which is the reading that produced the retracted claim. The fixture is now the last unversioned load-bearing artifact and is recorded as such. 55 tests, 99% coverage, 13 of 13 mutations caught, full suite 1817 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…he articles Two findings from re-review, both measured before accepting. A typo'd scheme cost fifteen minutes and lied about why. The exception classes do not separate a config error from an outage: gw.example/v1 raises ValueError, htp://gw.example raises URLError -- an OSError, so wait_for_endpoint read a typo as an outage, burned the whole 900 s deadline and aborted with "endpoint never came back" -- and http://gw .example raises http.client.InvalidURL, which is neither and crashed the arm mid-run. unusable_base_url now checks the shape once in main, before any hook is built, and the probe is left pure. And the report's model record was false. run_compile hardcodes all three write-path models to claude-sonnet-4-6 (compile.py:806-808) and reads LLM_MODEL only for the summarize fallback, so recording that env var published a model which wrote nothing -- inside the block whose whole purpose is FX7 self-description. The driver now sends the three models explicitly, at the same default the baseline ran, and records what it sent. Smaller, each a way to lose or misread an arm: --attempts 0 would have snapshotted every stage, called nothing and written a full-residual report at 0.00 USD, an arm that never ran looking finished; --workers 0 silently took compile's own 16. A stage blocked between attempts now snapshots what its earlier attempts wrote, Size being why snapshots exist. Errors carry an attempt index, so one document failing twice no longer serialises as two documents failing. KB_WORKERS is recorded, chunk-level extraction reading it independently of --workers. Two rules the last commit advertised were pinned by nothing: the per-stage checkpoint (its test asserted a stub calling its own callback) and the $TMPDIR refusal entry (disabled suite-wide by the fixture that makes tmp_path usable). Both now have real tests, and the tautological attempts assert reads 3 rather than the constant it was comparing against itself. scoring.md still published "one retry per stage" as this driver's policy while the default is 3 attempts -- in the one document FX7 reads its baseline from, understating the A1 arm's retry budget on the exact variable that choice was made to protect. 72 tests, 99% coverage, 18 of 18 mutations caught, full suite 1834 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e shifted The A1 arm ran attended at 14.3873 USD over 185 calls, four stages each finishing on its first attempt with an empty residual. Both FX4 article-shape defects are absent, so no case needed hand resolution and 14 of 18 chains resolve to one article against the baseline's 8. Every failure column improved and the one positive column got worse: gating Staleness 24 -> 19 of 40, drops 37 -> 29 of 41, corrections 34 -> 38 of 45, collateral 40 -> 41 of 42, Trail 7 -> 5 of 45. The reason is one behaviour. The arm consumes the ordering signal but attributes each value to its source version instead of asserting which one is dead, so its best cases read (Staleness 0, Trail 0) -- coequal presentation, the shape D1 rejects in terms. Where it stops labelling it fails in the same three places: Key Decisions sections, Action Items tables, and DDL cells copied from an older version into a table headed by a newer one. Two regressions belong to the classifier rather than the writer. P4 and P9 split by version, so 16 of the 45 contradiction rows sit in chains no single article can trail, and they carry 14 of the 19 stale gating rows. Four rulings are drafted and open (V35-V38). V36 -- how a chain the arm distributes should resolve -- moves P4 between 9 and 3 stale rows and the total between 19 and 13 of 40, so the FX7 verdict waits on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A1 does not clear the positives, so D2's condition fires and A2 moves from optional to required. The gate is test-set.md's -- path A ships first if and only if it clears the positives without tripping the negatives. A1 holds the negatives at 0 of 4 and 0 of 4 and leaves 19 of 40 contradictions stated as current. The four rulings the A1 scoring opened are all taken at their drafted positions, so no published figure moves: V35 name residue is recorded and not scored, V36 scores a distributed chain on the union with the newest-half figure reported beside it, V37 an accurate as-of stamp does not make a row stale when nothing newer is offered, V38 a tense-marked dated pair is not a Trail. Unlike the baseline's queue none closes for want of evidence, the arm's articles having survived. The verdict does not depend on any of them. The band across every drafted and alternative reading is 8-22 of 40 against the baseline's 24, so A1 is better on every reading and clean on none. Two findings carry into A2 rather than into the gate. Split by whether A1's articles saw the whole chain, staleness went 13 to 5 of 24 on P3, P7 and P10 and 11 to 14 of 16 on P4 and P9, which A1 split by version -- so 8 of the 19 stale rows are in an article that had both values in front of it and 11 exist only because a second article carries the older half of a chain. Version splitting is NG6's territory, upstream of this feature, and is now the column's largest single contributor with no owner on this branch. Second, A1's five-row advantage rests on basis-labelled coequal presentation scoring clean; strictly read, both arms land near 34-36 of 40 and it disappears. That cannot be settled -- the criterion can be applied to this arm's surviving articles and never to the baseline's -- so it is recorded as a bound, and it is why test-set.md's Scoring table should be settled before A2's arm is bought. One recorded counterfactual was wrong in four documents and is corrected: V36's alternative totals 8 of 40, not 13, which had applied the newest-half rule to P4 and not to P9 though P9 is split the same way and its v2-only article reads 0 of 6. The ruled figure never moved. The content-iteration diagram also credited the A1 arm with the baseline's Trail count; it is 5 of 45 against 7. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…clean The FX7 verdict named one thing to fix before A2's arm is bought: Staleness and Trail together certified basis-labelled coequal presentation -- the shape D1 rejects in terms -- as a clean latest-wins result, so A1's three best cases read (Staleness 0, Trail 0) and an A2 shipping a real trail would not have been distinguishable from them. V39 adds a third gating column, In force: a row fails when both its values are stated and nothing resolves which one holds. It is a new column rather than a stricter reading of Staleness, deliberately -- redefining the gating column would have replaced this branch's one measured comparison with a one-sided one, the baseline's articles being gone. So 24 against 19 of 40 stands untouched. Measured row by row on the surviving articles in ~/kaas-arms/a1, not derived from the scoring records: In force is 28 of 40 on the A1 arm, 18 inside a single article and 10 across a chain the classifier split, so the gate reads 18 and the rest sits with NG6. Presence was checked on the files -- 11,362 and 25,046 appear in comma form in P7's article, the only 7C match in it is inside 7197C, P4's nanoseconds appear in both articles with no millisecond form in either. Three consequences worth naming. P10 and P5 go from the cleanest results in the set to 7 of 7 and 5 of 5 while their Staleness stays 0. A trail no longer guarantees a pass: P3-C1 and P3-C5 each carry a correct directional statement and assert the superseded value as current elsewhere, which makes intra-article self-contradiction countable for the first time. And the strict reading this branch carried as "roughly 36 of 40" is now measured at 32 on the A1 side, with the baseline's 34 staying an estimate for good. The verdict does not move: the second gating column agrees with the first that A1 does not clear the positives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…odel An arm's write model is sent explicitly, but nothing checked that the resolved endpoint serves it. KaaS reads LLM_BASE_URL/LLM_API_KEY and falls back to OPENAI_BASE_URL/OPENAI_API_KEY, which on the laptop that ran both arms points at MiniMax -- eight MiniMax models, no Claude model. An arm launched there 400s on every call and "completes" with a full residual at 0.00 USD, which reads like a catastrophic writer failure rather than one unset variable. That cost an hour once. So main now reads the gateway's /models list before anything is written and refuses when the write model is absent, naming both what it needs and what the gateway serves. Same class as the URL-shape check, and placed after the --out refusal so a local mistake costs no round trip. The two readings of that payload are kept apart, because only one is evidence: an empty data list is a gateway saying it serves nothing and the arm refuses, while HTML, a bare string or entries without an id is a gateway that was asked something else -- that warns and runs, since a gateway not exposing /models would otherwise be unusable for an arm whose every write would have succeeded. Unlike the endpoint probe, no failure propagates: wait_for_endpoint owns outages. arm-report.json records models_verified, for the same reason it records the models. An arm that produced a residual has to be readable as a writer failure or as a gateway that was never confirmed. 16 new tests, 88 in the file, 99% coverage (the one miss is the __main__ guard), 11/11 mutations caught, full suite 1851 passed. Also verified the file opens no real socket, with socket.connect stubbed to raise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eways Review round on the pre-flight check: 3 Important + 6 Minor, every one fixed, adjudicated or recorded. The reviewer proved four surviving mutations rather than asserting gaps, and two of them were rules the commit message itself claimed. The two claimed-but-untested rules now have tests. Checking _models(_MODEL) instead of _models(args.model) passed the whole suite, so --model was checked against nothing: an override the gateway serves would have been refused, and one it does not serve would have been accepted and then 400 every write. And moving the check above the used---out refusal also passed, which mattered twice -- the ordering claim was decorative, and in that state the one --execute test that does not stub _model_catalog performed a real DNS lookup for gw.example. Both are pinned, the second by making that test fail if the gateway is asked anything. The guard's premise is now measured instead of assumed, which is this file's own standard for a claim about how a call fails. LiteLLM answers /models with 200, 30 ids, no wildcard entry and claude-sonnet-4-6 spelled exactly, so no arm can be falsely refused there. The MiniMax endpoint the OPENAI_* fallback points at answers 200 in 0.26 s with 8 ids and no Claude model at all -- so the recorded incident is refused rather than degraded to a warning, which was the one way this guard could have been decorative. http.client.HTTPException joins the cutset: InvalidURL, IncompleteRead, BadStatusLine and LineTooLong are neither OSError nor ValueError, and two are reachable through a URL unusable_base_url accepts (a nonnumeric port, and a control character in the path, which the netloc check does not inspect). The docstring claimed every failure reads as None and did not. An autouse fixture now deletes the four gateway variables for this file. There was no such isolation, and on this laptop OPENAI_BASE_URL is the MiniMax endpoint with a live key -- so the incident configuration was ambient during a bare pytest run, and suite hermeticity rested on check ordering rather than on isolation. Adjudicated, not implemented, and both recorded in main's comment: the summarize model is not checked, because compile.py:228 makes it mandatory only for a non-chunked strategy and checking it unconditionally would refuse an arm over a model no chunked run calls, while checking it conditionally restates compile.py's rule where it would drift; and a 401 on /models stays in the warn branch, because a completion-only key that cannot list models is a real configuration. Both would be answered by probing with a 1-token completion, which is noted as the cheaper fix if either premise stops holding. 93 tests, 99% coverage (the miss is the __main__ guard), 12/12 mutations caught including the four the review found surviving and the block move, full suite 1856 passed, and the file still opens no real socket with connect/create_connection/ getaddrinfo all stubbed to raise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
V39 made this caption stale and the V39 commit did not update it. The diagram's second shape -- coequal presentation, the one the A1 arm produces most -- was captioned as clearing Staleness and earning no Trail, which under the two-column rubric left it looking like an unremarkable latest-wins result. It now names the third column and what that column reads: nothing says which value holds. Rendered and checked rather than eyeballed as XML: the line is 126 characters and sits inside its box with margin on both sides at font-size 10. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…under
CI's first run of this branch failed 17 tests with `SystemExit: 2` and the reason
is a platform assumption in the autouse fixture, not in the driver. The driver
refuses an `--out` inside a volatile directory, so the suite cannot use `tmp_path`
unless the rule is narrowed for it -- and the fixture narrowed it by writing the
answer down: `("/tmp", "/private/tmp")`. On macOS that works, because `tmp_path`
lives under `$TMPDIR` (`/var/folders/...`) and dropping that one entry is enough.
On Linux `tempfile.gettempdir()` is `/tmp`, so every scratch path is still refused.
Reproduced locally before fixing, with `TMPDIR=/tmp uv run pytest` -- the same 17
failures as CI -- and the fixture now computes the entries to drop from where
`tmp_path` actually resolves, so it is correct wherever pytest puts its files.
The two tests that exercise the rule itself now install their own list instead of
inheriting the narrowed one. Without that, `/tmp` being dropped on Linux would
leave `test_the_out_directory_may_not_be_under_tmp` unable to refuse anything and
`..._merely_starts_with_the_same_letters_is_fine` passing for the wrong reason --
a green suite that had stopped testing the lesson that cost 18 USD.
Verified in both shapes: 93 passed under the macOS default and under `TMPDIR=/tmp`,
and disabling the production refusal fails 6 tests in each, so the rule is pinned
in both environments rather than only in one. Full suite 1917 passed in both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Path A increment 1 of the supersession work: carry document ordering to the writer, and report the version chains it cannot act on. The writer now receives one dated block per source instead of a flat bag of extractions, the ordering is stated to it in the system prompt, and a run reports the lineage groups a human has to read.
It also carries the measurement that decides what comes next. Two arms were run over a staged 38-document fixture — the pre-A1 code at
bd8252eand this branch — and scored against a hand-labelled set of 45 contradictions, 41 drops and 42 controls. A1 improves the gating column from 24 to 19 of 40 and clears it on no reading, so A2 is required rather than optional. The verdict isverdict-fx7.md.Nothing here can delete text. A1 adds no primitive that removes a claim — that is A2's job, and the reason this increment is safe to ship on its own.
What changed
Dates reach the writer (Go + Python).
POST /api/submitstamps a document's date only when the frontmatter does not already carry one, decided by a shared reader that both languages agree on byte for byte. The reader returns "may have a date" rather than "has a date" for a block it cannot parse, because the caller's real question is whether it may stamp the clock, and an unreadable block may hide a date PyYAML resolves.One block per source, oldest to newest (
core/merge.py).SourceBlock(source_path, extraction, date), duplicates collapsed on checksum, undated blocks last in path order. All seven write call sites moved together._combine_extractionshad no callers left and is gone.A budget priority that is not the render order. Blocks claim the budget newest-first; when they all fit, each is rendered whole. Two spec criteria were corrected against measurement here rather than left as written — BG2 said "trailing (oldest) blocks", which inverts the moment one block is undated.
The prompt states the order and withdraws what it cannot claim. A code constant appended to all three write-stage system prompts: what a
- Date:line dates, that an undated block's position carries no ordering claim, and — after ruling V20 — that two blocks sharing a day carry no claim relative to each other either. Purely factual, instructing nothing about contradictions, because FX7's arm exists to measure whether the signal alone suffices.Version chains are reported (
storage/lineage.py). Shape A (sameid, re-fetched) was already reported; shape B — v1 and v2 ingested as two documents, which noidconnects — was not reported at all, so an article holding both versions looked like an article holding one document twice.Fixture tooling, versioned and tested (
py/scripts/).select_cases.py,stage_fixture.py,audit_articles.py, andrun_fx4_arm.py, which drives a whole arm. The last one exists because its four shell predecessors were never committed and/tmpwas cleared on 2026-08-19, taking them and the baseline arm's 27 articles with them.What was measured
bd8252e)Two findings carry into A2 rather than into this PR. Version-split chains decided 11 of the 19 remaining stale rows — the classifier put v1 and v2 in different articles, so no write prompt could have retracted a value its article never received; that is upstream of this feature (NG6) and has no owner yet. And the arm shifted the failure mode rather than removing it: it attributes each value to its source version instead of asserting which one is dead, which clears the gating column while producing exactly the coequal presentation D1 rejects. That is what the third scoring column (
In force, V39) was added to make visible — before A2's arm is bought, not after.Scope
docs/features/supersession/holds the spec, the design options, the fixture description, the 45-row label set with per-row citations, both arms' scoring records and the verdict. The baseline arm's articles no longer exist, soscoring.mdis the only record of them.POST /api/submit/filesroute (still undated, which degrades to the pre-existing behaviour rather than being wrong), and the create-path prose comparison FX6 asks for.spec.mdfor the criteria, then the code, thenverdict-fx7.mdfor what the measurement decided.Verification
cd py && uv run pytest tests/ -q→ 1917 passed, 1 xfailed. One unrelated failure in this environment:test_distill.py::test_distill_end_to_end_produces_articleis a real-LLM test that skips only when no credentials are set, and it fails identically onmainhere because the ambientOPENAI_API_KEYpoints at a gateway serving nogpt-4o-mini.go test ./... -count=1→ 15 packages ok;go vet ./...clean. Three pre-existing unformatted files underinternal/api/are untouched and are unformatted onmaintoo.🤖 Generated with Claude Code