1
0
Fork 0

docs(spec): method-spec §3 Step 1 — Q3 navigation contract (hierarchy)

Ratified Q3 resolution: the navigator must traverse hierarchical bundles;
door A stays flat (ingest-spec unchanged). Replaces the path-separator ban
with resolve-and-boundary-check as one change (decision record §3 item 6):
link syntax normative (/ = bundle root, never fs-absolute; else relative;
nested allowed, escape not), depth-first first-seen traversal, dedup on
resolved path, one segment per level, missing index.md binds the root
alone, verdict-exclusion = type check per reached file (recursive, never a
graph property), flat read-context render. Robustness now covers malformed
targets (skipped never raised) — closes the null-byte class at spec level.
Two §11 seams. Framework-neutral; backward-compatible (golden unaffected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUCuNNvnCkayuUDy2WFgeU
This commit is contained in:
Kjell Tore Guttormsen 2026-07-21 09:26:43 +02:00
commit 9801d35636

View file

@ -65,20 +65,42 @@ progressive disclosure — never by stuffing the whole bundle (or keyword-retrie
it) into the prompt:
- Navigation starts at `index.md` and follows its intra-bundle markdown cross-links
(`](target.md)`). Targets containing a path separator are out-of-bundle and MUST be
skipped. Repeated links are de-duplicated; order is deterministic (index first, then links
in first-seen order). *(reference: the link pattern is `\]\(([^)]+\.md)\)`)*
- A missing `index.md` is an error (a bundle has no entry point without it). A broken or
bundle-escaping cross-link MUST be tolerated — skipped, never raised (OKF robustness rule);
path resolution MUST be boundary-checked against the bundle directory, fail-closed.
(`](target.md)`). A target is resolved **relative to the bundle** and boundary-checked
fail-closed (below): a leading `/` denotes the **bundle root** (NEVER a filesystem-absolute
path), any other form is relative to the linking file's own directory — so a target MAY
address a nested directory (`sub/index.md`, `/a/b.md`). It is **escape, not depth**, that is
forbidden: a target resolving outside the bundle is skipped; a legitimate nested target is
followed. (This resolve-and-boundary-check REPLACES the old "a path separator means
out-of-bundle" heuristic, which conflated depth with escape and forbade valid hierarchy.)
Each index entry descends **one path segment per level** — a per-level index links its
immediate children, never a multi-segment path. Traversal is **depth-first in first-seen
link order** and fully deterministic (the root index first, then each link followed in the
order it appears, recursively). Repeated links are de-duplicated **on the resolved path**, so
`./a.md` and `a.md` are one entry and cycles terminate. *(reference: the link pattern is
`\]\(([^)]+\.md)\)`)*
- A missing `index.md` **at the bundle root** is an error (a bundle has no entry point without
it) — this binds the **root alone**: an intermediate directory reached by a link is
navigated only through the links its own files carry, never by directory enumeration, so a
nested directory without its own `index.md` is not an error (its unlinked content is simply
unreachable). A broken, malformed, or bundle-escaping cross-link MUST be tolerated — skipped,
never raised (OKF robustness rule): a target that fails to resolve for ANY reason (missing
file, invalid path component, escape) is skipped, not raised. Path resolution MUST be
boundary-checked against the bundle directory, fail-closed — this is the SOLE
in-/out-of-bundle test.
- Frontmatter is the leading `---`-delimited block, parsed line-oriented as `key: value`
strings; the single required field is `type`; unknown fields MUST be preserved.
- The rendered read-context is the index body (the summary) followed by each non-index
concept file as a `## {type}: {title}` section; empty sections are dropped.
- **`type: verdict` files MUST be excluded from the read-context.** Prior verdicts reach the
hypothesis prompt ONLY via the gated experience fold below — never via context rendering,
and never via a query-time retrieval tool pointed at the bundle (which would re-leak the
verdict layer).
concept file as a `## {type}: {title}` section; empty sections are dropped. Rendering is
**flat regardless of nesting depth** — directory structure is navigation, not presentation,
so a nested concept file renders as the same `## {type}: {title}` section a root file would;
there is no level heading.
- **`type: verdict` files MUST be excluded from the read-context.** The exclusion is a **type
check on each file as it is reached** — applied recursively at every level, NEVER a property
of the link graph: a file is excluded because it is `type: verdict`, not because of where it
sits or how it was linked, so a mislabelled or injected navigation edge can never smuggle a
verdict into the context. Prior verdicts reach the hypothesis prompt ONLY via the gated
experience fold below — never via context rendering, and never via a query-time retrieval
tool pointed at the bundle (which would re-leak the verdict layer).
**Experience fold (ExpeL-style, the learning seam):** before generation, the candidate's
prior verdicts are retrieved from the store and folded into the hypothesis prompt:
@ -399,7 +421,8 @@ cross-reference):
| Seam | The test MUST fail when… | Reference test |
|---|---|---|
| Step-1 fold | a prior verdict no longer reaches the next hypothesis prompt; control: an empty store changes the outcome signal | `test_step1_expel_loadbearing.py` |
| Verdict-layer exclusion | the realization signal appears in the rendered read-context | `test_okf.py` (bundle-context exclusion) |
| Verdict-layer exclusion | the realization signal appears in the rendered read-context, at the root OR any nested level | `test_okf.py` (bundle-context exclusion) |
| Navigation boundary | an escaping cross-link (`..`, a filesystem-absolute path, or a bundle-root `/` read as filesystem-absolute) is followed, a malformed target (e.g. an invalid path component) is raised instead of skipped, or a legitimate nested in-bundle link is skipped | `test_okf.py` (navigation boundary) |
| Checker gate | the checker's surfaced output is detached OR its REJECT no longer overrides a validated outcome | `test_checker_gate_loadbearing.py` |
| Informed refinement | the prior rejection reason no longer appears verbatim in the next prompt / the outcome never flips | `test_step5_refine_loadbearing.py` |
| Async file loop | a verdict dropped after Run A fails to reach Run B's prompt via a FRESH store; control: an empty inbox | `test_step7_async_loop_loadbearing.py` |