gate: check 7 (register citations) + content WARNings on the memory index
gates / gates (push) Successful in 8s
gates / gates (push) Successful in 8s
Check 7 catches "cites a register item and calls it open when it is not" -- the R-168 class, four files, one self-contradicting. Trigger is an openness CLAIM, not any citation: policing every mention would fire on ~30 legitimate provenance citations and the gate would be switched off. Deliberate deviation from the task's literal wording, to keep it alive. Two bugs found by the check's own red-proofs, both of which would have shipped: - the state marker is not self-closing (**SHIPPED - text**), so the first parser read R-168 itself as OPEN -- a gate that cannot convict its founding case is decoration; - the CLOSED exemption was line-wide, so "shipped" in a title pardoned "OPEN R-25b". Check 6 gains WARN-only content classes on MEMORY.md. Link targets are stripped first: the earlier scan reported three expired statements, all three false (dates in filenames), while missing the one real expired claim, whose deadline was written ~08-02 with no ISO date. 39 -> 60 assertions. All four runners green.
This commit is contained in:
@@ -295,6 +295,165 @@ def test_memory_store_without_index_fails():
|
||||
check("message says unreachable knowledge", "unreachable knowledge" in out)
|
||||
|
||||
|
||||
# --- check 7: register citations ----------------------------------------------------------------
|
||||
#
|
||||
# The founding case is "CI is still owed (R-168)" shipped four days after R-168 closed, in four
|
||||
# files, one of which contradicted itself. The trigger is an OPENNESS CLAIM, not any citation:
|
||||
# requiring every mention of a non-open item to carry "CLOSED" would fire on ~30 legitimate
|
||||
# provenance citations like "(R-161)" or "R-117 spike §6.3", and a gate that noisy gets switched
|
||||
# off — which is the fate R-29 documented.
|
||||
|
||||
|
||||
def make_register(tmp, rows):
|
||||
"""rows: list of (item, what, state-cell). Mirrors the real 6-column table shape."""
|
||||
d = os.path.join(tmp, "felhom.eu", "documentation", "backlog")
|
||||
os.makedirs(d, exist_ok=True)
|
||||
body = ["| ID | What | State | Blocked on | Next action | Owner |", "|---|---|---|---|---|---|"]
|
||||
for item, what, st in rows:
|
||||
body.append("| **%s** | %s | %s | — | — | operator |" % (item, what, st))
|
||||
with open(os.path.join(d, "OPEN-ITEMS.md"), "w", encoding="utf-8") as fh:
|
||||
fh.write("\n".join(body) + "\n")
|
||||
with open(os.path.join(d, "ROADMAP.md"), "w", encoding="utf-8") as fh:
|
||||
fh.write("| R-900 | a historical item, closed long ago and pruned from OPEN-ITEMS |\n")
|
||||
|
||||
|
||||
REG_ROWS = [
|
||||
("R-168", "~~CI: no runner exists~~", "**SHIPPED — and the alarm is DEMONSTRATED** (2026-08-02)"),
|
||||
("R-161", "volume-persistence gate", "**REDUCED SCOPE — open** (operator ruling)"),
|
||||
]
|
||||
|
||||
|
||||
def test_citation_claiming_open_about_a_closed_item_fails():
|
||||
"""The founding case, verbatim."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(tmp, "# Repo\n\nBoth facts are why CI is still owed (`OPEN-ITEMS.md` R-168).\n")
|
||||
rc, out = run_gate(root)
|
||||
check("stale-open citation exits non-zero", rc != 0, "rc=%d" % rc)
|
||||
check("message names the item", "R-168" in out)
|
||||
check("message says the register disagrees", "register says it is closed" in out)
|
||||
|
||||
|
||||
def test_citation_that_says_closed_passes():
|
||||
"""Explicitly required by the spec: a correct citation must survive."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(
|
||||
tmp, "# Repo\n\na bypass is noticed even though it is not blocked (R-168, CLOSED 2026-08-02).\n"
|
||||
)
|
||||
rc, out = run_gate(root)
|
||||
check("citation saying CLOSED exits 0", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_bare_provenance_citation_of_a_closed_item_passes():
|
||||
"""Load-bearing negative: citing a closed item as the SOURCE OF A FACT is not a claim it is open."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(tmp, "# Repo\n\nThe canonical runner shape (R-168) is what survives.\n")
|
||||
rc, out = run_gate(root)
|
||||
check("provenance citation of a closed item exits 0", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_openness_claim_about_an_actually_open_item_passes():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(tmp, "# Repo\n\n**R-161 stays open at reduced scope** — enforcement is by convention.\n")
|
||||
rc, out = run_gate(root)
|
||||
check("openness claim about an OPEN item exits 0", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_closed_word_elsewhere_on_the_line_does_not_pardon_a_stale_claim():
|
||||
"""Regression. The exemption is scoped to the citation's CLAUSE, not the whole line.
|
||||
|
||||
`- [Customer RESET shipped](customer-reset-shipped-2026-07-17.md) — …; OPEN R-25b` contains
|
||||
"shipped" twice — once in a title, once in a filename — and a line-wide exemption pardoned the
|
||||
stale claim sitting at the end of it. Found by this check's own red-proof failing to go red,
|
||||
which is the only reason it was found at all."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(
|
||||
tmp,
|
||||
"# Repo\n\n- [Customer RESET shipped](customer-reset-shipped-2026-07-17.md) — "
|
||||
"teardown first; OPEN R-168\n",
|
||||
)
|
||||
rc, out = run_gate(root)
|
||||
check("a distant 'shipped' does not pardon the claim", rc != 0, "rc=%d" % rc)
|
||||
check("the stale item is still named", "R-168" in out)
|
||||
|
||||
|
||||
def test_citation_of_an_item_in_no_register_fails():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(tmp, "# Repo\n\nSee R-4242 for the rationale.\n")
|
||||
rc, out = run_gate(root)
|
||||
check("citation of a nonexistent item exits non-zero", rc != 0, "rc=%d" % rc)
|
||||
check("message says it is in neither register", "NEITHER" in out)
|
||||
|
||||
|
||||
def test_citation_in_an_html_comment_is_not_policed():
|
||||
"""Comments are stripped before injection, so a historical citation parked there costs nothing."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(tmp, "# Repo\n\n<!-- history: CI was still owed (R-168) at the time -->\n")
|
||||
rc, out = run_gate(root)
|
||||
check("citation inside a comment is not policed", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_citation_check_covers_rule_files_too():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_register(tmp, REG_ROWS)
|
||||
root = make_repo(
|
||||
tmp, "# Repo\n",
|
||||
rules={"g.md": '---\npaths: ["**/*.go"]\n---\n\nCI is still owed (R-168).\n'},
|
||||
)
|
||||
rc, out = run_gate(root)
|
||||
check("a rule file's stale citation also fails", rc != 0, "rc=%d" % rc)
|
||||
check("message names the rule file", "g.md" in out)
|
||||
|
||||
|
||||
# --- check 6: content WARNings on the memory index ------------------------------------------------
|
||||
|
||||
|
||||
def test_memory_expired_statement_warns_but_does_not_fail():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_memory(tmp, "# Index\n- [a](a.md) — demo boxes REMOTE till ~08-02\n", topics={"a.md": "# A\n"})
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root)
|
||||
check("expired statement in the index does NOT fail", rc == 0, "rc=%d" % rc)
|
||||
check("expired statement WARNs", "EXPIRED statement" in out)
|
||||
|
||||
|
||||
def test_memory_date_inside_a_link_target_is_not_an_expired_statement():
|
||||
"""THE load-bearing negative. On 2026-08-06 a scan matched the ISO date in the link TARGET and
|
||||
reported three expired statements, every one of them false, while missing the one real expired
|
||||
claim in the same file — whose deadline was written `~08-02` with no ISO date at all."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_memory(tmp, "# Index\n- [Customer RESET](customer-reset-shipped-2026-07-17.md) — teardown first\n",
|
||||
topics={"customer-reset-shipped-2026-07-17.md": "# X\n"})
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root)
|
||||
check("a dated FILENAME is not an expired statement", rc == 0 and "EXPIRED" not in out, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_memory_future_deadline_does_not_warn():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_memory(tmp, "# Index\n- [a](a.md) — rig stays up until 2026-12-31\n", topics={"a.md": "# A\n"})
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root)
|
||||
check("a future deadline does not warn", "EXPIRED" not in out)
|
||||
|
||||
|
||||
def test_memory_version_literal_and_address_warn_but_do_not_fail():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
make_memory(tmp, "# Index\n- [a](a.md) — ctrl 0.162.0 on 192.168.0.180\n", topics={"a.md": "# A\n"})
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root)
|
||||
check("version literal in the index does NOT fail", rc == 0, "rc=%d" % rc)
|
||||
check("version literal WARNs", "version literal" in out)
|
||||
check("host address WARNs", "host address" in out)
|
||||
check("loopback is not reported", "127.0.0.1" not in out)
|
||||
|
||||
|
||||
def main():
|
||||
print("test_instructions_gate")
|
||||
for fn in sorted(
|
||||
|
||||
Reference in New Issue
Block a user