build(deps): pin llm-ingestion-guard v1.3.0 so the gate reads our own goldens

The guard could not read back what this library WRITES. At 1.2.0,
`okf.parse_frontmatter` refused the OKF v0.2 golden outright --
`OKFFrontmatterError: value begins with a disallowed YAML indicator '['`
against `sources: [{ id: golden-v0-2-sales, resource: fixture }]`. Flow is
the only form this library can emit, because its own line-oriented parser
cannot round-trip the block form at all, so a gate that refuses flow
refuses everything Door A produces under `OKF_V0_2`.

The control was run BEFORE the bump, which is the only moment it exists:
the probe raised on 1.2.0, so the new test discriminates rather than
merely passes. `[project.dependencies]` already said `>=1.2,<2.0` and is
unchanged; only `[tool.uv.sources]` and `uv.lock` move.

TWO gate rows moved, not the one the work was scoped around, which is why
the whole documented probe was re-run instead of just the `sources` case:
the BLOCK form of `sources` now passes too, retiring G30. That changes
nothing about what we emit -- our own parser is still the binding
constraint on writing flow -- and `docs/okf-nokkelinventar.md` now carries
a `guard 1.3.0` column beside the 1.2.0 measurement rather than
overwriting it. A third row kept its verdict but changed its reason, so
the quoted message was corrected too.

The Door C boundary is unmoved, verified with a known-positive:
`resource` is allowlisted only inside a `sources` entry, so section
10.2's `executor.resource` and `attester.resource` are still rejected
("not on the OKF mapping allowlist under 'executor'") while top-level
`resource` passes.

`uv.lock` also gains `pypandoc-binary==1.17`. That is a stale lockfile
being corrected, not a new dependency: it was already declared in the
`[extract]` extra, and `uv lock --check` reports the lockfile out of date
on the untouched tree. Core keeps exactly one runtime dependency.

Not addressed, and recorded rather than built: the guard reports that
`sources[].resource` is scanned as text but never URL-validated, because
SPEC 5.1 permits bundle-relative paths and scope descriptions. No
consumer has asked for a gate there.

Guard 1.3.0 installed from 44e2b31, verified anonymously over https
against the remote tag. 1054 -> 1055 tests. `mypy --strict` clean, `ruff`
clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-03 20:35:27 +02:00
commit 2d9fb0f934
5 changed files with 92 additions and 24 deletions

View file

@ -71,6 +71,35 @@ def test_guard_version_is_inside_the_pin() -> None:
assert major == 1 and minor >= 2, guard.__version__
def test_the_guard_parses_the_flow_form_sources_our_goldens_emit() -> None:
"""The guard's parser must read back what this library WRITES.
A known-negative turned known-positive, and the control was run before the
bump so it is not a story: on 1.2.0 this exact call raised
`OKFFrontmatterError` -- "value begins with a disallowed YAML indicator
'['" -- against the v0.2 golden's `sources: [{ id: ..., resource: ... }]`.
That is not a cosmetic rejection. This library emits structured
frontmatter values in FLOW form as a hard convention, because its own
line-oriented parser cannot round-trip the block form at all, so a guard
that refuses flow refuses the only shape we are able to produce.
1.3.0 allowlists `resource` inside a `sources` entry, and the parent key
is what decides: section 10's `executor` and `attester` resource stays
rejected through every carrier. This test therefore pins the narrow thing
that changed, not the whole parse surface -- if a later guard widened
`resource` beyond `sources`, the assertion below would still pass and the
Door C boundary tests are what would move.
"""
golden = Path("examples/ingest-golden-okf-v0-2/expected-bundle/ingest-sales.md")
# `(mapping, body)`, not a mapping. Measured rather than assumed, and the
# unpacking is part of what this test pins: at 1.2.0 the call raised before
# returning anything, so the shape was not observable from here at all.
frontmatter, _body = guard_okf.parse_frontmatter(golden.read_text(encoding="utf-8"))
sources = frontmatter["sources"]
assert isinstance(sources, list) and len(sources) == 1
assert sources[0] == {"id": "golden-v0-2-sales", "resource": "fixture"}
def test_guard_screen_output_signature_is_what_door_b_calls() -> None:
parameters = inspect.signature(guard.screen_output).parameters
assert list(parameters) == ["text", "policy", "provenance", "transform_failed"]