release: 1.0.0 -- the exported Python surface is frozen under semver
Nine current-state surfaces bumped by hand. The classification sweep ran FIRST, before the first edit: 421 hits on 'v?0.N(.N)' across all tracked files, each read and sorted current-state vs provenance. Provenance is untouched -- 'New in v0.4.0', 'measured against 0.3.1', every '0.7.0' in a code comment or a census candidate name still says what it measured. The sweep found two surfaces the plan's nine-item list did not name: README's status BADGE (still 'alpha' -- a version string grep cannot see it) and ADOPTION-BRIEF's test count, which said 791 against a suite that runs 792. Both corrected. pyproject also moves Development Status :: 3 - Alpha -> 5 - Production/Stable, likewise invisible to a version grep. CHANGELOG [1.0.0] references [0.3.0] and [0.3.1] for the behaviour changes rather than repeating them, and carries the freeze point itself: what is frozen (the exported surface), what is deliberately NOT (all detection calibration), the three conceded limitations, the one known open defect (:43), and the runtime-coverage gap -- no external consumer has run 0.7.0. No code changed. Per docs/PLAN-v1.md the release gate is the whole suite green, not a new test: 792 passed, coverage matrix 129/129 + 6/6, exit 0.
This commit is contained in:
parent
e9d8fb2b9d
commit
98ebc07b56
7 changed files with 76 additions and 17 deletions
52
CHANGELOG.md
52
CHANGELOG.md
|
|
@ -10,6 +10,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
Nothing yet.
|
Nothing yet.
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.0] — 2026-08-13
|
||||||
|
|
||||||
|
### Changed — the exported Python surface is frozen under semver
|
||||||
|
|
||||||
|
No code changed in this release. `1.0.0` is a governance promise, not a claim that
|
||||||
|
the library is finished: **no name exported from `llm_ingestion_guard` is removed,
|
||||||
|
renamed or given a different meaning without a `2.0.0`.** Measured before the tag,
|
||||||
|
the surface has been stable in form since `0.3.4` — four names added, none removed
|
||||||
|
or renamed — while behaviour moved across five releases (`0.4.0` … `0.7.0`).
|
||||||
|
|
||||||
|
**Detection behaviour is deliberately outside the freeze.** Severities, thresholds,
|
||||||
|
lexicon entries and the dispositions they produce are calibration, and calibration
|
||||||
|
moves in minor and patch releases. A payload that disposes `WARN` here may dispose
|
||||||
|
`FAIL_SECURE` in a later `1.x`; that is a fix, not a break. Assert on the
|
||||||
|
disposition your policy requires, not on a severity you observed.
|
||||||
|
|
||||||
|
The behaviour changes this freeze rests on are not repeated here — see `[0.3.0]`
|
||||||
|
for the active-content gate and the OKF adapter, and `[0.3.1]` for the
|
||||||
|
ordinary-link/image calibration that the two consumer promises pin.
|
||||||
|
|
||||||
|
### Changed — three limitations are conceded for `1.x` rather than deferred
|
||||||
|
|
||||||
|
`docs/LIMITATIONS.md` no longer says "deferred" or "pending" about any of them:
|
||||||
|
|
||||||
|
- `Severity` still carries disposition intent on the detection side. Separating
|
||||||
|
*what was seen* from *how bad it is* changes `Finding` and `Severity`, so it is a
|
||||||
|
`2.0.0` change. Read a finding's `id` for the capability.
|
||||||
|
- The input-cap asymmetry at `MAX_INPUT_CHARS` is permanent in `1.x`: surfaces that
|
||||||
|
return content raise `OversizeInputError`, surfaces that return findings truncate
|
||||||
|
and emit `active:oversize-input`.
|
||||||
|
- The multilingual homoglyph false positive is conceded more narrowly — no fix is
|
||||||
|
promised, but it is calibration, so one may land in any `1.x` release.
|
||||||
|
|
||||||
|
`SECURITY.md` carries all three as documented boundaries and states the support
|
||||||
|
window for a `1.x` line.
|
||||||
|
|
||||||
|
### Known at the freeze, deliberately not blocking it
|
||||||
|
|
||||||
|
`docs/LIMITATIONS.md` §`:43` — an OKF block sequence with exactly one key per
|
||||||
|
element misparses silently in `okf.import_bundle`, so a pointer can ride through in
|
||||||
|
a key the `resource` allowlist never inspects. Closing it tightens what the adapter
|
||||||
|
admits: behaviour, not form, and shippable in a `1.x` minor. It is recorded here
|
||||||
|
because "we knew, and froze first" is a defensible position and "we forgot" is not.
|
||||||
|
|
||||||
|
Runtime coverage at the freeze: `llm-ingestion-okf` has measured `0.3.4` and run a
|
||||||
|
`0.3.4`→`0.6.1` differential on its own door across two Python versions;
|
||||||
|
`llm-security-commons` differentially tested its independent reconstruction of the
|
||||||
|
raw-HTML classifier against ours over 42 probe tags with 0 disagreements. **No
|
||||||
|
external consumer has run the `0.7.0` runtime**; the four symbols added since
|
||||||
|
`0.3.4` are additive, so a caller that does not invoke them is unaffected.
|
||||||
|
|
||||||
|
|
||||||
## [0.7.0] — 2026-08-13
|
## [0.7.0] — 2026-08-13
|
||||||
|
|
||||||
### Added — `active:raw-html-link`, a click-required carrier class for raw HTML
|
### Added — `active:raw-html-link`, a click-required carrier class for raw HTML
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ framework-agnostisk kode.
|
||||||
Referanse-implementasjon: `claude-code-llm-wiki` Stage B (`tools/wiki_ingest/`).
|
Referanse-implementasjon: `claude-code-llm-wiki` Stage B (`tools/wiki_ingest/`).
|
||||||
Lexikon-seed: `injection-patterns.mjs` fra `llm-security`-pluginen.
|
Lexikon-seed: `injection-patterns.mjs` fra `llm-security`-pluginen.
|
||||||
|
|
||||||
Repoet er på **v0.7 (alpha)**: stdlib-kjernen er bygget og testet (15 moduler +
|
Repoet er på **v1.0.0** — den eksporterte Python-surfacen er frosset under semver
|
||||||
|
(deteksjonsatferd er det IKKE; kalibrering flytter seg i 1.x). Stdlib-kjernen er
|
||||||
|
bygget og testet (15 moduler +
|
||||||
topp-nivå wiring, showcase + korpus), inkl. OKF-adapter og aktivt-innhold-
|
topp-nivå wiring, showcase + korpus), inkl. OKF-adapter og aktivt-innhold-
|
||||||
detektor (EchoLeak-klassen) i output-gaten. Mode-b `import_bundle` skanner
|
detektor (EchoLeak-klassen) i output-gaten. Mode-b `import_bundle` skanner
|
||||||
reserverte strukturfiler (`index.md`/`log.md`) i mottatte bundles i stedet for å
|
reserverte strukturfiler (`index.md`/`log.md`) i mottatte bundles i stedet for å
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure.
|
Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
|
@ -33,17 +33,20 @@ at write time, never assumed from the format. Any pipeline ingesting external da
|
||||||
into an agent-read store has this shape; an OKF wiki is its canonical form — which
|
into an agent-read store has this shape; an OKF wiki is its canonical form — which
|
||||||
is why the guard ships a first-class OKF adapter (below).
|
is why the guard ships a first-class OKF adapter (below).
|
||||||
|
|
||||||
**Status:** `v0.7`, alpha. The stdlib-only core — its detector, contract, and
|
**Status:** `v1.0.0`. The stdlib-only core — its detector, contract, and
|
||||||
OKF-adapter modules plus the top-level wiring — is built and tested, exercised by
|
OKF-adapter modules plus the top-level wiring — is built and tested, exercised by
|
||||||
an end-to-end showcase and adversarial + false-positive corpora. The public API
|
an end-to-end showcase and adversarial + false-positive corpora. The exported
|
||||||
may still change. There are real limitations, stated plainly below; read them.
|
Python surface is now frozen under semver: nothing exported is removed, renamed or
|
||||||
|
given a different meaning without a `2.0.0`. **Detection behaviour is not frozen** —
|
||||||
|
severities, thresholds and lexicon entries are calibration and move in `1.x`. There
|
||||||
|
are real limitations, stated plainly below; read them.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
Not on PyPI. The guard is distributed from its Forgejo origin — pin a release tag:
|
Not on PyPI. The guard is distributed from its Forgejo origin — pin a release tag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v0.7.0"
|
pip install "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v1.0.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
The `open/` mirror is anonymously readable, so CI needs no deploy key, token, or
|
The `open/` mirror is anonymously readable, so CI needs no deploy key, token, or
|
||||||
|
|
@ -65,7 +68,7 @@ pip install -e ".[dev]" && pytest # the whole suite
|
||||||
Two consequences worth knowing before you depend on this:
|
Two consequences worth knowing before you depend on this:
|
||||||
|
|
||||||
- A git URL is a PEP 508 *direct reference*: it pins one exact tag, not a range
|
- A git URL is a PEP 508 *direct reference*: it pins one exact tag, not a range
|
||||||
like `>=0.2,<0.3`. Real range pinning — and therefore automatic pickup of patch
|
like `>=1.0,<2.0`. Real range pinning — and therefore automatic pickup of patch
|
||||||
releases — arrives with a Forgejo PyPI registry, which becomes the durable
|
releases — arrives with a Forgejo PyPI registry, which becomes the durable
|
||||||
channel at the first patch release or the second downstream consumer, whichever
|
channel at the first patch release or the second downstream consumer, whichever
|
||||||
comes first. The distribution name (`llm-ingestion-guard`) and the version
|
comes first. The distribution name (`llm-ingestion-guard`) and the version
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
especially one converging on Google's Open Knowledge Format (OKF v0.1) — and needs
|
especially one converging on Google's Open Knowledge Format (OKF v0.1) — and needs
|
||||||
to decide **when** and **where** to add a write-time ingestion guard.
|
to decide **when** and **where** to add a write-time ingestion guard.
|
||||||
|
|
||||||
**Status of the guard:** `v0.7.0` (alpha). Stdlib-only core, framework-agnostic.
|
**Status of the guard:** `v1.0.0`. Stdlib-only core, framework-agnostic. The
|
||||||
Public API may still change. Read the known-limitations section before you rely
|
exported Python surface is frozen under semver — nothing exported is removed,
|
||||||
on it.
|
renamed or given a different meaning without a `2.0.0`. Detection behaviour is
|
||||||
|
*not* frozen: severities, thresholds and lexicon entries are calibration and move
|
||||||
|
in `1.x`. Read the known-limitations section before you rely on it.
|
||||||
|
|
||||||
This brief is self-contained: you can plan an inclusion from it alone. Every
|
This brief is self-contained: you can plan an inclusion from it alone. Every
|
||||||
technical claim below is checkable against the guard repo (commands given inline).
|
technical claim below is checkable against the guard repo (commands given inline).
|
||||||
|
|
@ -140,9 +142,9 @@ live payload:
|
||||||
python -m llm_ingestion_guard.coverage # exit 0 = all as documented
|
python -m llm_ingestion_guard.coverage # exit 0 = all as documented
|
||||||
```
|
```
|
||||||
|
|
||||||
As of `v0.7.0`: **129 / 129 defended classes demonstrated (recall 100%)** and **6 /
|
As of `v1.0.0`: **129 / 129 defended classes demonstrated (recall 100%)** and **6 /
|
||||||
6 documented gaps still hold** (a *closed* gap fails the test, forcing a doc
|
6 documented gaps still hold** (a *closed* gap fails the test, forcing a doc
|
||||||
update). The matrix is the single source of truth for the test suite (**791
|
update). The matrix is the single source of truth for the test suite (**792
|
||||||
passing**), which also asserts total recall, that every lexicon pattern has a
|
passing**), which also asserts total recall, that every lexicon pattern has a
|
||||||
case (so the matrix cannot fall behind the lexicon), the full LLM02 secret-egress
|
case (so the matrix cannot fall behind the lexicon), the full LLM02 secret-egress
|
||||||
set, and the container-layer front-end (CSV formula-injection, zip-slip/bomb,
|
set, and the container-layer front-end (CSV formula-injection, zip-slip/bomb,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
**A reusable, minimal, dependency-light defensive layer for LLM *ingestion*
|
**A reusable, minimal, dependency-light defensive layer for LLM *ingestion*
|
||||||
pipelines — the write-time siblings of query-time chatbot guardrails.**
|
pipelines — the write-time siblings of query-time chatbot guardrails.**
|
||||||
|
|
||||||
Status: implemented — v0.7 (alpha). This document defines what the repo contains
|
Status: implemented — v1.0.0, exported surface frozen under semver. This document defines what the repo contains
|
||||||
and why; the stdlib-only core is built and tested (see `README.md` for usage and
|
and why; the stdlib-only core is built and tested (see `README.md` for usage and
|
||||||
`docs/PLAN.md` for the build order).
|
`docs/PLAN.md` for the build order).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "llm-ingestion-guard"
|
name = "llm-ingestion-guard"
|
||||||
version = "0.7.0"
|
version = "1.0.0"
|
||||||
description = "Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure."
|
description = "Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|
@ -12,7 +12,7 @@ license = { file = "LICENSE" }
|
||||||
authors = [{ name = "Kjell Tore Guttormsen" }]
|
authors = [{ name = "Kjell Tore Guttormsen" }]
|
||||||
keywords = ["llm", "security", "prompt-injection", "rag", "ingestion", "guardrails", "write-time"]
|
keywords = ["llm", "security", "prompt-injection", "rag", "ingestion", "guardrails", "write-time"]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ from .grounding import (
|
||||||
)
|
)
|
||||||
from . import okf
|
from . import okf
|
||||||
|
|
||||||
__version__ = "0.7.0"
|
__version__ = "1.0.0"
|
||||||
|
|
||||||
|
|
||||||
# --- §6 bookends: the two library-side halves around the transform ---------
|
# --- §6 bookends: the two library-side halves around the transform ---------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue