docs(okf-v0.2): supporting the latest OKF version becomes standing policy
Operator directive 2026-07-26: the library always supports the current
latest version of Google OKF. v0.2 shipped 2026-07-25, so v0.2 support is
committed work rather than something a consumer has to request. This
overrides the previous default answer to open question V3 ("no until a
named consumer asks"), which is kept in the plan marked superseded so the
override reads as deliberate.
Support is additive: a new profile, never a migration of the existing two.
That single design choice is what makes an always-latest policy sustainable,
and it resolves the tension the directive would otherwise create with three
constraints that do not yield to it:
- DEFAULT states commons' ingest-spec section 5 layer, so its `generated`
shape is commons' call. Under the additive design this stops blocking us,
which takes commons off the critical path.
- STRICT_V1 mirrors the proving consumer's ratified contract; changing
another repo's contract from here would violate O2.
- v0.2 defers the attestation receipt and verdict wire formats upstream, so
the format is supportable and the unspecified runtime is not. It re-enters
scope when upstream specifies it.
This is also the first time the phase-3 profile abstraction is forced by
something outside this repo rather than by a second consumer, which is the
better test of whether the seam was cut in the right place.
Deliverables D1-D6 replace the earlier decision-round framing: a frontmatter
model that can carry block lists (`sources`, multi-verifier `verified`), an
OKF_V0_2 profile plus an OKF_LATEST alias whose moving-target tradeoff is
documented rather than hidden, Door C conformance against the consumer
tolerance rules, `Attested Computation` round-trip, v0.2 golden fixtures, and
a release-checklist re-check so the standing policy cannot decay silently.
Two new assumptions carry the weight. V-A7 forbids any profile from emitting
`timestamp` together with a malformed `generated`, since that combination
would have neither a valid `generated.at` nor an eligible section 13.1
fallback. V-A8 validates our own v0.2 fixture against upstream's reference
implementation, because every other test in the suite only asks whether we
agree with ourselves.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2aKJxLejT9S8jYwoZ9fut
This commit is contained in:
parent
ca453b2895
commit
cb23de4700
3 changed files with 257 additions and 171 deletions
31
CLAUDE.md
31
CLAUDE.md
|
|
@ -63,14 +63,29 @@ are the library baseline. First consumer: `portfolio-optimiser-claude`.
|
||||||
|
|
||||||
The two halves share the OKF contract and fixture suite, **not code**.
|
The two halves share the OKF contract and fixture suite, **not code**.
|
||||||
|
|
||||||
**Upstream version: everything above targets OKF v0.1.** Google published v0.2
|
### Upstream version policy (standing, non-negotiable)
|
||||||
on 2026-07-25 (two supersessions, both with documented consumer fallbacks; all
|
|
||||||
new fields optional). Alignment is a policy track between Phases 3 and 4, not a
|
**The library always supports the current latest version of Google OKF.** Set by
|
||||||
phase: `docs/plan/okf-v0.2-alignment.md`. Two constraints bind here — the
|
the operator 2026-07-26. Phases 1–3 were built against v0.1; v0.2 shipped
|
||||||
`generated` marker `DEFAULT` emits sits in commons' ingest-spec §5 layer, so its
|
2026-07-25, so v0.2 support is committed work — not contingent on a consumer
|
||||||
shape is commons' call, not ours; and `okf_version`'s value belongs to catalog
|
asking for it. Plan: `docs/plan/okf-v0.2-alignment.md`.
|
||||||
(decision E1). No profile may hard-code an upstream version, and no bundle
|
|
||||||
claims a version its shape has not earned.
|
Support is **additive, expressed as a new profile**, never a migration of
|
||||||
|
existing ones. This is what makes the policy sustainable instead of a recurring
|
||||||
|
crisis, and it is bounded by three facts that do not yield to it:
|
||||||
|
|
||||||
|
- `DEFAULT` states commons' ingest-spec §5 layer — its `generated` shape is
|
||||||
|
commons' call, raised there, never patched locally.
|
||||||
|
- `STRICT_V1` mirrors the proving consumer's ratified contract — changing another
|
||||||
|
repo's contract from here violates O2.
|
||||||
|
- `okf_version`'s *value* belongs to catalog (decision E1).
|
||||||
|
|
||||||
|
Two invariants fall out: no profile hard-codes an upstream version, and no bundle
|
||||||
|
declares a version its shape has not earned. Where upstream itself defers a
|
||||||
|
contract — v0.2's attestation receipt and verdict wire formats — the format is
|
||||||
|
supported and the unspecified runtime is not; it re-enters scope when upstream
|
||||||
|
specifies it. Because "always latest" decays silently, the release checklist
|
||||||
|
carries an upstream-version re-check.
|
||||||
|
|
||||||
Phase 4 preconditions (coordination, not unilateral moves):
|
Phase 4 preconditions (coordination, not unilateral moves):
|
||||||
- Lifts okr's reference implementations (`okf-check.mjs`, `okf-index.mjs`,
|
- Lifts okr's reference implementations (`okf-check.mjs`, `okf-index.mjs`,
|
||||||
|
|
|
||||||
|
|
@ -100,30 +100,37 @@ policy differs per consumer and becomes configurable in Phase 3." This is where
|
||||||
the contract becomes explicit and frozen — the precondition for a clean Node
|
the contract becomes explicit and frozen — the precondition for a clean Node
|
||||||
port.
|
port.
|
||||||
|
|
||||||
## OKF v0.2 alignment — decisions between 3 and 4, code possibly later
|
## OKF v0.2 support — between 3 and 4, and it is real code
|
||||||
|
|
||||||
Everything through Phase 3 targets OKF v0.1. Upstream published v0.2 on
|
Everything through Phase 3 targets OKF v0.1. Upstream published v0.2 on
|
||||||
2026-07-25. Detail and open questions: `docs/plan/okf-v0.2-alignment.md`.
|
2026-07-25, and the standing operator policy is that the library always supports
|
||||||
|
the current latest OKF version (see `CLAUDE.md`). So this is a committed
|
||||||
|
implementation track, not a decision round:
|
||||||
|
`docs/plan/okf-v0.2-alignment.md`.
|
||||||
|
|
||||||
**Why the decisions must land before Phase 4 code, even if the code does not.**
|
**Why it must land before Phase 4 code.** Phase 4 ports a *frozen, explicit*
|
||||||
Phase 4 ports a *frozen, explicit* contract and uses the shared fixture suite as
|
contract and uses the shared fixture suite as the cross-runtime conformance
|
||||||
the cross-runtime conformance oracle. Freezing that contract while its relation
|
oracle. Freezing that contract before v0.2 is supported means freezing a v0.1
|
||||||
to upstream v0.2 is undecided means freezing a v0.1 shape into two runtimes
|
shape into two runtimes instead of one, and the fixture suite would then certify
|
||||||
instead of one, and the fixture suite would then certify the drift rather than
|
the drift rather than catch it. Worse, the Node half would need the same v0.2
|
||||||
catch it. The expensive version of this mistake is discovered after the Node half
|
work done twice, in two languages, against a contract that had already been
|
||||||
exists; the cheap version is a decision recorded now.
|
declared final. The expensive version of this mistake is discovered after the
|
||||||
|
Node half exists.
|
||||||
|
|
||||||
**Why it is not a phase.** v0.2's breaking surface is two supersessions, both
|
**Why it is not a phase of its own.** It adds no new door and no new stage — it
|
||||||
with documented consumer fallbacks, and every new field is optional. The only
|
adds a *profile*, which is precisely what Phase 3 built the seam for. Support is
|
||||||
measured shape problem is `DEFAULT`'s `generated` marker, which lives in commons'
|
additive: `DEFAULT` (commons') and `STRICT_V1` (the wiki's) keep their contracts
|
||||||
ingest-spec §5 layer and is therefore not this repo's to change. So the work is
|
untouched, and v0.2 arrives as a third profile plus an `OKF_LATEST` alias. This
|
||||||
mostly *deciding and routing*, expressed through the Phase 3 profile object —
|
is the first time the Phase 3 abstraction is forced by something outside this
|
||||||
not a new implementation stage.
|
repo rather than by a second consumer, which is the better test of it.
|
||||||
|
|
||||||
**Order inside the track.** Characterization and audit first (they add tests and
|
**Order inside the track.** Characterization and audit first — they add tests and
|
||||||
change no behavior, so they are safe while the central question is still open),
|
change no behavior. Then the frontmatter model that can carry block lists
|
||||||
then the one blocking dependency — commons' answer on `generated` — and only then
|
(`sources`, multi-verifier `verified`), then the profile, then the golden
|
||||||
any migration, as its own release.
|
fixtures that make the support claim testable. The `okf_version: "0.2"`
|
||||||
|
declaration comes last, once the shape has earned it. Commons' answer on
|
||||||
|
`DEFAULT`'s `generated` runs in parallel and no longer blocks: the additive
|
||||||
|
design took it off the critical path.
|
||||||
|
|
||||||
## Phase 4 — Node half (two clocks)
|
## Phase 4 — Node half (two clocks)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,59 @@
|
||||||
# OKF v0.2 alignment — plan
|
# OKF v0.2 support — plan
|
||||||
|
|
||||||
Status: **decisions open, no code approved.** This is a policy track, not a
|
Status: **committed implementation track.** Standing policy (operator,
|
||||||
roadmap phase: it decides how the library relates to upstream OKF v0.2 and where
|
2026-07-26): *the library always supports the current latest version of Google
|
||||||
each decision is owned. Everything built so far targets v0.1.
|
OKF.* v0.2 is out, so v0.2 support is committed work — not conditional on a
|
||||||
|
consumer requesting it.
|
||||||
|
|
||||||
Read with: `docs/plan/execution-order.md` (where this track sits in the
|
Read with: `docs/plan/execution-order.md` (sequencing),
|
||||||
sequence), `docs/plan/phase-3-configurable-contract.md` (the profile object that
|
`docs/plan/phase-3-configurable-contract.md` (the profile object that carries
|
||||||
carries the outcome), `docs/phase-3-split-table.md` (the profile/guard/consumer
|
this), `docs/phase-3-split-table.md` (the profile/guard/consumer column
|
||||||
column discipline this track reuses).
|
discipline).
|
||||||
|
|
||||||
|
## What "support the latest version" means here
|
||||||
|
|
||||||
|
It means **additive**: the library can read, validate, materialize, and index
|
||||||
|
v0.2-shaped bundles. It does **not** mean migrating existing profiles onto v0.2.
|
||||||
|
That distinction is the whole design, and it is what makes a standing
|
||||||
|
always-latest policy implementable rather than a recurring crisis:
|
||||||
|
|
||||||
|
- `DEFAULT` states commons' ingest-spec §5 layer. Its shape is commons'
|
||||||
|
authorship, and editing it locally is a standing non-goal.
|
||||||
|
- `STRICT_V1` mirrors the proving consumer's contract, ratified by their operator
|
||||||
|
on 2026-07-25. Changing another repo's contract from here violates O2.
|
||||||
|
- So v0.2 support arrives as **a new profile**, alongside the existing two. The
|
||||||
|
phase-3 profile object is exactly the seam that makes this possible; this is
|
||||||
|
the first time that abstraction pays for itself against an external forcing
|
||||||
|
function rather than a second consumer.
|
||||||
|
|
||||||
|
The upper bound is set upstream, not by ambition: v0.2 **defers the receipt and
|
||||||
|
verdict wire formats and the full attestation runtime protocol to a future
|
||||||
|
revision**. The *format* is fully supportable; an unspecified runtime is not.
|
||||||
|
See D4.
|
||||||
|
|
||||||
## Provenance of the facts below
|
## Provenance of the facts below
|
||||||
|
|
||||||
Read from `GoogleCloudPlatform/knowledge-catalog`, `okf/SPEC.md` at **`main` on
|
Read from `GoogleCloudPlatform/knowledge-catalog`, `okf/SPEC.md` at **`main` on
|
||||||
2026-07-26** — a branch, not a tag. **First step of any implementation is to
|
2026-07-26** — a branch, not a tag. **First implementation step is to re-read the
|
||||||
re-read the spec at a pinned commit and record it**, exactly as assumption C2
|
spec at a pinned commit and record it**, exactly as assumption C2 pins the
|
||||||
pins the proving consumer's validator to `9ee5a8e`. An enumeration read off a
|
proving consumer's validator to `9ee5a8e`. An enumeration read off a moving
|
||||||
moving branch is a premise, not a fact.
|
branch is a premise, not a fact.
|
||||||
|
|
||||||
## What v0.2 actually changes
|
## What v0.2 actually changes
|
||||||
|
|
||||||
Two supersessions — the only backward-breaking changes, and both carry a
|
Two supersessions — the only backward-breaking changes, both with a documented
|
||||||
documented consumer fallback (§13.1):
|
consumer fallback (§13.1):
|
||||||
|
|
||||||
| v0.1 | v0.2 | Fallback the spec grants |
|
| v0.1 | v0.2 | Fallback the spec grants |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `timestamp` | `generated.at` | Consumers **MAY** fall back to legacy `timestamp` **when `generated` is absent** |
|
| `timestamp` | `generated.at` | Consumers **MAY** fall back to legacy `timestamp` **when `generated` is absent** |
|
||||||
| body `# Citations` list | `sources` frontmatter | Consumers **SHOULD** read `sources`, **MAY** still parse legacy `# Citations` |
|
| body `# Citations` list | `sources` frontmatter | Consumers **SHOULD** read `sources`, **MAY** still parse legacy `# Citations` |
|
||||||
|
|
||||||
Additive, all optional (§5): `sources` (per-source credibility signals —
|
Additive, all optional upstream (§5) — and all in scope for us under the standing
|
||||||
`author`, `usage_count`, `last_modified`, framed by `usage_window`), `generated
|
policy: `sources` (per-source credibility signals — `author`, `usage_count`,
|
||||||
{ by, at }`, `verified [ { by, at } ]`, `status` (`draft`/`stable`/`deprecated`,
|
`last_modified`, framed by `usage_window`), `generated { by, at }`,
|
||||||
absent means `stable`), `stale_after` (absolute `YYYY-MM-DD`).
|
`verified [ { by, at } ]`, `status` (`draft`/`stable`/`deprecated`, absent means
|
||||||
|
`stable`), `stale_after` (absolute `YYYY-MM-DD`).
|
||||||
|
|
||||||
Also new:
|
Also new:
|
||||||
|
|
||||||
|
|
@ -40,8 +63,7 @@ Also new:
|
||||||
human-confirmed content. Trust tiers (unverified / machine-confirmed /
|
human-confirmed content. Trust tiers (unverified / machine-confirmed /
|
||||||
human-reviewed) are *derived* advisory signals, never a stored field.
|
human-reviewed) are *derived* advisory signals, never a stored field.
|
||||||
- **`Attested Computation`** concept type, with `runtime`, `parameters`,
|
- **`Attested Computation`** concept type, with `runtime`, `parameters`,
|
||||||
`computation`, `executor`, `attester`. The receipt and verdict wire formats and
|
`computation`, `executor`, `attester`.
|
||||||
the full runtime protocol are **explicitly deferred to a future revision**.
|
|
||||||
- **`okf_version`** stays root-`index.md`-only and is a **MAY**: a declaration of
|
- **`okf_version`** stays root-`index.md`-only and is a **MAY**: a declaration of
|
||||||
the version a bundle *targets*, with no conformance checkpoint tying the
|
the version a bundle *targets*, with no conformance checkpoint tying the
|
||||||
declaration to compliance.
|
declaration to compliance.
|
||||||
|
|
@ -50,10 +72,11 @@ Also new:
|
||||||
keys, broken cross-links, or missing `index.md`. One additional MUST: a bare
|
keys, broken cross-links, or missing `index.md`. One additional MUST: a bare
|
||||||
`verified` mapping must be read as a one-element list.
|
`verified` mapping must be read as a one-element list.
|
||||||
|
|
||||||
One YAML detail that decides the parser scope: the canonical form for `generated`
|
One YAML detail that sizes the parser work: the canonical form for `generated`
|
||||||
and a single `verified` is an **inline flow mapping** on one line
|
and a single `verified` is an **inline flow mapping** on one line
|
||||||
(`generated: { by: …, at: … }`). Only a multi-verifier `verified` and `sources`
|
(`generated: { by: …, at: … }`), which the existing scalar parser already
|
||||||
are block lists.
|
round-trips as an opaque string. Only a multi-verifier `verified` and `sources`
|
||||||
|
are **block lists**, and those are what force a richer frontmatter model.
|
||||||
|
|
||||||
## Exposure audit — measured against the tree, not reasoned
|
## Exposure audit — measured against the tree, not reasoned
|
||||||
|
|
||||||
|
|
@ -62,151 +85,192 @@ are block lists.
|
||||||
| `DEFAULT` emits `generated: "true"` (`materialize.py:164`, `inbox.py:127`) | **Malformed for a v0.2 field**: `generated.by` is REQUIRED within `generated`. `generated` was *not* reserved in v0.1, so this was legal when written — v0.2 claimed the name | **commons** (ingest-spec §5) |
|
| `DEFAULT` emits `generated: "true"` (`materialize.py:164`, `inbox.py:127`) | **Malformed for a v0.2 field**: `generated.by` is REQUIRED within `generated`. `generated` was *not* reserved in v0.1, so this was legal when written — v0.2 claimed the name | **commons** (ingest-spec §5) |
|
||||||
| `_is_ingest_owned` requires `generated == "true"` (`materialize.py:143-149`) | **Fail-safe.** A v0.2 mapping is not the string `"true"`, so the predicate returns False → target not ours → collision → refuse to overwrite. No safety hole | this repo |
|
| `_is_ingest_owned` requires `generated == "true"` (`materialize.py:143-149`) | **Fail-safe.** A v0.2 mapping is not the string `"true"`, so the predicate returns False → target not ours → collision → refuse to overwrite. No safety hole | this repo |
|
||||||
| `STRICT_V1` emits `timestamp`, and **no** `generated` | **Conformant** via the §13.1 legacy fallback, which applies precisely *because* `generated` is absent. No action is forced on the wiki | wiki |
|
| `STRICT_V1` emits `timestamp`, and **no** `generated` | **Conformant** via the §13.1 legacy fallback, which applies precisely *because* `generated` is absent. No action is forced on the wiki | wiki |
|
||||||
| `parse_frontmatter` is scalar-only (`partition(":")` → `dict[str, str]`) | Reads an inline flow mapping as an **opaque string** — round-trip-safe. Cannot read block lists, so `sources` and multi-verifier `verified` are unreachable | this repo |
|
| `parse_frontmatter` is scalar-only (`partition(":")` → `dict[str, str]`) | Inline flow mappings round-trip as opaque strings. Block lists are unreachable, so `sources` and multi-verifier `verified` need a richer model — **now in scope** (D1) | this repo |
|
||||||
| Fixtures and tests pin `okf_version: 0.1` | Accurate today: a MAY-field target declaration | **catalog** (decision E1: `okf_version` tracks the upstream Google version) |
|
| Fixtures and tests pin `okf_version: 0.1` | Accurate for the v0.1 profiles. The new v0.2 profile declares `"0.2"` | **catalog** (E1: `okf_version` tracks the upstream Google version) |
|
||||||
| catalog's gate checks `okf_version` on **form** (`/^\d+(\.\d+)*$/`), not membership | `"0.2"` passes unchanged — an upstream bump breaks no gate | catalog |
|
| catalog's gate checks `okf_version` on **form** (`/^\d+(\.\d+)*$/`), not membership | `"0.2"` passes unchanged — an upstream bump breaks no gate | catalog |
|
||||||
|
|
||||||
Two results worth stating plainly, because both cut against the first reading:
|
Two results that cut against the first reading of the change:
|
||||||
|
|
||||||
1. **`STRICT_V1`'s `timestamp` is not broken.** It sits on the documented legacy
|
1. **`STRICT_V1`'s `timestamp` is not broken.** It sits on the documented legacy
|
||||||
path. The earlier framing of it as a required-field defect was wrong.
|
path. An earlier framing of it as a required-field defect was wrong.
|
||||||
2. **`DEFAULT` is the only surface with a real shape problem**, and it is the one
|
2. **`DEFAULT` is the only surface with a real shape problem**, and it is the one
|
||||||
surface this repo may not unilaterally change: `DEFAULT` states the
|
surface this repo may not unilaterally change. Under the additive design this
|
||||||
ingest-spec §5 layer, whose authorship is commons'. Patching it locally is an
|
stops being on our critical path (D2, V1).
|
||||||
existing non-goal.
|
|
||||||
|
|
||||||
Note the interaction that makes (1) conditional: the `timestamp` fallback is
|
The interaction that keeps (1) true and must never be violated: the `timestamp`
|
||||||
granted only when `generated` is **absent**. Any profile that emits both a
|
fallback is granted only when `generated` is **absent**. A profile emitting both
|
||||||
`timestamp` and a malformed `generated` would have neither a valid `generated.at`
|
a `timestamp` and a malformed `generated` would have neither a valid
|
||||||
nor an eligible fallback. No current profile does this — `DEFAULT` has no
|
`generated.at` nor an eligible fallback. No current profile does this — `DEFAULT`
|
||||||
`timestamp` and `STRICT_V1` has no `generated` — and no profile should be allowed
|
has no `timestamp`, `STRICT_V1` has no `generated` — and no profile may be
|
||||||
to reach that combination.
|
allowed to reach that combination. This becomes a profile-construction invariant
|
||||||
|
(V-A7).
|
||||||
|
|
||||||
## The sequencing rule we impose on ourselves
|
## The sequencing rule we impose on ourselves
|
||||||
|
|
||||||
**Conform first, claim after.** Do not move a bundle's `okf_version` to `"0.2"`
|
**Conform first, claim after.** No bundle declares an `okf_version` its shape has
|
||||||
before the bundle's shape satisfies what it claims.
|
not earned.
|
||||||
|
|
||||||
The spec does not require this — §12 is a MAY with no conformance checkpoint
|
The spec does not require this — §12 is a MAY with no conformance checkpoint, so
|
||||||
attached, so declaring `"0.2"` early would be permitted. We adopt the rule
|
declaring `"0.2"` early would be permitted. We adopt the rule anyway, for the
|
||||||
anyway, for the same reason as *measure first, widen after* on the guard pin: a
|
same reason as *measure first, widen after* on the guard pin: a version claim
|
||||||
version claim that is literally permitted but not earned is the true-sounding
|
that is literally permitted but not earned is the true-sounding misleading claim,
|
||||||
misleading claim, and that class of mistake has already cost this repo a session.
|
and that class of mistake has already cost this repo a session. Concretely, the
|
||||||
|
v0.2 profile declares `"0.2"` only once D1–D3 and their fixtures are green.
|
||||||
|
|
||||||
## Open questions — to answer before any code
|
## Deliverables
|
||||||
|
|
||||||
Numbered like the phase-3 assumptions so they can be cited in review.
|
**D1 — A frontmatter model that carries block lists.** The single largest piece,
|
||||||
|
and the one that must be designed rather than improvised: `parse_frontmatter`
|
||||||
|
returns `dict[str, str]` today, and `sources` / multi-verifier `verified` cannot
|
||||||
|
be expressed in it. Three directions:
|
||||||
|
|
||||||
**V1 — Does `generated` change shape in `DEFAULT`, and may it?**
|
- (a) Widen the value type in place (`str | Mapping | list`). Cheapest to write,
|
||||||
This is the central question and the answer is *not ours alone*: `DEFAULT` is
|
worst to consume: every existing caller must newly narrow, and `mypy --strict`
|
||||||
commons' §5 layer. Three directions to put to commons, with our recommendation:
|
makes that cost visible everywhere at once.
|
||||||
|
- (b) A typed frontmatter model for all profiles. Cleanest end state, but it
|
||||||
|
rewrites the v0.1 read path and puts C1 (default-profile behavior neutrality)
|
||||||
|
at risk for no v0.1 benefit.
|
||||||
|
- (c) **Recommended.** Keep the scalar reader as the v0.1 path, untouched, and
|
||||||
|
add a structured reader selected by the profile. C1 stays trivially true
|
||||||
|
(`DEFAULT` and `STRICT_V1` do not change code paths at all), the new
|
||||||
|
complexity is reachable only from the new profile, and the two readers share
|
||||||
|
the same byte-level guarantees.
|
||||||
|
|
||||||
- (a) Leave `generated: "true"`; document the deviation. Cheapest; keeps emitting
|
**D2 — An `OKF_V0_2` profile.** Frontmatter schema covering the §5 families;
|
||||||
a v0.2 field with a v1-era value.
|
`generated: { by: "llm-ingestion-okf/<version>", at: <ingested_at> }` using the
|
||||||
- (b) **Recommended.** Migrate to
|
§7 actor convention; `sources` emission from the manifest's source; `status` and
|
||||||
`generated: { by: "llm-ingestion-okf/<version>", at: <ingested_at> }` and
|
`stale_after` expressible; root-index `okf_version: "0.2"`.
|
||||||
derive the machine-generated predicate from `generated.by` instead of a bespoke
|
|
||||||
boolean. This is the spec-native answer, removes a hand-rolled key, and yields
|
|
||||||
a real `generated.at`. `at` binds to the already-validated required
|
|
||||||
`ingested_at` argument, so no wall-clock default is introduced and determinism
|
|
||||||
holds. Costs: a `_is_ingest_owned` change and a golden-fixture regeneration.
|
|
||||||
- (c) Rename our marker to a non-reserved key and leave `generated` free for v0.2
|
|
||||||
semantics. Preserves the predicate exactly; still a fixture regeneration.
|
|
||||||
|
|
||||||
**V2 — How far does the frontmatter parser need to go?**
|
Also an `OKF_LATEST` alias, which is how the standing policy becomes visible in
|
||||||
Two tiers, and only the first is cheap:
|
code. **Document the tradeoff rather than hiding it:** an alias that moves means
|
||||||
|
a consumer bound to `OKF_LATEST` inherits upstream's breaking changes on a
|
||||||
|
library upgrade. The versioned constants are the stable binding and are what
|
||||||
|
consumers should pin; `OKF_LATEST` is for callers who have explicitly opted into
|
||||||
|
tracking.
|
||||||
|
|
||||||
- Tier 1, inline flow mappings: already round-trip as opaque strings. This needs
|
`at` binds to the already-validated required `ingested_at` argument, so no
|
||||||
a **characterization test**, not a change.
|
wall-clock default is introduced and determinism holds.
|
||||||
- Tier 2, block lists (`sources`, multi-verifier `verified`): real work.
|
|
||||||
|
|
||||||
The question is whether any named consumer requires Tier 2 today. If none does,
|
**D3 — Door C accepts any v0.2 bundle.** This is where "we support v0.2" is most
|
||||||
Tier 2 stays an extension point — the inverse of *fields without a reader are not
|
user-visible: the §14 consumer tolerance MUST NOTs, plus the bare-`verified`
|
||||||
written*: do not build a parser for a field no profile reads.
|
coercion. Measured with one test per rule — Door C is a consumer in the OKF
|
||||||
|
sense and either honours these or does not.
|
||||||
|
|
||||||
**V3 — Do we add v0.2 trust fields to any profile at all?**
|
**D4 — `Attested Computation`: format yes, runtime no.** Support the type and its
|
||||||
Default answer **no**, until a named consumer asks. Neither wiki nor catalog has.
|
fields (`runtime`, `parameters`, `computation`, `executor`, `attester`) for
|
||||||
`status`, `stale_after`, `verified`, and `sources` are all optional upstream, and
|
parse, validate, round-trip, and index. Do **not** implement execution or
|
||||||
adding them speculatively is the speculative-abstraction anti-pattern that
|
attestation: the receipt and verdict wire formats are explicitly deferred
|
||||||
phase 3 exists to avoid.
|
upstream, so there is no contract to build against, and "did this run produce the
|
||||||
|
value the sanctioned way" sits against the guard's boundary rather than this
|
||||||
|
library's plumbing. When upstream specifies the protocol, the standing policy
|
||||||
|
brings it back into scope — and the boundary question goes to the operator first.
|
||||||
|
|
||||||
**V4 — What value does `okf_version` carry, and who sets it?**
|
**D5 — v0.2 golden fixtures.** A byte-exact v0.2 bundle in `examples/`. This is
|
||||||
Already recorded as policy-not-constant. E1 gives the decision to catalog. This
|
what converts "we support v0.2" from a claim into a test, and in phase 4 it
|
||||||
repo's obligation is narrower and testable: no profile may hard-code `0.1`, and
|
becomes the cross-runtime conformance oracle for the Node half too.
|
||||||
the root-frontmatter policy must express any value.
|
|
||||||
|
|
||||||
**V5 — Is `Attested Computation` in scope?**
|
**D6 — Keep the policy from decaying.** "Always latest" silently rots unless
|
||||||
Recommended **out**, on two independent grounds. Upstream has deferred the
|
something checks. Two mechanisms, both cheap: the spec commit is pinned and
|
||||||
receipt and verdict wire formats, so building now means porting an unfrozen
|
recorded in this doc (V-A1), and the release checklist gains one item — re-check
|
||||||
contract — the precise failure mode `execution-order.md` warns about for the Node
|
upstream for a newer OKF version and record the result, even when unchanged. A
|
||||||
half. And attestation ("did this run produce the value the sanctioned way") sits
|
standing policy with no detection mechanism is an intention, not a policy.
|
||||||
against the guard's boundary rather than this library's plumbing, so the boundary
|
|
||||||
question goes to the operator before any design.
|
|
||||||
|
|
||||||
## TDD order — when quota returns
|
## Open questions
|
||||||
|
|
||||||
Steps 1–3 are characterization and audit only: they add tests, change no
|
**V1 — `generated`'s shape in `DEFAULT` (commons').** *No longer blocks our v0.2
|
||||||
behavior, and are safe to run before V1 is answered.
|
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.
|
||||||
|
Recommendation to carry: `generated: { by: "llm-ingestion-okf/<v>", at:
|
||||||
|
<ingested_at> }`, deriving the machine-generated predicate from `generated.by`
|
||||||
|
instead of a bespoke boolean — spec-native, removes a hand-rolled key, costs a
|
||||||
|
`_is_ingest_owned` change and a fixture regeneration. If commons declines, the
|
||||||
|
deviation is documented, not patched here.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
**V3 — Do we add v0.2 families at all?** **Answered: yes**, by the standing
|
||||||
|
policy. Superseded — kept here to record that the earlier default answer ("no
|
||||||
|
until a named consumer asks") was overridden deliberately, not forgotten.
|
||||||
|
|
||||||
|
**V4 — `okf_version` values.** Policy, not constant. E1 gives the value to
|
||||||
|
catalog. Our obligation is narrower and testable: no profile hard-codes a
|
||||||
|
version, and the root-frontmatter policy expresses any value.
|
||||||
|
|
||||||
|
**V5 — Attestation scope.** Answered by D4: format in, runtime out, on upstream's
|
||||||
|
own deferral rather than our preference.
|
||||||
|
|
||||||
|
## TDD order
|
||||||
|
|
||||||
|
Steps 1–3 add tests and change no behavior, so they are safe first and de-risk
|
||||||
|
everything after.
|
||||||
|
|
||||||
1. **Characterize what already holds.** `parse_frontmatter` round-trips an inline
|
1. **Characterize what already holds.** `parse_frontmatter` round-trips an inline
|
||||||
flow mapping opaquely; `_is_ingest_owned` returns False for a v0.2 `generated`
|
flow mapping opaquely; `_is_ingest_owned` returns False for a v0.2 `generated`
|
||||||
mapping. The second test converts today's fail-safe from an accident into a
|
mapping. The second converts today's fail-safe from an accident into a
|
||||||
documented guarantee.
|
documented guarantee.
|
||||||
2. **Audit Door C against the tolerance rules** — one test per consumer MUST NOT
|
2. **Audit Door C against the tolerance rules** (D3): one test per MUST NOT plus
|
||||||
(unknown `type`, unknown key, broken cross-link, missing `index.md`) plus the
|
the bare-`verified` MUST. Failures here are real defects, not plan revisions.
|
||||||
bare-`verified`-as-one-element-list MUST. Measured, not reasoned: Door C is a
|
3. **Assert no hard-coded version** anywhere a profile should decide (V4), and
|
||||||
consumer in the OKF sense and either honours these or does not.
|
the no-`timestamp`-plus-malformed-`generated` construction invariant (V-A7).
|
||||||
3. **Assert no hard-coded `0.1`** anywhere a profile should decide (V4).
|
4. **D1** — the structured reader, behind the profile seam, with the v0.1 scalar
|
||||||
4. **Only after commons answers V1:** the `generated` migration, its
|
path untouched and the full existing suite as the net.
|
||||||
`_is_ingest_owned` change, and the golden-fixture regeneration — as its own
|
5. **D2** — the `OKF_V0_2` profile and `OKF_LATEST` alias.
|
||||||
release with its own CHANGELOG entry, never folded into another change.
|
6. **D5** — v0.2 golden fixtures; `okf_version: "0.2"` is declared only here,
|
||||||
|
once 1–5 are green (conform first, claim after).
|
||||||
|
7. **D4** — `Attested Computation` as a type with round-trip fidelity.
|
||||||
|
8. **V1 to commons** in parallel throughout; **D6** lands with the release.
|
||||||
|
|
||||||
## Key assumptions, each with its test
|
## Key assumptions, each with its test
|
||||||
|
|
||||||
| # | Assumption | Test |
|
| # | Assumption | Test |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| V-A1 | The spec enumeration above is complete | Re-read `okf/SPEC.md` at a **pinned commit**, record the commit, diff against this doc before step 4 |
|
| 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 our parser unmodified | Step 1 characterization test; byte-exact round-trip |
|
| 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 test: `_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 |
|
||||||
| V-A4 | Door C meets the v0.2 consumer tolerance rules | Step 2, one test per MUST NOT — a failure here is a real defect, not a plan revision |
|
| 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-A5 | No profile hard-codes an upstream version | Step 3 |
|
||||||
| V-A6 | The `generated` migration is byte-neutral outside frontmatter | Golden diff confined to the frontmatter block; every other byte identical |
|
| 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-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 |
|
||||||
|
|
||||||
|
V-A8 is the one that keeps this honest. Every other test asks whether we agree
|
||||||
|
with ourselves.
|
||||||
|
|
||||||
## Non-goals
|
## Non-goals
|
||||||
|
|
||||||
- Implementing `Attested Computation`, executors, attesters, receipts, or
|
- Implementing attestation execution — executors, attesters, receipts, verdicts
|
||||||
verdicts (V5).
|
(D4, on upstream's deferral).
|
||||||
- Adding any optional v0.2 family to a profile without a named consumer
|
- Migrating `DEFAULT` or `STRICT_V1` onto v0.2. Support is additive; those two
|
||||||
requesting it (V3).
|
contracts belong to commons and the wiki.
|
||||||
- Editing commons' ingest-spec locally. V1 is raised in commons; if commons
|
- Editing commons' ingest-spec locally. V1 is raised there.
|
||||||
declines, the deviation is documented rather than patched here.
|
- Declaring `okf_version: "0.2"` on any bundle whose shape has not earned it.
|
||||||
- Moving `okf_version` to `"0.2"` in any fixture or profile before the shape
|
- Config-file/DSL profile loading — still a phase-3 extension point.
|
||||||
earns it, and never without catalog.
|
|
||||||
- Any change to the wiki's `timestamp`. It is on the documented legacy path;
|
|
||||||
the wiki is informed, not asked.
|
|
||||||
|
|
||||||
## Coordination — who needs to know what
|
## Coordination — who needs to know what
|
||||||
|
|
||||||
Notification set, not an approval queue. Each entry names the one thing that
|
- **commons** — V1. `generated`'s shape in ingest-spec §5. No longer blocking us,
|
||||||
repo owns:
|
still theirs to decide.
|
||||||
|
- **catalog** — form owner. Upstream moved to v0.2; their form-not-membership
|
||||||
- **commons** — V1. The only blocking dependency: `generated`'s shape in the
|
gate absorbs the bump with no change; V4 is theirs; and a new profile now
|
||||||
ingest-spec §5 layer.
|
declares `"0.2"`, which is the first bundle shape in this repo to do so.
|
||||||
- **catalog** — form owner. That upstream moved to v0.2, that its form-not-
|
|
||||||
membership gate absorbs the bump with no change, and that V4 is theirs.
|
|
||||||
- **wiki** — informational. Their `timestamp` is legacy-but-readable under
|
- **wiki** — informational. Their `timestamp` is legacy-but-readable under
|
||||||
§13.1; no action is required of them, and the earlier reading that called it a
|
§13.1; nothing is required of them, and the earlier reading that called it a
|
||||||
defect was wrong.
|
defect was wrong.
|
||||||
- **okr** — before the reference-implementation lift, so the Node half is not
|
- **okr** — before the reference-implementation lift, so the Node half ports a
|
||||||
ported against a v0.1-shaped contract.
|
contract that already knows about v0.2 rather than a v0.1 shape.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
1. Spec re-read at a pinned commit; commit hash recorded in this doc.
|
1. Spec re-read at a pinned commit; hash recorded in this doc.
|
||||||
2. `pytest` green; `mypy --strict src/`; `ruff check .` and
|
2. `pytest` green; `mypy --strict src/`; `ruff check .` and
|
||||||
`ruff format --check .` clean.
|
`ruff format --check .` clean.
|
||||||
3. Steps 1–3 add tests and change zero production behavior: golden suite
|
3. V-A6: golden suite byte-for-byte under both existing profiles; zero fixture
|
||||||
byte-for-byte, `git diff --stat examples/` empty.
|
changes outside the new v0.2 fixtures (`git diff --stat examples/` shows
|
||||||
4. V1 answered in writing by commons before step 4 begins.
|
additions only).
|
||||||
5. If step 4 lands: golden diff confined to the frontmatter block; boundary
|
4. V-A7 and V-A5 named tests present and failing-by-construction if removed.
|
||||||
grep-gate still empty; its own release and CHANGELOG entry.
|
5. V-A8: the v0.2 fixture validates under upstream's reference implementation.
|
||||||
|
6. Boundary grep-gate still empty (`sanitize|quarantine|lexicon` absent outside
|
||||||
|
guard imports).
|
||||||
|
7. D6: release checklist contains the upstream-version re-check item.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue