[FIX] deferred decisions: check the trigger instead of remembering it
The 2026-05-16 jurist settlement deferred TEI-native authoring "until
Cluster A's MD-with-sidecar form is operational". Cluster A became
operational, the condition was met, and nobody looked — it surfaced months
later by accident, while reading an unrelated document for another purpose.
The steward's stated reason for settling it today was not the format question
at all: "I abhor deferring so many things and then forgetting them."
A deferral is a claim — "not yet". When its trigger fires the substrate
contradicts that claim, which is exactly what this instrument detects, so
check 8 belongs here rather than in a new register. A deferred decision now
declares a machine-checkable trigger in a comment block:
<!-- DEFERRED-DECISION: <slug>
since: YYYY-MM-DD
owner: steward | jurist | executor
trigger: glob <pat> | path-exists <p> | date <YYYY-MM-DD> | manual
discriminator: <where the deciding evidence is written down> -->
`manual` never auto-fires and is listed rather than checked — an honest way
to record a deferral whose condition cannot be mechanised, instead of
inventing a proxy. Proxies are the failure being fixed: the old trigger stood
in for "behavioural evidence on high-fidelity sources" and came true without
producing any, because neither named test case was ever manifested.
Scans */docs/**/*.md under ~/_Dev and ~/dotfiles; glob and path-exists
resolve against the containing repo's root. First and only entry today is
D-5 (tei-native), correctly reported as not due — no protocol spec exists yet.
Controls, five, per the standing epistemic standard. The load-bearing one is
the discriminating half: the evaluator must NOT fire on an unmet condition,
because a checker that fires on everything reports nothing. Red-witnessed
end-to-end by temporarily pointing D-5's trigger at a path that does exist:
reported COME DUE with slug, owner, deferral date, trigger and file; restored
after, and the spec's working tree verified clean.
Also fixed in passing: this file's own report block was briefly duplicated
and misplaced by a `str.replace` without a count, which substituted both
`sys.exit(0)` occurrences including the early-exit branch. Caught by reading
the output — the deferred-decisions line printed twice.
Wake-up §2.c updated to describe all three of the script's reports, and to
require that a COME DUE item be surfaced in the briefing under "What's
unresolved". That is a change to the wake protocol, not only to a
description: a mechanism nobody reads is not a mechanism.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEWjLBP4quXbDPDL2byEzZ
This commit is contained in:
co-authored by
Claude Opus 5
parent
5c4055a071
commit
97ae59a0d3
@@ -15,6 +15,7 @@ Built 2026-07-27 on steward authorization. Exit code is always 0 — this is a
|
|||||||
report, not a gate.
|
report, not a gate.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -255,6 +256,102 @@ control("register check DETECTS an amendment that replaced its record "
|
|||||||
control("register file is reachable", REVIEWED_MD.exists())
|
control("register file is reachable", REVIEWED_MD.exists())
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------ 8. deferred decisions, and their triggers
|
||||||
|
# EARNED 2026-08-07. The jurist settlement of 2026-05-16 deferred TEI-native
|
||||||
|
# authoring "until Cluster A's MD-with-sidecar form is operational". Cluster A
|
||||||
|
# became operational, the condition was met, and NOBODY LOOKED — it surfaced
|
||||||
|
# months later, by accident, while reading an unrelated document. The steward's
|
||||||
|
# stated reason for settling it that day was not the format question but the
|
||||||
|
# forgetting: "I abhor deferring so many things and then forgetting them."
|
||||||
|
#
|
||||||
|
# A deferral is a claim: "not yet". When its trigger fires, the substrate
|
||||||
|
# contradicts that claim — which is exactly what this instrument detects. So a
|
||||||
|
# deferred decision declares a MACHINE-CHECKABLE trigger and this checks it,
|
||||||
|
# rather than relying on anyone to remember.
|
||||||
|
#
|
||||||
|
# <!-- DEFERRED-DECISION: <slug>
|
||||||
|
# since: YYYY-MM-DD
|
||||||
|
# owner: steward | jurist | executor
|
||||||
|
# trigger: glob <pattern> | path-exists <path> | date <YYYY-MM-DD> | manual
|
||||||
|
# discriminator: <where the deciding evidence is written down> -->
|
||||||
|
#
|
||||||
|
# `manual` never auto-fires and is listed rather than checked — an honest way to
|
||||||
|
# record a deferral whose condition genuinely cannot be mechanised, instead of
|
||||||
|
# inventing a proxy. Proxies are what failed here: the old trigger stood in for
|
||||||
|
# "behavioural evidence on high-fidelity sources" and came true without it.
|
||||||
|
DEFERRED_RE = re.compile(
|
||||||
|
r"<!--\s*DEFERRED-DECISION:\s*([a-z0-9][a-z0-9-]*)\s*\n(.*?)-->", re.S)
|
||||||
|
|
||||||
|
SCAN_ROOTS = [HOME / "_Dev", HOME / "dotfiles"]
|
||||||
|
deferrals: list[dict] = []
|
||||||
|
|
||||||
|
|
||||||
|
def _repo_root(p: Path) -> Path:
|
||||||
|
for parent in [p] + list(p.parents):
|
||||||
|
if (parent / ".git").exists():
|
||||||
|
return parent
|
||||||
|
return p.parent
|
||||||
|
|
||||||
|
|
||||||
|
def parse_deferrals(text: str, src: Path) -> list[dict]:
|
||||||
|
out = []
|
||||||
|
for slug, body in DEFERRED_RE.findall(text):
|
||||||
|
fields = dict(re.findall(r"^\s*([a-z-]+):\s*(.+?)\s*$", body, re.M))
|
||||||
|
out.append({"slug": slug, "file": src, "root": _repo_root(src),
|
||||||
|
"trigger": fields.get("trigger", "manual"),
|
||||||
|
"owner": fields.get("owner", "?"),
|
||||||
|
"since": fields.get("since", "?")})
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_fired(d: dict) -> bool | None:
|
||||||
|
"""True = condition met (decision is due). None = not mechanically checkable."""
|
||||||
|
kind, _, arg = d["trigger"].partition(" ")
|
||||||
|
arg = arg.strip()
|
||||||
|
if kind == "glob":
|
||||||
|
return any(d["root"].glob(arg))
|
||||||
|
if kind == "path-exists":
|
||||||
|
return Path(os.path.expanduser(arg)).exists() if arg.startswith(("~", "/")) \
|
||||||
|
else (d["root"] / arg).exists()
|
||||||
|
if kind == "date":
|
||||||
|
return datetime.date.today().isoformat() >= arg
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
for root in SCAN_ROOTS:
|
||||||
|
if not root.is_dir():
|
||||||
|
continue
|
||||||
|
for f in root.glob("*/docs/**/*.md"):
|
||||||
|
try:
|
||||||
|
if f.stat().st_size > 400_000:
|
||||||
|
continue
|
||||||
|
body = f.read_text(errors="replace")
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
if "DEFERRED-DECISION:" in body:
|
||||||
|
deferrals.extend(parse_deferrals(body, f))
|
||||||
|
|
||||||
|
fired = [d for d in deferrals if trigger_fired(d) is True]
|
||||||
|
manual = [d for d in deferrals if trigger_fired(d) is None]
|
||||||
|
|
||||||
|
_T_OK = ("<!-- DEFERRED-DECISION: tei-native\n since: 2026-08-07\n"
|
||||||
|
" owner: steward\n trigger: date 2000-01-01\n-->")
|
||||||
|
_T_WAIT = _T_OK.replace("date 2000-01-01", "date 2999-01-01")
|
||||||
|
_p_ok = parse_deferrals(_T_OK, CLAUDE_MD)
|
||||||
|
_p_wait = parse_deferrals(_T_WAIT, CLAUDE_MD)
|
||||||
|
control("deferred-decision parser reads a well-formed block",
|
||||||
|
len(_p_ok) == 1 and _p_ok[0]["slug"] == "tei-native")
|
||||||
|
control("deferred-decision parser rejects a non-block",
|
||||||
|
not parse_deferrals("<!-- DEFERRED: nope -->", CLAUDE_MD))
|
||||||
|
control("trigger evaluator FIRES on a met condition",
|
||||||
|
_p_ok and trigger_fired(_p_ok[0]) is True)
|
||||||
|
control("trigger evaluator does NOT fire on an unmet condition "
|
||||||
|
"[the discriminating half]",
|
||||||
|
_p_wait and trigger_fired(_p_wait[0]) is False)
|
||||||
|
control("deferred-decision scan surface is reachable",
|
||||||
|
any(r.is_dir() for r in SCAN_ROOTS))
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------- report
|
# ------------------------------------------------------------- report
|
||||||
failed_controls = [lbl for lbl, ok in controls if not ok]
|
failed_controls = [lbl for lbl, ok in controls if not ok]
|
||||||
if failed_controls:
|
if failed_controls:
|
||||||
@@ -290,4 +387,18 @@ elif REVIEWED_MD.exists():
|
|||||||
print(f"✓ register integrity: every amendment link resolves "
|
print(f"✓ register integrity: every amendment link resolves "
|
||||||
f"({n_am} amendment(s) checked)")
|
f"({n_am} amendment(s) checked)")
|
||||||
|
|
||||||
|
# Deferred decisions: a fired trigger is a decision that has come DUE, not a defect.
|
||||||
|
if deferrals:
|
||||||
|
if fired:
|
||||||
|
print(f"\n⏰ deferred decisions: {len(fired)} of {len(deferrals)} have COME DUE")
|
||||||
|
for d in fired:
|
||||||
|
print(f" {d['slug']} — owner: {d['owner']}, deferred since {d['since']}")
|
||||||
|
print(f" trigger MET: {d['trigger']}")
|
||||||
|
print(f" {d['file'].relative_to(HOME)}")
|
||||||
|
print("\n A deferral is the claim 'not yet'. These triggers say otherwise.")
|
||||||
|
else:
|
||||||
|
waiting = len(deferrals) - len(manual)
|
||||||
|
print(f"✓ deferred decisions: {len(deferrals)} tracked, none due "
|
||||||
|
f"({waiting} checkable, {len(manual)} manual-only)")
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user