TWO STALE PREMISES IN THE SAME SECTION, BOTH NOW MEASURED
1. The pin. Session G's gate was written against okf pinning the guard
`>=0.2,<0.3` with `[tool.uv.sources]` tag `v0.2.0` — true when written
(their HEAD 4ea00a9), and the whole reason the gate says a green answer
proves nothing: `<0.3` excluded the versions the fixtures were meant to
exercise, so uv resolved v0.2.0 and came back green for free.
Read from their pyproject.toml today, not from their coord message: they are
on `>=0.3,<0.4` with tag `v0.3.4`. That inverts the consequence — an
unchanged tree now resolves v0.3.4, which is inside what the gate asks for,
so the null result is gone.
Two things follow and neither is settled here. `<0.4` excludes 0.4.0 and
0.5.0, so the axis separation and the input-cap refusal are outside anything
okf can measure today. And the gate says "passes against guard 0.3.1" while a
run today measures 0.3.4 — whether that counts as satisfied is an operator
decision, deliberately not taken. The transitive-arrival bullet is corrected
the same way: an accidental consumer lands on v0.3.4 now, not v0.2.0.
2. The file list. It named four release surfaces. The 0.5.0 sweep found five
more carrying a version claim that no release had ever touched — and one of
those five was `**Status:** v0.3`, which this very line already named, and
0.4.0 missed anyway. Writing down a trap is not applying it.
Replaced with the nine current-state surfaces, plus the rule that made the
sweep safe: sort every hit into current-state or measurement provenance
BEFORE editing, because a version sweep also hits "verified identical on
0.2.0 and 0.3.1" and bumping that falsifies the record. So it can never be a
sed pass.
The key-assumption test went with it. "grep all four files" presupposed the
list it was supposed to verify. It is now a git grep over all tracked files
with each hit classified, plus `git show <pre-tag-sha>:README.md` — the check
that proves what the tag will carry, run while the tag does not yet exist.
That ordering is the fix; v0.4.0 verified afterwards and carries a stale
README permanently as a result. SECURITY.md gets a note that at 1.0.0 its
sentence is rewritten, not bumped: "pre-1.0" stops being true.
`PLAN-v1.md`'s Session H block ended with "Neste: Session G", and that line is
a trap two ways over. "Session G" is a WRITTEN section at :231 — and it is
*v1.0 freeze + release*, not the axis separation. No plan section for the axis
separation ever existed; the pointer resolved to this one forward-reference
line. A session following it designs against the wrong section, which is
exactly what this session started doing before measuring the file.
The number was wrong too: 0.4.0 went to the input cap by operator choice, so
the axis separation landed under 0.5.0 instead.
STATE.md is LOCAL-ONLY and gets overwritten every session, so the plan file and
the CHANGELOG are the only durable record. Leaving the line meant the next
session would re-derive the same wrong pointer from the same text.
Also corrects a citation this session nearly propagated: the locked 0.3.1
grading table is at :288-290. `:246-252` is the okf pin discussion, and the
table at :302-309 is the *broken* v0.3.0 one — the row it asserts for an
ordinary image is `fail_secure`, the regression 0.3.1 exists to fix. Citing it
as the baseline would have inverted the check.
Adds the partial-action-map test: every level a caller leaves unnamed must fall
back rather than raise. The existing test passed a complete map, so the
fallback branch had no coverage — and a KeyError there would have been caught
by `guard` and rendered as a fail-closed with a useless reason.
716 passed; matrix 128/128 + 6/6.
Note on the one red seen while landing this: test_output.py's ReDoS wall-clock
budget failed on a loaded run (suite 37s vs 13.9s), then passed alone and in a
clean full run. It asserts `scan_output` under 2.0s, and `output.py` neither
imports `disposition` nor references it in code — its three mentions are
docstring prose — so this change cannot reach that timing. Load, as STATE
documents, not a regression.
okf asked outright whether the v1.0 gate requires 'the tagged artifact resolves
0.3.1' or 'the fixture set passes against 0.3.1'. It is the second, and the
answer is locked here so a later session cannot quietly upgrade the ask into a
release request against their operator.
They refused to widen their published range to run the measurement, and the
refusal is better than the ask it answers: widening a published range in order
to generate the evidence that would justify widening it is circular, and a red
result would then have meant unwinding a release to fix a test setup. The
measurement has to be able to say no. Their scratch-venv method -- outside the
project environment, --no-deps, guard installed from the v0.3.1 tag, resolved
version asserted from importlib.metadata -- satisfies the gate exactly.
Both were given to named consumers who are building on current behaviour, and
both were about to live only in STATE.md -- which is gitignored, so a promise
kept there does not survive a machine. Breaking either silently is a release
defect, not a preference.
1. Any change to how PRESET_USER_UPLOAD grades ordinary links and remote images
requires notice to linkedin-studio before it ships; they pin v0.3.1 at wiring.
Applies to 0.4.0: the axis separation must change disposition, not grading.
2. Closing the relative-target asymmetry requires notice to llm-ingestion-okf;
it is a Door C property rather than a guard gap, but closing it changes what
arrives at their persist gate.
Also records a mechanism we had not modelled: okf reports percent-escapes
reaching filenames through a slugger, so %20 is manufactured systematically from
document titles rather than being incidental as it is in the documentation URLs
the FP was calibrated against.
okf pins llm-ingestion-guard >=0.2,<0.3 in [project].dependencies and pins the
uv source to tag v0.2.0 -- verified at their v0.4.0 tag and at their HEAD. The
cap excludes 0.3.1, so the committed Door B+C fixture run cannot reach the
version the gate names. It does not fail either: uv resolves v0.2.0, the
constraint holds, and the fixtures come back green because v0.2.0 never had the
regression. Green from an unmodified tree is the one outcome that proves nothing
and reads as proof.
The gate now requires the result to name the resolved guard version, and records
that transitive arrival does not count as an integration -- okf v0.4.0 makes the
guard a mandatory runtime dependency, so a consumer can acquire us without
choosing us, and today lands on v0.2.0 without the 0.3.0 hardening or the 0.3.1
fix. Silent under-defend, not a break.
v0.3.0 makes the untrusted upload path refuse ordinary documents. Measured on
both doors under PRESET_USER_UPLOAD: one ordinary markdown image reaches
fail_secure, one ordinary link/autolink/refdef reaches quarantine_review, and
only a document with no external references persists.
Root cause is three independent defects that compound. Severity tracks
construct type rather than URL shape, so every external image is HIGH when the
exfiltration primitive is actually a URL that carries data outward. The
quarantine floor fires on any finding at all, a premise that broke once every
link became a finding. And the false-positive corpus could not have caught
either: it holds no markdown links or images, asserts only under
PRESET_TRUSTED_SOURCE where everything warns anyway, and runs _scan_input, so
the output gate where active_content lives is never exercised by it.
Both code changes are required together -- verified that fixing severity alone
still quarantines via the floor, and fixing the floor alone still fail-secures
on a HIGH image.
Records the version reasoning too: 0.3.1 is honest as a patch because the
lexicon carries no LOW/INFO patterns (40 high, 22 medium, 21 critical) and no
other detector emits LOW, so raising the floor to MEDIUM+ is a no-op for every
finding that existed before 0.3.0. The new middle preset stays out of this
release; it is additive API and belongs in 0.4.0.
PLAN-v1.md said consumer integration was NOT part of the v1.0 sequence, and
Session G listed A-F as its only dependency -- both of which are now false.
The gate change lived only in STATE.md, which is local-only and overwritten
each session, so the plan was the wrong side of the truth.
Records: 1.0.0 now gates on the first real integration coming back green
(llm-ingestion-okf step 4 against v0.3.0), not on our own suite; the reasoning
(522 self-authored tests prove the code matches the design, not that the
design survives contact -- our first external contact found both a
tag-vs-main divergence and three undocumented behaviour changes); and that
one validated `integrated` outweighs five `planned` declarations, so we do not
wait on repos that may never arrive.
Also fixes Session G's now-stale mechanics: its CHANGELOG entry can no longer
"list A-F" because A/A2/B already shipped under [0.3.0]; the version-sync file
list gains the README status line and install pin; and verification gains an
anonymous clean-venv install check against the new tag, since README must
never advertise a command we have not run.
Replace the unverified/absolute novelty statement with the defensible
four-part-contract form, verified against a focused adversarial PyPI+GitHub
survey (2026-07-15):
- BRIEF §11: 'assumed, not verified' -> verified survey with sources. Names
aig-guardian (real, query-time; blurs only the minimal-dep-library
differentiator), GuardLLM (nearest neighbour, runtime hardening, no
scan-before-persist / capability isolation / fail-secure), and ipi-scanner
(orphaned placeholder repo, recorded for honesty not as prior art).
- README: differentiator moved from 'library vs hosted/model' to the full
four-part write-time contract.
- PLAN §27-31: drop the unverifiable 'the first' superlative.
Also promotes the v1.0 session plan (PLAN-v1.md) and the cross-model review
(review-2026-07.md) into docs/ on the open/ mirror, referenced by PLAN.md's
re-sequencing addendum.