ADR-0021: the chaos roll is retired, and the condition that retired it was wrong
Some checks failed
ci / check (push) Failing after 4s

The condition is met and the tally was verified rather than recalled.
ADR-0017 D2 named window 3 as the decider; windows 2 and 3 each produced
exactly one override and each changed nothing. Every roll in window 3 was
cross-checked against the workplan that made it, because the last time
this project tallied chaos rolls from memory it was wrong and asserted the
wrong figure four times (F23). All twelve agree.

But meeting the condition is not evidence. P(an override changes nothing)
is 1/3, and each window had exactly one override, so the condition fires
on a 1/9 coincidence. ADR-0017 restated it to be REACHABLE and made it
weak in the process; reachability was checked and discriminating power was
not.

Worse, it measures the wrong subject. It asks whether an override changed
the tier; the question is whether changing the tier helped. Under it, a
die that always changed the tier could never be retired however useless
its changes were.

The real ground is stronger. Four overrides across roughly forty
declarations, and the mechanism's value has never once been demonstrated.
The one substantive intervention dropped CB-WP-0011 from a structural L to
S, and that work then needed CB-WP-0016 and CB-WP-0017 to fix defects a
human found by playing. Not offered as causation — a tier is process
weight, not a guarantee — but it is the only evidence we have about an
override's consequences and it points the wrong way.

And the purpose has no live evidence of need: 17 M, 11 S, 4 L across every
workplan, with the only two structural/declared mismatches being the
window-1 overrides themselves. Tier declaration has not ossified.

So: retired, with nothing replacing it. Adding a successor to guard
against ossification that has not occurred would invent a gate for an
instance we do not have. The revival trigger is stated: tiers collapsing
toward one value, or a pass declaring below its structural tier to dodge a
review.

InnerLoop loses the chaos paragraph, loop-lint loses the chaos-recorded
check — a check that outlives its rule becomes an obstruction — and its
self-test now asserts the opposite: a note with no roll must pass.
ChaosRollHistory is closed. Window 4 ends incomplete at four declarations,
the last of which is this one, rolled because the rule was still in force.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-08 15:51:52 +02:00
parent b0001b5760
commit 05d1a9aada
4 changed files with 183 additions and 46 deletions

View file

@ -191,7 +191,13 @@ def check_workplan_lifecycle(root=REPO):
def check_survey_tier_and_chaos(root=REPO):
"""§Loop tiers — tier declared, and the chaos roll recorded every time."""
"""§Loop tiers — the tier is declared.
**The chaos half is retired** (ADR-0021, 2026-08-08). Requiring the
roll would fail every future research note: a check that outlives its
rule stops being a control and becomes an obstruction. The name is
kept because `gates.toml` and the self-tests refer to it.
"""
out = []
base = os.path.join(root, "research")
if not os.path.isdir(base):
@ -203,12 +209,6 @@ def check_survey_tier_and_chaos(root=REPO):
text = open(os.path.join(root, rel)).read()
if not re.search(r"^tier:\s*[SML]\b", text, re.M):
out.append(Finding("tier-declared", rel, "no `tier:` declaration"))
elif "chaos" not in text.lower():
out.append(
Finding("chaos-recorded", rel,
"tier declared without the chaos roll; the rule requires "
"recording it even when it changes nothing")
)
return out
@ -644,15 +644,20 @@ def self_test():
check("evidence-unmeasured detects a table verdict, not prose",
len(f) == 1, f"{len(f)} finding(s), expected exactly 1")
# tier/chaos: missing tier trips; tier without chaos trips.
with open(os.path.join(tmp, "research", "A.md"), "w") as fh:
fh.write("# survey\nno tier here\n")
with open(os.path.join(tmp, "research", "B.md"), "w") as fh:
fh.write("tier: L (structural L)\n")
# tier: a missing declaration trips. The chaos half is retired
# (ADR-0021), so a note without a roll must now PASS — the
# control that used to require one would fail every new note.
os.makedirs(os.path.join(tmp, "research"), exist_ok=True)
with open(os.path.join(tmp, "research", "CB-RES-9999-x.md"), "w") as fh:
fh.write("---\nid: CB-RES-9999\n---\n\nno tier here\n")
f = check_survey_tier_and_chaos(tmp)
rules = sorted(x.rule for x in f)
check("tier/chaos detects both omissions",
rules == ["chaos-recorded", "tier-declared"], f"{rules}")
check("tier: a survey with no tier declaration is caught",
len(f) == 1 and f[0].rule == "tier-declared", f"{[x.rule for x in f]}")
with open(os.path.join(tmp, "research", "CB-RES-9999-x.md"), "w") as fh:
fh.write("---\nid: CB-RES-9999\ntier: M\n---\n\nno chaos line\n")
check("tier: a survey with no chaos roll now PASSES",
not check_survey_tier_and_chaos(tmp),
"ADR-0021 retired the roll; requiring it would fail every new note")
# self-test: a tool without the flag trips.
with open(os.path.join(tmp, "tools", "silent.py"), "w") as fh: