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:
Kjell Tore Guttormsen 2026-07-24 20:35:44 +02:00
commit 325727523d
20 changed files with 539 additions and 0 deletions

View 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.)