COSI_RUBY_PKG_COST_BLESS is outside the bless contract, no test blesses through an env switch and inspects the bytes, and bless_registry's own doc and floor have drifted below their population #177

Closed
opened 2026-09-06 02:40:58 +02:00 by buildagent · 3 comments
Member

Found during the #45.6 audit ("Bless requires reason, generation identities and proof that controls executed"). All three are fixed in gate: #45.6 — one bless verdict, six refusals, and the vacuity that hid a straggler, each with its own run mutation. Filed as a record and because the audit half is still open — see the last section.

Filed as one issue, and here is why. Defects 1 and 2 share a root — the bless wrote before the run was validated — and compose into a single worst case. Defect 3 is a genuinely different root (a refusal computed and never consulted). I chose one issue anyway because all three were found in one audit of one function, all three were closed by one change, and splitting a closed finding into two records helps no reader. The distinction is stated here rather than erased.

1. A bless taken with a repo unavailable SILENTLY DELETED that repo's row

rewrite_baseline built the committed rows from observed alone, with head/tail splices, and never merged the previous baseline. A repo that could not be staged is cov.skipped and therefore never enters observed.

So: fetch fails for one of the seven pinned repos, an operator blesses an intended change on the other six, and that repo's row disappears from tests/corpus/baseline.json. The next run has nothing to compare it against, and the ratchet that exists to notice a resolver change quietly stops covering a seventh of the corpus.

The tell was an asymmetry, not a hunch: corpus_cost's writer does merge — let mut merged = load_baseline(old) — so the cost baseline was immune and the content baseline was not. Two writers for two artifacts, one of which had thought about this.

2. The artifact was written BEFORE the coverage panic

The bless arm ran rewrite_baseline(...); cov.finish(ctl); return; — and Coverage::finish is where COSI_CORPUS_REQUIRE=1 turns an unavailable repo into a failure. So even under REQUIRE, the file was already on disk when the failure fired. The guard that was supposed to prevent exactly scenario 1 ran after the damage.

corpus_stage had the ordering right: its verdict refuses before fs::write. Again, two implementations, one of which was correct.

3. An empty categorised diff was blessable

drift was computed and the bless branch never consulted it, so a bless that moved nothing still rewrote the artifact and appended a reason. That is how a bless becomes a habit instead of an event — #45's anti-gaming list names it explicitly, and this switch had never enforced it.

Why existing gates could not see any of the three

All three live in a path that only executes under COSI_CORPUS_BLESS=1, which no CI job sets and no test exercised. The suite's own tests graded the comparison arm; the writer arm was reachable only by an operator typing the switch, and its failure mode is silent data loss in a committed file. There was no test that blessed anything and then looked at what was written.

The fix

All bless paths now route through corpus::projection::bless_verdict, which refuses before any write on all six of #45's clauses, and the writer merges rather than truncates. Mutations run for each: reinstating the truncating writer reddens with the dropped repo named; moving the write back before the refusal reddens; making the diff check vacuous reddens on all four suites.

The parameter list also became a BlessClaim struct, which removed three #[allow(clippy::too_many_arguments)] — and the reason is in the struct's doc: unavailable and degraded are both &[String] and adjacent, so transposing them compiles, and the refusal that then fires names the wrong rule.

What is still open, and it is the reason this is filed rather than only committed

  1. The other writers were not audited for the truncate-vs-merge pattern. corpus_cost merges and corpus_ratchet now merges. corpus_stage, corpus_tier3_ratchet and ruby_package_cost were brought onto the shared verdict but their writers were not individually re-read for this specific hazard. Any writer that constructs its output from the current run alone has defect 1.
  2. COSI_RUBY_PKG_COST_BLESS is still outside the contract — it enforces a non-empty reason only. Its waiver is written into bless_registry and is self-clearing (it reddens the moment that suite calls bless_verdict), but it is a real residual.
  3. No test blesses and then inspects the bytes. The mutations proved the refusals; what is still missing is a positive test that performs a real bless into a temp path with one repo unavailable and asserts the previous row survived. ruby_package_cost::the_bless_writes_only_its_own_baseline is the model — it hashes foreign artifacts around a real bless.

What must NOT be done

  • Do not bless tests/corpus/baseline.json to test any of this. It is at md5 534084b856c22566c48e386bc41ed67e and is mid-re-record on another branch. Every mutation above was run against a temp path or reverted with md5 verification.
  • Do not close item 1 by reading the writers and declaring them fine. The asymmetry that exposed this was invisible until two implementations were compared side by side; the durable answer is a shared writer or a test that grades the merge property per artifact.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K

Found during the #45.6 audit ("Bless requires reason, generation identities and proof that controls executed"). **All three are fixed** in `gate: #45.6 — one bless verdict, six refusals, and the vacuity that hid a straggler`, each with its own run mutation. Filed as a record and because the **audit half is still open** — see the last section. **Filed as one issue, and here is why.** Defects 1 and 2 share a root — *the bless wrote before the run was validated* — and compose into a single worst case. Defect 3 is a genuinely different root (a refusal computed and never consulted). I chose one issue anyway because all three were found in one audit of one function, all three were closed by one change, and splitting a closed finding into two records helps no reader. The distinction is stated here rather than erased. ## 1. A bless taken with a repo unavailable SILENTLY DELETED that repo's row `rewrite_baseline` built the committed rows from `observed` alone, with head/tail splices, and **never merged the previous baseline**. A repo that could not be staged is `cov.skipped` and therefore never enters `observed`. So: fetch fails for one of the seven pinned repos, an operator blesses an intended change on the other six, and that repo's row **disappears from `tests/corpus/baseline.json`**. The next run has nothing to compare it against, and the ratchet that exists to notice a resolver change quietly stops covering a seventh of the corpus. **The tell was an asymmetry**, not a hunch: `corpus_cost`'s writer *does* merge — `let mut merged = load_baseline(old)` — so the cost baseline was immune and the content baseline was not. Two writers for two artifacts, one of which had thought about this. ## 2. The artifact was written BEFORE the coverage panic The bless arm ran `rewrite_baseline(...); cov.finish(ctl); return;` — and `Coverage::finish` is where `COSI_CORPUS_REQUIRE=1` turns an unavailable repo into a failure. So **even under `REQUIRE`, the file was already on disk** when the failure fired. The guard that was supposed to prevent exactly scenario 1 ran after the damage. `corpus_stage` had the ordering right: its verdict refuses *before* `fs::write`. Again, two implementations, one of which was correct. ## 3. An empty categorised diff was blessable `drift` was computed and the bless branch never consulted it, so a bless that moved nothing still rewrote the artifact and appended a reason. That is how a bless becomes a habit instead of an event — #45's anti-gaming list names it explicitly, and this switch had never enforced it. ## Why existing gates could not see any of the three All three live in a path that only executes under `COSI_CORPUS_BLESS=1`, which no CI job sets and no test exercised. The suite's own tests graded the *comparison* arm; the *writer* arm was reachable only by an operator typing the switch, and its failure mode is silent data loss in a committed file. There was no test that blessed anything and then looked at what was written. ## The fix All bless paths now route through `corpus::projection::bless_verdict`, which refuses **before** any write on all six of #45's clauses, and the writer merges rather than truncates. Mutations run for each: reinstating the truncating writer reddens with the dropped repo named; moving the write back before the refusal reddens; making the diff check vacuous reddens on all four suites. The parameter list also became a `BlessClaim` struct, which removed three `#[allow(clippy::too_many_arguments)]` — and the reason is in the struct's doc: `unavailable` and `degraded` are both `&[String]` and adjacent, so **transposing them compiles**, and the refusal that then fires names the wrong rule. ## What is still open, and it is the reason this is filed rather than only committed 1. **The other writers were not audited for the truncate-vs-merge pattern.** `corpus_cost` merges and `corpus_ratchet` now merges. `corpus_stage`, `corpus_tier3_ratchet` and `ruby_package_cost` were brought onto the shared *verdict* but their **writers** were not individually re-read for this specific hazard. Any writer that constructs its output from the current run alone has defect 1. 2. **`COSI_RUBY_PKG_COST_BLESS` is still outside the contract** — it enforces a non-empty reason only. Its waiver is written into `bless_registry` and is self-clearing (it reddens the moment that suite calls `bless_verdict`), but it is a real residual. 3. **No test blesses and then inspects the bytes.** The mutations proved the refusals; what is still missing is a positive test that performs a real bless into a temp path with one repo unavailable and asserts the previous row survived. `ruby_package_cost::the_bless_writes_only_its_own_baseline` is the model — it hashes foreign artifacts around a real bless. ## What must NOT be done - **Do not bless `tests/corpus/baseline.json` to test any of this.** It is at md5 `534084b856c22566c48e386bc41ed67e` and is mid-re-record on another branch. Every mutation above was run against a temp path or reverted with md5 verification. - **Do not close item 1 by reading the writers and declaring them fine.** The asymmetry that exposed this was invisible until two implementations were compared side by side; the durable answer is a shared writer or a test that grades the merge property per artifact. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K
Author
Member

Open item 1 answered, and it was not clean: two more writers had defect 1, and they share one function

Worktree /tmp/cosi-lane-gates at f6a878a. Staged, not pushed. The instruction "do not close item 1 by reading the writers and declaring them fine" is why this is a fix plus a graded property per artifact rather than a verdict.

The full writer census — 6 switches, 7 registered artifacts

switch suite artifact verdict
COSI_CORPUS_BLESS corpus_ratchet baseline.json SAFE-BY-MERGE (this issue's fix)
COSI_COST_BLESS corpus_cost cost-baseline.json SAFE-BY-MERGE (let mut merged = load_baseline(old))
COSI_STAGE_BLESS corpus_stage stage-baseline.json ⚠️ HAZARDOUS
COSI_TIER3_BLESS corpus_tier3_ratchet tier3-baseline.json ⚠️ HAZARDOUS
COSI_RUBY_PKG_COST_BLESS ruby_package_cost ruby-package-cost.json safe on truncate, order inverted
COSI_BLESS_RUBY_EXPECT ruby_builtin_expectations fixtures/*.expected SAFE-BY-CONSTRUCTION (one file per fixture, no aggregate)
(none, by design) agent_task_bench bench/ratchet.json no bless path exists

The finding: the two hazardous writers are the two that share projection::render

corpus_ratchet and corpus_cost each hand-rolled a render_baseline and each learned to merge. corpus_stage and corpus_tier3_ratchet were brought onto the shared verdict but their write is fs::write(baseline_path(), render(&text, &observed, &act, &Bless{…})), and projection::render built repo_block from observed.iter() alone — taking from old only the comment head. That is the pre-fix corpus_ratchet shape, in a shared function, reached by two suites. Neither had a merge-property test: corpus_stage's nearest arm passes old = "{\n \"_comment\": [\"x\"],\n" — no repos block at all — so it was structurally incapable of noticing.

And the shrunken-universe refusal does not cover it. bless_verdict refuses when unavailable is non-empty, which catches the repo that failed to stage. It cannot catch a repo that was never iterated: corpus::tier(n) is manifest().filter(|r| r.tier == n), so a repo whose tier is edited in corpus.toml, or which is removed from it, is absent from observed and from unavailable — the verdict passes clean and the row goes. I verified that filter directly. One of those is a rule the operator can be told about; the other is a property of the writer, and it has to hold however the writer is called. On tier3-baseline.json the population is two rows, so one silent deletion halves the artifact.

The fix, in one place

projection::render now merges: load_baseline(old).0, then observed inserted over it.

Per-repo replace, not per-key union, and the difference is load-bearing. corpus_ratchet/corpus_cost merge per key over a closed DIMS list; render's rows are open key sets (rule.*, stage.*, influence.*, producer.*). A key union would resurrect a key that has stopped firing — destroying the KEY GONE signal categorised_diff exists to raise, which is the whole point of the stage artifact. A measured repo's row is replaced whole; an unmeasured repo's row is kept whole. Both halves are asserted.

The activation block is deliberately not merged: activation_facts() is a fixed global set (fact_abi, engine), not a per-repo map, so it has no member a partial run can drop. Written down so the omission is a decision, not a gap.

Item 3, partially: a test that renders and inspects the bytes

a_partial_bless_keeps_the_rows_it_did_not_measure added to both corpus_stage and corpus_tier3_ratchet, modelled on corpus_cost's. It builds a two-repo artifact through the real writer (so the fixture cannot drift from the format), asserts the fixture holds two rows, then blesses with only one measured — the proof minted through the real bless_verdict, because BlessProof's only field is private to projection and there is no other route.

MUTATION (RUN): revert projection::render to let mut merged: BTreeMap<String, Row> = BTreeMap::new().

corpus_stage:          a_partial_bless_keeps_the_rows_it_did_not_measure ... FAILED
  "a bless that measured 1 of 2 repos wrote 1 row(s)"
corpus_tier3_ratchet:  a_partial_bless_keeps_the_rows_it_did_not_measure ... FAILED

corpus_stage's existing the_writer_and_the_reader_round_trip_a_baseline stayed ok under that same mutation — the blindness, measured rather than asserted. Restored by cp + md5 verify; the committed baselines never moved.

What remains open on item 3. No test drives the env switch through fs::write(baseline_path(), …) with a repo genuinely unavailable. The write path is anchored to the repo root and there is no path-injection seam; adding one is a production-shaped change I did not want to bundle into a workflow lane. The bytes are now graded; the switch is not.

Defect 2 was still live in ruby_package_cost, and is now fixed

std::fs::write(baseline_path(), text)…;   //  <-- was here
cov.finish(ctl);

cov.finish is where COSI_CORPUS_REQUIRE=1 turns an unavailable repo into a failure, so under REQUIRE the artifact was already on disk when the failure fired — this issue's defect 2, unchanged, in a sixth suite. The order is now cov.finish(ctl) then fs::write.

Latent rather than live today only because that suite returns early when its single repo cannot be staged. That is a property of the current control flow, not of the writer — and closing open item 2 will change that control flow. The other five switches cannot have this bug for a structural reason worth stating: their writers take a &Bless carrying a BlessProof whose only field is private to projection, so "write before the verdict" is a compile error. ruby_package_cost::render_baseline takes no proof, so ordering is all it has.

A finding inside the test this issue names as the model

ruby_package_cost::the_bless_writes_only_its_own_baseline hashes foreign_baselines() around a bless — 2 of the 4 sibling artifacts. stage-baseline.json and tier3-baseline.json were not hashed, so this suite could have written either undetected. Widened to four, and the two hand-indexed assert_ne!s replaced by a loop over the whole set, because widening the array while leaving [0]/[1] asserts behind would have left the two new members ungraded while the code still looked like it covered them.

MUTATION (RUN): point baseline_path() at tests/corpus/stage-baseline.json — a sibling the old 2-member set did not cover.

the_bless_writes_only_its_own_baseline ... FAILED
  "this suite's baseline must not BE …/tests/corpus/stage-baseline.json,
   a ratchet another suite owns"

Related, and left as a note rather than acted on: the hash loop in that test writes to a tempdir dst, never to baseline_path(), so it can only ever catch a hidden side effect of render_baseline. Under its own recorded mutation the test does go red — but on the path-discrimination arm, not the hash arm, and its doc quotes a third failure string ("which belongs to corpus_cost") that appears nowhere in the file. The recorded mutation result does not match the code that would produce it.

Item 2 (COSI_RUBY_PKG_COST_BLESS outside the contract) — scoped, not done

The waiver in bless_registry is self-clearing and correct. What bringing it onto bless_verdict costs, field by field: reason and degraded_allowlist work today (*_DEGRADED already reduces via DERIVED); repos_graded is literal 1; controls needs a parallel Vec<String> because Controls::len is private, exactly as corpus_stage does and says why; identity_after and degraded both need measure_both_legs to return the package-leg db path it currently drops; diff needs load_baseline(&prior) wrapped as a one-key BTreeMap<String, Row> for the shared categorised_diff (which also lands defect 3 there). The one that is not plumbing: unavailable is vacuous while the suite returns early on repo_path Err — making the shrunken-universe refusal real requires replacing that early return with unavailable.push(fx::REPO) and falling through. Then render_baseline must take &Bless so the type-level ordering guarantee applies.

Two incidental drifts in bless_registry: its module doc still says "Six ratcheted artifacts … Five of them are unlocked by an environment variable" (it holds 7 entries and 6 switches — COSI_BLESS_RUBY_EXPECT was added without updating the prose), and every_bless_switch_in_the_tree_is_registered floors at >= 5 against an actual 6, so one switch deleted outright would not move it.

Gates

fmt 0 · clippy -D warnings 0 · rustdoc -D warnings 0 · COSI_CORPUS_DIR=… COSI_CORPUS_REQUIRE=1 cargo test --workspace --no-fail-fast 0 (301 suites ok, 0 failed) · COSI_E2E_LEG=daemon 0 · precision_gate 7/7 phantoms=0 · windows-gnu cross clippy 0.

Corpus ratchets re-run in release with the corpus env, --nocapture, so the floor is visible rather than assumed:

corpus[ratchet]: executed=7 unavailable=0 not_applicable=0 controls=14 (require=true)
corpus[stage]:   executed=7 unavailable=0 not_applicable=0 controls=14 (require=true)
corpus[tier3]:   executed=2 unavailable=0 not_applicable=0 controls=8  (require=true)

Nothing was blessed. baseline.json 914dda1a, tier3-baseline.json 94abf592, stage-baseline.json 7d9695be, ruby-package-cost.json f5a1a8f2 — all unmoved, verified after every mutation.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K

## Open item 1 answered, and it was not clean: **two more writers had defect 1, and they share one function** Worktree `/tmp/cosi-lane-gates` at `f6a878a`. Staged, not pushed. The instruction *"do not close item 1 by reading the writers and declaring them fine"* is why this is a fix plus a graded property per artifact rather than a verdict. ### The full writer census — 6 switches, 7 registered artifacts | switch | suite | artifact | verdict | |---|---|---|---| | `COSI_CORPUS_BLESS` | `corpus_ratchet` | `baseline.json` | SAFE-BY-MERGE (this issue's fix) | | `COSI_COST_BLESS` | `corpus_cost` | `cost-baseline.json` | SAFE-BY-MERGE (`let mut merged = load_baseline(old)`) | | `COSI_STAGE_BLESS` | `corpus_stage` | `stage-baseline.json` | ⚠️ **HAZARDOUS** | | `COSI_TIER3_BLESS` | `corpus_tier3_ratchet` | `tier3-baseline.json` | ⚠️ **HAZARDOUS** | | `COSI_RUBY_PKG_COST_BLESS` | `ruby_package_cost` | `ruby-package-cost.json` | safe on truncate, **order inverted** | | `COSI_BLESS_RUBY_EXPECT` | `ruby_builtin_expectations` | `fixtures/*.expected` | SAFE-BY-CONSTRUCTION (one file per fixture, no aggregate) | | *(none, by design)* | `agent_task_bench` | `bench/ratchet.json` | no bless path exists | ### The finding: the two hazardous writers are the two that share `projection::render` `corpus_ratchet` and `corpus_cost` each hand-rolled a `render_baseline` and each learned to merge. `corpus_stage` and `corpus_tier3_ratchet` were brought onto the shared **verdict** but their write is `fs::write(baseline_path(), render(&text, &observed, &act, &Bless{…}))`, and `projection::render` built `repo_block` from `observed.iter()` alone — taking from `old` only the comment head. **That is the pre-fix `corpus_ratchet` shape, in a shared function, reached by two suites.** Neither had a merge-property test: `corpus_stage`'s nearest arm passes `old = "{\n \"_comment\": [\"x\"],\n"` — no `repos` block at all — so it was structurally incapable of noticing. **And the shrunken-universe refusal does not cover it.** `bless_verdict` refuses when `unavailable` is non-empty, which catches the repo that *failed to stage*. It cannot catch a repo that was never **iterated**: `corpus::tier(n)` is `manifest().filter(|r| r.tier == n)`, so a repo whose tier is edited in `corpus.toml`, or which is removed from it, is absent from `observed` **and** from `unavailable` — the verdict passes clean and the row goes. I verified that filter directly. One of those is a rule the operator can be told about; the other is a property of the writer, and it has to hold however the writer is called. On `tier3-baseline.json` the population is two rows, so one silent deletion halves the artifact. ### The fix, in one place `projection::render` now merges: `load_baseline(old).0`, then `observed` inserted over it. **Per-repo replace, not per-key union**, and the difference is load-bearing. `corpus_ratchet`/`corpus_cost` merge per key over a *closed* `DIMS` list; `render`'s rows are **open** key sets (`rule.*`, `stage.*`, `influence.*`, `producer.*`). A key union would resurrect a key that has stopped firing — destroying the `KEY GONE` signal `categorised_diff` exists to raise, which is the whole point of the stage artifact. A measured repo's row is replaced whole; an unmeasured repo's row is kept whole. Both halves are asserted. The `activation` block is deliberately **not** merged: `activation_facts()` is a fixed global set (`fact_abi`, `engine`), not a per-repo map, so it has no member a partial run can drop. Written down so the omission is a decision, not a gap. ### Item 3, partially: a test that renders and inspects the bytes `a_partial_bless_keeps_the_rows_it_did_not_measure` added to **both** `corpus_stage` and `corpus_tier3_ratchet`, modelled on `corpus_cost`'s. It builds a two-repo artifact through the real writer (so the fixture cannot drift from the format), asserts the fixture holds two rows, then blesses with only one measured — the proof minted through the real `bless_verdict`, because `BlessProof`'s only field is private to `projection` and there is no other route. **MUTATION (RUN)**: revert `projection::render` to `let mut merged: BTreeMap<String, Row> = BTreeMap::new()`. ``` corpus_stage: a_partial_bless_keeps_the_rows_it_did_not_measure ... FAILED "a bless that measured 1 of 2 repos wrote 1 row(s)" corpus_tier3_ratchet: a_partial_bless_keeps_the_rows_it_did_not_measure ... FAILED ``` `corpus_stage`'s existing `the_writer_and_the_reader_round_trip_a_baseline` stayed **ok** under that same mutation — the blindness, measured rather than asserted. Restored by `cp` + md5 verify; the committed baselines never moved. **What remains open on item 3.** No test drives the env switch through `fs::write(baseline_path(), …)` with a repo genuinely unavailable. The write path is anchored to the repo root and there is no path-injection seam; adding one is a production-shaped change I did not want to bundle into a workflow lane. The bytes are now graded; the *switch* is not. ### Defect 2 was still live in `ruby_package_cost`, and is now fixed ```rust std::fs::write(baseline_path(), text)…; // <-- was here cov.finish(ctl); ``` `cov.finish` is where `COSI_CORPUS_REQUIRE=1` turns an unavailable repo into a failure, so under REQUIRE the artifact was already on disk when the failure fired — this issue's defect 2, unchanged, in a sixth suite. The order is now `cov.finish(ctl)` then `fs::write`. Latent rather than live *today* only because that suite returns early when its single repo cannot be staged. That is a property of the current control flow, not of the writer — and closing open item 2 will change that control flow. The other five switches cannot have this bug for a structural reason worth stating: their writers take a `&Bless` carrying a `BlessProof` whose only field is private to `projection`, so "write before the verdict" is a **compile error**. `ruby_package_cost::render_baseline` takes no proof, so ordering is all it has. ### A finding inside the test this issue names as the model `ruby_package_cost::the_bless_writes_only_its_own_baseline` hashes `foreign_baselines()` around a bless — **2 of the 4 sibling artifacts**. `stage-baseline.json` and `tier3-baseline.json` were not hashed, so this suite could have written either undetected. Widened to four, and the two hand-indexed `assert_ne!`s replaced by a loop over the whole set, because widening the array while leaving `[0]`/`[1]` asserts behind would have left the two new members ungraded while the code still *looked* like it covered them. **MUTATION (RUN)**: point `baseline_path()` at `tests/corpus/stage-baseline.json` — a sibling the old 2-member set did not cover. ``` the_bless_writes_only_its_own_baseline ... FAILED "this suite's baseline must not BE …/tests/corpus/stage-baseline.json, a ratchet another suite owns" ``` Related, and left as a note rather than acted on: the hash loop in that test writes to a tempdir `dst`, never to `baseline_path()`, so it can only ever catch a *hidden side effect* of `render_baseline`. Under its own recorded mutation the test does go red — but on the path-discrimination arm, not the hash arm, and its doc quotes a third failure string (*"which belongs to corpus_cost"*) that appears nowhere in the file. The recorded mutation result does not match the code that would produce it. ### Item 2 (`COSI_RUBY_PKG_COST_BLESS` outside the contract) — scoped, not done The waiver in `bless_registry` is self-clearing and correct. What bringing it onto `bless_verdict` costs, field by field: `reason` and `degraded_allowlist` work today (`*_DEGRADED` already reduces via `DERIVED`); `repos_graded` is literal `1`; `controls` needs a parallel `Vec<String>` because `Controls::len` is private, exactly as `corpus_stage` does and says why; `identity_after` and `degraded` both need `measure_both_legs` to return the package-leg db path it currently drops; `diff` needs `load_baseline(&prior)` wrapped as a one-key `BTreeMap<String, Row>` for the shared `categorised_diff` (which also lands defect 3 there). **The one that is not plumbing**: `unavailable` is vacuous while the suite returns early on `repo_path` Err — making the shrunken-universe refusal real requires replacing that early return with `unavailable.push(fx::REPO)` and falling through. Then `render_baseline` must take `&Bless` so the type-level ordering guarantee applies. Two incidental drifts in `bless_registry`: its module doc still says *"Six ratcheted artifacts … Five of them are unlocked by an environment variable"* (it holds 7 entries and 6 switches — `COSI_BLESS_RUBY_EXPECT` was added without updating the prose), and `every_bless_switch_in_the_tree_is_registered` floors at `>= 5` against an actual 6, so one switch deleted outright would not move it. ### Gates `fmt` 0 · `clippy -D warnings` 0 · `rustdoc -D warnings` 0 · `COSI_CORPUS_DIR=… COSI_CORPUS_REQUIRE=1 cargo test --workspace --no-fail-fast` 0 (301 suites ok, 0 failed) · `COSI_E2E_LEG=daemon` 0 · `precision_gate` 7/7 `phantoms=0` · windows-gnu cross clippy 0. Corpus ratchets re-run in release with the corpus env, `--nocapture`, so the floor is visible rather than assumed: ``` corpus[ratchet]: executed=7 unavailable=0 not_applicable=0 controls=14 (require=true) corpus[stage]: executed=7 unavailable=0 not_applicable=0 controls=14 (require=true) corpus[tier3]: executed=2 unavailable=0 not_applicable=0 controls=8 (require=true) ``` Nothing was blessed. `baseline.json` `914dda1a`, `tier3-baseline.json` `94abf592`, `stage-baseline.json` `7d9695be`, `ruby-package-cost.json` `f5a1a8f2` — all unmoved, verified after every mutation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K
Author
Member

STAYING OPEN, NARROWED — item 1 is discharged, items 2 and 3 are verbatim untouched

Close-out lane, master 552e3a2. Title corrected to the residual only.

Done — strike this clause from the issue

Item 1, the audit of the other bless writers, is complete. a_partial_bless_keeps_the_rows_it_did_not_measure now exists in all four suites:

crates/indexer/tests/corpus_ratchet.rs:600
crates/indexer/tests/corpus_stage.rs:983
crates/indexer/tests/corpus_tier3_ratchet.rs:799
crates/indexer/tests/corpus_cost.rs:832      (pre-existing)

All green — corpus_stage 11/11, corpus_tier3_ratchet 5/5, EXIT=0. The census found 6 switches over 7 artifacts and two further hazardous writers, both fixed; defect 2 in ruby_package_cost is fixed at crates/indexer/tests/ruby_package_cost.rs:690-691 (cov.finish(ctl); then fs::write).

Still open, verbatim

  • Item 2. crates/indexer/tests/bless_registry.rs:134-147 still carries switch: "COSI_RUBY_PKG_COST_BLESS" with waiver: "PENDING #45.6: this suite still enforces only a NON-EMPTY reason …". That switch is outside the bless contract.
  • Item 3. No test drives an env switch through fs::write(baseline_path(), …) with a repo genuinely unavailable — i.e. nothing blesses and then inspects the bytes, which is the only thing that would have caught the original three defects.
  • Both "incidental drifts" are also unfixed, and they are the same failure class this issue is about — a gate that cannot see its own population:
    • bless_registry.rs:3-4 reads "Six ratcheted artifacts … Five of them are unlocked by an environment variable" against an actual 7 entries / 6 switches.
    • bless_registry.rs:323 floors at found.len() >= 5 against an actual 6 — so one switch deleted outright would not move it.

Corrected scope

Retitle as above; strike "the audit of the other writers is open"; keep items 2, 3 and the two drifts as the remaining work.

## STAYING OPEN, NARROWED — item 1 is discharged, items 2 and 3 are verbatim untouched Close-out lane, master `552e3a2`. **Title corrected** to the residual only. ### Done — strike this clause from the issue **Item 1, the audit of the other bless writers, is complete.** `a_partial_bless_keeps_the_rows_it_did_not_measure` now exists in all four suites: ``` crates/indexer/tests/corpus_ratchet.rs:600 crates/indexer/tests/corpus_stage.rs:983 crates/indexer/tests/corpus_tier3_ratchet.rs:799 crates/indexer/tests/corpus_cost.rs:832 (pre-existing) ``` All green — `corpus_stage` 11/11, `corpus_tier3_ratchet` 5/5, **EXIT=0**. The census found 6 switches over 7 artifacts and two further hazardous writers, both fixed; defect 2 in `ruby_package_cost` is fixed at `crates/indexer/tests/ruby_package_cost.rs:690-691` (`cov.finish(ctl);` then `fs::write`). ### Still open, verbatim - **Item 2.** `crates/indexer/tests/bless_registry.rs:134-147` still carries `switch: "COSI_RUBY_PKG_COST_BLESS"` with `waiver: "PENDING #45.6: this suite still enforces only a NON-EMPTY reason …"`. That switch is outside the bless contract. - **Item 3.** No test drives an env switch through `fs::write(baseline_path(), …)` with a repo genuinely unavailable — i.e. nothing blesses and then *inspects the bytes*, which is the only thing that would have caught the original three defects. - **Both "incidental drifts" are also unfixed**, and they are the same failure class this issue is about — a gate that cannot see its own population: - `bless_registry.rs:3-4` reads *"Six ratcheted artifacts … Five of them are unlocked by an environment variable"* against an actual **7 entries / 6 switches**. - `bless_registry.rs:323` floors at `found.len() >= 5` against an actual **6** — so one switch deleted outright would not move it. ### Corrected scope Retitle as above; strike *"the audit of the other writers is open"*; keep items 2, 3 and the two drifts as the remaining work.
buildagent changed title from corpus_ratchet's bless path could delete a repo's row, wrote before its own refusal, and never consulted the diff it computed (found + fixed; audit of the other writers is open) to COSI_RUBY_PKG_COST_BLESS is outside the bless contract, no test blesses through an env switch and inspects the bytes, and bless_registry's own doc and floor have drifted below their population 2026-09-06 12:48:41 +02:00
Author
Member

All three residuals are closed on master 1d81180. Closing.

This issue's own last section listed three open items. All three are in the tree, and none of them was closed the way the issue forbade.

Item 2 — COSI_RUBY_PKG_COST_BLESS outside the contract. crates/indexer/tests/bless_registry.rs:139-160 now carries enforces: ALL, waiver: "", and the deleted waiver's replacement comment records why the waiver was not merely unimplemented: identity_after and degraded were unreachable, because they are properties of the package leg's database and Legs dropped the path. Legs keeps it now. The self-clearing mechanism the issue described did its job — every_registered_switch_routes_through_the_shared_verdict demands the waiver go the moment the suite starts calling bless_verdict.

Item 1 — the other writers were not audited for truncate-vs-merge. Not closed by reading them and declaring them fine, which the issue explicitly ruled out. Closed structurally: corpus::projection::render is now the shared writer and it merges (let mut merged = load_baseline(old).0;), so the asymmetry that exposed the original defect cannot exist between two implementations any more.

Item 3 — no test blesses and then inspects the bytes. corpus_tier3_ratchet.rs::a_partial_bless_keeps_the_rows_it_did_not_measure does exactly that: it builds a two-repo artifact through the real writer (so the fixture cannot drift from the format), blesses a run that measured one of the two, and reads the bytes back — the measured repo carries its new number, the unmeasured repo keeps its blessed row and every one of its dimensions.

Two details in it are better than the issue asked for:

  • It names the second channel by which a repo leaves observed, which the shrunken-universe refusal does not cover: the repo was never iterated because someone edited a tier or removed a row from corpus.toml. Nothing is unavailable, the verdict passes clean, and a truncating writer drops the row in silence. That is why this has to be a property of the writer rather than a rule an operator can be told.
  • It asserts the merge is a per-repo replace, not a per-key union — a measured repo's row is replaced whole, so a key that stopped firing must disappear or categorised_diff's KEY GONE signal is unreachable. That is the failure mode a naive fix for item 1 would have introduced.

The declared mutation (truncating writer) is recorded as run and RED, and tests/corpus/baseline.json was not touched.

## All three residuals are closed on master `1d81180`. Closing. This issue's own last section listed three open items. All three are in the tree, and none of them was closed the way the issue forbade. **Item 2 — `COSI_RUBY_PKG_COST_BLESS` outside the contract.** `crates/indexer/tests/bless_registry.rs:139-160` now carries `enforces: ALL, waiver: ""`, and the deleted waiver's replacement comment records *why* the waiver was not merely unimplemented: `identity_after` and `degraded` were **unreachable**, because they are properties of the package leg's database and `Legs` dropped the path. `Legs` keeps it now. The self-clearing mechanism the issue described did its job — `every_registered_switch_routes_through_the_shared_verdict` demands the waiver go the moment the suite starts calling `bless_verdict`. **Item 1 — the other writers were not audited for truncate-vs-merge.** Not closed by reading them and declaring them fine, which the issue explicitly ruled out. Closed structurally: `corpus::projection::render` is now the shared writer and it merges (`let mut merged = load_baseline(old).0;`), so the asymmetry that exposed the original defect cannot exist between two implementations any more. **Item 3 — no test blesses and then inspects the bytes.** `corpus_tier3_ratchet.rs::a_partial_bless_keeps_the_rows_it_did_not_measure` does exactly that: it builds a two-repo artifact **through the real writer** (so the fixture cannot drift from the format), blesses a run that measured one of the two, and reads the bytes back — the measured repo carries its new number, the unmeasured repo keeps its blessed row and every one of its dimensions. Two details in it are better than the issue asked for: - It names the **second** channel by which a repo leaves `observed`, which the shrunken-universe refusal does **not** cover: the repo was never iterated because someone edited a tier or removed a row from `corpus.toml`. Nothing is unavailable, the verdict passes clean, and a truncating writer drops the row in silence. That is why this has to be a property of the writer rather than a rule an operator can be told. - It asserts the merge is a **per-repo replace, not a per-key union** — a measured repo's row is replaced whole, so a key that stopped firing must disappear or `categorised_diff`'s KEY GONE signal is unreachable. That is the failure mode a naive fix for item 1 would have introduced. The declared mutation (truncating writer) is recorded as run and RED, and `tests/corpus/baseline.json` was not touched.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#177
No description provided.