feat(learning-harness): declared twins and a fixture-difficulty check

The five byte-identical vibe-py twins now say so in the catalog instead of
only hashing to it, and a declared limit that names one of the unscorable
vocabulary's own reasons keeps that spelling, so `identical_twin` stays one
fact. Leave-one-out over vibe-py consequently runs on 30 rows, not 35.

The difficulty check measures three axes the corpus varies on: binding hops
from the identity source to the constrained use, registration distance, and
guard distance. Measured first, and it failed: the shared obligations
fixture reached (1, 0, 2) where the vibe-py absence rows reach (5, 2, 2).
Every fixture handler carried its own route decorator, so nothing in the
suite exercised a handler registered from another document and no binding
chain was longer than one hop -- the checker was passing on a simpler world
than the one it meets. `from_spec` closes that with the connexion shape
those rows really have. The verdict is committed beside the numbers.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
Marius Ciepluch
2026-09-06 13:09:56 +02:00
co-authored by Claude Opus 5
parent 1843ef9a02
commit d1faa04771
10 changed files with 393 additions and 9 deletions
+10 -2
View File
@@ -625,10 +625,18 @@ def _body_digest(path: Path) -> str | None:
return hashlib.sha256(body.encode()).hexdigest() if body else None
# The reasons a row may carry verbatim from the catalog, because the loader computes them under the same names.
UNSCORABLE_REASONS = frozenset({"identical_twin"})
def _unscorable_reason(known_limit: object, vuln_file: Path, fixed_file: Path, *, vendored: bool) -> str | None:
"""Why this pair cannot be scored, or None. A declared known limit wins over anything computed."""
"""Why this pair cannot be scored, or None. A declared known limit wins over anything computed.
A limit that names one of the vocabulary's own reasons keeps that spelling: `identical_twin` declared and
`identical_twin` computed are one corpus fact, and two spellings would split it across two buckets in every
aggregation (Req 4.1, 10.3)."""
if known_limit:
return f"known_limit:{known_limit}"
return str(known_limit) if str(known_limit) in UNSCORABLE_REASONS else f"known_limit:{known_limit}"
if not vendored:
return None
digest = _body_digest(vuln_file)