[FIX] Reduction 02: package reduces to 68.6% — the genre reading confirmed, Reduction 01 corrected

Prediction recorded in Reduction 01 BEFORE this census, so it could fail: the
package's Part I is 'Grounding (quoted verbatim)' and quotes CLAUDE.md directly,
so Q should be non-zero where it was zero. Q=9. D=40, where the ruling had none.

                 ruling    package
  sound           8.5%      68.6%
  PERFORMATIVE      12          0      <- the genre signature
  BLEND              9         25
  INHERITED          4          0
  UNSOURCED-QUOTE    3          0      <- §1's header clause worked

Genre reading confirmed eightfold: a package proposes, a ruling determines.

CORRECTS Reduction 01's strong conclusion that 'the reduction arm collapses into
the synthetic arm'. On package prose repair touches 31.4%, not 91.5% — reduction,
not authoring, and the two arms stay distinct. That conclusion was correctly
bounded at n=1; the bound was the whole of its content and one document collapsed
it. Reduction 01 now carries the correction inline.

BLEND is now the blocker and is genre-independent: 25 of 33 quarantines, 7 of
them rows of the Part IV table, which pairs a quote with an end-state and a
verdict — three primitives by construction.

Two check findings, one good and one bad:

§3.2 CAUGHT A REAL TAGGING ERROR OF MINE. Unit 145 was tagged Q; it is a sentence
ABOUT a quotation, not a quotation, so not verbatim-as-a-unit. Corrected to D.
The check found it, the reading did not — the 'quoted but not traced' defect the
jurist caught on 2026-07-19, mechanised.

§3.3 GAVE A FALSE PASS, found by looking. Part VII 'Disconfirming evidence' IS a
collected limitations section under §2a — the exact section trial 03 showed the
model skipping wholesale — and the screen missed it because it never says
'limitations'. Widened; the package now correctly FAILS §3.3. But no pattern can
decide this: a section titled only 'Part VII' defeats any wordlist, and a control
now asserts that. §3.3 is a SCREEN, not a decision; §2a belongs in §4's judgement
residue. Fourth time in three days a passing check certified the code while the
property failed, and the fourth found by a person looking.

A=0 IN BOTH DOCUMENTS, and it is the same fact as the §2a failure seen from the
other side: we do not name assumptions inline, we collect them into a section.
Our best governance prose is written in exactly the shape that defeats the reader
the section was written for.

Also fixed: the tool was still printing 'NOT checked here: §3.2' after §3.2 was
implemented — under-claiming, but still a false statement about what ran.

Kernel v1.1 candidates are now evidence-backed and remain UNAPPLIED; v1.0 stays
frozen and a revision is a new experiment. The false-positive control remains
unrun and neither reduction produced a usable control document.
This commit is contained in:
David F Glidden
2026-08-02 17:57:53 +02:00
parent 1ebaf6aba5
commit 4408506ffa
6 changed files with 593 additions and 199 deletions
+132 -8
View File
@@ -46,7 +46,15 @@ from pathlib import Path
# (c) a `?` inside a quotation split a sentence mid-clause, yielding a FRAGMENT
# ("…asserts to be true?" | "alone — is less safe…"). Tagging a fragment is
# meaningless, so it must not be produced.
SPLITTER_VERSION = "1.1.0"
# 1.2.0 — two further defects, again found by contact rather than review, this
# time on a package rather than a ruling:
# (d) a numbered marker ("**1.", "2.") was read as a sentence end, orphaning the
# marker as a fragment and decapitating the sentence after it.
# (e) YAML frontmatter was treated as flowing prose and shredded mid-key
# (`…quoted verbatim below." status: "DRAFT.`). Frontmatter is line-oriented.
# It stays TAGGABLE — it carries real assertions about the document, and
# excluding it would quietly shrink the quarantine in the author's favour.
SPLITTER_VERSION = "1.2.0"
KERNEL_SHA256 = "67c9b870491db7444e98b680c7c80dcd99de376dda09b3e1758b27b1229ab045"
@@ -81,8 +89,21 @@ QUARANTINE_REASONS = {
}
# Kernel §3.3 — a control document may not collect its caveats into a section.
# Widened after a FALSE PASS on a real package: "Part VII — Disconfirming
# evidence, which the steward specifically asked to be carried" is a collected
# limitations section in §2a's sense — trial 03 showed the model skipping exactly
# that section wholesale — and the original pattern did not match it because it
# never says "limitations".
#
# THIS CHECK IS A SCREEN, NOT A DECISION. No pattern can decide whether a section
# collects the author's own caveats; a section titled "Part VII" alone would defeat
# any wordlist. §2a compliance therefore belongs in Kernel §4's judgement residue,
# and a pass here means only that the obvious namings were absent.
FORBIDDEN_HEADING_RE = re.compile(
r"limitation|caveat|assumption|what this does not|open question", re.IGNORECASE
r"limitation|caveat|assumption|what this does not|open question"
r"|disconfirming|evidence against|weakness|objection|counter-?argument"
r"|self-?critique|known (?:issue|gap|problem)|shortcoming|scope boundary",
re.IGNORECASE,
)
# Abbreviations after which a period does NOT end a sentence. Deliberately short:
@@ -108,6 +129,25 @@ def _is_abbrev(text: str, dot_index: int) -> bool:
return text[start:dot_index].rstrip(".") in ABBREVIATIONS
def _is_enumerator(text: str, dot_index: int) -> bool:
"""
True if the period at dot_index closes a numbered marker such as `1.` or
`**2.` rather than a sentence.
Deliberately narrow: at most two digits, and nothing before them on the line
except markdown emphasis or whitespace. A bare numeric token is NOT enough —
"…formalized in 2026. The next…" is a real boundary and must stay one.
"""
start = dot_index
while start > 0 and text[start - 1].isdigit():
start -= 1
digits = text[start:dot_index]
if not (1 <= len(digits) <= 2):
return False
line_start = text.rfind("\n", 0, start) + 1
return text[line_start:start].strip(" \t*_>#") == ""
def split_prose(block: str, offset: int) -> list[tuple[int, int]]:
"""
Split a prose block into sentence spans as (start, end) absolute offsets.
@@ -120,7 +160,7 @@ def split_prose(block: str, offset: int) -> list[tuple[int, int]]:
cursor = 0
for m in _SENT_END.finditer(block):
dot = m.start(1)
if block[dot] == "." and _is_abbrev(block, dot):
if block[dot] == "." and (_is_abbrev(block, dot) or _is_enumerator(block, dot)):
continue
end = m.end() # include the closing punctuation and the following space
# A sentence-ending mark inside a quotation is usually not the end of the
@@ -149,6 +189,15 @@ def split_spans(text: str) -> list[dict]:
in_fence = False
lines = text.splitlines(keepends=True)
# YAML frontmatter: a `---` on the very first line opens it, the next `---`
# closes it. Line-oriented, so it must not flow into the prose splitter.
fm_end = -1
if lines and lines[0].strip() == "---":
for i in range(1, len(lines)):
if lines[i].strip() == "---":
fm_end = i
break
para: list[str] = []
para_start = 0
@@ -161,8 +210,15 @@ def split_spans(text: str) -> list[dict]:
spans.append({"kind": "prose", "start": s, "end": e})
para = []
for line in lines:
for lineno, line in enumerate(lines):
stripped = line.strip()
if 0 < lineno < fm_end:
flush_para()
spans.append({"kind": "frontmatter", "start": pos, "end": pos + len(line)})
pos += len(line)
continue
fence = stripped.startswith("```")
structural = (
fence
@@ -227,7 +283,7 @@ def verify_tiling(spans: list[dict], text: str) -> list[str]:
# Spans that carry an assertion and therefore require a tag. Headings are
# INCLUDED: kernel §4 rules that "Why the current approach fails" asserts that it
# fails, so a heading is X only if declarative conversion yields no claim.
TAGGABLE = {"prose", "heading", "block"}
TAGGABLE = {"prose", "heading", "block", "frontmatter"}
def load_tags(path: Path) -> dict[int, tuple[str, str]]:
@@ -300,6 +356,64 @@ def cmd_split(doc: Path) -> None:
print("\nTILING GATE PASSED — spans reproduce the source byte-for-byte.")
_MD_NOISE = re.compile(r"[*_`>]+")
_WS = re.compile(r"\s+")
def normalise_quote(s: str) -> str:
"""
Normalise for §3.2 containment.
'Verbatim' is operationalised as: identical after removing markdown emphasis
and collapsing whitespace. This is WEAKER than byte-identity and is declared
as such — a blockquote re-wraps its source's lines, and bolding a phrase for
emphasis is a presentational act, not a change of words. What it does NOT
tolerate is a changed, added or dropped word, which is the failure §3.2 exists
to catch.
"""
s = _MD_NOISE.sub("", s)
s = s.replace("…", "...").replace("—", "-").replace("–", "-")
s = s.replace("“", '"').replace("”", '"').replace("’", "'").replace("‘", "'")
return _WS.sub(" ", s).strip()
def check_q_resolution(
spans: list[dict], text: str, tags: dict[int, tuple[str, str]], sources: dict[str, Path]
) -> list[str]:
"""
§3.2 — every `Q` must appear verbatim in a declared §1 source.
A `Q` whose note names no source, or names one not in the axiom set, fails:
an unlocatable quotation is exactly the 'quoted but not traced' defect.
"""
problems: list[str] = []
cache = {k: normalise_quote(p.read_text(encoding="utf-8")) for k, p in sources.items()}
for idx, (tag, note) in sorted(tags.items()):
if tag != "Q":
continue
key = note.split(":", 1)[0].strip()
if key not in cache:
problems.append(f"§3.2 span {idx}: Q names source {key!r}, not in the axiom set")
continue
quoted = normalise_quote(text[spans[idx]["start"]:spans[idx]["end"]].lstrip("> "))
if quoted and quoted not in cache[key]:
problems.append(
f"§3.2 span {idx}: NOT FOUND verbatim in {key} — {quoted[:70]!r}…"
)
return problems
# Axiom sources per kernel §1, plus documents a given package names in its header.
AXIOM_SOURCES: dict[str, Path] = {
"CLAUDE.md": Path.home() / "CLAUDE.md",
"REVIEWED.md": Path.home() / "REVIEWED.md",
"contamination-problem.md": Path.home()
/ "_Dev/CapableMind-AI/docs/thinking/David/methodology/contamination-problem.md",
"central-path.md": Path.home()
/ ".claude/projects/-Users-davidglidden/memory/feedback-central-path-answerability-not-purity.md",
}
def cmd_check(doc: Path, tags_path: Path) -> None:
text = doc.read_text(encoding="utf-8")
spans = split_spans(text)
@@ -323,6 +437,13 @@ def cmd_check(doc: Path, tags_path: Path) -> None:
if stray:
failures.append(f"§3.1 STRAY TAGS on non-assertive spans: {stray[:12]}")
# §3.2 — every Q resolves verbatim in a declared axiom source.
available = {k: p for k, p in AXIOM_SOURCES.items() if p.is_file()}
missing = sorted(set(AXIOM_SOURCES) - set(available))
if missing:
failures.append(f"§1 SOURCE UNRESOLVABLE: {missing}")
failures.extend(check_q_resolution(spans, text, tags, available))
# §3.3 — no collected limitations section.
for i in sorted(taggable_idx):
if spans[i]["kind"] != "heading":
@@ -360,9 +481,12 @@ def cmd_check(doc: Path, tags_path: Path) -> None:
print(f" - {f}")
sys.exit(1)
print("\nMechanical checks passed (§3.1 tagging completeness, §3.3 headings, tiling).")
print("NOT checked here: §3.2 Q-resolution, and the whole of §4 — which is")
print("judgement and is not mechanisable. This is not a soundness verdict.")
print("\nMechanical checks passed: tiling · §3.1 tagging completeness ·")
print("§3.2 Q-resolution against the declared axiom sources · §3.3 heading screen.")
print("NOT checked, and NOT checkable: the whole of §4 — whether a D demonstrates,")
print("an N is inert, an X asserts nothing, a Q sits within its source's scope, a")
print("sentence carries one primitive. §3.3 is a SCREEN over obvious namings, not a")
print("decision on §2a. This is not a soundness verdict.")
if quarantined:
print(f"\nThe document is NOT kernel-sound as written: {len(quarantined)} units")
print("cannot be typed under Kernel v1.0. The census above is the finding.")