[FIX] source_has: close the polarity source_lacks missed (PENDING-180)
PENDING-180's own order — (c) census, (b) counterpart, (a) instance. The census swept 15 positive-form source assertions across 8 governed scripts and found exactly one self-planted needle: the one the item filed. tarbuckle-seam.py:165 searched its OWN source for a string that lives only in tarbuckle-mumble.py:142, so it could never have found it and could only ever pass on the copy it had planted in itself. The polarity argument predicted siblings; there are none. The sweep bounds the problem from below — a needle assembled from parts inside a defective control is invisible to it. source_has() joins its needle from parts exactly as source_lacks() does, and ships with the must-fail arm the negative form has had since it was written. The seam control is re-aimed at the writer's file and split into two arms that assert different things, plus S3nn. Verified by mutation rather than by a green selftest: the repaired control FAILS on both mutations, the old form PASSES the one that matters. 136 controls green across the five surfaces. The first mutation did not fail on its first run. The repair's own explanatory comment named the truncation literally and planted a contiguous copy in the file being searched — the bug re-created inside the sentence explaining it. source_lacks/source_has cover the ASSERTION's needle, never the file; prose can plant one. Warned at the site, and filed as a separate decidable question. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsN7nKHjKBsn5bfNRRCNmo
This commit is contained in:
co-authored by
Claude Opus 5
parent
bf1bd802a2
commit
049ca57a35
@@ -191,6 +191,26 @@ def source_lacks(path: str, *parts: str) -> bool:
|
|||||||
return "".join(parts) not in open(path, encoding="utf-8").read()
|
return "".join(parts) not in open(path, encoding="utf-8").read()
|
||||||
|
|
||||||
|
|
||||||
|
def source_has(path: str, *parts: str) -> bool:
|
||||||
|
"""True if the joined needle DOES appear in `path`. The positive counterpart.
|
||||||
|
|
||||||
|
⚠ THIS IS THE POLARITY `source_lacks()` DOES NOT COVER, AND IT IS THE ONE THAT
|
||||||
|
HIDES. Both bugs come from writing a needle as a literal, which plants it in the
|
||||||
|
file being searched. In the NEGATIVE form that makes the control always FAIL —
|
||||||
|
loudly, so it gets fixed. In the POSITIVE form it makes the control always PASS —
|
||||||
|
silently, forever. The louder failure got the mechanism first; this is the quieter
|
||||||
|
one. Assembling from parts is the whole protection, exactly as above.
|
||||||
|
|
||||||
|
⚠ WHAT IT STILL CANNOT SEE: whether the code it finds ever RUNS. A source control
|
||||||
|
is a claim about text, never about behaviour — `tarbuckle-seam.py:165` asserted the
|
||||||
|
rejection log keeps evidence and did not move when condition G made every rejection
|
||||||
|
write path inert (15/15 before, 15/15 after). Aim it at the file that holds the
|
||||||
|
code, and pair it with a behavioural control where activation is the question.
|
||||||
|
PENDING-180.
|
||||||
|
"""
|
||||||
|
return "".join(parts) in open(path, encoding="utf-8").read()
|
||||||
|
|
||||||
|
|
||||||
def soul_register() -> str | None:
|
def soul_register() -> str | None:
|
||||||
"""The soul, verbatim, from the filed artifact. None if unreadable."""
|
"""The soul, verbatim, from the filed artifact. None if unreadable."""
|
||||||
try:
|
try:
|
||||||
@@ -466,6 +486,13 @@ def selftest() -> int:
|
|||||||
ck("A4n the predicate can fail",
|
ck("A4n the predicate can fail",
|
||||||
any(("PENDING" in q) for q in paths + ("/x/PENDING.md",)))
|
any(("PENDING" in q) for q in paths + ("/x/PENDING.md",)))
|
||||||
|
|
||||||
|
# A10 — the positive-form source predicate, with the arm the negative form has had
|
||||||
|
# since it was built. A control that cannot be shown to fail is not evidence.
|
||||||
|
ck("A10 source_has finds a needle that is really there",
|
||||||
|
source_has(__file__, "def source_", "lacks("))
|
||||||
|
ck("A10n the predicate can fail",
|
||||||
|
not source_has(__file__, "def source_", "nowhere("))
|
||||||
|
|
||||||
for name in checks:
|
for name in checks:
|
||||||
print(f" {'FAIL' if name in failed else 'ok '} {name}")
|
print(f" {'FAIL' if name in failed else 'ok '} {name}")
|
||||||
print(f"{len(checks) - len(failed)}/{len(checks)} controls passed")
|
print(f"{len(checks) - len(failed)}/{len(checks)} controls passed")
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|||||||
# reimplementing is the "one canonical source" rule applied to a constraint: a second
|
# reimplementing is the "one canonical source" rule applied to a constraint: a second
|
||||||
# copy of `acceptable()` is a second, quietly divergent standard.
|
# copy of `acceptable()` is a second, quietly divergent standard.
|
||||||
from tarbuckle_mumble_shim import (acceptable, soul_register, session_material, # noqa: E402
|
from tarbuckle_mumble_shim import (acceptable, soul_register, session_material, # noqa: E402
|
||||||
source_lacks, muted, log_event, # noqa: E402
|
source_lacks, source_has, muted, log_event, # noqa: E402
|
||||||
echoes_soul, log_rejection, REJECTS)
|
echoes_soul, log_rejection, REJECTS)
|
||||||
|
|
||||||
LAST_TICK = os.path.expanduser("~/.claude/state/tarbuckle-last-tick")
|
LAST_TICK = os.path.expanduser("~/.claude/state/tarbuckle-last-tick")
|
||||||
@@ -161,8 +161,24 @@ def selftest() -> int:
|
|||||||
ck("S3 generation is bounded", SEAM_TIMEOUT_S <= 20)
|
ck("S3 generation is bounded", SEAM_TIMEOUT_S <= 20)
|
||||||
ck("S3 timeout path returns silence, not a line",
|
ck("S3 timeout path returns silence, not a line",
|
||||||
"log_silence(f\"seam generation exceeded" in src and "TimeoutExpired" in src)
|
"log_silence(f\"seam generation exceeded" in src and "TimeoutExpired" in src)
|
||||||
ck("S3 rejection log keeps the evidence, not just the verdict",
|
# ⚠ AIMED AT THE WRITER'S FILE, NOT THIS ONE. The 200-character truncation lives
|
||||||
"line[:200]" in src and "log_silence(why, line)" in src)
|
# in the canonical writer (tarbuckle-mumble.py); the old form searched THIS source
|
||||||
|
# for it, found only the copy it had planted in itself, and could only ever pass.
|
||||||
|
# ⚠⚠ AND THE NEEDLE CAN BE PLANTED BY PROSE. Naming that truncation literally in
|
||||||
|
# this comment re-created the bug in the sentence explaining it — caught by mutation
|
||||||
|
# test, not by the selftest. source_has/source_lacks assemble the ASSERTION's needle
|
||||||
|
# from parts; nothing stops a comment elsewhere in the file planting a contiguous
|
||||||
|
# copy. Do not write the literal here. PENDING-180.
|
||||||
|
# ⚠ AND IT IS A CLAIM ABOUT TEXT, NEVER ABOUT BEHAVIOUR: it did not move when
|
||||||
|
# condition G made every rejection write path inert. Activation is covered
|
||||||
|
# behaviourally by the generator's own G / A8 controls, not here.
|
||||||
|
import tarbuckle_mumble_shim as _shim
|
||||||
|
ck("S3 the canonical writer keeps the evidence, not just the verdict",
|
||||||
|
source_has(_shim.__file__, "line[:", "200]"))
|
||||||
|
ck("S3 this seam routes rejections through that writer",
|
||||||
|
source_has(__file__, "log_silence(", "why, line)"))
|
||||||
|
ck("S3nn the predicate can fail",
|
||||||
|
not source_has(__file__, "log_silence(", "why, absent)"))
|
||||||
ck("S3n no cached or fallback line exists",
|
ck("S3n no cached or fallback line exists",
|
||||||
source_lacks(__file__, "FALLBACK", "_LINE"))
|
source_lacks(__file__, "FALLBACK", "_LINE"))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user