docs(phase-3): split table over all 25 gates, and two corrected premises

Phase 3 starts with a written mapping of the proving consumer's gates to
exactly one of Profile / Guard / Consumer, reviewed before any porting.
Drafted here against claude-code-llm-wiki's validate.py and bundle.py at
their 9ee5a8e, which is their single gate entrypoint, so the enumeration
is exhaustive against that commit and no other.

Reading the validator corrected two things this plan asserted before it
had been read, both of which would have produced a wrong STRICT_V1:

- Required frontmatter keys are FOUR (type, title, description,
  timestamp), not the eight the plan listed. Those eight were a
  truncation of FRONTMATTER_KEY_ORDER, which is an eleven-key allowlist
  doubling as canonical emission order. frontmatter_schema therefore
  needs three fields -- required, allowlisted, ordered -- not one
  required/optional pair.
- Reserved files are THREE basenames, not two: README.md is reserved
  like index.md and log.md but in a third way, present and exempt from
  the document gates while still content-scanned. A two-valued
  required/required-absent policy cannot express it.

Two of the 25 gates bundle checks from different columns
(LLM_OUTPUT_LINT, BUNDLE_URL_ALLOWLIST). They are decomposed per check
rather than assigned wholesale to a dominant column, which would have
moved the residue to the wrong side of the boundary.

Also recorded: index policy is the widest gap between the two profiles
(per-bundle vs per-directory, two link formats, append-if-absent vs
exact match, root index with or without frontmatter), and C4 is
confirmed with the operator -- profiles in code, no config-file loading
in v1.

Four open questions are addressed to the proving consumer in the
artifact; no porting until they and the table come back reviewed.
This commit is contained in:
Kjell Tore Guttormsen 2026-07-25 12:30:51 +02:00
commit d8e466791c
2 changed files with 200 additions and 13 deletions

View file

@ -18,21 +18,37 @@ the golden suite is the regression harness for that claim.
profiles are constructed in code by the consumer):
- `type_policy`: closed enum vs. open set; the reserved `verdict` exclusion
stays unconditional (it is a spec invariant, not profile config).
- `frontmatter_schema`: ordered required keys + optional keys, per concept
type where needed (Phase 1's seven-key layer and Phase 2's inbox layer are
expressions of this schema).
- `frontmatter_schema`: three distinct fields, not one — the *required* key
set, the *allowlisted* key set, and the canonical emission *order*. The
proving consumer keeps four required keys inside an eleven-key allowlist
(see `docs/phase-3-split-table.md`), so a single ordered required/optional
pair cannot express it. Also carries nullable keys and the scalar encoding
subset. Phase 1's seven-key layer and Phase 2's inbox layer are
expressions of this schema.
- `path_policy`: layer/path prefixes, filename namespaces, reserved filename
patterns (`index.md`, `promoted-verdict-*`, …).
- `reserved_files`: per-file required / optional / required-absent policy
(e.g. a profile may demand that `log.md` is absent).
- `index_policy`: managed-link format and per-level index expectations.
- `reserved_files`: per-file policy, THREE values not two — required,
required-absent, and present-but-exempt-from-document-gates (the proving
consumer's `README.md`, which carries no frontmatter and is never indexed
yet is still content-scanned).
- `index_policy`: managed-link format and per-level index expectations. This
is the widest gap between the two profiles: one index per bundle versus
one per directory, `- [label](target)` versus
`* [Title](link) - description`, append-if-absent versus exact match in
both directions, and a root index with or without frontmatter.
2. **Built-in profiles:**
- `DEFAULT` (implicit): exactly the ingest-spec v1 + Phase 2 contract.
- `STRICT_V1`: the `claude-code-llm-wiki` contract — closed type enum
(`Concept`/`Guide`/`Reference`/`Release`), extended required frontmatter
(`type`, `title`, `description`, `timestamp`, `layer`, `source_tier`,
`source_url`, `source_sha`), layer path prefixes, `log.md` required-absent,
root-index metadata.
(`Concept`/`Guide`/`Reference`/`Release`), four required frontmatter keys
(`type`, `title`, `description`, `timestamp`) inside an eleven-key
allowlist that doubles as emission order, layer/path/type/source_tier
agreement rules, `log.md` required-absent, `README.md` reserved-exempt,
per-directory indexes, and root-index metadata (`okf_version`,
`bundle_profile`, `okf_spec_commit`).
An earlier draft of this line listed eight required keys. That was the
allowlist read as the required set; corrected against the validator on
2026-07-25.
3. **Plumbing change:** materialization, inbox, import, and index generation take
an optional `profile` argument defaulting to `DEFAULT`. No behavior branches
outside what the profile object expresses.
@ -41,7 +57,10 @@ the golden suite is the regression harness for that claim.
The wiki's existing validator mixes three kinds of gates. First implementation
step is a written mapping of every gate to exactly one column — the mapping is
reviewed with the operator before any porting:
reviewed with the operator before any porting. **Drafted 2026-07-25 in
`docs/phase-3-split-table.md`**, over all 25 gates, and sent to the proving
consumer for review; two gates turned out to bundle checks from different
columns and are decomposed there rather than forced into one.
| Column | Meaning | Goes where |
|---|---|---|
@ -69,9 +88,9 @@ reviewed with the operator before any porting:
| # | Assumption | Test |
|---|---|---|
| C1 | Default-profile refactor is behavior-neutral | Phase 1 golden suite byte-identical; full Phase 1/2 test suite green, unmodified |
| C2 | `strict-v1` requirements are fully enumerable from the wiki's validator | The split table is exhaustive: every wiki gate appears in exactly one column; reviewed with the operator |
| C2 | `strict-v1` requirements are fully enumerable from the wiki's validator | The split table is exhaustive: every wiki gate appears in exactly one column; reviewed with the operator. Drafted 2026-07-25 against `validate.py`/`bundle.py` at their `9ee5a8e`, which is the single gate entrypoint — the enumeration holds only against that commit, so re-check before porting. Two gates required decomposition rather than a single column |
| C3 | Verdict reservation must survive every profile | Named test: no profile construction can permit `type: verdict` |
| C4 | Profiles-in-code (no config files) suffice for the proving consumer | Confirmed with the operator at phase start; config-file loading is an extension point |
| C4 | Profiles-in-code (no config files) suffice for the proving consumer | CONFIRMED with the operator 2026-07-25 at phase start: profiles are constructed in code, config-file loading stays an extension point |
## Non-goals