feat(consume): the payload says when the bundle looks like it does not cover the question

C4. `coverage` gains two keys, and every key it had keeps its bytes:

- `absent_terms`: the question's words the bundle holds in NO form -- not as
  written, and not through a relative it uses (`bm25.query_groups`, the same
  bridge the ranking reads through);
- `weak`: true when one such word exists or nothing was delivered.

A reading with its rule in the open, never a verdict about the bundle. It is
computed for both rankings (`bm25.absent_terms` serves the fusion). The
retrieval gate's `marked` -- the one reading both gates share -- reads `weak`
beside its own bar, never instead of it; the known-negative that strips the
payload's words now strips both readings.

Words that only FRAME a question are stopwords in both languages (`how
often`, `hvor ofte`, `hva står i`, `what does it say`), and so are the
Norwegian function words spelled without their letters (`naar`, `paa`), the way
ASCII-only text writes them. Read as topic words they would be "absent" from
any collection that never uses them, which is what the synthetic sets showed
on three answered questions before the list was extended.

The working method says what to do with it, in one sentence each: the skill
template's step 3 and the MCP server's instructions (1 253 bytes, under the
2 048 a client keeps) -- rephrase in the bundle's words, and if it stays weak,
say the bundle does not cover the question.

The search gate's table for this commit is kept in local state.

Suite on a clean tree after `git add`: 2397 passed, 2 skipped, 4 xfailed.
ruff, ruff format, mypy --strict clean. Retrieval gate unchanged at the rows
the previous commit left red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-21 07:12:43 +02:00
commit ab6e24aa22
12 changed files with 183 additions and 8 deletions

View file

@ -81,7 +81,9 @@ titles — if one of them is what you were after, that is a signal about the
WORDS, not a closed door. Search again with the words that concept uses, or
ask for it by name. There is no limit on runs and no penalty for a run that
found nothing; a run that found nothing is a measurement, and its denominator
is worth carrying.
is worth carrying. When `coverage.weak` is true — a word of yours the bundle
holds in no form (`coverage.absent_terms`), or nothing came back — rephrase in
the bundle's own words, and if it stays weak, say the bundle does not cover it.
**4. Several bundles, same method.** When more than one bundle could answer,
run the same sub-questions against each, and keep track of which bundle each

View file

@ -92,7 +92,9 @@ titles — if one of them is what you were after, that is a signal about the
WORDS, not a closed door. Search again with the words that concept uses, or
ask for it by name. There is no limit on runs and no penalty for a run that
found nothing; a run that found nothing is a measurement, and its denominator
is worth carrying.
is worth carrying. When `coverage.weak` is true — a word of yours the bundle
holds in no form (`coverage.absent_terms`), or nothing came back — rephrase in
the bundle's own words, and if it stays weak, say the bundle does not cover it.
**4. Several bundles, same method.** When more than one bundle could answer,
run the same sub-questions against each, and keep track of which bundle each

View file

@ -37,7 +37,9 @@
"unanswered_in_payload": [
"hva",
"sier"
]
],
"absent_terms": [],
"weak": false
},
"excerpts": [
{