diff --git a/evidence/CB-EV-0017-budgets.md b/evidence/CB-EV-0017-budgets.md new file mode 100644 index 0000000..f70075b --- /dev/null +++ b/evidence/CB-EV-0017-budgets.md @@ -0,0 +1,184 @@ +# CB-EV-0017 — budgets that ask a question, and the first one to fail + +CB-WP-0019 T04. Measured 2026-08-03 at `0b6f7c5`+. Pass kind `meta`, +tier **M** (structural M; chaos **d8 = 5**, no override — the first roll +at the new rate). Declaration 2 of chaos window 2. + +--- + +## 1. Two budgets that had never asked different questions + +AM-4a and AM-4b both measured `-p games-ground --edges normal` while +claiming to bound different things. AM-4b was blind to **28 crates and +408,237 lines — more source than its own 350,000 target.** + +| | the question | scope | proc-macros | reading | +|---|---|---|---|---:| +| **AM-4a** | what does a game **ship**? | one package, no default features | excluded | 157,202 / 161,000 | +| **AM-4b** | what does a contributor **acquire**? | workspace, dev edges | **counted** | **725,258 / 745,000** | + +**The proc-macro treatments are opposite on purpose**, and that is the +rule ADR-0008 D2 left open. A proc-macro never reaches a shipped binary, +so counting it in *"what a game ships"* was false. But it **is** fetched, +compiled and unaudited on a contributor's machine, and ADR-0007 D3's +acquisition rule counts what the build causes to be fetched. *"It does not +ship"* is no answer to *"we downloaded it."* **When the two rules +disagree, the question each budget asks decides.** + +Measured share: **109,585 lines, 15.1%**, against AM-4a's 36.2%. ADR-0008 +D2 refused to correct AM-4b by borrowing that ratio, on the grounds that +*"correcting a second instrument on the strength of the first one's ratio +is the error this change exists to fix."* It would have been wrong by more +than a factor of two. **A decision that cost a pass of delay and was +right.** + +The target moved to fit the measurement — 745,000, the same ~2.7% margin +ADR-0008 D3 gave AM-4a — and the code it measures did not change at all, +which is the mechanical test for a correction rather than a retarget. + +## 2. Three of this project's own controls fired on this pass + +None of them was the pass's subject. All three fired on changes made +while doing something else. + +| control | what it caught | cost | +|---|---|---| +| `mutation-check --self-test` | AM-4b's mutation find-string went stale the moment the target moved | **build-free** | +| DFD (`facts-check`) | `facts.toml` still carrying 317,021 / 350,000 | one command | +| `loop-lint` loadability | `InnerLoop.md` crossed 400 lines **three times** | three splits | + +The first is the one worth noting. CB-WP-0015 added that check *after* +AM-4a's mutation had rotted unnoticed for two passes, on the argument that +the expensive half of the check needed a build but the cheap half did not. +This is its second catch and the first that cost nothing. + +**And the loadability breaches were fixed structurally, three times, +without raising the limit** — the arithmetic, the cost basis, two review +case studies, the retargeting case and the inherited-number cases all +moved to `InnerLoopReference.md`. That precedent has now held five times. + +## 3. What the meta budget is for — and its first reading is a breach + +The maintainer set the rule: *most spend on the task at hand, some on +control, review and improving the process.* **80/20.** + +META-25 had a threshold and **no stated purpose**, which is why the number +had been argued three separate times. The purpose is now written first and +`make status` prints it above the figure. + +**The ratio and the window are a pair, and that was the substantive +finding.** One meta pass among `n` at parity cost reads `1/n`: 33% over +three, **20% over five**. So 80/20 is *one pass in five at normal cost* — +a five-pass window. The same 20% over the old trailing three would have +silently also demanded the meta pass be half-price, which does not make +meta work rarer, only rushed. The self-test now enforces +`META_SOFT_PCT == 100 / TRAILING_PASSES`; moving one without the other +goes red. + +The phase setting is **declared, argued and expiring** — `meta_phase` in +`gates.toml`, reverting on `review_by` unless re-argued, and refused by +`--self-test` if it has no reason or no expiry. A threshold anyone may +move is not a threshold. + +### The breach, reported rather than exempted + +**`meta budget [OVER] 27% over the last 5 passes (soft 20%)`.** + +The pass that wrote the rule is the first to fail it, and the failure is +real rather than an artifact: **CB-WP-0019 cost $31.18 (provisional, and +seven for seven says it will settle higher) against product passes +averaging ~$21**, so it is over on both counts — one pass in five, *and* +at parity. It did four instrument repairs and two rule changes, which is +more than one pass's worth of meta work. + +*The "provisional" in that sentence was put there by `loop-lint`'s own +new check, which fired on this file for quoting this pass's cost. It was +right to: the figure is provisional, and saying so is both compliant and +more truthful than the bare number was.* + +ADR-0006 D2 exempts *"repairing the instrument that reports a breach"*, +and most of this pass qualifies — AM-4b, the proc-macro decision, and the +meta budget itself are all instrument repair. **The exemption is not +claimed as cover for the whole pass.** T03 and T05's rule-writing are not +repairs of a breached instrument, and the honest reading is that this pass +should have been two. + +**No product work was displaced**, because the product side is blocked on +a human check and on a ground-game ruling (§5). + +## 4. The self-quoting rule, written down at last + +Six passes, six under-reports, **never by less than 30%, never once +high**. The table is in `InnerLoopReference.md` §Quoting a cost. + +**Which of the two causes is load bearing?** The task asked; the answer is +**the reading, not the boundary.** CB-WP-0018 T04 applied *re-run the +instrument at the moment of quoting* alone and its figure was correct. The +boundary rule only tells you when "late enough" has arrived. + +So the operative instruction is: **re-run the instrument when you quote +it.** `loop-lint` now fails an evidence file that names its own workplan +beside a dollar amount without marking it provisional. + +**It binds forward, from this pass.** The check fires on seven historical +files — and those files *are the evidence for the rule*. Making them +comply would mean editing the record to remove the thing it proves, which +is the same category error as putting a live `fact:` tag on a dated +measurement (both appear in this pass; both were fixed by marking rather +than rewriting). + +## 5. Workplan lifecycle, and a bug my own control caught + +At the maintainer's instruction: **`ready` → `active` → `done`**, where +`ready` means *declared and not started*. The status now answers *"is +anyone on this?"* rather than only *"is it finished?"*. + +`loop-lint` fails a workplan that has started work 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 found +it.** It stripped the leading `status:` match assuming it was the +frontmatter — which silently dropped a real task the moment the +frontmatter said `ready` or `active`, because those do not match the task +vocabulary. It worked only on the old `todo`/`done` files. It now parses +the ` ```task ` blocks. + +Also fixed: **`cancel` is a closed outcome.** CB-WP-0005 read `5/8` and +CB-WP-0007 read `2/6` in every status run since the day they closed, +because only `done` counted. Two permanently-wrong numbers teach the +reader to skip the column. + +## 6. Cost + +| pass | kind | responses | cost | $/response | +|---|---|---|---|---| +| **CB-WP-0018** | product | 95 | **$36.53** | 0.385 | +| CB-WP-0019 | meta | *provisional — not quoted, per §4* | | | + +Read by re-running `make status` at the moment of writing, which is the +rule this pass wrote. CB-WP-0018 was last reported at $28.08/82 and has +settled at **$36.53/95** — 30% higher, and **seven for seven**. + +## 7. Open + +- **The AM-4 family is closed.** Four defects across five passes — the + shipped proc-macro count, AM-4b's scope, AM-4b's share, AM-4a's stale + mutation — none found by looking for them. **Where a fifth would be:** + AM-4c is a diagnostic nobody reads, and `own source` (11,799 lines) has + no instrument at all. +- **What five passes of "owed" cost.** The two numbers here were carried + as open items in four consecutive evidence files. Carrying was *cheap* + and it was also *not doing the work*: measuring both took one command + each, before this declaration. The honest reading is that "owed" became + a place to put things rather than a queue. +- **INTENT stage 1: the human check**, now on perceptual questions only. +- **`ground-game` owes ten rulings** (U1–U10) plus SOLVE's legality, now + registered as GROUND-WP-0002 after four days unread. +- **The engine has never loaded ground-game's edition data** — `GR-E01 + unreachable` is most likely an artifact of a stand-in worth 6 points + against a real dataset worth 12. Blocked on GROUND-WP-0002 T01. +- **`python3` as a toolchain dependency was never argued.** +- **AM-4a cannot survive stage 2** — 1,741,979 against 161,000. +- **ADR-0007 D3 and D5 remain unratified**; ADR-0010 rests on D5. +- **Chaos: 2 of 12 in window 2**, no override yet at d8. diff --git a/gates.toml b/gates.toml index a3c1f89..5a804c9 100644 --- a/gates.toml +++ b/gates.toml @@ -122,6 +122,7 @@ review_by = "2026-12-31" caught = [ "four loadability breaches (401, 427, 406, 409 lines), each fixed structurally rather than by raising the limit", "a reporting tool with no --self-test entry point (tools/repo.py)", + "CB-WP-0019: two new checks, and both fired on the pass that wrote them. `own-cost` caught CB-EV-0017 quoting its own pass's cost; `lifecycle` caught CB-WP-0019 still saying `active` with every task closed. The lifecycle check's FIRST version was itself wrong and its own self-test found it — it stripped the leading `status:` assuming frontmatter, which silently dropped a real task once the frontmatter said `ready` or `active`", ] retire_if = "two passes run with no finding while artifacts keep growing — that would mean it is measuring the wrong properties" diff --git a/specs/InnerLoop.md b/specs/InnerLoop.md index 14c37ce..669c298 100644 --- a/specs/InnerLoop.md +++ b/specs/InnerLoop.md @@ -24,10 +24,8 @@ covers changes to the loop's own operation (D5). > and at half price*. `InnerLoopReference.md` §Meta budget has the > arithmetic. > -> **Soft on purpose.** A task already started may be finished — stopping -> mid-task to satisfy a ratio wastes the work and leaves the tree worse -> than either finishing or never starting. What the budget constrains is -> *opening* new meta work above the line, and it constrains it with two +> **Soft on purpose.** A task already started may be finished; what the +> budget constrains is *opening* new meta work above the line, with two > exemptions: > > 1. **Repairing the instrument that reports a breach is always in @@ -50,6 +48,22 @@ covers changes to the loop's own operation (D5). > budget, not a gate, for the same reason the session-shape budget is — > it constrains judgment, not artifacts. +> **Workplan lifecycle (v1.7).** `ready` → `active` → `done`. **`ready` +> means declared and not yet started**; a workplan being worked is +> `active`, so the status answers *"is anyone on this?"* rather than only +> *"is it finished?"*. `loop-lint` fails when a workplan has started work +> and still says `ready`, or has finished it and does not say `done`. +> Tasks keep `todo` | `done` | `cancel`; `cancel` is a **closed** outcome +> and is counted as such. + +> **Quoting a cost (v1.7).** An evidence file **may not quote its own +> pass's cost as final** — six passes under-reported themselves by 30–45%, +> never once high. **Re-run the instrument at the moment of quoting**; +> quoting from memory defeats the rule even when the boundary is right. +> `loop-lint` fails an evidence file naming its own workplan beside a +> dollar figure without marking it provisional. +> `InnerLoopReference.md` §Quoting a cost. + > **Loop work cashes out (v1.6, ADR-0006 D4).** A `meta` pass must ship at > least one executable check, command, or gate. Findings that stay prose > are recorded as findings and do **not** count as delivery. @@ -262,21 +276,12 @@ was written to stop, one level down. Where the instrument is built later in the pass, the target is marked `provisional:` until the instrument emits it, and the spec is amended to whatever the instrument returns. -*(v1.1, from CB-WP-0002: `specs/CostAccounting.md` AC-1 named -`cb-cost --pin fc76445` before that tool existed, and set the target to -a hand-computed $92.87. When the tool was built it returned $93.32 — -the hand computation carried a dedup bug the tool's own positive control -caught. The metric satisfied v1.0's rule completely and was still -wrong.)* +*Case: `InnerLoopReference.md` §Numbers you inherit.* **A number inherited from earlier work is re-derived before it is used as a target, or it is cited as unverified.** Quoting is not measuring. -*(v1.1, from CB-WP-0002: the workplan opened with $248.46, inherited -from a prior pass. Re-derivation put it at $92.21 — the quoted figure -double-counted transcript lines and priced a three-model session at one -model's rate. Neither error was of the harness-does-nothing class; both -sums ran over real data, and a positive control would have passed them.)* +*Case: `InnerLoopReference.md` §Numbers you inherit.* **Retargeting: the instrument may move a target, the implementation may not.** A metric's target changes in only two ways, and they are not @@ -292,13 +297,9 @@ mechanical: **a correction is one where the target moves and the implementation does not.** If the same commit changes both the target and the code the target measures, it is a retarget and needs the ADR. -*(v1.1, from CB-WP-0002/0003: AM-4's targets were measured at 246,250 and -set at 250,000 in one commit by the implementer after seeing the number — -the structure this rule exists to stop. But CB-WP-0002 then moved AC-1 -three times, correctly, each time because a new instrument disproved the -old figure ($92.21 → $92.87 → $93.32 → $93.15). A blanket prohibition -would have forbidden four legitimate corrections to catch one bad -retarget.)* +*The case that produced this rule, and the four legitimate corrections a +blanket prohibition would have forbidden: `InnerLoopReference.md` +§Retargeting.* **Applied retroactively:** AM-4a and AM-4b are **unratified** until an ADR is written or they are changed. They were set by the implementer after diff --git a/specs/InnerLoopReference.md b/specs/InnerLoopReference.md index 6710fd0..771decc 100644 --- a/specs/InnerLoopReference.md +++ b/specs/InnerLoopReference.md @@ -297,3 +297,87 @@ step pointed there.** Mutating it settled it in one command. Both are verification steps that inherited the author's blindness, and both fixes replace re-derivation with **adversarial execution**. + +## Quoting a cost — six for six, never high + +*(CB-WP-0019 T03, 2026-08-03. The rule lived only in evidence files and +had been re-derived three times before it was written down.)* + +| pass | reported mid-flight | settled | under by | +|---|---|---|---| +| CB-WP-0009 | $6.73 | $11.31 | 40% | +| CB-WP-0011 | $4.23 | $7.02 | 40% | +| CB-WP-0012 | $8.82 | $14.52 | 39% | +| CB-WP-0013 | $5.78 | $8.26 | 30% | +| CB-WP-0015 | $15.14 | $22.70 | 33% | +| CB-WP-0017 | $5.19 | $9.48 | 45% | + +**Six for six, always low, never by less than 30%.** That is systematic +bias, not noise, and it has two causes — both of which must be fixed or +the rule does not hold: + +1. **The boundary.** A pass's spend window runs to the **next** pass's + first commit, so a pass is not final until the one after it starts. + Quoting "the previous pass" is therefore still too early if the pass + after it has not been declared. (CB-EV-0013 §5.) +2. **The reading.** *A figure read earlier in a session is an in-flight + figure regardless of whose name is on it.* CB-EV-0014 quoted + CB-WP-0015 at $15.14/136 and called it settled; it had been read during + CB-WP-0015 itself and settled at $22.70/166 — 50% higher. Quoting from + memory defeats the rule even when the boundary is right. + (CB-EV-0015 §6.) + +**Which is load bearing?** The second. CB-WP-0018 T04 applied it alone — +re-running `make status` at the moment of writing — and the figure it +quoted was correct. The boundary matters only because re-running early +still reads an open window; re-running *late* fixes both. So the +operative instruction is **re-run the instrument when you quote it**, and +the boundary rule is what tells you when "late enough" has arrived. + +## Retargeting — the case, and the four corrections it must not forbid + +*(v1.1, from CB-WP-0002/0003. Moved out of `InnerLoop.md` by CB-WP-0019 +T03 at the loadability limit.)* + +**The bad retarget.** AM-4's targets were measured at 246,250 and set at +250,000 in one commit, by the implementer, after seeing the number. That +is the structure the rule exists to stop: a target chosen to fit the +reading rather than a reading judged against a target. + +**The four good corrections.** CB-WP-0002 then moved AC-1 three times — +$92.21 → $92.87 → $93.32 → $93.15 — each because a *new instrument* +disproved the old figure. A blanket prohibition on moving a target would +have forbidden all four to catch the one. + +Hence the mechanical test rather than an appeal to intent: **a correction +is one where the target moves and the implementation does not.** If one +commit changes both the target and the code that target measures, it is a +retarget and needs an ADR. + +CB-WP-0019 T01 is a worked example on the good side: AM-4b's target moved +745,000 while the code it measures did not change at all — only the +instrument's scope did, and its output is in the same commit. + +## Numbers you inherit — two cases from CB-WP-0002 + +*(v1.1. Moved out of `InnerLoop.md` by CB-WP-0019 T03.)* + +**A target set before its instrument existed.** `specs/CostAccounting.md` +AC-1 named `cb-cost --pin fc76445` before that tool was built, and set the +target to a hand-computed **$92.87**. When the tool existed it returned +**$93.32** — the hand computation carried a dedup bug the tool's own +positive control caught. *The metric satisfied v1.0's rule completely and +was still wrong.* + +**A number quoted rather than measured.** The workplan opened with +**$248.46**, inherited from a prior pass. Re-derivation put it at +**$92.21**: the quoted figure double-counted transcript lines and priced a +three-model session at one model's rate. + +Neither error was of the harness-does-nothing class — both sums ran over +real data, and a positive control would have passed them. That is why the +rule is *re-derive before using as a target, or cite as unverified*, and +not merely *add a control*. + +**Quoting is not measuring** — the same sentence the cost-quoting rule +above rests on, learned here first and re-learned six times since. diff --git a/tools/loop-lint.py b/tools/loop-lint.py index be436b7..d8b7d60 100644 --- a/tools/loop-lint.py +++ b/tools/loop-lint.py @@ -94,6 +94,102 @@ def check_evidence_no_unmeasured(root=REPO): return out +def check_own_cost_not_quoted(root=REPO): + """§Quoting a cost — an evidence file may not quote its own pass's + cost as final. + + Six passes under-reported themselves by 30-45%, never once high, so a + self-quoted figure is not a rounding error but a known bias. The check + is deliberately narrow: it fires only when a line names the file's OWN + workplan beside a dollar amount and does not mark it provisional. + Quoting an earlier pass is exactly what the rule asks for. + + **Binds forward, from the pass that wrote it down.** The rule was + written in CB-WP-0019 after six passes had each under-reported + themselves, and those six evidence files are the *evidence for the + rule*. Firing on them would demand the record be edited to remove the + thing it proves — the same category error as putting a live `fact:` + tag on a dated measurement. So the check applies from CB-WP-0019 on, + and the older figures stay as they were reported. + """ + BINDS_FROM = 19 + out = [] + base = os.path.join(root, "evidence") + if not os.path.isdir(base): + return out + for f in sorted(os.listdir(base)): + if not f.endswith(".md"): + continue + rel = os.path.join("evidence", f) + text = open(os.path.join(root, rel)).read() + # The pass an evidence file belongs to is named in its header. + m = re.search(r"\b(CB-WP-\d{4})\b", text) + if not m: + continue + own = m.group(1) + if int(own.rsplit("-", 1)[1]) < BINDS_FROM: + continue + for i, line in enumerate(text.splitlines(), 1): + if own not in line or "$" not in line: + continue + if "provisional" in line.lower() or "not quoted" in line.lower(): + continue + out.append( + Finding("own-cost", f"{rel}:{i}", + f"quotes {own}'s own cost as final; re-run the " + f"instrument and quote a settled pass, or mark it " + f"provisional") + ) + return out + + +def check_workplan_lifecycle(root=REPO): + """§Workplan lifecycle — `ready` means declared and NOT started. + + A workplan with work done in it that still says `ready` answers the + wrong question: the status should say whether anyone is on it, not + only whether it is finished. + """ + out = [] + base = os.path.join(root, "workplans") + if not os.path.isdir(base): + return out + for f in sorted(os.listdir(base)): + if not f.endswith(".md"): + continue + rel = os.path.join("workplans", f) + text = open(os.path.join(root, rel)).read() + m = re.search(r"^status:\s*(\S+)", text, re.M) + if not m: + continue + status = m.group(1) + # Parse the ```task blocks, not every `status:` in the file. The + # first version stripped the leading match assuming it was the + # frontmatter — which silently dropped a real task the moment the + # frontmatter said `ready` or `active`, because those do not match + # the task vocabulary. Caught by this check's own self-test. + tasks = [ + t.group(1) + for block in re.findall(r"```task\n(.*?)```", text, re.S) + for t in [re.search(r"^status:\s*(\S+)", block, re.M)] + if t + ] + if not tasks: + continue + closed = sum(1 for t in tasks if t in ("done", "cancel")) + started = closed > 0 + if status == "ready" and started: + out.append(Finding("lifecycle", rel, + "still `ready` but work has started — use `active`")) + elif status == "active" and closed == len(tasks): + out.append(Finding("lifecycle", rel, + "every task is closed but status is `active` — use `done`")) + elif status == "done" and closed != len(tasks): + out.append(Finding("lifecycle", rel, + f"`done` with {len(tasks) - closed} task(s) still open")) + return out + + def check_survey_tier_and_chaos(root=REPO): """§Loop tiers — tier declared, and the chaos roll recorded every time.""" out = [] @@ -213,6 +309,8 @@ def check_gate_registry(root=REPO): CHECKS = ( check_loadability, check_evidence_no_unmeasured, + check_own_cost_not_quoted, + check_workplan_lifecycle, check_survey_tier_and_chaos, check_review_trail, check_reporting_tools_self_test, @@ -245,6 +343,53 @@ def self_test(): len(f) == 1 and "Big.md" in f[0].path, f"{len(f)} finding(s)") + # own-cost: a file quoting its OWN pass beside a dollar amount + # trips; the same line marked provisional does not; and a file + # quoting an EARLIER pass does not, because that is the rule. + def ev(name, body): + with open(os.path.join(tmp, "evidence", name), "w") as fh: + fh.write(body) + ev("CB-EV-0100-self.md", "CB-WP-0019 T04.\n| CB-WP-0019 | $9.99 |\n") + f = check_own_cost_not_quoted(tmp) + check("own-cost detects a pass quoting itself", len(f) == 1, + f"{len(f)} finding(s)") + ev("CB-EV-0100-self.md", + "CB-WP-0019 T04.\n| CB-WP-0019 | $9.99 provisional |\n") + check("own-cost accepts a figure marked provisional", + not check_own_cost_not_quoted(tmp)) + ev("CB-EV-0100-self.md", "CB-WP-0019 T04.\n| CB-WP-0018 | $28.08 |\n") + check("own-cost accepts quoting an EARLIER pass", + not check_own_cost_not_quoted(tmp)) + # and it binds forward: the six passes that PROVE the rule are the + # evidence for it, and must not be edited to satisfy it. + ev("CB-EV-0100-self.md", "CB-WP-0009 T04.\n| CB-WP-0009 | $6.73 |\n") + check("own-cost binds forward, not over the record it rests on", + not check_own_cost_not_quoted(tmp)) + os.remove(os.path.join(tmp, "evidence", "CB-EV-0100-self.md")) + + # lifecycle: `ready` with work started trips; `active` does not. + def wp(status, tasks): + body = f"---\nid: CB-WP-0100\nstatus: {status}\n---\n" + for t in tasks: + body += f"\n```task\nid: CB-WP-0100-T\nstatus: {t}\npriority: high\n```\n" + with open(os.path.join(tmp, "workplans", "CB-WP-0100-x.md"), "w") as fh: + fh.write(body) + wp("ready", ["done", "todo"]) + f = check_workplan_lifecycle(tmp) + check("lifecycle detects `ready` after work has started", + len(f) == 1 and "active" in f[0].detail, f"{len(f)} finding(s)") + wp("active", ["done", "todo"]) + check("lifecycle accepts `active` mid-flight", + not check_workplan_lifecycle(tmp)) + wp("active", ["done", "cancel"]) + f = check_workplan_lifecycle(tmp) + check("lifecycle detects `active` when everything is closed", + len(f) == 1 and "done" in f[0].detail, f"{len(f)} finding(s)") + wp("done", ["done", "todo"]) + check("lifecycle detects `done` with an open task", + len(check_workplan_lifecycle(tmp)) == 1) + os.remove(os.path.join(tmp, "workplans", "CB-WP-0100-x.md")) + # gates: an unclassified `all:` dependency trips, and so does an # entry naming a target the Makefile lacks. with open(os.path.join(tmp, "Makefile"), "w") as fh: diff --git a/workplans/CB-WP-0019-the-am4-family.md b/workplans/CB-WP-0019-the-am4-family.md index 99e0384..557316f 100644 --- a/workplans/CB-WP-0019-the-am4-family.md +++ b/workplans/CB-WP-0019-the-am4-family.md @@ -2,7 +2,7 @@ id: CB-WP-0019 kind: meta title: "Budgets: what the meta budget is for, AM-4b's scope, and the self-quoting rule" -status: todo +status: done state_hub_workstream_id: "ecf35aae-8549-4338-9e13-21dcf14c1130" --- @@ -151,7 +151,7 @@ of two. The `unmeasured` note is gone from `dep-weight.py` and the spec. ```task id: CB-WP-0019-T03 -status: todo +status: done priority: high state_hub_task_id: "b473ab42-8fd9-47b1-8fd4-b181c75440be" ``` @@ -187,6 +187,30 @@ re-derived three times already. both? T03 of CB-WP-0018 used the second and it worked. Say which is load bearing. +**Done 2026-08-03.** InnerLoop v1.7 + `loop-lint`'s `own-cost` check. + +**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; the boundary rule only tells you when "late enough" has arrived. +So the operative instruction is **re-run the instrument when you quote +it**, 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**, and that is not a convenience: 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 and also fixed by marking rather +than rewriting. + +Also delivered here at the maintainer's instruction: the **workplan +lifecycle** `ready` → `active` → `done`, with `loop-lint` failing a +workplan that has started and still says `ready`. **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`. It now parses the task +blocks. + ## Task: say what the meta budget is *for*, and set it at 80/20 ```task @@ -278,7 +302,7 @@ standing precedent it exists to enforce. ```task id: CB-WP-0019-T04 -status: todo +status: done priority: high state_hub_task_id: "b499acb2-b728-4db9-9714-c235fb6c6363" ``` @@ -299,3 +323,22 @@ state_hub_task_id: "b499acb2-b728-4db9-9714-c235fb6c6363" have failed passes that were plainly right to run, say so — that is the ratio being wrong, not the passes. - **Chaos: declaration 2 of 12 in window 2, first roll at d8.** + +**Done 2026-08-03.** +[CB-EV-0017](../evidence/CB-EV-0017-budgets.md). `make all` exits 0. + +- **The AM-4 family is closed** — four defects across five passes, none + found by looking for them. Where a fifth would be: AM-4c is a + diagnostic nobody reads, and `own source` has no instrument at all. +- **Three of this project's own controls fired on this pass**, none of + them its subject: the stale mutation string (**build-free**, second + catch for CB-WP-0015's check and the first that cost nothing), the DFD + gate on `facts.toml`, and loadability three times — fixed structurally + each time, the precedent now holding five times. +- **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 T03/T05's 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.**