fix(structure): the index resolves a parent naming a segment of its own document
K3-21 C. `resolve_structure` asks `_segment_lookup` first for a `parent`
edge: `(source_file, segment_id)` -> concept name, keyed off each concept's
own frontmatter (`DocumentStructure.declared`, no file read again), so a
pointer lands only inside the pointing concept's document -- `p1` exists in
every document of a multi-document bundle. A value no segment answers to is a
document number and is looked up exactly as before; a pointer naming nothing
keeps `UNRESOLVED_MARKER`. The rendering rule is untouched: a resolved
relation renders as its subject, so `parent: p1977?` becomes `parent: p1977`.
Moved on purpose, each named: both segmented goldens' index files
(`examples/ingest-golden-segmented{,-okf-v0-2}/expected-bundle/krav/1-{1,2}/
index.md`), whose declared parents s1 and s2 -> s0 rendered `parent: s0?`
while s0 stood in the bundle -- four lines, `?` removed. The four goldens
`test_the_four_existing_goldens_are_untouched` guards are not among them.
`skills/okf-consume/` regenerated, because the golden's index bytes -- and so
its ref -- moved. `test_shell_parent`'s byte test now expects the resolved
facet. README and CLAUDE.md no longer say the index renders it unresolved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c188a0c749
commit
59703699a5
10 changed files with 50 additions and 17 deletions
11
CLAUDE.md
11
CLAUDE.md
|
|
@ -641,10 +641,13 @@ and fixtures, never code.
|
|||
set is the same with it as without it; a text that does not fit is cut to
|
||||
the longest prefix that does and marked `truncated`. Whether either default
|
||||
moves is K3-21 B's measurement, not this line's.
|
||||
**The index renders every such parent
|
||||
UNRESOLVED** (`parent: p1?`): `structure` reads `parent` as a document
|
||||
NUMBER, and a segment id answers to none -- the one key with two meanings
|
||||
`inbox.py` already names for a declared parent. Report:
|
||||
**Since K3-21 C the index RESOLVES such a parent**: it rendered every one
|
||||
unresolved (`parent: p1?`, 675 of 675) because `structure` read `parent` as
|
||||
a document NUMBER and a segment id answers to none. `structure._segment_lookup`
|
||||
keys `(source_file, segment_id)` off the concept's own frontmatter and is
|
||||
asked first, inside the pointing concept's document; a value no segment
|
||||
answers to is a number, looked up as before, and a pointer naming nothing
|
||||
keeps `?`. The one key keeps its two meanings (`inbox.py`). Report:
|
||||
`docs/2026-09-11-k3-runde20-delt-katalog-og-arvet-kontekst.md`.
|
||||
- **A TWELFTH flag, `--pdf-outline`, is OFF** (round 12, 2026-09-10) and it is
|
||||
the only one here that does not read the extracted text at all: it cuts a PDF
|
||||
|
|
|
|||
|
|
@ -177,9 +177,9 @@ heading-only body gains one line, `Enclosing section: [title](/path)`, in the
|
|||
bundle-relative form SPEC § 6.1 recommends. `okf consume --follow-parent`
|
||||
carries the enclosing section's text inside `parent` as well, with that
|
||||
concept's own `sha256`, and only from the room the cut left — so it never
|
||||
displaces an excerpt. Whether either default moves is measured separately. One cost is known and not repaired: the index projects
|
||||
`parent` as a document number, so a segment id always renders there as
|
||||
unresolved (`parent: p1?`), even though the concept it names is in the bundle.
|
||||
displaces an excerpt. Whether either default moves is measured separately. The index resolves the pointer too: a segment id is looked up among the
|
||||
concepts of its own document, so it renders `parent: p1` when the concept it
|
||||
names is in the bundle and keeps the `?` only when nothing answers to it.
|
||||
|
||||
### The segmentation flags
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
- [Foerste krav](foerste-krav.md) — parent: s0?; adjudication: proposed
|
||||
- [Foerste krav](foerste-krav.md) — parent: s0; adjudication: proposed
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
- [Andre krav](andre-krav.md) — parent: s0?; adjudication: proposed
|
||||
- [Andre krav](andre-krav.md) — parent: s0; adjudication: proposed
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
- [Foerste krav](foerste-krav.md) — parent: s0?
|
||||
- [Foerste krav](foerste-krav.md) — parent: s0
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
- [Andre krav](andre-krav.md) — parent: s0?
|
||||
- [Andre krav](andre-krav.md) — parent: s0
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: b-golden-segmented-okf-v0-2-consume
|
||||
description: Answer one question about the OKF bundle `b-golden-segmented-okf-v0-2` (3 concepts, ref sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe) from a bounded payload assembled by a deterministic pre-pass, marking every claim with its source, its title and its provenance locator. Use whenever a question is about what that bundle's documents require, say or contain. Generated by `okf skill`; every value below is measured against this bundle at this ref.
|
||||
description: Answer one question about the OKF bundle `b-golden-segmented-okf-v0-2` (3 concepts, ref sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f) from a bounded payload assembled by a deterministic pre-pass, marking every claim with its source, its title and its provenance locator. Use whenever a question is about what that bundle's documents require, say or contain. Generated by `okf skill`; every value below is measured against this bundle at this ref.
|
||||
---
|
||||
|
||||
# b-golden-segmented-okf-v0-2 consumption
|
||||
|
|
@ -9,7 +9,7 @@ Answer one question about the `b-golden-segmented-okf-v0-2` bundle, from the pay
|
|||
assembled, at one ref.
|
||||
|
||||
**This file is an instantiated copy of `skills/okf-consume-template/SKILL.md`,** generated by `okf skill` for one bundle: `b-golden-segmented-okf-v0-2` at ref
|
||||
`sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe`. Every value below was measured against those bytes. If the
|
||||
`sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f`. Every value below was measured against those bytes. If the
|
||||
bundle moves, the ref moves with it and this file is stale — regenerate
|
||||
it rather than editing a number here. The section headings are fixed:
|
||||
the contract checker reads them by name.
|
||||
|
|
@ -25,7 +25,7 @@ Step 1 is always the pre-pass. Run it, read its JSON payload, and judge that.
|
|||
okf consume \
|
||||
examples/ingest-golden-segmented-okf-v0-2/expected-bundle \
|
||||
--question "your question" \
|
||||
--ref sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe \
|
||||
--ref sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f \
|
||||
--out /tmp/payload.json
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"contract": "okf-consumption/1",
|
||||
"bundle": {
|
||||
"bundle_id": "b-golden-segmented-okf-v0-2",
|
||||
"ref": "sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe"
|
||||
"ref": "sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f"
|
||||
},
|
||||
"budget": {
|
||||
"unit": "utf-8 bytes of emitted JSON",
|
||||
|
|
|
|||
|
|
@ -411,6 +411,28 @@ def _lookup(documents: Mapping[str, DocumentStructure]) -> dict[str, str]:
|
|||
return {key: next(iter(owners)) for key, owners in claims.items() if len(owners) == 1}
|
||||
|
||||
|
||||
#: The key a segmentation plan's entry id is written under (`inbox.py`), and
|
||||
#: the value a declared `parent` names.
|
||||
SEGMENT_ID_KEY = "segment_id"
|
||||
|
||||
|
||||
def _segment_lookup(documents: Mapping[str, DocumentStructure]) -> dict[tuple[str, str], str]:
|
||||
"""`(source_file, segment_id)` -> concept name, for every concept a plan wrote.
|
||||
|
||||
A plan entry's `parent_id` names another entry of the SAME plan, and a plan
|
||||
is one document's: `p1` exists in every document of a multi-document bundle,
|
||||
so the key carries the source file. `declared` is the concept's own
|
||||
frontmatter, verbatim, which is where the door wrote `segment_id` -- no
|
||||
file is read again. A key claimed twice is dropped, `_lookup`'s rule.
|
||||
"""
|
||||
claims: dict[tuple[str, str], set[str]] = {}
|
||||
for name, document in documents.items():
|
||||
segment_id = document.declared.get(SEGMENT_ID_KEY, "").strip()
|
||||
if segment_id:
|
||||
claims.setdefault((document.source_file, segment_id), set()).add(name)
|
||||
return {key: next(iter(owners)) for key, owners in claims.items() if len(owners) == 1}
|
||||
|
||||
|
||||
def resolve_structure(documents: Mapping[str, DocumentStructure]) -> BundleStructure:
|
||||
"""Resolve every pointer in `documents` against the bundle as a whole.
|
||||
|
||||
|
|
@ -426,17 +448,24 @@ def resolve_structure(documents: Mapping[str, DocumentStructure]) -> BundleStruc
|
|||
function proposes on its own — same number, ordered versions — always is.
|
||||
"""
|
||||
by_key = _lookup(documents)
|
||||
by_segment = _segment_lookup(documents)
|
||||
edges: list[StructureEdge] = []
|
||||
|
||||
for name in sorted(documents):
|
||||
document = documents[name]
|
||||
if document.parent_number is not None:
|
||||
# One key, two meanings (`inbox.py`): a plan's DECLARED `parent_id`
|
||||
# names a segment of the same document, and `structure`'s DERIVED
|
||||
# parent is a document number. The segment is asked first and only
|
||||
# inside the pointing concept's own document; a value no segment
|
||||
# answers to is a number, looked up exactly as before.
|
||||
edges.append(
|
||||
StructureEdge(
|
||||
source=name,
|
||||
kind="parent",
|
||||
subject=document.parent_number,
|
||||
target=by_key.get(document.parent_number.upper()),
|
||||
target=by_segment.get((document.source_file, document.parent_number))
|
||||
or by_key.get(document.parent_number.upper()),
|
||||
derived="parent" in document.derived,
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -179,7 +179,8 @@ def test_a_build_without_the_flag_is_the_build_with_the_opt_out(tmp_path: Path)
|
|||
text = (flagged / relative).read_text(encoding="utf-8")
|
||||
if relative.name == "index.md":
|
||||
after = text.split("\n")
|
||||
assert [re.sub(r"parent: p\d+\?; ", "", line) for line in after] == before
|
||||
# Resolved since K3-21 C: the concept the pointer names is here.
|
||||
assert [re.sub(r"parent: p\d+; ", "", line) for line in after] == before
|
||||
continue
|
||||
text, links = re.subn(r"\n\nEnclosing section: \[[^\]]+\]\(/[^)\s]+\)\n\Z", "\n", text)
|
||||
linked += links
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue