[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:
David F Glidden
2026-09-09 21:55:51 +02:00
co-authored by Claude Opus 5
parent bf1bd802a2
commit 049ca57a35
2 changed files with 46 additions and 3 deletions
+19 -3
View File
@@ -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
# copy of `acceptable()` is a second, quietly divergent standard.
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)
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 timeout path returns silence, not a line",
"log_silence(f\"seam generation exceeded" in src and "TimeoutExpired" in src)
ck("S3 rejection log keeps the evidence, not just the verdict",
"line[:200]" in src and "log_silence(why, line)" in src)
# ⚠ AIMED AT THE WRITER'S FILE, NOT THIS ONE. The 200-character truncation lives
# 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",
source_lacks(__file__, "FALLBACK", "_LINE"))