T03: InnerLoop v1.7 plus loop-lint's own-cost check. Six passes
under-reported themselves by 30-45%, never once high, and the rule lived
only in evidence files having been re-derived three times. The READING
is load bearing, not the boundary: CB-WP-0018 T04 applied 're-run the
instrument at the moment of quoting' alone and its figure was correct.
So the operative instruction is re-run when you quote, and loop-lint
fails an evidence file naming its own workplan beside a dollar amount
without marking it provisional.
It binds forward from this pass. The check fires on seven historical
files which ARE the evidence for the rule; making them comply would edit
the record to remove the thing it proves -- the same category error as a
live fact: tag on a dated measurement, which this pass also hit.
Lifecycle, at the maintainer's instruction: ready -> active -> done,
where ready means declared and not started. loop-lint fails a workplan
that has started and still says ready, one that is active with
everything closed, and one that is done with an open task. The first
version of that check was WRONG and its own self-test caught it: it
stripped the leading status: assuming frontmatter, which silently
dropped a real task once the frontmatter said ready or active.
Both new checks then fired on this pass's own artifacts and both were
right to.
T04: CB-EV-0017. The new meta budget's first reading is a breach it
caused -- 27% against the 20% line, because this pass cost $31.18
against product passes averaging ~$21. Reported rather than exempted:
ADR-0006 D2 covers the instrument repairs but not the rule-writing, and
the honest reading is that this should have been two passes.
CB-WP-0018 settled at $36.53/95 against $28.08/82 last reported, 30%
higher. Seven for seven.
make all exits 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-0006 D3. Nine standing control gates now say what they check, what
they have caught with pointers, when their keep-or-kill argument is due,
and what would retire them. make gate-review reports what is overdue and
what has caught nothing; it never fails the build, for CB-RES-0005 §4's
reason.
Drift is checked in both directions and both are pinned by self-tests: a
dependency of `make all` that is neither a registered control gate nor
listed in not_control_gates is a loop-lint finding, so a new gate cannot
acquire permanence without a review date, and an entry naming a target
the Makefile lacks is a finding too.
First run: 0 due, 2 silent. The silent two are the chaos roll, whose
12-declaration window exists precisely to find out, and gate-review
itself, which is not exempt from its own rule — if it has retired,
tightened or forced the re-justification of nothing by 2026-12-31 it is
a ritual and goes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CB-RES-0003 measured 84 turns and $15.33 — the largest mechanical
category — spent prefixing commands with `cd` and
`export PATH="$HOME/.cargo/bin:$PATH"`. Both causes are now fixed once
instead of per-leaf.
tools/repo.py resolves the repo root from __file__ and cargo from PATH
then the standard rustup locations. Every tool imports ROOT from it, so
the repo path is stated once rather than redefined in four files —
single source of fact, the rule DFD earned in InnerLoop v1.2.
rule-coverage and dep-weight now call enter_root(), which is why their
relative paths did not need rewriting one by one.
The Makefile derives REPO from MAKEFILE_LIST and resolves CARGO the same
way, so `make -C <repo> <target>` works from any directory with no
prefix.
make env-test is the positive control, and is in `make all`: every tool
runs from / with PATH=/usr/bin:/bin. Without it this fix could regress
silently and invalidate T05's measurement — the whole point of the
control loop.
dep-weight's "cargo not on PATH" error is kept rather than deleted. It
should now be unreachable, and --self-test asserts cargo_bin() resolves
unaided; a control that never fires is cheaper than a regression.
loop-lint failed on repo.py on its first run — a reporting tool with a
positive control but no --self-test entry point. Second time the gate
has caught work from its own pass within the hour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
41 rules classified executable / checkable / decorative, each tagged with
the failure class it catches. Counts: 11 executable, 22 checkable, 4
decorative (one of them dead policy).
Audit: history/260731-inner-loop-rule-audit.md
New tools/loop-lint.py makes 7 rules executable (tier declared, chaos
roll recorded, tier-L review trail, unmeasured-in-evidence, whole-file
loadability, reporting tools expose --self-test). It found three real
violations on its first run, none previously visible:
- specs/ArchitectureBlueprint.md was 543 lines against a ~400 limit
the loop has stated since v0.2 and never measured. Split at its own
section boundaries into Blueprint (1-8) + Runtime (9-15).
- tools/dep-weight.py and tools/rule-coverage.py had positive-control
logic and no --self-test, so nothing verified the control worked.
Adding rule-coverage's self-test exposed a latent instance of the exact
class this workplan is about: if the spec regex stopped matching, rules
was empty, missing was empty, and the tool exited 0 reporting "0/0" --
a silent pass, in the tool that reports our headline AM-1 number. Both
tools now assert they found something before reporting.
Two demotions applied in the spec rather than left implicit: "structured
over prose" is marked guidance (nothing can check it), and the 8k/10k
token budget is struck through and marked DEAD POLICY pointing at T05.
The audit's uncomfortable finding: rule 13 (re-derive inherited numbers)
has no mechanical form, is deliberately left decorative, and caught the
LARGEST error in CB-WP-0002. That is a counter-example to this
workplan's own hypothesis. "A rule that cannot be executed is not a
rule" is wrong as stated; the defensible version is that such a rule
cannot be relied on to fire, so it must not be the only defence for a
class that matters.
Class coverage: harness-does-nothing has five executable rules;
trusted-arithmetic has ZERO and produced the largest single error.
make loop-lint and make self-tests wired into `make all` and CI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>