Skip to content

fix(verify): bound the exec mirror by its own skip ceiling, not the runner's - #152

Merged
stranske merged 1 commit into
mainfrom
claude/xenodochial-austin-7a9386
Aug 29, 2026
Merged

fix(verify): bound the exec mirror by its own skip ceiling, not the runner's#152
stranske merged 1 commit into
mainfrom
claude/xenodochial-austin-7a9386

Conversation

@stranske

Copy link
Copy Markdown
Owner

The defect

.verify-floor.json's skipped_max = 26 is, by the floor file's own note, "exactly what a machine with none of this instance's local prerequisites skips (a GitHub runner: no agent CLIs, no ~/.codex/skills, no /Applications/ChatGPT.app, no populated capability ledger)".

That same number was also applied to the exec mirror, which is the opposite deprivation: every local prerequisite is present (it exists only on the machine the system runs on) but it is a flat file copy, so it is not a git repository and has no .github/. It skips 31 tests a runner skips none of:

family count detector test file
.github/workflows absent 12 repo_files_absent(...) tests/test_ci_gate_config.py
not a git repository 19 git_repo_absent() tests/test_repo_artifact_hygiene.py

So python3 verify.py from ~/.codex/orchestrator-mirror was RED on every input, correct trees included — and CLAUDE.md §1 makes that run the verdict ("cmp-clean is not agreement"), so the one instrument that catches cross-tree divergence had stopped protecting anything. A gate red whatever you do is a gate that gets ignored, then switched off.

Measured, not inferred. Unmodified main: 471 passed, 0 failed, 31/26 max skipped (502 collected; floor 502), sole problem CEILING exceeded. Syncing the previous main into a scratch mirror gave the same 31, so the breach is structural, not caused by any PR.

Why not just raise skipped_max to 31

CI runs on a runner where 26 is the measured bound. Raising it would hand the runner five units of slack — one gate going quiet to un-stick another. Each shape gets its own agreed number, measured where it is enforced: latched-gate question 3 taken literally, the measuring window equal to the draining window.

The change

  • env_prereq.exec_mirror_shape() detects the tree — no .github/ and git reports no repository. The PREREQUISITE, never $CI, exactly as every other detector there does. Both marks required, because the mirror number is the looser one, so an ambiguous tree falls back to the base agreement. It is the same two detectors that cause the skips, so there is no second literal to drift.
  • verify.mirror_key() derives the floor key from the base key — one rule consumed by both the check and --update-floor, so any ceiling gets a mirror_ variant for free and an unset or misspelt one falls back to base (the strict direction). The mirror value replaces the base rather than adding to it: 26+31 would buy 26 units of headroom nothing on the mirror can legitimately spend.
  • _ceiling_report() returns the verdict and the count/limit rendering from one shape decision. They reached it separately in my first draft, which is the mypy-ratchet defect exactly (the line said NOT COUNTED while the enforcement cleared) — caught because a break→revert demo failed to fire, the pinned fragment matching at both wiring points.
  • _preserved_ceilings() carries both shapes through --update-floor. ci.yml's reconcile job rewrites this file on every push to main from a checkout, where the mirror keys are never read — a writer keeping only the keys it used would have deleted mirror_skipped_max and re-latched the mirror silently, as a bot commit nobody reads.
  • The summary's first line names the tree in both shapes, and the pytest line reads 31/31 max [mirror_skipped_max] — the key named whenever it is not the base one, so a mirror reader is never sent to raise the number CI depends on.

Deliberately not asserted: that mirror_skipped_max >= skipped_max. It holds today (31 vs 26) by coincidence — the two populations are disjoint, not nested — and the drain named in the floor note (teach orch-sync-mirror.sh to copy .github/, dropping 12) would take it to 19, so that assertion would refuse the drain it exists to encourage. The reasoning is left in place beside the omission.

Verification

python3 src/verify.py, green from both trees, measured on the rebase onto b80e6e4:

tree result
checkout 502 passed, 0 failed, 0/26 max skipped (502 collected; floor 502), 87/87 selftests, 5/5 gates
scratch exec mirror 471 passed, 0 failed, 31/31 max [mirror_skipped_max], 87/87 selftests, 5/5 gates, VERIFIED

The mirror was synced with ORCH_MIRROR=<tmp> so the live mirror is untouched — it still needs the manual orch-sync-mirror.sh after merge, per CLAUDE.md §1.

collected stays 502 in both and is unchanged: the new coverage lives in verify.py's and env_prereq.py's selftests, which pytest does not collect.

Six deliberate-break→revert demonstrations, each confirmed to discriminate: ANDOR in the shape detector; ceiling_limit ignoring the mirror key; _preserved_ceilings dropping it; the renderer reaching the shape separately; verify() hardcoding mirror=False (the single wiring pin — smallest fragment, split so it cannot match its own line, verified stable under black 26.5.1, which reflowed the call and left the fragment intact); and the real floor file losing the key.

Formatted and linted at the pinned CI versions (black 26.5.1, ruff 0.16.4, isort 8.0.1, mypy 2.3.1 — clean, no new exemptions).

🤖 Generated with Claude Code

…unner's

`.verify-floor.json`'s `skipped_max` = 26 is, by the floor file's own note,
"exactly what a machine with none of this instance's local prerequisites skips
(a GitHub runner)". It was ALSO applied to the exec mirror, which is the
opposite deprivation: every local prerequisite present (it exists only on the
machine the system runs on) but a flat file copy, so no `.github/` and no
`.git`. The mirror skips 31 tests a runner skips none of — 12 from
`repo_files_absent(".github/workflows", ...)` in test_ci_gate_config.py and 19
from `git_repo_absent()` in test_repo_artifact_hygiene.py.

So `python3 verify.py` from `~/.codex/orchestrator-mirror` was RED on every
input, correct trees included. Measured on unmodified main: 471 passed, 0
failed, 31/26 max skipped, sole problem "CEILING exceeded". Confirmed
structural rather than caused by any PR by syncing the PREVIOUS main into a
scratch mirror and getting the same 31. CLAUDE.md §1 makes the mirror run the
verdict ("cmp-clean is not agreement"), so the one instrument that catches
cross-tree divergence had stopped protecting anything, and a gate red whatever
you do is a gate that gets switched off.

NOT fixed by raising `skipped_max` to 31: CI runs on a runner where 26 is the
measured bound, and the extra five would let a runner skip five more checks in
silence — one gate going quiet to un-stick another. Instead each shape carries
its own agreed number, measured where it is enforced, which is latched-gate
question 3 taken literally: the measuring window equal to the draining window.

* `env_prereq.exec_mirror_shape()` detects the tree — no `.github/` AND git
  reports no repository — the PREREQUISITE and never `$CI`, as every other
  detector there does. BOTH marks required, because the mirror number is the
  looser one, so an ambiguous tree falls back to the base agreement.
* `verify.mirror_key()` derives the floor key from the base key: ONE rule
  consumed by both the check and `--update-floor`, so any ceiling gets a
  `mirror_` variant for free and an unset or misspelt one falls back to base.
  The mirror value REPLACES the base rather than adding to it — 26+31 would buy
  26 units of headroom nothing on the mirror can legitimately spend.
* `_ceiling_report()` returns the verdict AND the count/limit rendering from ONE
  shape decision. They used to reach it separately, which is the mypy-ratchet
  defect exactly (the line said NOT COUNTED while the enforcement cleared); the
  selftest now holds both halves against each other.
* `_preserved_ceilings()` carries both shapes through `--update-floor`. The
  reconcile job rewrites this file on every push to main FROM A CHECKOUT, where
  the mirror keys are never read, so a writer keeping only the keys it used
  would have deleted `mirror_skipped_max` and re-latched the mirror silently.
* The summary's first line now names the tree in BOTH shapes, and the pytest
  line reads `31/31 max [mirror_skipped_max]` — the key named whenever it is not
  the base one, so a mirror reader is never sent to raise the number CI needs.

Deliberately NOT asserted: that `mirror_skipped_max >= skipped_max`. It holds
today by coincidence — the two populations are disjoint, not nested — and the
drain named in the floor note (teach orch-sync-mirror.sh to copy `.github/`,
dropping 12) would take it to 19, so the assertion would refuse the drain it
exists to encourage. The reasoning is left in place beside the omission.

Verified: `python3 src/verify.py` green from BOTH trees. Checkout: 502 passed,
0 failed, 0/26 max skipped, 87/87 selftests, 5/5 gates. Scratch exec mirror
(synced with ORCH_MIRROR so the live mirror is untouched): 471 passed, 0
failed, 31/31 max [mirror_skipped_max], 87/87 selftests, 5/5 gates, VERIFIED.
`collected` is 502 in both and unchanged — the new coverage lives in the
verify.py and env_prereq.py selftests, which pytest does not collect. Six
deliberate-break→revert demonstrations, each confirmed to discriminate: AND→OR
in the shape detector, `ceiling_limit` ignoring the mirror key,
`_preserved_ceilings` dropping it, the renderer reaching the shape separately,
`verify()` hardcoding `mirror=False` (the single wiring pin, formatter-checked
against black 26.5.1), and the real floor file losing the key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 8 minutes.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 57 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b2fe0d47-d009-4ead-87ea-d6fcd90ecb34

📥 Commits

Reviewing files that changed from the base of the PR and between b80e6e4 and 89032fd.

📒 Files selected for processing (5)
  • .verify-floor.json
  • CLAUDE.md
  • docs/MIRROR_SYNC_PATCH.md
  • src/env_prereq.py
  • src/verify.py

Comment @coderabbitai help to get the list of available commands.

@agents-workflows-bot

Copy link
Copy Markdown
Contributor

Workflow source needed

PR #152 needs either a linked GitHub issue or one valid non-issue Workflow Source before PR metadata automation can manage it safely.

Please do one of:

  • Add <!-- meta:issue:123 --> or a normal Closes #123 / Related to #123 line.
  • Check one Workflow Source option in the PR body.
  • Add a hidden marker such as <!-- workflow-source:local_request -->, <!-- workflow-source:manual_remote -->, <!-- workflow-source:review_followup -->, <!-- workflow-source:sync_campaign -->, or <!-- workflow-source:dependabot -->.
  • Add a workflow source label such as workflow:source-direct-pr, workflow:source-local-request, workflow:source-review-followup, workflow:source-sync, or workflow:no-automation.

Once a valid source is present, this warning will not be reposted.

@agents-workflows-bot

Copy link
Copy Markdown
Contributor

Automated Status Summary

Head SHA: 3aaa62e
Latest Runs: ⏳ pending — Gate
Required: core tests (3.12): ⏳ pending, core tests (3.13): ⏳ pending, docker smoke: ⏳ pending, gate: ⏳ pending

Workflow / Job Result Logs
(no jobs reported) ⏳ pending

Coverage Overview

  • Coverage history entries: 1

Coverage Trend

Metric Value
Current 33.70%
Baseline ⚠️ not configured (absent)
Delta n/a — nothing to compare against
Minimum 70.00%
Status ❌ Below minimum

No baseline was read (absent), so the delta above is not a measurement. Status reflects only the --minimum floor. Write config/coverage-baseline.json with a line or coverage percentage to enable the comparison; that file is deliberately not synced from Workflows, so each repo owns its own.

Top Coverage Hotspots (lowest coverage)

File Coverage Missing
src/capability_effectiveness.py 0.0% 154
src/capability_firing_monitor.py 0.0% 192
src/capability_matcher_proposals.py 0.0% 111
src/capability_opportunity.py 0.0% 143
src/capability_propensity.py 0.0% 2160
src/capability_task_proposals.py 0.0% 195
src/ccusage_reconcile.py 0.0% 286
src/codemod_lane.py 0.0% 351
src/evidence_acquisition.py 0.0% 103
src/exploration_collection.py 0.0% 331
src/feature_scan.py 0.0% 118
src/frontend_verify.py 0.0% 255
src/improvement_log.py 0.0% 248
src/issue_readiness.py 0.0% 507
src/keepalive_evidence.py 0.0% 378

Low Coverage Files (<50.0%)

File Coverage Missing
src/capability_effectiveness.py 0.0% 154
src/capability_firing_monitor.py 0.0% 192
src/capability_matcher_proposals.py 0.0% 111
src/capability_opportunity.py 0.0% 143
src/capability_propensity.py 0.0% 2160
src/capability_task_proposals.py 0.0% 195
src/ccusage_reconcile.py 0.0% 286
src/codemod_lane.py 0.0% 351
src/evidence_acquisition.py 0.0% 103
src/exploration_collection.py 0.0% 331
src/feature_scan.py 0.0% 118
src/frontend_verify.py 0.0% 255
src/improvement_log.py 0.0% 248
src/issue_readiness.py 0.0% 507
src/keepalive_evidence.py 0.0% 378

Updated automatically; will refresh on subsequent CI/Docker completions.


Keepalive checklist

Scope

No scope information available

Tasks

  • No tasks defined

Acceptance criteria

  • No acceptance criteria defined

@github-actions

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Gate Followups. Do not edit.

@stranske
stranske merged commit c79aa83 into main Aug 29, 2026
37 checks passed
@stranske
stranske deleted the claude/xenodochial-austin-7a9386 branch August 29, 2026 18:31
stranske pushed a commit that referenced this pull request Aug 29, 2026
…erge result

#152 landed underneath this branch and added a NEW floor key, mirror_skipped_max, bounding the
exec mirror by its own skip ceiling rather than the runner's. Resolved as the UNION per the rule
this file states: main's structure kept in full including that key, this branch's rationale
appended rather than either note replacing the other, and the count RE-MEASURED on the merge
result rather than carried forward from either side.

515 from verify.py's own run after the rebase, which confirms #152 added no collected tests. That
makes 502 + 13 correct -- but measured, not assumed. Taking a side would have been silently right
this time, and it is what put the floor 8 below reality on an earlier occasion.

Verified on the merge result: 515 passed, 0 failed, 0 skipped, 88/88 selftests, 5/5 gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 29, 2026
…D, not by uncovered lines (#153)

* feat(testgen): rank test-writing work by where testing actually FAILED, not by uncovered lines

DEDUP (CLAUDE.md §0). Checked src/ for priorit/rank/hotspot/target — only capability_targets.py,
which ranks CAPABILITIES not test targets. Grepped the tree for hotspot/prioriti/rank_. Searched
the improvement log for "escaped defect" and "test priority": both reported a real absence with
the log read in full. Nearest existing thing is coverage_trend.compute_top_files, which ranks by
LOWEST COVERAGE — precisely the ordering this exists not to lead with. Not present; building new.
`capability_admission.py --preflight` clears with zero blocking failures; caller, heartbeat and
fixture remain obligations, and the fixture is discharged here.

WHY NOT MOST-UNCOVERED-FIRST. That maximises percentage-per-PR and points agents at the largest
uncovered files, which are the glue modules where a meaningful test is hardest to write. It is the
ordering most likely to produce hollow tests, so uncovered mass is the LAST tier, not the first.

THREE TIERS, lexicographic:
  1. ESCAPED DEFECTS — a file that later needed a fix is a file whose tests missed something. The
     only tier reporting observed failure of the TESTS rather than a property of the code.
  2. CHURN — where regressions actually arrive.
  3. UNCOVERED MASS — how far the metric moves. Last, deliberately.
All three multiplied by (1 - hollow_rate), so a module where agents keep producing tests that pass
against a broken base sinks however much uncovered code it has. That term only became measurable
when testgen_gate grew no_hollow_nodes in #131.

LEXICOGRAPHIC, NOT A WEIGHTED SUM, and the first version was the latter. Multiplying the tiers
apart (1e6/1e3/1) and summing holds only while the lower tiers stay small: at 1,000,000 uncovered
statements tier 3 exactly equals one escaped defect and the ordering inverts. A scoring function
whose correctness depends on inputs staying under a magic threshold is a defect waiting for a big
repository. Two of the new tests caught it during review; the tuple holds at any magnitude and the
tests now assert at 10**9. No blended "score" is reported at all — one number formed from three
incomparable tiers invites exactly the trade-off the tuple forbids.

TIER 1 IS A GIT PROXY TODAY AND SAYS SO. The Brain has the better signal in outcomes.durability,
where broke_later means merged, CI green, broke afterwards. Measured across 4,665 outcome rows:
durable 2842, abandoned 1300, pending 517, reverted 4, reworked 2, broke_later ZERO —
durability_sweep assigns "reopened, reverted, or durable" and never broke_later, while
pattern_miner.TERMINAL_FAILURE_DURABILITY consumes it. A consumer for a label nothing produces.
Six escaped-defect rows cannot order a queue, so tier 1 reads git history, which needs no
instrumentation and exists in every repo. brain_signal_status() reports which source is live and
returns "unknown" rather than zero when the store cannot be read, so the day the Brain signal
becomes usable is visible rather than assumed.

RANKING IS NOT TRAINING. A fix commit touching a file is decent evidence for ORDERING work and
poor evidence for a learner: code changes for many reasons. This module ranks; it never writes
durability labels. A broke_later producer must clear a higher bar and is deliberately separate.

A SECOND DEFECT OF MY OWN, caught while validating on real data: the CLI treated a missing
--coverage-json as an empty report, so tier 3 rendered as a column of zeros that reads as
"everything is covered" rather than "nothing was read" — the same could-not-measure-as-measured-
zero shape this module's own notes describe. It now names the file and the failure. Found when a
scratch path was cleaned up between runs and the ranking carried cheerfully on.

VALIDATED ON REAL DATA. stranske/Trend_Model_Project, its real Gate coverage payload and its real
history: multi_period/engine.py ranks first on 9 fix commits, 28 churn, 335 uncovered — while
3_Results.py, which has the MOST uncovered statements at 759, ranks third. That inversion is the
design working.

Break -> revert on both invariants: restoring the weighted sum fails the two tier-ordering tests;
removing the hollow discount fails the two hollow tests. Byte-identical revert, 13 pass.

Tests are pytest, not selftest cases, on purpose: local_verify grades per pytest NODE, so a
selftest is one node and its assertions are invisible to hollow detection. A module that orders
test-writing work should have its own tests gradeable by the gate judging that work. The module
keeps a --selftest as well (88/88), exercising the CLI as it ships including live git parsing.

Verified: 515 passed, 0 failed, 0 skipped, 88/88 selftests, 5/5 gates. Floor 502 -> 515.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(floor): resolve against #152 as the union, re-measured on the merge result

#152 landed underneath this branch and added a NEW floor key, mirror_skipped_max, bounding the
exec mirror by its own skip ceiling rather than the runner's. Resolved as the UNION per the rule
this file states: main's structure kept in full including that key, this branch's rationale
appended rather than either note replacing the other, and the count RE-MEASURED on the merge
result rather than carried forward from either side.

515 from verify.py's own run after the rebase, which confirms #152 added no collected tests. That
makes 502 + 13 correct -- but measured, not assumed. Taking a side would have been silently right
this time, and it is what put the floor 8 below reality on an earlier occasion.

Verified on the merge result: 515 passed, 0 failed, 0 skipped, 88/88 selftests, 5/5 gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Tim Stranske <tim@stranskemo.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 29, 2026
…loor writer must not whitelist (#154)

Two generalisable remainders from #152. Both are the same shape: a guard that
was correct in the instance and silent in the general case.

1. A WIRING PIN THAT SILENTLY STOPS FIRING.

`assert needle in src` proves the wiring only while the needle matches ONE site.
Add a second call site and deleting the one the pin MEANS leaves it matching the
other — the guard passes over the fully restored defect, which is this repo's
founding failure wearing the costume of a guard against it.

Not hypothetical. #152's exec-mirror pin FAILED TO FIRE against a deliberate
break, because the detected shape was reaching the ceiling check and the summary
renderer through two separate calls. The break demo caught it; an `in` pin never
would have. CLAUDE.md's pin rule covered only the false POSITIVE (a pin firing on
a correct reformat) and had nothing to say about this direction.

Audited all six pins in the repo — verify.py's `--update-floor` guard and
exec-mirror shape, `test_checks_reported`'s ratchet union, and
`test_verify_coverage_mode`'s three runner needles. EVERY ONE matched exactly
once, so there is no live false negative; what this change fixes is that
uniqueness decays QUIETLY. All six now assert `count(...) == 1` and report the
observed count, so the decay is a red that names the choice to make.

A count above 1 is usually a design smell rather than a pin problem: two
consumers reaching one decision separately can disagree. #152 already routed the
shape through `_ceiling_report`, which returns the verdict and its rendering from
one decision — and that is what makes the pin unique again for free.

2. THE FLOOR WRITER WAS A WHITELIST, SO A NEW KEY WAS ONE FORGOTTEN
   REGISTRATION FROM SILENT DELETION.

`--update-floor` wrote only the keys it recognised (`CEILINGS` plus their mirror
variants). Anything else in `.verify-floor.json` was discarded — and ci.yml's
reconcile job runs it on EVERY push to main, so the discard would arrive as a bot
commit nobody reads. `mirror_skipped_max` escaped that only because #152
remembered to register it.

Registering each key was never the fix; the registration step IS the trap, and
forgetting it is silent. Inverted: `REMEASURED_FLOOR_KEYS` names the three keys
the writer rewrites (`collected`, `passed`, `note`) and `_carried_forward` passes
everything else through verbatim. A key the writer has never heard of now
survives by default — failing toward keeping evidence rather than losing it — and
values are no longer coerced to `int`, which was a type assumption a general
carry-forward has no business making. Ceilings are still never re-measured, and
that is now asserted directly rather than implied by the whitelist.

CLAUDE.md §1's wiring-pin rule gains the false-negative mode, the design smell,
and the preference for a registration-free design over a pin where one exists.

Verified: `python3 src/verify.py` green from BOTH trees. Checkout: 502 passed, 0
failed, 0/26 max skipped, 87/87 selftests, 5/5 gates. Scratch exec mirror:
471 passed, 0 failed, 31/31 max [mirror_skipped_max], 87/87 selftests, 5/5
gates, VERIFIED. `collected` unchanged at 502 — no new pytest tests; the new
coverage is in verify.py's selftest and in strengthened assertions inside two
existing test files.

Four deliberate-break→revert demonstrations, each confirmed to discriminate:
the floor writer reverted to a CEILINGS whitelist (only the unknown-key assert
fails); a second consumer of the detected shape added (the uniqueness pin fires
where `in` would have stayed green); a duplicated `child_argv` gates call site
(same, in test_verify_coverage_mode); and the ratchet union removed outright
(count 0).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant