feat(profiles): DEFAULT stamps commons' O2 generated, V1 executed

Commons ratified V1 2026-08-02 and executed it at `54e0ec7`; verified
against their tree rather than taken on report. ingest-spec.md:217 now
defines `generated` as `{ by: process:okf-ingest, at: <ingested_at> }`,
unquoted, `at` repeating `ingested_at` verbatim. `generated: true` no
longer appears in the spec.

`DEFAULT` states commons' §5 layer, so its stamp is theirs to decide.
`DEFAULT.ownership` gains the actor; the four goldens this repo's plan
named in advance were regenerated by RUNNING the materializer, each on
its own case's `ingested-at.txt`. The v0.2 golden was untouched, as
predicted -- it has carried the O2 form since D5.

Not a migration onto OKF v0.2: `DEFAULT` stays v0.1 on every axis
upstream owns and still emits no `sources`. Commons' spec and the Google
version are independent axes, and comments that narrated them as one
were rewritten rather than left to mislead. README and CLAUDE.md said
the additive rule without that boundary, which would have told a
consumer their DEFAULT bytes can never move; both now state it.

V-A3 is amended, not dropped. `DEFAULT` must OWN the mapping it now
writes -- a profile refusing its own output fires the collision gate on
files its own previous run wrote -- while a mapping naming a foreign
actor, or §7's `human:` actor on curated content, stays unowned. That
half is what carried the safety and it is asserted directly.

§11's stamp-integrity condition moved with the value: the forgeable
stamp was `true` and is now the mapping naming the ingest actor. The
defence was never the value -- the §3 scan globs `ingest-*.md`, so a
Door C import is unreachable however well it forges. Second spoof test
added; both were hand-mutated (glob widened to `*.md`) to confirm they
can fail.

The characterization test derived its foreign-stamp fixture from the
literal `generated: true`, which V1 leaves without a referent -- a
silent no-op waiting to happen. It now derives the needle from the
profile and asserts the substitution occurred.

Door B is deliberately untouched: not the ingest-spec's, marker is
`generated` + `source_file`, disjoint from Door A's `ingest_manifest`,
and the divergence predates V1.

Nothing released or notified. The pilot set pins `v0.5.0a2`, not `main`,
so this is invisible to portfolio-optimiser's freeze and demo; the
consumer exposure report is owed at the release that carries this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwcjUXbKySLbEG5WqTNkta
This commit is contained in:
Kjell Tore Guttormsen 2026-08-09 12:29:05 +02:00
commit 8318605e34
15 changed files with 280 additions and 50 deletions

View file

@ -1368,8 +1368,12 @@ unearned-claim pattern that "conform first, claim after" exists to prevent.
## Open questions
**V1 — `generated`'s shape in `DEFAULT` (commons').** *No longer blocks our v0.2
support*, because D2 puts v0.2 in a new profile. Still raised with commons,
**V1 — `generated`'s shape in `DEFAULT` (commons').** **CLOSED 2026-08-09 —
ratified, executed by commons at `54e0ec7`, and implemented here the same day.
The outcome is at the end of this section; what follows first is the record of
how it was decided, kept because the reasoning is still what justifies the
value.** *No longer blocks our v0.2 support*, because D2 puts v0.2 in a new
profile. Still raised with commons,
because `DEFAULT` keeps emitting a v0.2-reserved key with a v1-era value. Commons
confirmed authorship, verified our four premises against `okf/SPEC.md`
independently, and put it in their ratification queue as item 8. They are not
@ -1447,6 +1451,52 @@ constant actor, so there is no regeneration to do later. It also makes our
recommendation to commons and our own implementation agree, which is worth
something when they weigh it: we took the cost we were recommending they take.
**V1 IS EXECUTED, AND SO IS OUR HALF — 2026-08-09.** Commons ratified 2026-08-02
and executed at `54e0ec7`, verified here against their tree rather than taken on
report: `ingest-spec.md:217` now defines `generated` as the inline mapping
`{ by: process:okf-ingest, at: <ingested_at> }`, unquoted, with `at` repeating
`ingested_at` verbatim, and `generated: true` appears nowhere in the spec.
The hold recorded above — *do not regenerate against unratified text* — is
therefore discharged, and this repo's half landed the same day:
`DEFAULT.ownership` gained the actor, and the four fixtures this section named in
advance regenerated by RUNNING the materializer, each on its own case's
`ingested-at.txt`. The v0.2 fixture was untouched, exactly as predicted: it has
carried the O2 form since D5.
Three consequences worth having written down, because none is visible in the diff:
1. **`DEFAULT` and `OKF_V0_2` now write the same stamp, and are not thereby the
same profile.** They agree because commons adopted §7's actor, not because one
defers to the other. `OKF_V0_2` restates the policy rather than referencing
`DEFAULT.ownership` so that a future commons change cannot drag upstream's
profile along with it.
2. **The "v0.1 profile" framing died, not just aged.** `DEFAULT` writes the O2
mapping while remaining v0.1 on every axis upstream owns. Commons' spec and
the Google version are independent axes; comments that narrated them as one
were rewritten rather than left to mislead.
3. **What §11's stamp-integrity condition protects moved with the value.** The
forgeable stamp used to be the literal `true` and is now the mapping naming
the ingest actor. The defence was never the value: the §3 scan globs
`ingest-*.md`, so a Door C import cannot be reached however well it forges.
Pinned by a second spoof test, and both spoof tests were hand-mutated
(glob widened to `*.md`) to confirm they can actually fail.
**Consumer exposure is real but not yet delivered.** `DEFAULT`-profile bundles
change one line per generated file, so a consumer's own goldens churn. Recognition
is one-way — a profile with an actor still owns the literal stamp — so the cost is
a re-run and nothing more, which is the black-box promise. **Nothing is released
or notified yet:** the pilot set pins the `v0.5.0a2` tag, not `main`, so this is
invisible to `portfolio-optimiser`'s freeze (2026-08-12) and demo (2026-08-13).
The exposure report is owed at the release that carries this, not before.
**Out of scope, deliberately, and recorded so it is not mistaken for an
oversight:** Door B (`inbox.py`) still writes `generated: true` and gates on it.
Door B is not the ingest-spec's, its marker is `generated` + `source_file`
(disjoint from Door A's `ingest_manifest`), and the divergence predates V1 —
`OKF_V0_2` has carried the actor since D2. Whether Door B should follow is a
question for the operator, not a consequence of this change.
**V2 — Which D1 direction?** (c) recommended above; needs a decision before code
because it determines whether `mypy --strict` churn lands across the existing
call sites or stays confined to the new path.
@ -1629,10 +1679,10 @@ everything after. **Done 2026-07-26** (`1215f98`, `7bc366b`).
|---|---|---|
| V-A1 | The spec enumeration here is complete | Re-read `okf/SPEC.md` at a **pinned commit**, record the commit, diff against this doc before step 4 |
| V-A2 | Inline flow mappings survive the scalar parser unmodified | Step 1 characterization; byte-exact round-trip |
| V-A3 | v0.2 input cannot cause an unowned overwrite | Step 1: `_is_ingest_owned` False on a `generated` mapping |
| V-A3 | v0.2 input cannot cause an unowned overwrite | Step 1: `_is_ingest_owned` False on a `generated` mapping. **AMENDED by V1 (2026-08-09):** the check is False on a mapping naming a FOREIGN actor. `DEFAULT` now writes the O2 mapping itself, so it must own the one naming `process:okf-ingest` — a profile that refuses its own output fires the collision gate on the files its own previous run wrote |
| V-A4 | Door C meets the v0.2 consumer tolerance rules | Step 2, one test per MUST NOT |
| V-A5 | No profile hard-codes an upstream version | Step 3 |
| V-A6 | Adding v0.2 support is behavior-neutral for v0.1 profiles | Golden suite byte-for-byte under `DEFAULT` **and** `STRICT_V1`; existing tests unmodified and green (C1 extended) |
| V-A6 | Adding v0.2 support is behavior-neutral for v0.1 profiles | Golden suite byte-for-byte under `DEFAULT` **and** `STRICT_V1`; existing tests unmodified and green (C1 extended). **SUPERSEDED for `DEFAULT` 2026-08-09 — by commons, not by v0.2 support.** V1 moved `DEFAULT`'s `generated` and four goldens with it. The claim as written holds for what it was written about: adding v0.2 support changed no `DEFAULT` byte, and `STRICT_V1` is still byte-stable and its tests unmodified. A future session reading a golden diff here should not file it as a v0.2 regression |
| V-A7 | No profile can emit `timestamp` together with a malformed `generated` | Named construction-time test, same shape as C3's verdict reservation |
| V-A8 | A v0.2 bundle we emit is accepted by an independent v0.2 consumer | Validate the D5 fixture against upstream's reference implementation, not only against our own reader. **DONE 2026-07-31 @ `3fcbb9f`: 13/13.** Procedure is runbook Step 3a |
@ -1688,8 +1738,15 @@ is also where an upstream reader change would be caught.
## Coordination — who needs to know what
- **commons** — V1. `generated`'s shape in ingest-spec §5. No longer blocking us,
still theirs to decide.
- **commons** — V1. `generated`'s shape in ingest-spec §5. **Decided by them and
done on both sides 2026-08-09** (`54e0ec7` there, `DEFAULT.ownership` plus four
regenerated goldens here). What remains is a courtesy note that our fixtures are
green, not a dependency. One thing they raised is open and is THEIRS: whether
§12's cross-check table gains rows for the named sub-keys `by` and `at`. They
deliberately did not add them — that would change the conformance contract
without ratification — and §7's field row documents both meanwhile, so the
"stops documenting a contract field" seam is not tripped. Nothing here waits on
it.
- **catalog** — form owner. Upstream moved to v0.2; their form-not-membership
gate absorbs the bump with no change; V4 is theirs; and a new profile now
declares `"0.2"`, which is the first bundle shape in this repo to do so.