docs(lexicon): split the alias evidence, correct a false absence claim

Advisor review found six gaps the session's own checks did not cover. The one
that mattered was outward-facing: the divergence report told the guard repo
that two sub-agent bounds were undocumented. That was wrong. lexicon.py's
module docstring documents them explicitly under "Bounded token gaps", and
git log -S dates {0,12} to the original port commit f397cd9 and [^><] to the
ReDoS fix cff0437. Every divergence on the guard's side is documented and
traceable. The claim rested on two sed slices of one file; an absence claim
needs a search over the whole repository. Corrected here and by coord.

lexicon/injection-lexicon.json 0.2.0 -> 0.3.0:

- pattern_id_space.alias_evidence records the two aliases separately instead
  of averaging them. llm_ingestion_guard is verified — coverage.py asserts on
  that exact string, so it is demonstrably what a guard finding carries.
  llm_security is not: it is the pattern table's name, the finding producer
  was never supplied, and the known Node finding shape uses title, not label.
- normalisations[].affects now keys on id, with the prose names kept beside it
  as affects_labels. An internal cross-reference on label was a second
  identity space inside the file the id exists to unify.

Detection data unmoved again: labels, patterns, flags and the ids and aliases
added in 7b70f5b are all byte-identical in sequence; 166/166 Node compiles.

Also: the README lexicon row described thematic families the file does not
have (they are severity families; the theme is the id prefix), and the
conformance convertibility table gained its missing second condition — a case
is buildable only if the label it asserts maps to data this repository
publishes. Eleven cases fail that test (entropy, decoded, the sanitize rows,
the OKF scans), so the buildable set is ~94, not 105.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
This commit is contained in:
Kjell Tore Guttormsen 2026-08-09 21:56:45 +02:00
commit f68f1e19d5
5 changed files with 78 additions and 11 deletions

View file

@ -279,8 +279,25 @@ engine composes two findings a particular way. This repository publishes data an
explicitly does not own an API, so those rows belong to the guard's own suite, the same way
the `Planned` rows in the README are named rather than faked.
Of the 103 `_scan_case` rows, 83 are one-per-lexicon-pattern. Those are also the rows most
affected by the id question below.
**Convertibility has a second condition, and it is the one easy to miss.** A case is a
candidate only if the probe is text-in / findings-out **and** the label it asserts maps to data
this repository actually publishes. A fixture asserting a label commons has no table for would
quietly extend the contract to cover engine behaviour the charter excludes — the corpus would
then be testing something this repository does not define.
| Group | Cases | Asserted label maps to commons data? |
| --- | --- | --- |
| `lexicon` | 83 | Yes — `lexicon/injection-lexicon.json`, now via the `id` field |
| `active` | 7 | Yes — `signatures/active-content.json` |
| `carrier` | 8 | Partly. `output:*-present` and `lexicon:unicode-tags-present` rest on the code-point tables in `codepoints/carriers.json`. The five `sanitize:*` rows assert **stripper** behaviour, which is engine. |
| `egress` | 1 | Yes — `signatures/secret-egress.json` |
| `entropy` | 2 | **No.** Shannon-entropy detection is the guard's `entropy.py`; commons publishes no entropy table. (`active-content.json` carries an opacity floor — a different thing, for a different pass.) |
| `decoded` | 2 | **No.** These assert a finding *after* a decode pass. The decode order is exactly what `spec/decode-pipeline.md` would fix, and it is Planned because it is engine. |
| `okf` (`_scan_case_okf`) | 2 | No — the OKF document model is not published here. |
So the buildable set is smaller than 105: roughly 83 + 7 + 3 + 1 ≈ 94, minus the 13 lexicon
patterns whose expected behaviour is still disputed. The rest are named here so a later session
does not rediscover them as a gap.
**Blocking issue found while counting.** The guard and the Node table are two ports of one
source file and they do not agree: 64 of 83 patterns byte-identical, 6 differing only by