A concept named its source file by basename and, when segmented, carried a
`source_offset` into the text THIS LIBRARY extracted. Following that pointer
needed the corpus directory, the extractor and its exact transitive version --
none of which the bundle carries. Hand-walked on a real K2 concept: six steps,
four of them requiring knowledge from outside the bundle, to learn that a
requirement sits on pages 12-13 of a 20-page document.
The address is spec's: `sources: [{ resource, title }]`, where `resource` is
the dropped file's inbox-relative path (SPEC v0.2 5.1:303-306 -- "an absolute
URL, a bundle-relative path, or a path into a `references/` subdirectory").
The locator is ours, and it has to be: 5.1 has no field for a place within a
resource, and the pinned guard (1.3.0) rejects every route to putting one
inside a `sources` entry -- a non-allowlisted key by name, a nested flow list
as "scalar leaves only", and quoting as an unsupported form. So the locator is
top-level keys shaped like `source_offset`, and a path carrying a flow
terminator is refused fail-fast rather than mangled.
The unit table is built AT EXTRACTION, where the extracted text and the
original's structure are known to agree: pdf -> `source_pages` from
pdfplumber's own page numbers (a page that yielded no text does not renumber
the ones after it), xlsx -> `source_sheet` + `source_rows`, everything else ->
`source_lines`. `source_offset` stays.
Two measurements changed the design before it shipped. A `paragraphs` key for
docx would name a number the document does not have: `<w:p>` counts of
108/27/65/176/57 against converted-markdown lines of 75/33/67/144/63, not one
pair agreeing -- so the key is `source_lines` and says what it indexes. And an
empty spreadsheet row renders exactly like a table separator: the content-based
rule ate 8 empty rows on the K2 price sheet and reported its last row as 92
against a workbook that says 100. The separator is now found by position, and
`tomrad.xlsx` keeps that red.
One profile moves. `provenance` is a policy object, `None` everywhere but
`SEGMENTED_OKF_V0_2`; the other five shipped profiles are byte-identical.
K2 rebuilt from a frozen src copy: 629 concepts, 1108 files, name set identical,
0 ids moved, 479 files byte-identical, 629 changed and 0 lines removed anywhere.
629/629 now carry an address and a locator. New ref
`sha256-tree:665563a2f74423fcbcc8e4f0b0954ee73b73985ac0418de4f6987bd162a1f7c8`;
`2f82fcfe...` is stale. The pre-pass payload does not grow by one byte
(209 092 B before and after, 18 changed lines: the ref and eight per-concept
digests) -- because an excerpt carries the body, not the frontmatter, which is
also why the consumer still cannot cite "file X page 12" from a payload alone.
Report: docs/2026-09-08-proveniens-k2.md. 1339 tests, ruff and mypy clean.
Co-Authored-By: Claude <claude-opus-5>
62 lines
2.2 KiB
JSON
62 lines
2.2 KiB
JSON
{
|
|
"contract": "okf-consumption/1",
|
|
"bundle": {
|
|
"bundle_id": "b-golden-segmented-okf-v0-2",
|
|
"ref": "sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe"
|
|
},
|
|
"budget": {
|
|
"unit": "utf-8 bytes of emitted JSON",
|
|
"instrument": "okf_consume.measure (len of the ensure_ascii=False JSON encoding, utf-8)",
|
|
"limit": 120000,
|
|
"spent": 1306,
|
|
"known_positive": {
|
|
"case": "docs/consumption-contract.md, encoded as a JSON string",
|
|
"expected": 10349,
|
|
"measured": 10349,
|
|
"raw_bytes": 10060,
|
|
"encoding_delta": 289
|
|
}
|
|
},
|
|
"denominators": {
|
|
"considered": 3,
|
|
"withheld": 0,
|
|
"delivered": 3
|
|
},
|
|
"question": "Hva sier veiledningen om krav?",
|
|
"excerpts": [
|
|
{
|
|
"bundle_id": "b-golden-segmented-okf-v0-2",
|
|
"concept_id": "krav/1-1/foerste-krav",
|
|
"sha256": "84145512284a8bbc1a8905c73d0de3f0e0cb7081cf517f778fe88a610d2b4f62",
|
|
"adjudication": "proposed",
|
|
"trust_tier": "unverified",
|
|
"bundle_id_inherited": false,
|
|
"text_sha256": "08447c690087834883a78fb9f40d474c68b2526ed57d0dafe01c4868db3c04f0",
|
|
"text": "\n## 1.1 Foerste krav\n\nEt krav som beskriver den foerste betingelsen i eksempelet.",
|
|
"rank": 1
|
|
},
|
|
{
|
|
"bundle_id": "b-golden-segmented-okf-v0-2",
|
|
"concept_id": "veiledning",
|
|
"sha256": "8f1f4d940887b96b39496d0aceb7a4fa212553510165917427e4f7e9efb98b03",
|
|
"adjudication": "proposed",
|
|
"trust_tier": "unverified",
|
|
"bundle_id_inherited": false,
|
|
"text_sha256": "82d67ff01367a1a56532130e077956048004ac047e6062eae2143d96704c4a92",
|
|
"text": "\n# Veiledning for eksempelbundel\n\nDenne teksten er syntetisk og finnes kun for a pinne bytes.",
|
|
"rank": 2
|
|
},
|
|
{
|
|
"bundle_id": "b-golden-segmented-okf-v0-2",
|
|
"concept_id": "krav/1-2/andre-krav",
|
|
"sha256": "4f8a869aa4e898ec1a30595951b3e198e09091d76c41078a52e821000eb9e22c",
|
|
"adjudication": "proposed",
|
|
"trust_tier": "unverified",
|
|
"bundle_id_inherited": false,
|
|
"text_sha256": "4c181e1debb141d3cb1a7bd47249fdac1c0b2c5db1b47cf255ef8f04f83ec840",
|
|
"text": "\n## 1.2 Andre krav\n\nEt krav som beskriver den andre betingelsen i eksempelet.",
|
|
"rank": 3
|
|
}
|
|
],
|
|
"withheld": []
|
|
}
|