test(okf): consume nav-golden fixtures + thin STEG 0 corpus gate
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
This commit is contained in:
parent
0bca9c7525
commit
325727523d
20 changed files with 539 additions and 0 deletions
5
test/nav-golden-corpus/.gitattributes
vendored
Normal file
5
test/nav-golden-corpus/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Preserve the consumed fixtures byte-exact (mirrors test/okf-parity-corpus).
|
||||
# The expected-read-context.md goldens are byte-exact fasit from commons @ b641741;
|
||||
# a future navigator-conformance consumer may compare byte-for-byte, so git must
|
||||
# not normalize EOL/BOM on any file in this corpus.
|
||||
* -text
|
||||
20
test/nav-golden-corpus/manifest.json
Normal file
20
test/nav-golden-corpus/manifest.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"_doc": "STEG 0 nav-golden corpus. Fixtures consumed byte-exact from portfolio-optimiser-commons @ b641741 (examples/nav-golden-*). Gate: scripts/check-nav-golden.mjs. SCOPE (thin, by design): the catalog is the convention owner and holds no consumer (null konsument), so this gate does NOT run a read-context navigator. It keeps each consumed fixture's bundle/ under the existing §3 OKF conformance check (every concept typed + root okf_version present) and guards that the committed expected-read-context.md golden is present and non-empty. Byte-exact navigator conformance against the goldens is a consumer concern (okr STEG 4) and the deferred shared retrieval skill (spec.md §10 Stage 3), NOT catalog's. Normative navigation rules the goldens derive from: commons method-spec.md §3 Step 1 (five read-context bullets) + §11 Navigation boundary.",
|
||||
"source": {
|
||||
"repo": "portfolio-optimiser-commons",
|
||||
"commit": "b641741",
|
||||
"path": "examples/",
|
||||
"consumedBundleSubdir": "bundle",
|
||||
"golden": "expected-read-context.md"
|
||||
},
|
||||
"fixtures": {
|
||||
"nav-golden-hierarchy": {
|
||||
"axis": "valid nested navigation",
|
||||
"note": "positive golden: depth-first traversal, both link forms, recursive verdict exclusion, resolved-path dedup, cycle termination, root-only missing-index rule"
|
||||
},
|
||||
"nav-golden-escape": {
|
||||
"axis": "out-of-bundle escape",
|
||||
"note": "boundary golden: parent/deep-parent/root-relative-trap escapes all skipped, one valid in-bundle sibling returned"
|
||||
}
|
||||
}
|
||||
}
|
||||
27
test/nav-golden-corpus/nav-golden-escape/README.md
Normal file
27
test/nav-golden-corpus/nav-golden-escape/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# nav-golden-escape — negative navigation golden (the gate must be able to go red)
|
||||
|
||||
Per catalog's requirement that step 0's gate must be able to **fail** (a gate that can
|
||||
only pass proves nothing), this negative case makes a conformant navigator and a naive one
|
||||
**provably diverge**. It is the counterpart to `nav-golden-hierarchy` (the positive case).
|
||||
|
||||
`bundle/index.md` links one valid sibling and three escaping / trap targets:
|
||||
|
||||
| Link | Class | Conformant outcome |
|
||||
|---|---|---|
|
||||
| `valid.md` | in-bundle | returned |
|
||||
| `../SHOULD-NOT-BE-READ.md` | `..` escape (the decoy really exists, one level up) | skipped; decoy never read |
|
||||
| `../../../../etc/passwd` | deep `..` escape | skipped |
|
||||
| `/etc/passwd` | root-relative **trap** | skipped |
|
||||
|
||||
The trap is the load-bearing one. Under the ratified rule, a leading `/` denotes the
|
||||
**bundle root**, so `/etc/passwd` resolves to `{bundle}/etc/passwd` (no such file → skip),
|
||||
NOT the filesystem path. A naive implementation that reads `/` as filesystem-absolute opens
|
||||
the real `/etc/passwd` — a path-traversal breach. This case fails for any implementation
|
||||
that raises, reads the decoy, or leaks `/etc/passwd` content; it passes only when the
|
||||
read-context is exactly `valid.md`.
|
||||
|
||||
The malformed-target sub-class (an embedded null byte, other invalid path components) is
|
||||
covered by the method-spec §11 **Navigation boundary** seam as a unit test — a literal null
|
||||
byte does not belong in a committed text fixture. (See the relocated finding
|
||||
`docs/plan/2026-07-20-funn-portfolio-optimiser-nullbyte.local.md` for the concrete
|
||||
null-byte reproduction that motivates the seam.)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: project
|
||||
title: "Decoy — MUST NOT be read"
|
||||
---
|
||||
|
||||
This file sits ONE level above `bundle/`, outside the bundle. If its text ever appears in a read-context, the navigator resolved a `..` escape and breached the bundle boundary. It MUST never be reached.
|
||||
12
test/nav-golden-corpus/nav-golden-escape/bundle/index.md
Normal file
12
test/nav-golden-corpus/nav-golden-escape/bundle/index.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
type: index
|
||||
okf_version: 0.1
|
||||
title: "Nav-golden — escape / boundary case"
|
||||
---
|
||||
|
||||
Nav-golden escape case. Every link but the first escapes the bundle or is a root-relative trap; a conformant navigator skips them all, reads none of them, raises nothing, and still returns the one valid sibling.
|
||||
|
||||
- [Valid sibling](valid.md)
|
||||
- [Parent escape](../SHOULD-NOT-BE-READ.md)
|
||||
- [Deep escape](../../../../etc/passwd)
|
||||
- [Root-relative trap](/etc/passwd)
|
||||
6
test/nav-golden-corpus/nav-golden-escape/bundle/valid.md
Normal file
6
test/nav-golden-corpus/nav-golden-escape/bundle/valid.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: project
|
||||
title: "Valid sibling"
|
||||
---
|
||||
|
||||
The only in-bundle target. A conformant navigator returns exactly this file.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Nav-golden escape case. Every link but the first escapes the bundle or is a root-relative trap; a conformant navigator skips them all, reads none of them, raises nothing, and still returns the one valid sibling.
|
||||
|
||||
- [Valid sibling](valid.md)
|
||||
- [Parent escape](../SHOULD-NOT-BE-READ.md)
|
||||
- [Deep escape](../../../../etc/passwd)
|
||||
- [Root-relative trap](/etc/passwd)
|
||||
|
||||
## project: Valid sibling
|
||||
|
||||
The only in-bundle target. A conformant navigator returns exactly this file.
|
||||
34
test/nav-golden-corpus/nav-golden-hierarchy/README.md
Normal file
34
test/nav-golden-corpus/nav-golden-hierarchy/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# 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.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: reference
|
||||
title: "Doc B"
|
||||
---
|
||||
|
||||
Level-2 concept reached depth-first, deepest in the traversal.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: index
|
||||
okf_version: 0.1
|
||||
title: "Subsection B index"
|
||||
---
|
||||
|
||||
- [Doc B](doc-b.md)
|
||||
- [Back to A](/a/index.md)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: methodology
|
||||
title: "Doc A"
|
||||
---
|
||||
|
||||
Level-1 concept reached depth-first after Overview.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
type: index
|
||||
okf_version: 0.1
|
||||
title: "Section A index"
|
||||
---
|
||||
|
||||
- [Doc A](doc-a.md)
|
||||
- [Nested verdict](verdict-nested.md)
|
||||
- [Subsection B](b/index.md)
|
||||
- [Overview again](/overview.md)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: verdict
|
||||
title: "Nested verdict — must be excluded"
|
||||
decision: approved
|
||||
description: "A verdict file at a nested level. A conformant navigator reaches it (dedup marks it seen) but MUST exclude it from the read-context — recursively, not only at the root. This is the leakage surface a graph-based exclusion would miss."
|
||||
---
|
||||
|
||||
This body MUST NOT appear in the read-context.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: project
|
||||
title: "Orphan — unreachable"
|
||||
---
|
||||
|
||||
Directory `c/` has no `index.md`, and nothing links to this file. A link-following navigator never reaches it; a directory-walking one wrongly would. It MUST be absent from the read-context, and its parent directory's missing `index.md` MUST NOT be an error (that rule binds the bundle root alone).
|
||||
10
test/nav-golden-corpus/nav-golden-hierarchy/bundle/index.md
Normal file
10
test/nav-golden-corpus/nav-golden-hierarchy/bundle/index.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
type: index
|
||||
okf_version: 0.1
|
||||
title: "Nav-golden — hierarchical navigation case"
|
||||
---
|
||||
|
||||
Nav-golden hierarchical case. This bundle exercises depth-first traversal, both link forms (root-relative and relative), recursive verdict exclusion, resolved-path de-duplication, cycle termination, and the root-only binding of the missing-index rule.
|
||||
|
||||
- [Overview](overview.md)
|
||||
- [Section A](/a/index.md)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: project
|
||||
title: "Overview"
|
||||
---
|
||||
|
||||
Root-level concept reached by a relative link.
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Nav-golden hierarchical case. This bundle exercises depth-first traversal, both link forms (root-relative and relative), recursive verdict exclusion, resolved-path de-duplication, cycle termination, and the root-only binding of the missing-index rule.
|
||||
|
||||
- [Overview](overview.md)
|
||||
- [Section A](/a/index.md)
|
||||
|
||||
## project: Overview
|
||||
|
||||
Root-level concept reached by a relative link.
|
||||
|
||||
## methodology: Doc A
|
||||
|
||||
Level-1 concept reached depth-first after Overview.
|
||||
|
||||
## reference: Doc B
|
||||
|
||||
Level-2 concept reached depth-first, deepest in the traversal.
|
||||
Loading…
Add table
Add a link
Reference in a new issue