1
0
Fork 0
llm-ingestion-pipeline-secu.../docs
Kjell Tore Guttormsen a59184bb7f fix(zwj): the zero-width check tested identity, so every emoji-composed document was hard-blocked
`_ZERO_WIDTH` (sanitize, input) and `_ZERO_WIDTH_CPS` (output,
`_scan_invisible_carriers`) tested U+200D on codepoint membership alone.
`disposition._CARRIER_LABELS` grades both as any-tier FAIL_SECURE with no
appeal, so any first-party document containing a ZWJ-composed emoji --
professions, families, skin tones, flag variants -- was hard-blocked forever.
Reported by ms-ai-architect; confirmed here against the code.

The strip was the worse half and was not in the report: sanitize *removed* the
joiner, silently decomposing the emoji into two unrelated ones. A module whose
contract is "only ever removes carriers" was corrupting content.

The fix is the one our own lexicon row `unicode:zero-width-in-word` (`\w[ZW]\w`)
already used: judge the joiner by CONTEXT, not identity. A ZWJ is exempt only
when BOTH neighbours are emoji-context codepoints. Half-context is not context,
so `a<ZWJ>{emoji}` stays a carrier and an attacker cannot buy exemption with a
single emoji.

Blocks, not an emoji table. Measured against Unicode 17.0's
`emoji-zwj-sequences.txt`: 1614 RGI sequences use 122 distinct codepoints
adjacent to a ZWJ, and the five ranges cover 122/122. The measurement earned
its keep -- the hand-reasoned candidate table missed U+2194, U+2195 and U+2B1B.
Shipping the RGI list itself would be exact on the day it landed and stale at
the next Unicode release, reopening this same false positive for every new
emoji; whole blocks carry the unassigned headroom (458 Cn codepoints) that
future emoji are allocated into, so the table does not age.

The predicate is defined once in sanitize and imported by output. A second copy
is how the input side stops flagging while the output side keeps blocking; the
cross-surface test asserts the two agree on six inputs.

Two residuals, both in LIMITATIONS (33 -> 34, README bumped): a ZWJ between two
emoji is now exempt and could carry a covert channel (one emoji per bit, cannot
split a word); and U+200C (ZWNJ) still has no context test, so Persian, Arabic
and Devanagari documents -- where it is orthographically required -- stay
blocked. That needs a script-based criterion and no corpus is here to verify it
against, so it is parked as a known FP class rather than guessed at.

736 green (was 727), coverage 128/128, 6/6 documented gaps hold.
2026-08-11 22:14:47 +02:00
..
ADOPTION-BRIEF.md release(0.6.0): the raw-html narrowing ships, and the version claims it already made become true 2026-08-11 18:01:36 +02:00
BRIEF.md release(0.6.0): the raw-html narrowing ships, and the version claims it already made become true 2026-08-11 18:01:36 +02:00
fp-sweep.py measure(fp): the upload door costs a human on 16-53% of benign documents 2026-08-10 21:32:56 +02:00
LIMITATIONS.md fix(zwj): the zero-width check tested identity, so every emoji-composed document was hard-blocked 2026-08-11 22:14:47 +02:00
OKF-INGESTION-BRIEF.md docs: version-sync + SECURITY/CONTRIBUTING + honest-limits (Session E) 2026-07-15 10:08:24 +02:00
PLAN-v1.md docs(plan): the v1.0 gate rested on okf's old pin, and its file list on four surfaces 2026-08-11 06:46:29 +02:00
PLAN.md fix(output): 19 quadratic regex runs on the output path, worst ~5.7h at the cap 2026-07-31 18:31:58 +02:00
rawhtml-census.py fix(active-content): raw-html graded two inert shapes HIGH, and the fix moved a second surface 2026-08-11 16:56:31 +02:00
redos-sweep.py fix(sanitize,okf,active_content): three quadratic patterns, two on the input path 2026-08-01 20:06:36 +02:00
review-2026-07.md docs: reframe novelty claim to composite write-time contract (review MAJOR #3) 2026-07-15 09:22:38 +02:00
URL-SHAPE.md docs(url-shape): make the rule reconstructable, and record what three corpora measured 2026-07-27 08:56:24 +02:00