feat(codepoints): add carriers.json from verified llm-security dump

Six independent carrier tables: zero-width characters (5), the Unicode Tags
block with its subtraction decode rule, the two Supplementary Private Use
Areas, BIDI controls (9, the Trojan Source class CVE-2021-42574), the
Cyrillic presence set (13), and the fold-to-Latin homoglyph map (28).

Proven, not transcribed: five of the six tables were rebuilt from the commons
JSON alone and diffed against the imported dump module — every constant
identical, and the homoglyph map identical down to insertion order. Folding a
corpus through the rebuilt table and the source table gives identical results.

The tables overlap but are NOT merged, and cross_table_notes states each
divergence as fact: the zero-width carrier set includes U+00AD while the
lexicon's pattern class does not; the lexicon class holds U+0456 which
CYRILLIC_CONFUSABLES lacks, and CYRILLIC_CONFUSABLES holds U+0445 which the
class lacks. Reporting that to llm-security, not fixing it here.

Two honest limits, marked in the file rather than smoothed over: the private
use ranges arrived as a source comment with no constant behind them and carry
verified: false, and the dump's own "~25 entries" estimate for the homoglyph
map is wrong — counted mechanically it is 28.

Character names resolved through Python unicodedata against the Unicode
character database, not written from recollection. Verification log in
docs/extraction-plan.md.

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:08:01 +02:00
commit f4aa8b66f4
2 changed files with 537 additions and 0 deletions

View file

@ -133,6 +133,37 @@ Every check above proves this JSON agrees with **the dump**; dump-to-module fide
repository. The severity the engine assigns to `HYBRID_PATTERNS` was not supplied and is
left `null` rather than inferred from its three sibling arrays.
### `codepoints/carriers.json` — extracted 2026-08-09
Source: `llm-security/scanners/unicode-scanner.mjs` (charset constants) and
`llm-security/scanners/lib/string-utils.mjs` (`HOMOGLYPH_MAP`), supplied as operator dump
2/2 through the local coord mailbox. No commit hash accompanied it.
| Check | Method | Result |
| --- | --- | --- |
| JSON well-formed, `version` present, no raw invisible code points | `python3 -m json.tool` + byte scan for zero-width, BIDI and Tag-block characters | pass, 0 raw invisible code points |
| Five of the six tables reproduce the source constants | rebuilt each **from the commons JSON alone** (`parseInt(codepoint.slice(2), 16)`) and diffed against the imported dump module | `ZERO_WIDTH_CHARS` 5/5, `BIDI_CHARS` 9/9, `CYRILLIC_CONFUSABLES` 13/13, tag start/end — 0 differences |
| The homoglyph map reproduces the source, including order | rebuilt the object from the entries array and compared keys, values and the whole object | 28/28 keys, values and insertion order identical |
| The map folds identically | applied NFKC + lookup with both the rebuilt and the source table over 12 inputs (Cyrillic and Greek injection spellings, Norwegian and German orthography, empty) | 0 differences |
| The exclusion rationale in the source comment is true | checked whether any of `帿ŨÆäöüßéèêñç` is a key | 0 touched — ordinary Norwegian and German orthography is not folded |
| Convenience `char` fields agree with their own `codepoint` field | `String.fromCodePoint` round-trip on every entry | 41/41, 0 mismatches |
| Character names are not from recollection | resolved every name through Python `unicodedata` against the Unicode character database | all resolved |
| Table sizes were counted, not quoted | counted from the imported constants | homoglyph map holds **28** entries, not the "~25" the dump's own comment estimates; the counted number is the one recorded |
Not verified, and marked `verified: false` **in the file itself**: the two Supplementary
Private Use Area ranges. They arrived as a source comment with no constant behind them, so
unlike the other five tables there was nothing to import and diff. That asymmetry is
recorded per-table rather than averaged into a single file-level verdict.
Recorded and deliberately **not** reconciled, in `cross_table_notes`: the repository now
holds three overlapping Cyrillic sets and two overlapping zero-width sets, and none agree
exactly. The zero-width carrier table includes U+00AD while the lexicon's pattern class does
not; the lexicon's class contains U+0456 which `CYRILLIC_CONFUSABLES` lacks, and
`CYRILLIC_CONFUSABLES` contains U+0445 which the class lacks; and six of the confusables
have no entry in the fold map. The dump states the presence set and the fold map are
deliberately distinct. The U+0456 / U+0445 divergence is reported to `llm-security` rather
than fixed here.
## Definition of done for v0.1.0
1. Repository initialized, Forgejo remote `open/llm-security-commons`, MIT, `STATE.md`