Repository navigation
AC4 arming policy: retired-filename blocks, stale-version warns (each CURRENT_VERSION bump is a measure-then-arm event) #991
Description
standards#960's AC4 gate (scripts/check-launcher-standard-currency.sh) is
implemented + tested + — once the wiring PR lands — wired. This issue records the
arming policy: which defect class blocks, which warns, and the rule for re-measuring
before the warn tier is ever promoted.
Filed per the standing stopping rule (a new scanner finding becomes an issue with
acceptance criteria, not a merge blocker).
The gate emits two defect classes, and they have opposite volatility
| class | predicate | volatility | tier as wired |
|---|---|---|---|
retired-filename |
names launcher-standard.a2ml, a file deleted upstream 2026-09-22 (#952) |
stable — a deleted file stays deleted; a consumer that is clean today cannot become defective without editing the citation itself | fail |
stale-version |
cites a version other than the gate's CURRENT_VERSION |
time-dependent — see below | warn (::warning::, non-blocking) |
Why stale-version cannot block today
The gate compares each citation against CURRENT_VERSION (0.4.0 at time of writing).
When the standard bumps to 0.5.0, every correctly-citing consumer flips to defect with
zero action of its own. That is the guard-asks-a-different-question trap in its
time-delayed form: the gate asks "does this cite the newest version", while the consumer
can only answer "does this cite the version that was newest when I last touched it".
A baked-in cutoff date does not fix this. The docs-gate precedent (check-docs-presence.sh,
#505) could use a date because its missing-CONTRIBUTING population was static — the set
of defective repos only shrank. Here the population is regenerated at every version bump.
⇒ Each CURRENT_VERSION bump is a measure-then-arm event, not a date.
Blast radius as measured (2026-09-22, post-fix)
Census over the estate's consumers of the governance reusable:
distinct consumer slugs 26
with >=1 defect 3
clean 23
| slug | max defects | retired | stale | archived? |
|---|---|---|---|---|
hyperpolymath/tma-mark2 |
7 | 5 | 2 | YES (private) |
metadatastician/canonical-ums |
4 | 3 | 1 | YES (public) |
hyperpolymath/the-nash-equilibrium |
4 | 3 | 1 | no — live, but AC1-exempt and on the DO-NOT-MERGE list (2 corrupt remote branches) |
All three pin the reusable at a SHA, not @main. The 13 @main-pinned consumers carry
zero defects.
⇒ Arming retired-filename at fail tier today reds ZERO live, mergeable consumers.
That is the evidence the fail tier rests on, and it is the number that must be re-measured
before any later promotion.
Acceptance criteria
- The wiring is not vacuous. A seeded
retired-filenamecitation in a consumer's tree
makes thequalityjob red; a seededstale-version-only citation makes it green
with a::warning::. Proven by a mutant, not by reading the YAML —::warning::cannot
fail a job, so a comment claiming "blocks" above a warning asserts the opposite of what
the code does. - A broken invocation fails, never warns. The gate returns rc=2 for a usage error or
a surviving self-test mutant. The wrapper must treat rc=2 as fail. Control: invoke with
a bogus flag and require the step to red. - A vacuous pass is visible. The gate's
check-launcher-standard-currency: canonical=… expected=…
header is echoed unconditionally, so a run that scanned nothing is distinguishable from a
run that scanned and found nothing. - The re-arm rule is honoured. Before
CURRENT_VERSIONis bumped in the gate, the
estate blast radius is re-measured at the new version and posted here. A bump that reds
live consumers is a sweep-then-arm, not a bump. - The
stale-versiontier decision is recorded here when taken — see the open question
below — with the measurement it rests on.
⚖ Open question for the owner
Once an AC1-style sweep confirms stale-version reds 0 live consumers at the then-current
version:
- (a) warn permanently — accept that the class can never block, because the next bump
re-creates the population regardless of any sweep. Simplest; the gate stays informational
for this class forever. - (b) warn until a sweep confirms 0, then promote to fail, and demote back to warn on each
bump — blocks drift between bumps, at the cost of a measure-then-arm ritual attached to
everyCURRENT_VERSIONchange, and a window after each bump where the class is silent.
Both are defensible; (b) buys real enforcement between bumps but only if the demote step is
never skipped, and a skipped demote reds the whole estate. Recording the choice here rather
than leaving it to decay.
References
hyperpolymath/standards#960— the parent AC set (AC4)hyperpolymath/standards#983— the gate itself (mergededac0d6a)hyperpolymath/standards#990— the false-positive cure + this wiringhyperpolymath/standards#952— the upstream deletion oflauncher-standard.a2mlhyperpolymath/standards#505— the docs-gate split-tier precedent
🤖 Generated with Claude Code
Activity
ci: wire the launcher-standard currency gate
fix(ci): cure the AC4 currency gate's false positives, and wire it (#990