Session 7 of the 2026 threat plan (attack row 3): A08, A09, A12, A16 and
A19 were red. Their payloads are ordinary English with no marker.
- indirect:prose-instruction (MEDIUM): a paragraph that combines two of
four classes: it speaks to the model, it is meant to act later, it
writes to the model's memory, it hides from the user. One class alone is
ordinary prose. A keyword prefilter skips text where no non-address
class can match. Catches A08, A09, A16 and A19.
- A12 (a task with no marker) is the seventh documented gap; a rule that
caught it would be fitted to the payload's words.
- redos-sweep walked no dicts, so the new class patterns were swept by
nothing. It walks dicts now: 168 patterns, 0 flagged; positive control
flagged at x4.0.
Measured before building: 0 of 5494 benign documents fire (the three FP
corpora, 577 package READMEs, 1412 vendor-published agent skills). Guard
rule before/after: FP 106/198, 196/2918, 108/389 identical line for line;
OKF import 47/31 identical. Matrix 144/144 + 7/7 gaps, suite 1233 passed.
Row 3: 17 caught, 2 gaps, 0 open.
Session 6 of the 2026 threat plan (attack row 3): A05 output was red.
CamoLeak renders a secret as one image per character from a URL alphabet;
each URL is ordinary, so each image graded LOW and the gate WARNed.
- active:markdown-image-sequence (MEDIUM): at least 4 ordinary external
images, inline or reference-style, on one URL template whose varying
tokens are 2 chars or fewer, or digit runs. Digits that count up in
document order are a counter and carry nothing. The per-image grade is
unchanged; the finding sits beside it.
- Accepted twins (flag tables, figures 1a/1b) go to review; measured
evasions (word dictionary, 3-char symbols, counter increments, run of 3,
a template per symbol) are in LIMITATIONS.
Guard rule before/after: FP 106/198, 196/2918, 108/389 identical. Those
corpora hold no external markdown image, so the rule was also run on 577
package READMEs (312 with external images): 0 firings at run lengths 3-8.
OKF import 47/31 identical. Matrix 140/140, ReDoS 163 patterns 0 flagged,
suite 1179 passed + 5 xfailed. Row 3: 13 caught, 1 gap, 5 open.
Session 5 of the 2026 threat plan (attack row 3): A04 and A15 were red.
- html-obfuscation:tiny-font (HIGH): font below 4px. ShadowLeak's 1px passed
because the commons zero-font row only matches a leading 0.
- html-obfuscation:invisible-colour (HIGH): text within 8 per channel of the
background in the same style attribute, or transparent. White alone is not
a signal (email buttons); measured residual in LIMITATIONS.
- output:html-comment-present (MEDIUM): a comment in the artifact outside
fenced code and inline code. 253/254 comments in the reference corpus sit
in code.
Local to output.py; the vendored lexicon stays byte-equal with commons.
Guard rule before/after: FP 106/198, 196/2918, 108/389 identical; OKF 6/53
and 47/31 identical. Matrix 139/139, ReDoS 161 patterns 0 flagged, suite
1142 passed + 6 xfailed. Row 3: 12 caught, 1 gap, 6 open.
Variation-selector smuggling (A01) and Sneaky Bits (A02) gave 0 findings
on 1.4.1 and stayed in the sanitized text. The denominator is now the
frozen Unicode 18.0 set (DICP | Cf | Co, 141 674 codepoints); each one is
stripped and flagged unless a known legitimate use exempts it on context:
one VS15/16 after an emoji base, one ideographic selector after a CJK
ideograph, ZWNJ/ZWJ beside Arabic-script or Indic letters, LRM/RLM/ALM
in a document with RTL text, an Arabic number sign before a digit. A run
is always a carrier; private use is caught in full (operator decisions
2026-10-28). One predicate serves sanitize, the output gate and the
lexicon's word-split row, whose regex stays byte-identical with commons.
A01 and A02 are green; the FP populations and the pinned OKF corpus are
identical before and after.
It was the only docs/ measurement script without a row here, and this
repo just made it load-bearing for two published LIMITATIONS.md numbers
(the 1.5 ms floor, the 2.6 flag ratio). Pins structure only, per the
sweep's own docstring: the suite clock (not a reimplemented wall clock),
the constants against the doc's prose, and the 152-pattern/11-table
collector count. Never pins a timing outcome -- that would be red
several runs in twenty.
Two changes that had to ship together, because they co-occur.
`active:raw-html-link` (MEDIUM) splits the click-required carriers out of
`active:raw-html`. The same URL was LOW as `[t](url)` and HIGH as
`<a href="url">` — an asymmetry produced by syntax, not by affordance, on a
carrier the markdown path has graded MEDIUM since 0.3.1. The event-handler test
runs first, so `<a onclick=...>` stays HIGH. The url-attribute branch stays HIGH
too: a name outside the active set has unknown rendering, and grading
`<Card src=...>` as a link would be reasoning rather than measurement.
The no-URL narrowing makes `</a>`, `<Frame>`, `<video />` and `<img alt=...>`
without `src` inert — `<base />`'s argument from 0.6.0 applied to the rest of the
name branch. It tests for the URL attribute's PRESENCE, not for a readable value,
so the fail-secure gap `_url_attr_is_external` leaves open is not reopened here.
WHY TOGETHER: the narrowing strips a document's `</a>`/`<Frame>` and what remains
is the `<a href=...>` the split grades down, so each alone leaves the document
blocked by the other's residue.
`active_tag_class` is now the classification point and `is_active_tag` wraps it.
The census patches the former: a boolean could only express a narrowing, never a
regrade, so every carrier candidate would have measured equal to PRODUCTION —
silently, and in the direction that reads as "no change helps".
TWO COSTS, BOTH RECORDED RATHER THAN GLOSSED:
- The split TIGHTENS the trusted tier. One finding becomes two, and >=2 findings
at MEDIUM+ trip the compound overlay, so a document carrying both an `<img src>`
and an `<a href>` goes WARN -> quarantine_review on PRESET_TRUSTED_SOURCE. On
that preset it is the only direction the split can move anything. The census
now reports a TIGHTENS column on both trust tiers against the previously
shipped row — "frees N" without "tightens M" is a one-sided number.
- `count` drops on documents containing `</a>`, a published field moving under a
meaning that did not change.
MEASURED: reference-corpus (389) 54 -> 53 fail_secure, tightens 0/0, and the
census `PRODUCTION` row equals its `C1 + D` candidate row for row. The census
also reproduces 133/3/13/108/25 exactly, so it is calibrated against every
published historical number. The two wiki corpora are NOT yet re-measured; the
tree says so explicitly in the docstring, LIMITATIONS and CHANGELOG rather than
carrying probe numbers as fact.
791 tests (was 759), coverage 129/129, 6/6 documented gaps holding. Version
bumped to 0.7.0 across every surface; no tag is set until the measurement lands.
`docs/fp-sweep.py` and `docs/rawhtml-census.py` produce the numbers published in
`docs/LIMITATIONS.md`, and both reach past the public API into private module
state -- `active_content._ACTIVE_TAGS`, `_EVENT_ATTR_RE`, `_URL_ATTR_RE`,
`_has_external_target`, `calibration.RISK_RANK`. A rename inside `src/` broke
them while the suite stayed green, and the breakage would have surfaced months
later, at the moment someone tried to re-measure a published claim. This was the
last uncovered contract in the repo.
The coverage found a live one. `rawhtml-census.has_external_url_attr` parsed
attributes with its own pattern instead of calling the shipped reader, and the
copy had drifted on two shapes:
- a URL attribute reached through a prefix. `_URL_ATTR_RE` matches `src=`
inside `data-src=` on a word boundary, so the shipped predicate reads the
value and blocks; the census's own name table saw `data-src` and skipped it.
- a multi-candidate `srcset`. The shipped reader splits on `[,\s]+` so a
relative first candidate cannot mask an external one behind it; the census
tested the whole attribute value as a single URL.
Both made the `A` candidate rows free documents the shipped predicate keeps --
under-counting against the `PRODUCTION` row printed directly beside them, which
that row exists to expose. The census now delegates to
`active_content._url_attr_is_external`, so there is one reader, not two. This
repo already carries the general form of that lesson in `docs/URL-SHAPE.md`:
three consumers reconstructed a predicate from prose and each got a different
wrong answer.
NO PUBLISHED NUMBER MOVED. Re-measured against all three live populations after
the fix, in one session each: reference-corpus 389 docs (A frees 3, base-url 13,
both 25 -- the numbers in `docs/LIMITATIONS.md`, unchanged), vendor-harvest 187,
generated-notes 550. `PRODUCTION` equals `A + base-url` in all three (108/108,
98/98, 88/88), and vendor-harvest exercises the corrected branch for real (8
external `Card` attributes). The defect was latent, not published.
The tests are scoped to what a test here can honestly hold. The corpora live
outside this repo in private consumer repos, so neither script can be run end to
end from the suite and a stand-in corpus would only pin a fiction. What is
pinned: every imported name still exists with the shape used; `fp-sweep`'s
metric guard fails when the action map is re-mapped (a guard that cannot fail
protects nothing); `measure` still reads `.disposition` and `.assessment` and
excludes empty files from the denominator; the census's in-process patch point
still moves the gate, so a census patching a dead symbol cannot print six
identical rows and read as a finding; `PRODUCTION` equals `A + base-url` across
every branch of the predicate; and both scripts still refuse an argument-less
run rather than measuring nothing.
759 passing (was 736). Coverage matrix unchanged at 128/128 with 6/6 documented
gaps holding. The `736` in `docs/ADOPTION-BRIEF.md` is scoped "as of v0.6.1" and
is correct for that tag; it moves to 759 at the next version bump.