fix(inbox): refuse a segmentation plan that matches no dropped file

A plan is selected by content hash, so a mistyped source_sha256 matched
nothing, every dropped file fell through to the one-concept rule, and
process_inbox returned an ordinary success over a flat bundle. The
operator asked for segmentation, got none, and had no error to read --
the silent skip this library refuses everywhere else. vegnormal-okf is
about to run an N500 corpus through this path, where a silent zero
would read as "the corpus has no concepts".

The refusal asks whether a covering plan was FOUND, not whether every
file was examined, so an unreadable drop cannot mask it; and coverage
is recorded at selection, not after path validation, so a matched plan
with a refused entry path still reports its own per-file code. The
first cut got that second question wrong and an existing collision test
caught it; the case is now pinned by its own test, verified red against
the earlier form.

New code segmentation_plan_unmatched, registered in the SegmentationError
docstring register in the same commit. Fail-fast before any disk
mutation. The four existing goldens are byte-identical to baseline.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-01 19:27:27 +02:00
commit 8f9b4c8cca
3 changed files with 123 additions and 0 deletions

View file

@ -177,6 +177,12 @@ class SegmentationError(IngestError):
offset had silently moved
- `segmentation_unsupported_profile` a plan was passed to a profile that
does not declare the segmentation capability
- `segmentation_plan_unmatched` the plan is well-formed but its
`source_sha256` matches no dropped file, so nothing would be segmented
and the run would report an ordinary success over a flat bundle. A
mistyped hash is the likely cause and it is unreadable from the result;
refusing is the only way the operator learns that the judgement they
adjudicated was never replayed
"""

View file

@ -531,6 +531,11 @@ def process_inbox(
# would silently claim the first's concepts.
named: list[tuple[Path, tuple[str, ...], bytes, bool]] = []
slug_owners: dict[str, list[Path]] = {}
# Recorded at the moment of SELECTION, not after validation: a plan whose
# hash matched a drop but whose entry paths were then refused is a covered
# document with a bad plan, and it must keep reporting its own per-file
# code rather than being re-reported as a plan that matched nothing.
plan_matched = False
for path in dropped:
try:
# Read HERE rather than in the write loop: a plan is selected by
@ -550,6 +555,7 @@ def process_inbox(
continue
try:
covering = _plan_covering(segmentation, source_bytes)
plan_matched = plan_matched or covering is not None
targets: tuple[str, ...]
if covering is None:
targets = (inbox_filename(inbox_slug(path.name), profile=profile),)
@ -562,6 +568,23 @@ def process_inbox(
for target in targets:
slug_owners.setdefault(target, []).append(path)
# A plan that covered nothing is a misuse, not an outcome. `_plan_covering`
# selects on content hash, so a mistyped `source_sha256` matches no drop,
# every file falls through to the one-concept rule, and the run returns an
# ordinary success over a flat bundle -- the silent skip this library
# refuses everywhere else. Asked as "was a covering plan actually found?"
# rather than "was every file examined?", so a file that could not be read
# cannot mask the refusal. Still before any disk mutation: Phase 1 only
# named things.
if segmentation is not None and not plan_matched:
raise SegmentationError(
f"the segmentation plan's source_sha256 {segmentation.source_sha256!r} matches "
f"none of the {len(dropped)} dropped file(s) — nothing would be segmented and "
"the run would report success over a flat bundle; check the hash against the "
"bytes it was adjudicated over",
code="segmentation_plan_unmatched",
)
contested = {name for name, owners in slug_owners.items() if len(owners) > 1}
# One refusal per DOCUMENT, not per contested path: a document expanding to
# five colliding paths is one thing the operator has to fix, and five