docs(okf): tre kryss-repo-kontrakter i EN tracked fil, med nevneren maalt (B-i)

Planen som baerer dem er local-only (repoet har et offentlig speil, saa den
globale regelen gjelder). Kontraktene selv er ikke arbeidsbenk - de spenner
produsent og konsument, og en kontrakt som bare bor i den ene sidens planfil er
en kontrakt den andre siden ikke kan holdes til. Fila erklaerer seg som kilden,
saa docstrings og invariantrader kan peke hit i stedet for aa kopiere regelen.

Nevneren i K5-terskelen var FEIL i planen og er rettet begge steder: SPEC 5.1
lister SEKS oppfoeringsnoekler (resource, id, title, author, usage_count,
last_modified - lest i den kanoniske SPEC-en l.303-313), ikke fem. Produsenten
skriver to av dem (62b6192: `sources: [{ id: ..., resource: fixture }]`, 1 av 1
fil som baerer noekkelen). 2 av 6, ikke 2 av 5 - samme nevner-disiplin som F15.

Hver kommando i fila er kjoert og gir tallet den staar ved siden av.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-02 19:55:55 +02:00
commit f6b1b779e2
2 changed files with 125 additions and 0 deletions

View file

@ -0,0 +1,121 @@
# OKF consumption contracts
> **This file is the source.** Three facts below span a producer
> ([`llm-ingestion-okf`](https://git.fromaitochitta.com/open/llm-ingestion-okf)) and this consumer,
> so neither side can hold the other to them from inside its own plan file. Docstrings, tests and
> the invariant ledger in `CLAUDE.md` point *here*; they do not restate the rule. A second copy of a
> contract is the drift this repository has a rule against.
>
> The producer's half is recorded in that repository's `docs/plan/office-intake.md` §§ 45 and
> `docs/consumption-contract.md`. Ratified at programme level 2026-09-02. Written in English because
> the counterparty half is, and a contract split across two languages is a contract nobody reads
> whole.
>
> Every number below comes from a command, and each command is written next to its number.
## § 1. The falsification threshold — `present` and not `unverified`
A falsification verdict may rest on a concept **only when both hold**:
```
evidence_for(path).state == "present" AND tier != "unverified"
```
Everything else is **reported and explicitly discounted**, never silently excluded. The report
carries the triple `(state, reason, items_seen)`: a concept that was dropped and a concept that was
read-and-discounted are different facts, and only the second is honest about what was actually read.
The threshold is expressed in **exactly one place**`okf.admits_falsification(evidence) -> bool`.
A threshold spelled inline at each caller is a threshold nobody can find, and a second copy is free
to drift from the first.
**`author`, `usage_count` and `last_modified` are deliberately NOT required, and the denominator is
written down rather than implied.** SPEC § 5.1 names **six** keys on a `sources` entry — `resource`,
`id`, `title`, `author`, `usage_count`, `last_modified` — and the producer writes **two of them**:
```sh
sed -n '303,313p' ~/repos/_okf-canonical/SPEC.md # the six entry keys
grep -rh '^sources:' ~/repos/llm-ingestion-okf/examples/
# -> sources: [{ id: golden-v0-2-sales, resource: fixture }] (1 of 1 file carrying the key)
```
Measured 2026-09-02 against producer `62b6192`. **2 of 6, not 2 of 5** — an earlier draft of this
contract carried the smaller denominator, which would have understated how much of § 5.1 the
producer leaves unwritten. Requiring the three credibility signals would make the threshold
unreachable in practice while looking strict on paper: the worst of both. **The threshold names only
what is actually written.**
`usage_window` is a sibling of `sources`, not an entry key, and is outside the six.
## § 2. The adjudication state — absence is `unknown`, never `absent`
A concept carries its adjudication state in the frontmatter key **`adjudication`**, whose value set
is **closed**: `proposed` or `adjudicated`.
| Observation | State |
|---|---|
| `adjudication: proposed` | `proposed` |
| `adjudication: adjudicated` | `adjudicated` |
| the key is not present | **`unknown`** |
| any other value | **refused by name** — never mapped into the vocabulary |
**The third row is the whole contract.** A concept that does not carry the key means *we did not
learn whether this was adjudicated* (an older bundle), and collapsing that into `absent` — *it was
not adjudicated* — is a verdict on missing evidence presented as evidence of absence. It is the same
defect as collapsing `unreadable` into `absent` one layer up, and the same defect the ungiven-verdict
work removed from `RunResult.verdict`.
The fourth row is **validation, never repair**: an out-of-vocabulary value is an error, not an
extension point, and mapping it to `unknown` would silently invent the very state this contract
exists to keep honest.
**Honesty limit, stated:** this consumer's fixtures are **hand-written to the contract above**, not
produced by `llm-ingestion-okf`. Integration against the producer's own golden is later work and is
not claimed here.
## § 3. Identity across bundles — the pair `(bundle_id, concept_id)`
A concept ID is **bundle-local and stable**. Identity **across** bundles is the pair
**`(bundle_id, concept_id)`** — never the concept ID alone.
`bundle_id` resolves in a **fixed order**, and the resolved value carries **which source answered**:
| Order | Source | `origin` |
|---|---|---|
| 1 | the concept's own frontmatter | `declared-concept` |
| 2 | the bundle root's `index.md` | `declared-index` |
| 3 | neither declared it — the mount basename is used | `mount-derived` |
**Three origins, not a boolean.** A caller that cannot tell *"the concept said so"* from *"we fell
back twice"* has been handed a stamp it cannot audit.
**A base with no readable `index.md` is not "undeclared".** The existing navigation fail-fast
propagates unchanged; reading an unreadable base as *"no declaration"* is the tolerant-read defect
that widens an answer instead of refusing it. Only a base whose index *is* readable and declares
nothing falls through to the next row.
**Measured today: every base resolves `mount-derived`.** No shipped `index.md` declares the key:
```sh
find shared -name index.md | wc -l # -> 7
grep -l 'bundle_id' $(find shared -name index.md) | wc -l # -> 0
```
So this contract changes which sources are **consulted**, not what happens when none of them
declares anything — which is why adopting it moves no existing call site.
**There is no cross-bundle link form.** A consumer holding several bundles partitions per bundle;
the producer emits no syntax for pointing from inside one bundle into another, and adding one is out
of scope until a consumer states the need.
## § 4. What these three do not settle
- **The wire form of `sources` is the producer's to fix.** Flow-sequence-of-mappings is the normative
emission form; block form remains conformant OKF but outside the accepted subset. A known defect
stands on the producer side: `llm-ingestion-guard` 1.2.0 rejects a flow sequence of mappings for
`sources`. That is a **known producer-side gate defect, not a consumer error**, and this consumer
does not wait on it.
- **The trust tiers themselves** (§ 5.3 of the SPEC) are inferred, never stored — no credibility
score is written by either side.
- **Nothing here wires a library primitive into a run's stdout.** The reader reads; the caller
decides. Both halves of that split predate these contracts and are unchanged by them.