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

@ -1,5 +1,5 @@
{
"version": "0.2.0",
"version": "0.3.0",
"id": "injection-lexicon",
"description": "Prompt-injection pattern lexicon: the four pattern families a detector matches against untrusted text, and the severity family each belongs to. Data only. The variant building that feeds these patterns (normalisation, homoglyph folding, rot13, unicode-tag escalation) and the buried-payload heuristic are engine behaviour and are deliberately NOT described here.",
"owasp": "LLM01",
@ -10,8 +10,18 @@
"adopted_from": "llm-ingestion-pipeline-security src/llm_ingestion_guard/injection_lexicon.json (lexicon version 1.0, repo v0.3.4, commit 0bf0729) — the `id` field of its port of the same source table. Adopted verbatim rather than invented: the guard's port already carries both names (`id` and `desc`), so the mapping is read from verified source data rather than constructed here.",
"matching_method": "Each commons pattern was matched to a guard pattern by comparing this file's `label` to the guard's `desc`, with em-dash normalised to hyphen (the two differ only by that character, in the eight hitl-trap entries). 83/83 matched, one-to-one.",
"stability": "An id is a stable identifier. Changing one is a BREAKING change for any consumer matching on it, and requires a major bump of this file.",
"aliases": "Each pattern carries an `aliases` object naming what each seeding runtime calls it today. A runtime renames its own label by changing its alias here; the `id` does not move.",
"not_yet_confirmed": "Neither llm-security nor the guard has yet agreed to this id space — both were asked via coord on 2026-08-09. Until they answer, `id` is this repository's proposal, not a ratified cross-runtime contract."
"aliases": "Each pattern carries an `aliases` object naming what each seeding runtime calls it today. A runtime renames its own label by changing its alias here; the `id` does not move. The two aliases do NOT have the same evidentiary status — see alias_evidence.",
"not_yet_confirmed": "Neither llm-security nor the guard has yet agreed to this id space — both were asked via coord on 2026-08-09. Until they answer, `id` is this repository's proposal, not a ratified cross-runtime contract.",
"alias_evidence": {
"llm_ingestion_guard": {
"verified": true,
"method": "The guard's coverage matrix asserts on this exact string: coverage.py builds one case per lexicon pattern passing `pattern.id` as the expected value, and its probe compares that against the set of `label` fields on the findings the guard actually returns. The id is therefore demonstrably what a guard finding carries."
},
"llm_security": {
"verified": false,
"method": "Not established. This value is the `label` field of the pattern table, which is what the source module names the pattern — not necessarily what a llm-security FINDING carries. The finding producer was never supplied (see finding.schema.json), and the known Node finding shape uses `title`, not `label`, with the SARIF profile deriving rule ids by slugging that title. Treat this alias as the pattern's name in the source table, and confirm the finding-level string before matching on it."
}
}
},
"$comment": "Extracted without behaviour change from llm-security/scanners/lib/injection-patterns.mjs, delivered as operator dump 2/2 through the local coord mailbox on 2026-08-09. Only the four pattern arrays are data. The dump states explicitly that checkCognitiveLoadTrap (the buried-after-2000-chars logic) and scanForInjection's variant building are ENGINE logic that never moves here; they are absent by intent, not by omission. Array order is preserved exactly as delivered.",
"provenance": {
@ -59,6 +69,10 @@
{
"id": "unicode-escape-invisible-and-confusable",
"affects": [
"homoglyph:cyrillic-latin-mix",
"unicode:zero-width-in-word"
],
"affects_labels": [
"homoglyph: Cyrillic-Latin mixing in adjacent characters",
"unicode: zero-width character inside word (keyword splitting)"
],