feat(phase-3): the index policy becomes configurable, with the reader that judges it
`IndexPolicy` grew five judging fields and `IndexPolicy.violations`, closing the
gap a test has been pinning since `848e395`. `STRICT_V1.index` is now the proving
consumer's shape rather than DEFAULT's.
The design was settled by a conflict rather than by a preference. The convention
owner reported that an index is an authored count of a directory's children and
that a validator enumerating the directory has implemented the wrong contract.
Checked against the proving consumer before adopting it, the two turn out to be
directly opposed: gate BUNDLE_INDEX_COMPLETE (validate.py:1081-1120, ERROR) builds
its expected set by enumerating the directory and demands an exact bidirectional
match, and bundle.py:498-567 writes every index from a tree walk. Neither is
incoherent inside its own spec, so authored-versus-derived is a policy field in
both directions and a library invariant in neither.
Consequences encoded rather than documented: nothing here enumerates a directory
— the caller supplies the listing, `violations` refuses one when the profile's
index is authored and refuses to run without one when it is derived, so code
written to the wrong contract fails at the call instead of passing every test one
would think to write. Root and nested indexes are asymmetric (confirmed in both
consumers, different key sets). A per-entry description is template-level, so
`render_link` refuses both a missing description and an unwanted one.
DEFAULT keeps upstream's root-only index and judges nothing, for the same measured
reason it carries no required frontmatter key set: upstream binds `index.md` to
the bundle root alone, so a judging default would condemn conforming bundles.
25 new tests, 493 green. C1 re-proven: `git diff --stat examples/` empty.
This commit is contained in:
parent
848e3953fc
commit
9436427520
6 changed files with 626 additions and 29 deletions
|
|
@ -251,6 +251,55 @@ them:
|
|||
directions, and a root index carrying `okf_version` / `bundle_profile` /
|
||||
`okf_spec_commit` frontmatter in that key order.
|
||||
|
||||
## The index policy, and the conflict that shaped it
|
||||
|
||||
The convention owner reported on 2026-07-25 that the second-brain spec's §3
|
||||
mandates an `index.md` at every directory level, that `IndexPolicy` as it then
|
||||
stood could not express that, and — the load-bearing part — that an index is an
|
||||
**authored** count of a directory's children and never a filesystem lookup. On
|
||||
their reading, an index reader or validator that enumerates a directory to
|
||||
build or check an index has implemented the wrong contract, with a silent
|
||||
failure mode: code written to the wrong reading passes every test one would
|
||||
think to write.
|
||||
|
||||
That was checked against the proving consumer before it was adopted, and the
|
||||
two consumers turn out to be **directly opposed on exactly this point**:
|
||||
|
||||
- `validate.py:1081-1120`, gate `BUNDLE_INDEX_COMPLETE` (severity ERROR),
|
||||
builds its expected set by enumerating the directory and fails unless the
|
||||
index matches it exactly in both directions.
|
||||
- `bundle.py:498-567` writes every index from what a tree walk finds, and its
|
||||
own docstring calls `index.md` machine-generated.
|
||||
|
||||
So one consumer mandates the derivation the other calls the wrong contract.
|
||||
Neither is incoherent inside its own spec, and this repository is not the venue
|
||||
to adjudicate between them. What it settles is narrower and sufficient:
|
||||
**authored-versus-derived cannot be a library invariant in either direction.**
|
||||
It is a policy field (`entries_match_directory`), as are per-directory scope,
|
||||
the heading requirement, whether prose is admitted, and the root-index key set.
|
||||
|
||||
Three consequences that outlive this phase:
|
||||
|
||||
1. **Nothing in this library enumerates a directory.** The caller supplies the
|
||||
listing; `IndexPolicy.violations` refuses one when the profile's index is
|
||||
authored, and refuses to run without one when it is derived. The
|
||||
convention owner's construction rule is enforced at the call site rather
|
||||
than documented and hoped for.
|
||||
2. **Root and nested indexes are asymmetric**, confirmed independently in both
|
||||
consumers: the root carries frontmatter (`okf_version`/`bundle_profile`/
|
||||
`okf_spec_commit` for the wiki, `okf_version`/`okf_layout` for the catalog)
|
||||
and nested indexes carry none. Different key sets, same shape — which is
|
||||
why it is a profile field and not a constant.
|
||||
3. **A per-entry description is template-level, not a separate requirement.**
|
||||
The wiki requires `* [Title](link) - description`; the catalog requires
|
||||
prose in the index and no per-entry description. A profile that wants none
|
||||
simply does not name `{description}` in its template.
|
||||
|
||||
`DEFAULT` keeps upstream's root-only index and judges nothing, for the same
|
||||
measured reason it carries no required frontmatter key set: upstream OKF binds
|
||||
`index.md` to the bundle root alone, so a default demanding one per level would
|
||||
declare upstream-conforming bundles invalid.
|
||||
|
||||
## What this table does not do
|
||||
|
||||
It does not port anything. Per the plan, porting starts only after this
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue