Repository navigation
Record the enforced witness clock; seed half of the clock-basis ruling (7820A) - #7820
Conversation
…k at its carrier The fast-lane witness budget is enforced on THREAD CPU, but every cost artifact in the tree recorded WALL. run_claim_measured computed cpu_nanos, spent it on the budget decision, and dropped it, so the cap was compared against a number no receipt carried and any threshold built on a cost receipt selected a different population than the cap kills. Found by still-bat-561; verified at both producers before acting. - PerformanceReceipt carries cpu_nanos beside wall_nanos, and run_claim_measured feeds the SAME binding to budget_completion_outcome and to the receipt, so the enforced and the recorded quantity cannot drift apart. Both clocks are required parameters: a defaulted cpu_nanos would record zero for the enforced quantity, which reads as "measured, and free" rather than "not measured". - InterpError names each clock at its carrier: EvalBudgetExceeded.elapsed_ms -> cpu_ms (it is thread CPU) and WitnessWallBudgetExceeded.elapsed_ms -> wall_ms. A shared "elapsed_ms" spelling let a CPU figure be read as wall at every consumer. - The EvalBudgetExceeded message no longer instructs authors to relocate the file. It told them a slow witness "lives in a long/ test dir and runs via its dedicated lane" — the exact move the 2026-08-04 admission ruling retired, and one that deletes the coverage while retaining the source. ci_floor_plan already records this message misleading a real lane. The stable "eval budget exceeded" prefix is unchanged, so falsifier_failure_mode's classification is untouched. - floor-witness-row-cost-receipt.tsv: eval_ms -> eval_wall_ms (it was always wall), and outcome/detail are emitted rather than dropped. The row tuple always carried them, and because selection-skipped rows are pushed into this receipt with zero timings, a 0 in the eval column meant "never executed" OR "ran in under a millisecond" with no way to tell — the empty-observation narrow, in an artifact whose purpose is per-row cost. The bound that keeps this honest (wise-ram-22, verified): eval is single-threaded, so cpu <= wall. A wall figure under the cap PROVES cpu under it, so existing "lands under the fast-lane budget" triggers were always decidable on the wall number. What wall cannot answer is the ranking direction — how near the cap a row sits — which is what the per-witness cost-envelope lane needs. NOT improvised here: declaration-grain rows project through std.observation ObservationEvent, which carries wall and rss but no cpu, so discovery-grain rows still record wall only. Closing that is a load-bearing std.observation change (a third measured quantity, plus a clock basis on TimedOut) and is raised rather than built. Also restores the claim_executor unit suite to executable: its test target did not compile on main (two ClaimResult initializers missing selection_degradation), so all 65 tests were unrunnable, and CI does not run nextest. Fixing compilation exposed one stale fixture — discovery() built a batch with empty scan_dirs AND empty explicit_entries and asserted it yields a discovery unit, which contradicts the documented empty-and-empty means zero-nodes rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…90-witness-cost-clock
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
…ated zero Emitting the outcome column made "never executed" and "ran in under a millisecond" DECIDABLE, but the number itself was still fabricated: a selection-skipped row wrote 0 into the timing columns for a measurement that does not exist. std.observation observation_measured_note already rules on exactly this shape, in the module this receipt's rows project through: "Absence of a measurement is a NAMED state carrying its cause, never a fabricated zero. A renderer projecting MeasuredUnavailable prints the cause; it never prints 0 and never omits the field, because a silently omitted number is the same fabrication one layer up." So the timing cells of a row that never ran render as `unmeasured` and the cause rides in outcome/detail. The cell is deliberately non-numeric: a consumer reaching for a number fails loudly instead of counting an unexecuted row as a fast one, which is the failure mode this receipt had while the cell said 0. The two cases are genuinely different facts and both are preserved: an executed witness may legitimately measure 0 ms (sub-millisecond), and those rows keep their 0. Absence is keyed on the same selection-skipped outcome spelling discovery_claim_result writes and wet_witness_row_outcome_label already dispatches on -- never inferred from the numbers, since inferring absence from a zero is the conflation being closed. Test strengthened accordingly: the two rows now differ in the cost columns THEMSELVES rather than only in the outcome column, and every absent cell is asserted to fail u128::parse. Proven RED by reverting the absence detection -- the failure prints the fabricated zero row verbatim. Found by royal-raven-604 via still-bat-561, before merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ty design notes
Operator ruling 2026-08-05 on the clock question, plus the review follow-up.
THE RULING. Recording BOTH clocks is correct and is not the defect. What a second bare
field would introduce is a duration whose meaning lives only in its field NAME. The ruled
model carries the basis on the measurement itself -- ClockBasis = CpuClock | WallClock, a
basis-carrying elapsed measurement, and a basis on TimedOut so a crossing names its cap --
under which a receipt may legitimately hold both a cpu and a wall observation because
neither relies on its name to say what it is.
So the "third measured quantity beside wall and rss" framing is REMOVED from
WITNESS_COST_CLOCK_BASIS_NOTE and from the PerformanceReceipt field docs; it contradicts
the basis model and is the exact framing ruled against. The note now states the seed
disposition plainly: these u128 fields are seed instrumentation that says which clock it is
only by name, retained because the enforced quantity had to stop being dropped before the
authority lands, with the dissolution trigger named (ClockBasis lands in std.observation and
the declaration-grain receipt projects both clocks through it).
This PR is the seed half (7820A) and lands independently of the observation authority.
DESIGN NOTE THE OPERATOR ASKED BE LANDED IN THE COST AUTHORITY:
witness_decomposition_does_not_reduce_entry_cost_note. Do not split a witness expecting
entry startup to get cheaper -- per-witness eval and per-entry resolve are different terms,
and splitting AMORTIZES one expensive resolve across more rows rather than dividing it, so
a fall in per-row eval is an artifact of the split. Measured on falsifier run 30824310833:
682 of 930 entries resolve at 1000ms or more (max 11223ms); corpus 1638s resolve vs 3987s
eval. The repeated-resolve term belongs to the shared-floor / materialization lane.
witness_row_cost_clock_basis_note records the two-clock fact and the bound on the same
carrier the columns live on.
REVIEW FOLLOW-UP (review 48405, REQUEST_CHANGES). The finding claims the header guard
asserts !contains("\teval_ms") against a header containing "\teval_wall_ms" and therefore
fails. That is not correct -- after "\teval_" comes "wall_ms", so "\teval_ms" does not occur,
and the test passes (verified by execution both ways). But the suggestion is right on the
merits: a substring test answers a question about column NAMES with a question about
characters, and the two coincide only by accident, which is exactly why it could be misread.
The guard now splits on tabs and compares at column grain, and its failure prints the parsed
columns. Proven RED by reverting the column name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed in The claim: Checked by execution, both ways: After That said, the suggestion is right on the merits and I've taken it. A substring test answers a question about column names with a question about characters, and the two coincide only by accident here — which is precisely why it was misreadable. The guard now splits on tabs and compares at column grain: let header: Vec<&str> = body.lines().next().expect("header").split('\t').collect();
assert!(header.contains(&"eval_wall_ms"), ...);
assert!(!header.contains(&"eval_ms"), ...);Proven RED by reverting the column name to Same commit also carries the operator's clock-basis ruling: the "third measured quantity beside wall and rss" framing is removed (it contradicts the ruled basis model), the seed disposition and dissolution trigger are stated, and the two design notes the operator asked be landed in the cost authority are in |
…before comparing Follow-up from review 48447, which flagged that the drift comparator still floored selection-skipped rows to observed_eval_ms=0. Verified, and it is worse than a cosmetic mismatch with the sibling receipt: with a basis present, a skipped row compared as 0 <= basis and reported WithinBasis -- a POSITIVE verdict that the row met its cost basis, derived from a measurement that does not exist, and one that could never fail because 0 never exceeds anything. The drift wire silently passed unexecuted rows. That is the fabricated zero of the previous commit promoted into a verdict, so it gets the same treatment one layer up. The observed column renders unmeasured, the verdict is ObservationAbsent, and the row is counted into a new observation_absent tally reported on both the summary and the receipt line -- typed, located, counted, never absorbed. ObservationAbsent is deliberately the mirror of the BasisAbsent arm this writer already had: there a measurement exists with no basis to judge it, here a basis exists with no measurement to judge. Neither is a comparison and neither is now reported as one. MECHANISM: the fail-open was not a bad comparison, it was comparing AT ALL, so the fix decides comparability BEFORE any comparison runs. drift_row_disposition returns ObservationAbsent | BasisAbsent | Comparable, with observation-absence outranking basis-presence -- precisely the case that was broken. Extracting it also makes the property testable without resolving the .dag authority the writer needs, so the test is a fast pure check rather than a filesystem fixture. Discriminating test asserts the sharp case -- a skipped row WITH a basis present must still refuse -- plus that the two meaningful states stay reachable, so this is not a blanket refusal. An executed row that genuinely measured 0 ms remains comparable, which is the distinction the whole change rests on. Proven RED by disabling the absence arm. Also replaces the previous filesystem-fixture version of this test, which the dashboard's mid-edit auto-commit pushed unformatted and which redded the fmt gate on 450690c. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…90-witness-cost-clock
The operator's 2026-08-05 ruling: recording both clocks is correct; the defect is a duration whose meaning lives only in its field NAME. This is the observation-authority half of that ruling (7820A landed the seed half in #7820). std.observation gains ClockBasis = CpuClock | WallClock and TimedMeasurement { basis, elapsed }, and two carriers stop naming their clock in prose: ObservationOutcome.TimedOut now carries `basis`, so a kill says WHICH cap it crossed — a 5000ms thread-CPU fail-stop and a 600000ms wall receipt ceiling were previously indistinguishable, and the CI line now renders the clock beside both figures. ObservationEvent.wall becomes `durations: List<TimedMeasurement>`. A list rather than one tagged duration because the seed already holds both clocks for every occurrence (run_claim_measured), and because the operator ruled thread CPU is the REMEDY DISCRIMINATOR beside a wall threshold: high wall + high CPU is algorithm or repeated evaluation, high wall + low CPU is waiting, I/O or scheduling. One clock cannot make that call. A record with `cpu` and `wall` fields would have been the nickname twice, which is what the operator refused when 7820A's first draft proposed cpu as a third measured quantity beside wall and rss. The payoff is a construction wall, not a rename: witness_row_cost_verdict now takes the observed clock, WitnessRowCostDatedBasis carries its own, and a cross-clock comparison answers BasisClockMismatch — a fourth arm, not a Bool collapse, on the same reasoning std.content_hash refuses cross-family comparison. Comparing a CPU figure against a wall baseline used to typecheck and answer confidently; four sessions spent an evening doing exactly that. Not walled, and said so on the carrier: two entries may share one basis. The construction that would forbid it is a total function from a closed sum, which this substrate lacks (Map is a closure, not wire-serializable, and refused by the determinism gate). So observation_duration_of REFUSES an ambiguous read with the duplicate as its cause rather than silently picking the first — rung mechanically preventable, ceiling structurally impossible, trigger named. Green by execution with discriminating REDs, all run locally: witness_row_cost_projection_holds PASS; RED when the basis filter is removed from observation_clock_lookup (the silent first-match pick) witness_row_cost_drift_comparator_holds PASS incl. two new cross-clock controls on BOTH sides of the 2x ratio, so the refusal is proven to be decided by the clock and not by the magnitude; RED when the comparator stops checking it floor_component_receipt (15), observation_model (36), ci_render (19), tty_render (16), seed_scoped_run (10), crawl_replay (3) all PASS ClockBasis is exported vocabulary: gunbc#7831 states WallClock in its own policy carrier and rebases onto this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last piece of the 2026-08-05 clock-basis ruling with a real consumer gap. #7820 renamed eval_ms to eval_wall_ms and #7837 made the row carry both clocks; nothing yet printed the second one, so the remedy that second clock exists to discriminate could not be read from the artifact at all. The seven-wide anonymous tuple becomes WitnessRowCost. That is not tidying: a positional tuple is how `eval` came to mean "wall" by index and nothing else — the same defect one layer below the ObservationEvent.wall field name this lane retired — and it is exactly what would have made a second clock "the third u128". eval_cpu_ms sits immediately beside eval_wall_ms, asserted by the test rather than left to convention, so an author reads the remedy from one file without joining another: high wall with high CPU is algorithm or repeated evaluation, high wall with low CPU is waiting, I/O, subprocess or scheduling. It is not a second threshold — the witness threshold is stated on wall. An unsampled clock renders `unmeasured`, never 0. A `0` there would claim the witness used no CPU at all, which reads as the strongest possible remedy signal — pure waiting — about a row for which nothing was measured. That is the fabricated zero the outcome column already closed, one column over. Green by execution, with the discrimination proven rather than assumed: witness_row_cost_receipt_distinguishes_unexecuted_from_sub_millisecond gains a wall-only fixture, and goes RED when the renderer is changed to `unwrap_or(0)` — failing on the exact fabricated cell: cpu_clock_not_sampled 4 0 0 0 Done It also asserts the two clocks are independent carriers (500us wall against 300us cpu, so a producer filling both from one figure would be caught) and that the two columns are adjacent in the header. cargo test --bin claim_executor 68 passed, 0 failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * Retire the wall nickname: durations carry their clock (7820B) The operator's 2026-08-05 ruling: recording both clocks is correct; the defect is a duration whose meaning lives only in its field NAME. This is the observation-authority half of that ruling (7820A landed the seed half in #7820). std.observation gains ClockBasis = CpuClock | WallClock and TimedMeasurement { basis, elapsed }, and two carriers stop naming their clock in prose: ObservationOutcome.TimedOut now carries `basis`, so a kill says WHICH cap it crossed — a 5000ms thread-CPU fail-stop and a 600000ms wall receipt ceiling were previously indistinguishable, and the CI line now renders the clock beside both figures. ObservationEvent.wall becomes `durations: List<TimedMeasurement>`. A list rather than one tagged duration because the seed already holds both clocks for every occurrence (run_claim_measured), and because the operator ruled thread CPU is the REMEDY DISCRIMINATOR beside a wall threshold: high wall + high CPU is algorithm or repeated evaluation, high wall + low CPU is waiting, I/O or scheduling. One clock cannot make that call. A record with `cpu` and `wall` fields would have been the nickname twice, which is what the operator refused when 7820A's first draft proposed cpu as a third measured quantity beside wall and rss. The payoff is a construction wall, not a rename: witness_row_cost_verdict now takes the observed clock, WitnessRowCostDatedBasis carries its own, and a cross-clock comparison answers BasisClockMismatch — a fourth arm, not a Bool collapse, on the same reasoning std.content_hash refuses cross-family comparison. Comparing a CPU figure against a wall baseline used to typecheck and answer confidently; four sessions spent an evening doing exactly that. Not walled, and said so on the carrier: two entries may share one basis. The construction that would forbid it is a total function from a closed sum, which this substrate lacks (Map is a closure, not wire-serializable, and refused by the determinism gate). So observation_duration_of REFUSES an ambiguous read with the duplicate as its cause rather than silently picking the first — rung mechanically preventable, ceiling structurally impossible, trigger named. Green by execution with discriminating REDs, all run locally: witness_row_cost_projection_holds PASS; RED when the basis filter is removed from observation_clock_lookup (the silent first-match pick) witness_row_cost_drift_comparator_holds PASS incl. two new cross-clock controls on BOTH sides of the 2x ratio, so the refusal is proven to be decided by the clock and not by the magnitude; RED when the comparator stops checking it floor_component_receipt (15), observation_model (36), ci_render (19), tty_render (16), seed_scoped_run (10), crawl_replay (3) all PASS ClockBasis is exported vocabulary: gunbc#7831 states WallClock in its own policy carrier and rebases onto this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * State where the clock wall runs and where it does not The .dag verdict authority now refuses a cross-clock comparison, but the production falsifier receipt does not reach it: the seed calls only witness_row_cost_exceeds_basis and rebuilds the verdict arms in Rust, so the clock never crosses that seam. That comparison is still correct today — both sides are wall — but for a reason about the current producers rather than about the mechanism, which is exactly the state this ruling exists to end. Said on the carrier with its next trigger, so the rung is not inflated to cover a path the wall does not stand on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: Witness cost/purpose/admission: retire long/ as authority * Fix the seed decode path for the tagged eval durations The row's eval term became List<TimedMeasurement>, and the seed's extractor still called nanosecond_count on it — so production project_witness_cost_receipt refused with "cannot access field 'count' on List" while every .dag witness stayed green, because none of them cross that Rust seam. Found two ways, independently: by running the existing production_witness_cost_projection_* Rust tests (2 of 3 failed), and by review 48651, which prescribed the same remedy. Worth naming why CI would not have: nextest was removed from CI in 2026-07-11, so those tests run locally only, and the witness corpus proves the .dag projection rather than the transport that reads it. The fix reads ONE clock through the authored projection rather than walking the list in Rust: witness_cost_clock_nanos calls std.observation.observation_duration_of, the same accessor every .dag consumer uses, so the seed cannot grow a second copy of the lookup or of its ambiguity refusal. Which clock it wants is now a thing it has to say, and it says wall — the clock the witness threshold is stated on. An unsampled clock comes back None, never 0, matching the unmeasured-cell discipline the sibling receipt already keeps. Wall coming back None refuses: the authored projection already guarantees a wall figure, so its absence here means the row reached the transport without the one measurement the receipt exists to carry. production_witness_cost_projection_preserves_exact_nanoseconds_and_ordering ok production_witness_cost_projection_preserves_failed_and_refused ok production_witness_cost_projection_refuses_missing_and_duplicate_parent ok Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…econstruction (#7844) * WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * Retire the wall nickname: durations carry their clock (7820B) The operator's 2026-08-05 ruling: recording both clocks is correct; the defect is a duration whose meaning lives only in its field NAME. This is the observation-authority half of that ruling (7820A landed the seed half in #7820). std.observation gains ClockBasis = CpuClock | WallClock and TimedMeasurement { basis, elapsed }, and two carriers stop naming their clock in prose: ObservationOutcome.TimedOut now carries `basis`, so a kill says WHICH cap it crossed — a 5000ms thread-CPU fail-stop and a 600000ms wall receipt ceiling were previously indistinguishable, and the CI line now renders the clock beside both figures. ObservationEvent.wall becomes `durations: List<TimedMeasurement>`. A list rather than one tagged duration because the seed already holds both clocks for every occurrence (run_claim_measured), and because the operator ruled thread CPU is the REMEDY DISCRIMINATOR beside a wall threshold: high wall + high CPU is algorithm or repeated evaluation, high wall + low CPU is waiting, I/O or scheduling. One clock cannot make that call. A record with `cpu` and `wall` fields would have been the nickname twice, which is what the operator refused when 7820A's first draft proposed cpu as a third measured quantity beside wall and rss. The payoff is a construction wall, not a rename: witness_row_cost_verdict now takes the observed clock, WitnessRowCostDatedBasis carries its own, and a cross-clock comparison answers BasisClockMismatch — a fourth arm, not a Bool collapse, on the same reasoning std.content_hash refuses cross-family comparison. Comparing a CPU figure against a wall baseline used to typecheck and answer confidently; four sessions spent an evening doing exactly that. Not walled, and said so on the carrier: two entries may share one basis. The construction that would forbid it is a total function from a closed sum, which this substrate lacks (Map is a closure, not wire-serializable, and refused by the determinism gate). So observation_duration_of REFUSES an ambiguous read with the duplicate as its cause rather than silently picking the first — rung mechanically preventable, ceiling structurally impossible, trigger named. Green by execution with discriminating REDs, all run locally: witness_row_cost_projection_holds PASS; RED when the basis filter is removed from observation_clock_lookup (the silent first-match pick) witness_row_cost_drift_comparator_holds PASS incl. two new cross-clock controls on BOTH sides of the 2x ratio, so the refusal is proven to be decided by the clock and not by the magnitude; RED when the comparator stops checking it floor_component_receipt (15), observation_model (36), ci_render (19), tty_render (16), seed_scoped_run (10), crawl_replay (3) all PASS ClockBasis is exported vocabulary: gunbc#7831 states WallClock in its own policy carrier and rebases onto this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * State where the clock wall runs and where it does not The .dag verdict authority now refuses a cross-clock comparison, but the production falsifier receipt does not reach it: the seed calls only witness_row_cost_exceeds_basis and rebuilds the verdict arms in Rust, so the clock never crosses that seam. That comparison is still correct today — both sides are wall — but for a reason about the current producers rather than about the mechanism, which is exactly the state this ruling exists to end. Said on the carrier with its next trigger, so the rung is not inflated to cover a path the wall does not stand on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: Witness cost/purpose/admission: retire long/ as authority * Fix the seed decode path for the tagged eval durations The row's eval term became List<TimedMeasurement>, and the seed's extractor still called nanosecond_count on it — so production project_witness_cost_receipt refused with "cannot access field 'count' on List" while every .dag witness stayed green, because none of them cross that Rust seam. Found two ways, independently: by running the existing production_witness_cost_projection_* Rust tests (2 of 3 failed), and by review 48651, which prescribed the same remedy. Worth naming why CI would not have: nextest was removed from CI in 2026-07-11, so those tests run locally only, and the witness corpus proves the .dag projection rather than the transport that reads it. The fix reads ONE clock through the authored projection rather than walking the list in Rust: witness_cost_clock_nanos calls std.observation.observation_duration_of, the same accessor every .dag consumer uses, so the seed cannot grow a second copy of the lookup or of its ambiguity refusal. Which clock it wants is now a thing it has to say, and it says wall — the clock the witness threshold is stated on. An unsampled clock comes back None, never 0, matching the unmeasured-cell discipline the sibling receipt already keeps. Wall coming back None refuses: the authored projection already guarantees a wall figure, so its absence here means the row reached the transport without the one measurement the receipt exists to carry. production_witness_cost_projection_preserves_exact_nanoseconds_and_ordering ok production_witness_cost_projection_preserves_failed_and_refused ok production_witness_cost_projection_refuses_missing_and_duplicate_parent ok Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Put the drift comparator on the clock wall, and delete the Rust arm reconstruction The follow-up gunbc#7837's witness_row_cost_clock_mismatch_note declared, now dissolved in place rather than left as a note. That PR grew a cross-clock refusal on the .dag comparator, and the production falsifier cadence could not reach it: the seed called only witness_row_cost_exceeds_basis, the bare ratio predicate, and rebuilt DriftExceeded / WithinBasis / BasisAbsent as Rust string literals. Two defects in one shape — a second representation of WitnessRowCostVerdict, and a seam the clock never crossed, so a CPU figure against a wall basis would still have answered confidently. It was correct only because both sides happened to be wall, which is a fact about the producers and not a property of the mechanism. Three parts, and the third is the load-bearing one: Both basis files carry a REQUIRED per-row clock cell. An unstated clock refuses at parse and an unmodelled one refuses too — never a default to wall, which would be right for every row today and silently wrong the first time someone seeds from a CPU receipt. The 1176 existing rows are stamped wall because that is what they ARE: before the ruling the seed's PerformanceReceipt held only wall_nanos. The seed calls witness_row_cost_seed_verdict_dated / _undated and renders the arm the AUTHORITY named. It constructs no carrier — the Optional stays inside .dag and whether a dated basis exists is the map lookup the seed already had, which is data presence, not judgement. The Rust arm reconstruction is DELETED, not kept beside the carrier. An arm added to WitnessRowCostVerdict now reaches the cadence receipt with no Rust edit, and BasisClockMismatch is counted on its own line because its remedy differs from BasisAbsent's: fix the producer handing over the wrong clock, versus seed the missing row. Both comparators move together — the compile-clean cost drift shares this parser and authority by design, so leaving it on the old predicate would have forked what it was built to share. Green by execution, with the discrimination named: drift_verdicts_come_from_the_authority_and_a_cross_clock_basis_refuses asserts the cross-clock refusal on BOTH sides of the 2x ratio (21ms and 20ms against a 10ms basis), so it is proven decided by the clock and not by the magnitude. This is the ONLY test that crosses this Rust seam — the .dag witnesses cannot reach it and the parser tests only show the cell is read. parse_witness_row_cost_basis_line_requires_srv_fleet_arm64 gains a cpu-clock positive, a missing-clock refusal, and an unknown-clock refusal. committed_witness_row_cost_basis_loads_and_excludes_the_censored_row ok over all 1176 migrated rows. ObservationAbsent stays decided seed-side, deliberately: an absent observation has no counterpart in the sum, and giving it one would let a row with no measurement reach a comparator at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Count clock_mismatch on the compile-clean receipt line too review 48672, correctly: the sibling witness-row-cost path reports clock_mismatch on its [receipt] summary and the compile-clean path did not, so the two receipts disagreed about whether the state this change exists to expose is worth surfacing. The summary line is where a reader looks to see whether a state fired. A degradation that is counted internally but omitted from the line someone actually reads is the counting half-done: its frequency is observable in principle and invisible in practice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Merge main (#7837 squash-merged) into the drift lane One conflict, in witness_row_cost_clock_mismatch_note, and it is the note this PR exists to rewrite: main carries #7837's version declaring the production drift path as not-yet-covered with its trigger named, and this branch carries the version saying the wall now runs there. Resolved to ours, because this PR is what makes that true — the seed calls the authored verdict and the Rust arm reconstruction is gone. Green by execution on the resolved tree: witness_row_cost_projection_holds and witness_row_cost_drift_comparator_holds both PASS, cargo check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * WIP: Witness cost/purpose/admission: retire long/ as authority * Retire the wall nickname: durations carry their clock (7820B) The operator's 2026-08-05 ruling: recording both clocks is correct; the defect is a duration whose meaning lives only in its field NAME. This is the observation-authority half of that ruling (7820A landed the seed half in #7820). std.observation gains ClockBasis = CpuClock | WallClock and TimedMeasurement { basis, elapsed }, and two carriers stop naming their clock in prose: ObservationOutcome.TimedOut now carries `basis`, so a kill says WHICH cap it crossed — a 5000ms thread-CPU fail-stop and a 600000ms wall receipt ceiling were previously indistinguishable, and the CI line now renders the clock beside both figures. ObservationEvent.wall becomes `durations: List<TimedMeasurement>`. A list rather than one tagged duration because the seed already holds both clocks for every occurrence (run_claim_measured), and because the operator ruled thread CPU is the REMEDY DISCRIMINATOR beside a wall threshold: high wall + high CPU is algorithm or repeated evaluation, high wall + low CPU is waiting, I/O or scheduling. One clock cannot make that call. A record with `cpu` and `wall` fields would have been the nickname twice, which is what the operator refused when 7820A's first draft proposed cpu as a third measured quantity beside wall and rss. The payoff is a construction wall, not a rename: witness_row_cost_verdict now takes the observed clock, WitnessRowCostDatedBasis carries its own, and a cross-clock comparison answers BasisClockMismatch — a fourth arm, not a Bool collapse, on the same reasoning std.content_hash refuses cross-family comparison. Comparing a CPU figure against a wall baseline used to typecheck and answer confidently; four sessions spent an evening doing exactly that. Not walled, and said so on the carrier: two entries may share one basis. The construction that would forbid it is a total function from a closed sum, which this substrate lacks (Map is a closure, not wire-serializable, and refused by the determinism gate). So observation_duration_of REFUSES an ambiguous read with the duplicate as its cause rather than silently picking the first — rung mechanically preventable, ceiling structurally impossible, trigger named. Green by execution with discriminating REDs, all run locally: witness_row_cost_projection_holds PASS; RED when the basis filter is removed from observation_clock_lookup (the silent first-match pick) witness_row_cost_drift_comparator_holds PASS incl. two new cross-clock controls on BOTH sides of the 2x ratio, so the refusal is proven to be decided by the clock and not by the magnitude; RED when the comparator stops checking it floor_component_receipt (15), observation_model (36), ci_render (19), tty_render (16), seed_scoped_run (10), crawl_replay (3) all PASS ClockBasis is exported vocabulary: gunbc#7831 states WallClock in its own policy carrier and rebases onto this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * State where the clock wall runs and where it does not The .dag verdict authority now refuses a cross-clock comparison, but the production falsifier receipt does not reach it: the seed calls only witness_row_cost_exceeds_basis and rebuilds the verdict arms in Rust, so the clock never crosses that seam. That comparison is still correct today — both sides are wall — but for a reason about the current producers rather than about the mechanism, which is exactly the state this ruling exists to end. Said on the carrier with its next trigger, so the rung is not inflated to cover a path the wall does not stand on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: Witness cost/purpose/admission: retire long/ as authority * Fix the seed decode path for the tagged eval durations The row's eval term became List<TimedMeasurement>, and the seed's extractor still called nanosecond_count on it — so production project_witness_cost_receipt refused with "cannot access field 'count' on List" while every .dag witness stayed green, because none of them cross that Rust seam. Found two ways, independently: by running the existing production_witness_cost_projection_* Rust tests (2 of 3 failed), and by review 48651, which prescribed the same remedy. Worth naming why CI would not have: nextest was removed from CI in 2026-07-11, so those tests run locally only, and the witness corpus proves the .dag projection rather than the transport that reads it. The fix reads ONE clock through the authored projection rather than walking the list in Rust: witness_cost_clock_nanos calls std.observation.observation_duration_of, the same accessor every .dag consumer uses, so the seed cannot grow a second copy of the lookup or of its ambiguity refusal. Which clock it wants is now a thing it has to say, and it says wall — the clock the witness threshold is stated on. An unsampled clock comes back None, never 0, matching the unmeasured-cell discipline the sibling receipt already keeps. Wall coming back None refuses: the authored projection already guarantees a wall figure, so its absence here means the row reached the transport without the one measurement the receipt exists to carry. production_witness_cost_projection_preserves_exact_nanoseconds_and_ordering ok production_witness_cost_projection_preserves_failed_and_refused ok production_witness_cost_projection_refuses_missing_and_duplicate_parent ok Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Put the drift comparator on the clock wall, and delete the Rust arm reconstruction The follow-up gunbc#7837's witness_row_cost_clock_mismatch_note declared, now dissolved in place rather than left as a note. That PR grew a cross-clock refusal on the .dag comparator, and the production falsifier cadence could not reach it: the seed called only witness_row_cost_exceeds_basis, the bare ratio predicate, and rebuilt DriftExceeded / WithinBasis / BasisAbsent as Rust string literals. Two defects in one shape — a second representation of WitnessRowCostVerdict, and a seam the clock never crossed, so a CPU figure against a wall basis would still have answered confidently. It was correct only because both sides happened to be wall, which is a fact about the producers and not a property of the mechanism. Three parts, and the third is the load-bearing one: Both basis files carry a REQUIRED per-row clock cell. An unstated clock refuses at parse and an unmodelled one refuses too — never a default to wall, which would be right for every row today and silently wrong the first time someone seeds from a CPU receipt. The 1176 existing rows are stamped wall because that is what they ARE: before the ruling the seed's PerformanceReceipt held only wall_nanos. The seed calls witness_row_cost_seed_verdict_dated / _undated and renders the arm the AUTHORITY named. It constructs no carrier — the Optional stays inside .dag and whether a dated basis exists is the map lookup the seed already had, which is data presence, not judgement. The Rust arm reconstruction is DELETED, not kept beside the carrier. An arm added to WitnessRowCostVerdict now reaches the cadence receipt with no Rust edit, and BasisClockMismatch is counted on its own line because its remedy differs from BasisAbsent's: fix the producer handing over the wrong clock, versus seed the missing row. Both comparators move together — the compile-clean cost drift shares this parser and authority by design, so leaving it on the old predicate would have forked what it was built to share. Green by execution, with the discrimination named: drift_verdicts_come_from_the_authority_and_a_cross_clock_basis_refuses asserts the cross-clock refusal on BOTH sides of the 2x ratio (21ms and 20ms against a 10ms basis), so it is proven decided by the clock and not by the magnitude. This is the ONLY test that crosses this Rust seam — the .dag witnesses cannot reach it and the parser tests only show the cell is read. parse_witness_row_cost_basis_line_requires_srv_fleet_arm64 gains a cpu-clock positive, a missing-clock refusal, and an unknown-clock refusal. committed_witness_row_cost_basis_loads_and_excludes_the_censored_row ok over all 1176 migrated rows. ObservationAbsent stays decided seed-side, deliberately: an absent observation has no counterpart in the sum, and giving it one would let a row with no measurement reach a comparator at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Count clock_mismatch on the compile-clean receipt line too review 48672, correctly: the sibling witness-row-cost path reports clock_mismatch on its [receipt] summary and the compile-clean path did not, so the two receipts disagreed about whether the state this change exists to expose is worth surfacing. The summary line is where a reader looks to see whether a state fired. A degradation that is counted internally but omitted from the line someone actually reads is the counting half-done: its frequency is observable in principle and invisible in practice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Give the row-cost receipt its CPU column, beside the wall one The last piece of the 2026-08-05 clock-basis ruling with a real consumer gap. #7820 renamed eval_ms to eval_wall_ms and #7837 made the row carry both clocks; nothing yet printed the second one, so the remedy that second clock exists to discriminate could not be read from the artifact at all. The seven-wide anonymous tuple becomes WitnessRowCost. That is not tidying: a positional tuple is how `eval` came to mean "wall" by index and nothing else — the same defect one layer below the ObservationEvent.wall field name this lane retired — and it is exactly what would have made a second clock "the third u128". eval_cpu_ms sits immediately beside eval_wall_ms, asserted by the test rather than left to convention, so an author reads the remedy from one file without joining another: high wall with high CPU is algorithm or repeated evaluation, high wall with low CPU is waiting, I/O, subprocess or scheduling. It is not a second threshold — the witness threshold is stated on wall. An unsampled clock renders `unmeasured`, never 0. A `0` there would claim the witness used no CPU at all, which reads as the strongest possible remedy signal — pure waiting — about a row for which nothing was measured. That is the fabricated zero the outcome column already closed, one column over. Green by execution, with the discrimination proven rather than assumed: witness_row_cost_receipt_distinguishes_unexecuted_from_sub_millisecond gains a wall-only fixture, and goes RED when the renderer is changed to `unwrap_or(0)` — failing on the exact fabricated cell: cpu_clock_not_sampled 4 0 0 0 Done It also asserts the two clocks are independent carriers (500us wall against 300us cpu, so a producer filling both from one figure would be caught) and that the two columns are adjacent in the header. cargo test --bin claim_executor 68 passed, 0 failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Merge main (#7844 squash-merged) into the cpu-column lane Three conflicts, all one shape: main's claim_executor.rs reads the row positionally (row.0 / row.1 / row.2) because #7844 landed without cli_run.rs, where this branch defines the named WitnessRowCost. Resolved to ours at all three, which is the only consistent resolution -- our cli_run.rs is what declares the struct those field names read. Verified: zero conflict markers tree-wide; cargo check --workspace --all-targets clean. --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The fast-lane witness budget is enforced on thread CPU, but every cost artifact in the tree recorded wall.
run_claim_measuredcomputedcpu_nanos, spent it on the budget decision, and dropped it — so the cap was compared against a number no receipt carried, and any threshold built on a cost receipt selects a different population than the cap kills.Found by still-bat-561. I verified all three claims at source before building:
cpu_nanoscomputed and dropped,PerformanceReceiptcarrying no CPU field, and the TSV'seval_mstracing back through the.dagprojection toperformance_receipts[index].wall_nanos.What landed
The enforced quantity is now recorded.
PerformanceReceiptcarriescpu_nanosbesidewall_nanos, andrun_claim_measuredfeeds the same binding tobudget_completion_outcomeand to the receipt, so enforced and recorded cannot drift apart. Both clocks are required parameters — a defaultedcpu_nanoswould silently record zero for the enforced quantity, which reads as "measured, and free" rather than "not measured".Each clock is named at its carrier.
EvalBudgetExceeded.elapsed_ms→cpu_ms(it is thread CPU);WitnessWallBudgetExceeded.elapsed_ms→wall_ms. One sharedelapsed_msspelling let a CPU figure be read as wall at every downstream consumer.The refusal message no longer recommends the retired move. It told authors a slow witness "lives in a
long/test dir and runs via its dedicated lane" — the exact relocation the 2026-08-04 admission ruling retired, which deletes the coverage while retaining the source.ci_floor_planalready records this message misleading a real lane (seven rows killed at 5001–5013ms "by a refusal whose own text says the row lives in a long/ test dir"). The stableeval budget exceededprefix is unchanged, sofalsifier_failure_mode's classification is untouched.floor-witness-row-cost-receipt.tsvcan now say what it means. Worth naming precisely: the.dagmodel was never wrong here —WitnessCostReceiptRowalready carriesoutcome, and the projection witness already matches on it. Only the seed writer discarded the field. So this is the model/realization fork DESIGN names as a recurring mode, not a modeling gap: the fix realigns the realization with a model that already said the right thing.eval_ms→eval_wall_ms(it was always wall), andoutcome/detailare emitted rather than dropped. The row tuple always carried them. Becausediscovery_claim_resultpushes selection-skipped rows into this same receipt with zero timings, a0in the eval column meant "never executed" or "ran in under a millisecond" with no way to tell — the empty-observation narrow, in an artifact whose entire purpose is per-row cost. A census taken from a selection-applied per-PR run would have counted skipped rows as fast ones.And the number itself is no longer fabricated. Emitting
outcomemade the two cases decidable, but a selection-skipped row still wrote0into all three timing cells for a measurement that does not exist.std.observation'sobservation_measured_noterules on exactly this shape, in the module these rows project through: "Absence of a measurement is a NAMED state carrying its cause, never a fabricated zero... A renderer projecting MeasuredUnavailable prints the cause; it never prints 0 and never omits the field." So an absent measurement renders asunmeasured, deliberately non-numeric, and the cause rides inoutcome/detail. Both facts survive: an executed witness may legitimately measure 0 ms, and those rows keep their0. Absence is keyed on theselection-skippedoutcome spelling the seed already dispatches on — never inferred from the numbers, since inferring absence from a zero is the conflation being closed. Caught by royal-raven-604 via still-bat-561 before merge.The bound that keeps this honest
From wise-ram-22, verified: eval is single-threaded, so cpu ≤ wall. A wall figure under the cap proves cpu under it — so existing "lands under the fast-lane budget" dissolve triggers were always decidable on the wall number and are not blocked on this. What wall cannot answer is the other direction: how near the cap a row sits, or whether an over-cap wall figure reflects CPU at all. That ranking direction is exactly what the per-witness cost-envelope lane needs.
The clock question is now DECIDED — this PR is the seed half
Operator ruling, 2026-08-05. Recording both clocks is correct and is not the defect. What a second bare field would introduce is a duration whose meaning lives only in its field name. The ruled model carries the basis on the measurement itself:
Under that model a receipt may legitimately hold both a cpu and a wall observation, because neither is relying on its name to say what it is.
Consequence applied here: the earlier "add cpu as a third measured quantity beside wall and rss" framing was the exact thing ruled against, and it has been removed from
WITNESS_COST_CLOCK_BASIS_NOTEand from thePerformanceReceiptfield docs. (It was also already refuted on the merits:wallisMeasured<Nanosecond>andrssisMeasured<ByteSize>— two magnitudes, not two clocks on one magnitude.)The work splits, and this is 7820A — seed instrumentation, landing independently:
unmeasuredfor absent measurements · claim_executor test-target repair · seed disposition + dissolution triggerClockBasis· basis-carrying elapsed measurement · basis onTimedOut· migrate the affected.dagconstruction sites · row-cost consumer projects cpu and wall without confusing themThe seed fields here say which clock they are only by name — that is the provisional part, and it is stated as such rather than presented as the end state.
WITNESS_COST_CLOCK_BASIS_NOTEcarries the disposition and the dissolution trigger: whenClockBasislands in thestd.observationauthority and the declaration-grain receipt projects both clocks through it, these two bare fields are replaced by basis-carrying measurements and the note is deleted with them.Design notes landed in the cost authority
Two notes on
dag/gunbc/witness_row_cost.dag, at operator request:witness_decomposition_does_not_reduce_entry_cost_note— do not split a witness expecting entry startup to get cheaper. Per-witness eval and per-entry resolve are different terms; splitting amortizes one expensive resolve across more rows rather than dividing it, so a fall in per-row eval is an artifact of the split itself. Measured on falsifier run30824310833: 682 of 930 entries resolve at ≥1000ms (max 11223ms); corpus totals 1638s resolve against 3987s eval. The repeated-resolve term belongs to the shared-floor / materialization lane, not to witness decomposition. Witness decomposition is justified by what a witness proves, never by a startup saving it cannot deliver.witness_row_cost_clock_basis_note— the two-clock fact, thecpu ≤ wallbound and its one-directional consequence, and the fact that a row at or past the cap is a censored measurement rather than a cost (its value is where the kill landed; the true figure is unbounded above).Evidence
performance_receipt_carries_the_enforced_cpu_clock_beside_wall— asserts the two clocks are carried independently (a receipt aliasing one value under both names would pass a weaker test), and that the same occurrence passes on CPU while crossing on wall, so the bases genuinely disagree.witness_row_cost_receipt_distinguishes_unexecuted_from_sub_millisecond— the fixture's executed row (500,000ns) and never-run row (0ns) collide on every cost column, asserted as a premise, and are separated only byoutcome.ran_in_under_a_millisecond → 0 0 0.Also: the claim_executor unit suite was not running at all
Its test target did not compile on main — two
ClaimResultinitializers missingselection_degradation— so all 65 tests were unrunnable, and CI does not run nextest. Verified against a cleanorigin/mainworktree rather than assumed.Fixing compilation exposed one stale fixture:
discovery()built a batch with emptyscan_dirsand emptyexplicit_entriesand asserted it yields a discovery unit, which contradicts the documented "empty entries AND empty discovery dirs = zero witness-corpus nodes" rule. Production was correct; the fixture had been frozen since the target stopped compiling. Suite is now 66/66 (65 restored, plus the new drift-comparator control), verified by execution on the post-merge tree.Open question, raised not answered: whether an executable does-the-test-target-compile check belongs on the floor. That is a much cheaper question than putting the whole suite back in CI (nextest was removed 2026-07-11 by operator ruling, and I am not proposing to reverse that) — it would catch this exact rot, where the failure mode is not a test passing wrongly but a test that was never a consumer at all. The floor is load-bearing and under the five-minute-gate program, so this is flagged for the operator rather than added here.