R-404: the golden NOTICE, in the repo where the debt is created - NOT A RELEASE
gates / gates (push) Successful in 12s
gates / gates (push) Successful in 12s
No version heading on purpose. No Go code, no image, no version bump; giving this one would create the exact golden debt the change is about. Until today this repo - where a release actually happens - had NO golden-currency check at all, while felhom.eu ran one on every push including documents-only ones that can neither create the debt nor clear it. The person who could act heard nothing; the person who could not act was blocked, thirteen --no-verify uses' worth. golden_notice.py is ADVISORY IN EVERY CASE, and that is the only correct behaviour rather than timidity: at the moment a release is committed the golden legitimately does not exist yet, so blocking there would refuse the commit that STARTS the process - and blocking later is the mistake being undone. NO SECOND IMPLEMENTATION: it IMPORTS felhom.eu/scripts/golden_currency_gate.py and calls that gate's own released_versions()/newest_baked(), so it is the same comparison read in the other direction. Cross-repo shape copied from instructions_gate.py; never a copy of the script, because a copy recreates the drift these gates exist to detect. An absent sibling clone is INCONCLUSIVE and silent about currency - it never guesses. controller_gates.py GAINED A FIFTH `blocking` FIELD. It could not express a reporting-only gate at all before: every registered gate's non-zero exit failed the run, so the only way to add a notice was to give it the power to refuse a push. The capability was added rather than the notice compromised (R-420). False for exactly one gate, and test_golden_notice.py asserts it stays one. Tests N1-N4 with a positive control that every other gate is still blocking. RED-PROOF RUN: making the debt branch return 1 fails N1 - in production that would refuse the commit that starts a release.
This commit is contained in:
@@ -52,28 +52,44 @@ SHARED_INSTRUCTIONS = os.path.join(
|
||||
SHARED_OBSERVATIONS = os.path.join(
|
||||
os.path.dirname(REPO), "felhom.eu", "scripts", "observations_gate.py")
|
||||
|
||||
# (label, absolute script path, args, fast)
|
||||
# R-404 — the golden NOTICE. Lives here, beside the runner, because it is about THIS repo's
|
||||
# releases; it imports the felhom.eu gate rather than copying its comparison.
|
||||
GOLDEN_NOTICE = os.path.join(SCRIPTS, "golden_notice.py")
|
||||
|
||||
# (label, absolute script path, args, fast, blocking)
|
||||
#
|
||||
# `blocking` — R-404, 2026-09-01. FALSE means this gate REPORTS and never changes the runner's exit
|
||||
# code. Before this the runner could not express such a gate at all: every registered gate's
|
||||
# non-zero exit failed the run, so the only way to add a notice was to give it the power to refuse
|
||||
# a push. That was the wrong trade for the golden notice, whose whole point is that it fires at the
|
||||
# moment a release is committed — when the golden legitimately does not exist yet and refusing
|
||||
# would be absurd. The capability was added rather than the notice compromised.
|
||||
#
|
||||
# It is FALSE for exactly one gate. Everything else blocks, as it always has.
|
||||
GATES = [
|
||||
("template-id", os.path.join(SCRIPTS, "template_id_gate.py"), [], True),
|
||||
("emoji", os.path.join(SCRIPTS, "emoji_gate.py"), [], True),
|
||||
("native-confirm", os.path.join(SCRIPTS, "native_confirm_gate.py"), [], True),
|
||||
("offbox-rename", os.path.join(SCRIPTS, "offbox_rename_gate.py"), [], True),
|
||||
("app-row-dedup", os.path.join(SCRIPTS, "app_row_dedup_gate.py"), [], True),
|
||||
("mojibake", os.path.join(SCRIPTS, "mojibake_gate.py"), [], True),
|
||||
("docker-v", os.path.join(SCRIPTS, "docker_run_volume_path_gate.py"), [], True),
|
||||
("secret-markup", os.path.join(SCRIPTS, "secret_in_markup_gate.py"), [], True),
|
||||
("retrieval-promise", os.path.join(SCRIPTS, "retrieval_promise_gate.py"), [], True),
|
||||
("template-id", os.path.join(SCRIPTS, "template_id_gate.py"), [], True, True),
|
||||
("emoji", os.path.join(SCRIPTS, "emoji_gate.py"), [], True, True),
|
||||
("native-confirm", os.path.join(SCRIPTS, "native_confirm_gate.py"), [], True, True),
|
||||
("offbox-rename", os.path.join(SCRIPTS, "offbox_rename_gate.py"), [], True, True),
|
||||
("app-row-dedup", os.path.join(SCRIPTS, "app_row_dedup_gate.py"), [], True, True),
|
||||
("mojibake", os.path.join(SCRIPTS, "mojibake_gate.py"), [], True, True),
|
||||
("docker-v", os.path.join(SCRIPTS, "docker_run_volume_path_gate.py"), [], True, True),
|
||||
("secret-markup", os.path.join(SCRIPTS, "secret_in_markup_gate.py"), [], True, True),
|
||||
("retrieval-promise", os.path.join(SCRIPTS, "retrieval_promise_gate.py"), [], True, True),
|
||||
# R-400 — every debug-page control resolves to a handler, and every handler is reachable.
|
||||
# Registered AFTER the seven dead controls were implemented or deleted: a registered-but-failing
|
||||
# gate refuses every push, so the order matters here exactly as it did for instructions_gate.
|
||||
("debug-routes", os.path.join(SCRIPTS, "debug_route_gate.py"), [], True),
|
||||
("reuse-refs", SHARED_REUSE, [REPO], True),
|
||||
("instructions", SHARED_INSTRUCTIONS, [REPO], True),
|
||||
("debug-routes", os.path.join(SCRIPTS, "debug_route_gate.py"), [], True, True),
|
||||
("reuse-refs", SHARED_REUSE, [REPO], True, True),
|
||||
("instructions", SHARED_INSTRUCTIONS, [REPO], True, True),
|
||||
# R-389 — a REPORT.md observation with no register row behind it. Fast: stdlib file reads.
|
||||
("observations", SHARED_OBSERVATIONS, [REPO], True),
|
||||
("observations", SHARED_OBSERVATIONS, [REPO], True, True),
|
||||
# R-404 — ADVISORY. Reports the golden debt where it is created; never refuses.
|
||||
("golden-notice", GOLDEN_NOTICE, [REPO], True, False),
|
||||
]
|
||||
|
||||
VERDICT = {0: "OK", 1: "FAILED", 2: "INCONCLUSIVE"}
|
||||
ADVISORY = "ADVISORY" # R-404: a non-blocking gate — it reports, it never refuses
|
||||
|
||||
|
||||
def hooks_armed_note(root):
|
||||
@@ -124,21 +140,26 @@ def main(argv):
|
||||
print(" --fast SKIPPED (deliberate periodic runs, never in a hook): %s" % ", ".join(skipped))
|
||||
hooks_armed_note(REPO)
|
||||
|
||||
results = [(label, run_gate(label, path, args)) for label, path, args, _f in selected]
|
||||
results = [(label, run_gate(label, path, args), blocking)
|
||||
for label, path, args, _f, blocking in selected]
|
||||
|
||||
print("\n" + "=" * 78)
|
||||
print("== summary")
|
||||
print("=" * 78)
|
||||
worst = 0
|
||||
for label, rc in results:
|
||||
for label, rc, blocking in results:
|
||||
if not blocking:
|
||||
# A non-blocking gate's exit code is INFORMATION, never a verdict on the push.
|
||||
print(" %-18s %-13s (exit %d, advisory)" % (label, ADVISORY, rc))
|
||||
continue
|
||||
print(" %-18s %-13s (exit %d)" % (label, VERDICT.get(rc, "ERROR"), rc))
|
||||
if rc != 0:
|
||||
worst = 1 if rc == 1 or worst == 1 else 2
|
||||
if worst == 0:
|
||||
print("\nall controller gates OK")
|
||||
return 0
|
||||
convicted = [l for l, rc in results if rc == 1]
|
||||
undecided = [l for l, rc in results if rc not in (0, 1)]
|
||||
convicted = [l for l, rc, b in results if rc == 1 and b]
|
||||
undecided = [l for l, rc, b in results if rc not in (0, 1) and b]
|
||||
if convicted:
|
||||
print("\nCONVICTED: %s" % ", ".join(convicted))
|
||||
if undecided:
|
||||
|
||||
Reference in New Issue
Block a user