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
|
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
|
the longest prefix that does and marked `truncated`. Whether either default
|
||||||
moves is K3-21 B's measurement, not this line's.
|
moves is K3-21 B's measurement, not this line's.
|
||||||
**The index renders every such parent
|
**Since K3-21 C the index RESOLVES such a parent**: it rendered every one
|
||||||
UNRESOLVED** (`parent: p1?`): `structure` reads `parent` as a document
|
unresolved (`parent: p1?`, 675 of 675) because `structure` read `parent` as
|
||||||
NUMBER, and a segment id answers to none -- the one key with two meanings
|
a document NUMBER and a segment id answers to none. `structure._segment_lookup`
|
||||||
`inbox.py` already names for a declared parent. Report:
|
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`.
|
`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
|
- **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
|
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`
|
bundle-relative form SPEC § 6.1 recommends. `okf consume --follow-parent`
|
||||||
carries the enclosing section's text inside `parent` as well, with that
|
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
|
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
|
displaces an excerpt. Whether either default moves is measured separately. The index resolves the pointer too: a segment id is looked up among the
|
||||||
`parent` as a document number, so a segment id always renders there as
|
concepts of its own document, so it renders `parent: p1` when the concept it
|
||||||
unresolved (`parent: p1?`), even though the concept it names is in the bundle.
|
names is in the bundle and keeps the `?` only when nothing answers to it.
|
||||||
|
|
||||||
### The segmentation flags
|
### 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
|
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
|
# 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.
|
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
|
**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
|
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:
|
it rather than editing a number here. The section headings are fixed:
|
||||||
the contract checker reads them by name.
|
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 \
|
okf consume \
|
||||||
examples/ingest-golden-segmented-okf-v0-2/expected-bundle \
|
examples/ingest-golden-segmented-okf-v0-2/expected-bundle \
|
||||||
--question "your question" \
|
--question "your question" \
|
||||||
--ref sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe \
|
--ref sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f \
|
||||||
--out /tmp/payload.json
|
--out /tmp/payload.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"contract": "okf-consumption/1",
|
"contract": "okf-consumption/1",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"bundle_id": "b-golden-segmented-okf-v0-2",
|
"bundle_id": "b-golden-segmented-okf-v0-2",
|
||||||
"ref": "sha256-tree:f85646c1f77982a69b97afca08209f369b79cd39c217f6f2c074c2dc5bac23fe"
|
"ref": "sha256-tree:cce7a02c769793cdb6e3afda45c955461b57373deab13a986d8bf7843d6e436f"
|
||||||
},
|
},
|
||||||
"budget": {
|
"budget": {
|
||||||
"unit": "utf-8 bytes of emitted JSON",
|
"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}
|
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:
|
def resolve_structure(documents: Mapping[str, DocumentStructure]) -> BundleStructure:
|
||||||
"""Resolve every pointer in `documents` against the bundle as a whole.
|
"""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.
|
function proposes on its own — same number, ordered versions — always is.
|
||||||
"""
|
"""
|
||||||
by_key = _lookup(documents)
|
by_key = _lookup(documents)
|
||||||
|
by_segment = _segment_lookup(documents)
|
||||||
edges: list[StructureEdge] = []
|
edges: list[StructureEdge] = []
|
||||||
|
|
||||||
for name in sorted(documents):
|
for name in sorted(documents):
|
||||||
document = documents[name]
|
document = documents[name]
|
||||||
if document.parent_number is not None:
|
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(
|
edges.append(
|
||||||
StructureEdge(
|
StructureEdge(
|
||||||
source=name,
|
source=name,
|
||||||
kind="parent",
|
kind="parent",
|
||||||
subject=document.parent_number,
|
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,
|
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")
|
text = (flagged / relative).read_text(encoding="utf-8")
|
||||||
if relative.name == "index.md":
|
if relative.name == "index.md":
|
||||||
after = text.split("\n")
|
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
|
continue
|
||||||
text, links = re.subn(r"\n\nEnclosing section: \[[^\]]+\]\(/[^)\s]+\)\n\Z", "\n", text)
|
text, links = re.subn(r"\n\nEnclosing section: \[[^\]]+\]\(/[^)\s]+\)\n\Z", "\n", text)
|
||||||
linked += links
|
linked += links
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue