Consume commons' nav-golden fixture class byte-exact from portfolio-optimiser-commons @ b641741 (nav-golden-hierarchy positive + nav-golden-escape boundary) into test/nav-golden-corpus/ and wire a thin gate scripts/check-nav-golden.mjs (+ .test.mjs, 10 tests). Scope (operator decision, thin): the catalog is the convention owner and holds no consumer (null konsument), and the shared retrieval skill is deferred (spec.md §10 Stage 3). So the gate does NOT run a read-context navigator and does NOT assert the goldens byte-exact. It asserts only what the catalog owns: each fixture bundle/ is a conformant OKF bundle under the existing §3 checkBundle (every concept typed + root okf_version), and the committed expected-read-context.md golden is present and non-empty. Byte-exact navigator conformance stays a consumer concern (okr STEG 4 / Stage 3 skill). Fixtures pinned byte-exact (.gitattributes -text); manifest carries source repo+SHA per the vendoring-provenance rule. Naming: the stale "§5 pts 1-5" read-context label maps to the settled method-spec §3 Step 1 (commons 9801d35); no open §5 dependency. commons confirmed b641741 complete + goldens derived from §3 Step 1 (via coord). Verified: check-nav-golden 10/10; gate CLI exit 0 (2 fixtures PASS); full suite 73/73 across the six test files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NeK9hkxrU9wFPBYGYnSV1V
2.5 KiB
nav-golden-hierarchy — hierarchical navigation golden
Fixture class nav-golden (commons-owned, per the D4 step-0 split): bundle/ in,
expected-read-context.md out. Unlike the ingest-golden class (ingest-spec §11,
extraction-shaped: manifest.json → expected-bundle/), a nav-golden case is
bundle → read-context — the only shape that can express the load-bearing property
"two conformant implementations MUST produce an identical read-context from the same
bundle" (method-spec §3 Step 1).
This positive case exercises every decision the Q3 navigation contract pins:
| Decision (method-spec §3 Step 1) | How this bundle exercises it |
|---|---|
| Hierarchy allowed; escape, not depth, forbidden | a/, a/b/ are navigated; nothing escapes |
Link syntax: leading / = bundle root, else relative |
index.md: relative overview.md + root-relative /a/index.md; a/index.md: relative b/index.md + root-relative /overview.md |
| Depth-first, first-seen order | render order is overview → doc-a → doc-b |
| Dedup on resolved path | /overview.md (from a/) resolves to the already-seen overview.md → one entry |
| Cycle termination | a/b/index.md links back to /a/index.md (already seen) → stops |
| One segment per level | each index links only its immediate children |
Missing index.md binds the root alone |
c/ has no index.md and nothing links c/orphan.md; it is simply unreachable, not an error |
| Verdict exclusion = type check per reached file, recursive | a/verdict-nested.md is reached but excluded |
| Flat render regardless of depth | nested concepts render as the same ## {type}: {title} sections; no level heading; nested index bodies are navigation, not content, and are not rendered |
Traversal trace: index.md (its body is the leading summary) → overview.md →
/a/index.md → a/doc-a.md → a/verdict-nested.md (reached, excluded) → a/b/index.md
→ a/b/doc-b.md → /a/index.md (seen, deduped) → /overview.md (seen, deduped).
Unreachable: c/orphan.md.
Serialization the gate compares against: the root index body verbatim, then each
non-index concept as ## {type}: {title} + blank line + the file body, sections
separated by one blank line, file ending in exactly one trailing newline. The spec does
not pin whitespace beyond this shape; a gate MAY compare byte-exact or after
trailing-whitespace normalization. Only the root index body is the summary — nested
index bodies (a/index.md, a/b/index.md) are navigation and do not appear.