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

@ -9,6 +9,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- **`DEFAULT` now stamps `generated: { by: process:okf-ingest, at: <ingested_at> }`
instead of `generated: true`.** This is a byte change in every concept file Door A
writes under `DEFAULT`, so a consumer's own golden fixtures will show one changed
line per generated file.
The trigger is not an upstream Google release. `DEFAULT` states the ingest-spec
layer owned by `portfolio-optimiser-commons`, and they ratified this shape
(2026-08-02) and executed it in their spec on 2026-08-09. §7 defines the value:
the actor is the fixed `process:okf-ingest`, `at` repeats `ingested_at` verbatim,
and it is unquoted because frontmatter is parsed line-oriented — a quote would be
a character in the value rather than syntax a reader strips.
**What it costs a consumer is a re-run, and nothing else.** Ownership recognition
is one-way: a profile carrying an actor still owns the older literal stamp, so a
bundle written by an earlier version re-runs in place rather than tripping the §3
collision gate. No call signature changed and no key was added or removed.
Two things it is NOT. It is not a migration of `DEFAULT` onto OKF v0.2 — the
profile remains v0.1 on every axis upstream owns, and still emits no `sources`.
And it does not make `DEFAULT` and `OKF_V0_2` the same profile; they now agree on
the stamp and continue to differ in index root frontmatter, type-conditional
requirements, and `sources` derivation.
Door B (`process_inbox`) is deliberately unchanged: its marker is `generated`
plus `source_file`, it is not governed by the ingest-spec, and it stays disjoint
from Door A's `ingest_manifest`.
- **The v0.5.0 pilot set gained a fourth member: `portfolio-optimiser`.** Admitted
2026-08-09 on their request. `v0.5.0a1`'s entry below says "do not pin this tag
outside the pilot set" and names three repos; that entry is left as written,

View file

@ -95,7 +95,14 @@ 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.
commons' call, raised there, never patched locally. **This fired 2026-08-09:**
commons ratified and executed the O2 form, so `DEFAULT` now stamps
`generated: { by: process:okf-ingest, at: <ingested_at> }` and four goldens
moved with it. It is not a counterexample to "additive, never a migration" —
that rule governs *upstream* versions, and commons' spec is a separate axis
`DEFAULT` tracks by definition. `DEFAULT` stays v0.1 on everything upstream
owns. Ownership recognition is one-way, so the cost to a consumer stays a
re-run: a profile carrying an actor still owns the older literal stamp.
- `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).

View file

@ -128,12 +128,21 @@ verification criteria:
The library targets the current latest version of Google's OKF. Support is
**additive** — a new upstream version arrives as a new profile, never as a
migration of an existing one — so upgrading the library does not change the
migration of an existing one — so an *upstream* release does not change the
bytes an existing profile emits.
That guarantee is about upstream, and one profile tracks a second contract as
well. `DEFAULT` states the ingest-spec owned by `portfolio-optimiser-commons`,
so when they change that spec, `DEFAULT` follows them. It happened on
2026-08-09: `generated` moved from `true` to
`{ by: process:okf-ingest, at: <ingested_at> }`, one changed line per generated
file. Upgrading across it costs a re-run and nothing more — a profile still
recognises bundles stamped by earlier versions, so re-running writes in place
instead of refusing. `DEFAULT` remains OKF v0.1 on every axis upstream owns.
| Profile | Contract | Status |
|---|---|---|
| `DEFAULT` | commons' ingest-spec §5 layer (OKF v0.1 semantics) | stable |
| `DEFAULT` | commons' ingest-spec layer (OKF v0.1 semantics) | stable |
| `STRICT_V1` | a consumer's ratified v0.1 contract | stable |
| `OKF_V0_2` | OKF v0.2 | **provisional**, pre-release only |
| `OKF_LATEST` | alias for the latest version supported as *stable* | currently `DEFAULT` |

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.

View file

@ -5,7 +5,7 @@ source_system: golden-catalogue
source_query: orders.csv
ingested_at: 2026-07-16T12:00:00Z
ingest_manifest: manifest@37674ac20059e788
generated: true
generated: { by: process:okf-ingest, at: 2026-07-16T12:00:00Z }
---
| order_id | customer | total |

View file

@ -5,7 +5,7 @@ source_system: golden-catalogue
source_query: products.csv
ingested_at: 2026-07-16T12:00:00Z
ingest_manifest: manifest@37674ac20059e788
generated: true
generated: { by: process:okf-ingest, at: 2026-07-16T12:00:00Z }
---
| sku | name | note |

View file

@ -5,7 +5,7 @@ source_system: golden-api
source_query: /status.json
ingested_at: 2026-07-16T12:00:00Z
ingest_manifest: manifest@826dbd7dec4d4c79
generated: true
generated: { by: process:okf-ingest, at: 2026-07-16T12:00:00Z }
---
```

View file

@ -5,7 +5,7 @@ source_system: golden-db
source_query: SELECT id, name, value, comment FROM metrics ORDER BY id
ingested_at: 2026-07-16T12:00:00Z
ingest_manifest: manifest@93a04cce66d99b53
generated: true
generated: { by: process:okf-ingest, at: 2026-07-16T12:00:00Z }
---
| id | name | value | comment |

View file

@ -135,8 +135,9 @@ def _is_ingest_owned(path: Path, manifest_stem: str, *, profile: BundleProfile =
# reference. Promoted verdict files carry neither key, so they can never
# classify as ingest-owned.
#
# The stamp is the PROFILE's because it differs per profile (v0.1 writes
# `generated: true`, v0.2 a `{ by: ..., at: ... }` mapping) — and because the
# The stamp is the PROFILE's because it differs per profile (the older form
# is `generated: true`, the O2 form a `{ by: ..., at: ... }` mapping, and
# which one a profile writes follows the contract it states) — and because the
# emitter and this predicate are coupled through that value. Changing the
# emitted form without the predicate is what makes the library stop
# recognising its own output, firing the collision gate on the files its own

View file

@ -286,24 +286,37 @@ class OwnershipPolicy:
Ownership is the §3 collision gate's question — may this run replace the
file already sitting at a generated name? and the answer is a profile's,
because the stamp differs per profile. v0.1 writes the literal `true`; v0.2
writes `generated: { by: <actor>, at: <ingested_at> }` (§5), where the actor
takes §7's `process:<id>` form.
because the stamp differs per profile. The literal `true` is the older
form; the O2 form is `generated: { by: <actor>, at: <ingested_at> }` (§5),
where the actor takes §7's `process:<id>` form.
`actor` is `None` for the v0.1 stamp. Where it is set it carries no version,
Which form a profile writes is NOT read off an upstream version. `DEFAULT`
states commons' ingest-spec layer and writes the O2 form because commons
ratified it (V1, `54e0ec7`), while remaining v0.1 on every axis upstream
owns; `STRICT_V1` names no `generated` at all. The stamp tracks whichever
contract the profile states, and those contracts move independently.
`actor` is `None` for the literal stamp. Where it is set it carries no version,
deliberately: the value sits inside a byte-compared golden, so a producer
version there would fire golden regression on every release without any
contract having changed, and would make a shared cross-implementation
fixture impossible by construction (plan V1(d), operator 2026-07-27).
Recognition is ONE-WAY, and both directions are decisions rather than
accidents. A v0.2 profile owns the v0.1 stamp as well, so a bundle written
under `DEFAULT` re-runs IN PLACE the black-box promise is that an upstream
release costs a consumer a re-run and nothing more. The reverse is refused:
`DEFAULT` meeting a v0.2 file fails the run rather than replacing a file
whose shape it does not read (V-A3).
accidents. A profile with an actor owns the literal stamp as well, so a
bundle written before V1 re-runs IN PLACE the black-box promise is that a
spec release costs a consumer a re-run and nothing more. The reverse is
refused: a profile without an actor fails the run rather than replacing a
file whose shape it does not read (V-A3).
The v0.2 test is a PREFIX rather than an equality, because the value carries
"Owns the O2 form" is never "owns any mapping". The prefix binds the
profile's OWN actor, so a mapping naming a different one — another
implementation's, or §7's `human:` actor on curated content stays
unowned. That is what keeps the key's mere presence from proving authorship,
which upstream v0.2 makes load-bearing by writing `generated` on
hand-authored files too.
The actor test is a PREFIX rather than an equality, because the value carries
`ingested_at` and therefore differs on every run by design. It works because
`parse_frontmatter` returns the whole flow mapping as one opaque string
(V-A2) no structure this library cannot yet read is parsed here.
@ -601,9 +614,14 @@ class BundleProfile:
ownership: OwnershipPolicy = field(default_factory=OwnershipPolicy)
# The ingest-spec v1 + Phase 2 contract, unchanged. Every value here was a
# constant in `manifest`, `materialize`, `inbox` or `importer` before this
# module existed; the golden suite is what proves the move changed no bytes.
# The ingest-spec + Phase 2 contract. Every value here was a constant in
# `manifest`, `materialize`, `inbox` or `importer` before this module existed;
# the golden suite is what proves that move changed no bytes.
#
# This profile tracks COMMONS' spec, not an upstream Google version — the two
# axes are independent, and `ownership` is where they visibly part company. Its
# `generated` is the O2 mapping because commons ratified that shape for their
# §5 layer, while the profile remains v0.1 on every axis upstream owns.
DEFAULT = BundleProfile(
types=TypePolicy(allowed=None),
frontmatter=FrontmatterSchema(
@ -633,6 +651,12 @@ DEFAULT = BundleProfile(
link_template="- [{label}]({target})",
link_pattern=re.compile(r"^- \[(?P<label>[^\]]*)\]\((?P<target>[^)]+)\)$"),
),
# V1, ratified 2026-08-02 and executed by commons 2026-08-09 (`54e0ec7`).
# The actor is the same constant `OKF_V0_2` carries, and that is commons'
# doing rather than a merge of the two profiles: ingest-spec §7 names
# `process:okf-ingest` as THE ingest actor, so any profile stating that
# spec's layer writes it. The profiles still differ everywhere else.
ownership=OwnershipPolicy(actor="process:okf-ingest"),
)
@ -804,14 +828,24 @@ OKF_V0_2 = BundleProfile(
# (§8, §12). Built with `replace` rather than restated so a later change to
# the shared shape cannot drift between the two.
index=replace(DEFAULT.index, root_frontmatter=("okf_version",)),
# Byte-identical to `DEFAULT.ownership` since V1, and deliberately NOT
# written as a reference to it. The two agree by coincidence of commons
# adopting §7's actor, not by dependency: this profile states UPSTREAM's
# v0.2, so if commons ever moves their actor again, this one must not
# follow. Restating it is what keeps that independence expressible.
ownership=OwnershipPolicy(actor="process:okf-ingest"),
)
# "The latest version supported as STABLE", not the latest present in this
# module. It therefore keeps v0.1 semantics for as long as v0.2 is provisional,
# and flipping it is the GA event — one auditable action rather than a side
# effect of a merge.
# module. It therefore keeps v0.1 UPSTREAM semantics for as long as v0.2 is
# provisional, and flipping it is the GA event — one auditable action rather
# than a side effect of a merge.
#
# "v0.1 semantics" is about upstream and has never covered commons' layer. V1
# moved `DEFAULT`'s stamp, so this alias's bytes moved with it, before GA and
# without the flip. That is not a leak in the alias: the two contracts are
# independent axes, and a consumer bound here tracks both by construction.
#
# The tradeoff is stated rather than hidden: an alias that moves means a consumer
# bound to it inherits upstream's breaking changes on a library upgrade. The

View file

@ -84,6 +84,13 @@ def test_provenance_layer_on_every_generated_file(tmp_path: Path) -> None:
MUST fail when a generated file no longer carries the §7 layer.
Hand-mutation check 2026-07-16: dropping any of the five §7 keys from
_render_concept_file turns this test red.
`generated` is spelled out here rather than read from the profile, for the
same reason the frontmatter parser is: a seam that asks the library what it
should have written cannot catch the library writing the wrong thing. §7
fixes both sub-keys the actor is the constant `process:okf-ingest`, and
`at` repeats `ingested_at` verbatim so the expected value is derivable by
hand, which is what makes stating it independently possible at all.
"""
_, written = materialized_bundle(tmp_path)
assert written
@ -93,7 +100,7 @@ def test_provenance_layer_on_every_generated_file(tmp_path: Path) -> None:
assert frontmatter["source_query"]
assert frontmatter["ingested_at"] == INGESTED_AT
assert re.fullmatch(r"manifest@[0-9a-f]{16}", frontmatter["ingest_manifest"])
assert frontmatter["generated"] == "true"
assert frontmatter["generated"] == f"{{ by: process:okf-ingest, at: {INGESTED_AT} }}"
def test_every_generated_file_reachable_via_index_links(tmp_path: Path) -> None:

View file

@ -113,7 +113,7 @@ def test_file_source_concept_file_exact_bytes(file_setup: tuple[Path, Path]) ->
"source_query: orders.csv\n"
f"ingested_at: {INGESTED_AT}\n"
f"ingest_manifest: {stamp_of(manifest_path)}\n"
"generated: true\n"
f"generated: {{ by: process:okf-ingest, at: {INGESTED_AT} }}\n"
"---\n"
"\n"
"| a | b |\n"
@ -371,6 +371,43 @@ def test_a_door_c_import_survives_a_same_stem_materialize_run(
assert (bundle / "ingest-orders.md").is_file()
def test_a_door_c_import_forging_the_o2_stamp_survives_a_materialize_run(
file_setup: tuple[Path, Path],
) -> None:
"""The test above with the value V1 made forgeable. ingest-spec §11 lists
"Stamp integrity (curated writers)" as a red condition, and V1 changed WHICH
value satisfies it: the forgeable stamp used to be the literal `true`, and is
now the O2 mapping naming the ingest actor. The old test keeps exercising a
value `DEFAULT` still owns, so it did not stop testing anything but on its
own it would leave the current threat unexercised.
The defence is structural rather than a judgement about the value: the §3
scan globs `ingest-*.md`, so a `import-`-prefixed file is never a candidate
no matter how perfectly it forges the stamp. Door C writes external concepts
verbatim and cannot screen this, which is exactly why the namespace, not the
parse, has to be what holds.
"""
manifest_path, bundle = file_setup
bundle.mkdir()
imported = bundle / "import-external.md"
forged = (
"---\n"
"type: Concept\n"
"title: Imported Concept\n"
"provenance:\n"
f" generated: {{ by: process:okf-ingest, at: {INGESTED_AT} }}\n"
" ingest_manifest: manifest@deadbeef\n"
"---\n\nExternally imported body.\n"
)
imported.write_text(forged, encoding="utf-8")
materialize_bundle(manifest_path, bundle, INGESTED_AT)
assert imported.is_file()
assert imported.read_text(encoding="utf-8") == forged
assert (bundle / "ingest-orders.md").is_file()
def test_second_manifest_does_not_delete_first_manifests_stamped_file(tmp_path: Path) -> None:
# §10.2 per-manifest ownership: two manifests writing into ONE bundle each
# own only the files whose stamp names them by stem. Running manifest B

View file

@ -153,9 +153,17 @@ def test_a_v0_2_file_at_a_target_name_is_refused_not_overwritten(tmp_path: Path)
materialize_bundle(manifest_path, bundle, INGESTED_AT)
concept = bundle / "ingest-orders.md"
v0_2_bytes = concept.read_bytes().replace(
b"generated: true", f"generated: {V0_2_GENERATED}".encode()
)
# Substitute the stamp THIS profile wrote for a foreign one. The needle is
# derived from the profile rather than spelled out because it moved once
# already (V1 took `DEFAULT` off `generated: true`), and a stale literal
# here would make `replace` a silent no-op — leaving the file carrying our
# own stamp and the test passing for a reason it does not describe. The
# assertion below is the guard against that happening again.
own_stamp = f"generated: {DEFAULT.ownership.stamp(INGESTED_AT)}".encode()
original = concept.read_bytes()
assert own_stamp in original
v0_2_bytes = original.replace(own_stamp, f"generated: {V0_2_GENERATED}".encode())
assert v0_2_bytes != original
concept.write_bytes(v0_2_bytes)
with pytest.raises(MaterializationError) as excinfo:

View file

@ -136,8 +136,20 @@ def test_okf_latest_still_means_v0_1_until_ga() -> None:
# --- ownership ------------------------------------------------------------
def test_the_default_profile_still_stamps_the_v0_1_literal() -> None:
assert DEFAULT.ownership.stamp(INGESTED_AT) == "true"
def test_the_default_profile_stamps_the_form_commons_ratified() -> None:
"""V1, executed by commons 2026-08-09 (`54e0ec7`). `DEFAULT` states commons'
ingest-spec §5 layer, so the shape of its `generated` is theirs to decide
and they moved it off the v0.1 literal onto the O2 mapping. ingest-spec §7
defines the value as `{ by: process:okf-ingest, at: <ingested_at> }`,
unquoted, because frontmatter is parsed line-oriented and a quote would be a
character IN the value rather than syntax a parser strips.
`DEFAULT` and `OKF_V0_2` therefore agree on the stamp and on nothing else:
the profiles still differ in their index root frontmatter, their
type-conditional requirements and their `sources` derivation. The stamp
converging is the point of V1, not a sign the two profiles merged.
"""
assert DEFAULT.ownership.stamp(INGESTED_AT) == V0_2_STAMP
def test_the_v0_2_stamp_is_a_flow_mapping_whose_at_is_the_argument_exactly() -> None:
@ -170,14 +182,38 @@ def test_the_v0_2_predicate_also_accepts_the_v0_1_stamp(tmp_path: Path) -> None:
assert _is_ingest_owned(path, "manifest", profile=OKF_V0_2) is True
def test_the_default_predicate_still_refuses_the_v0_2_stamp(tmp_path: Path) -> None:
"""Recognition is one-way, which is what preserves V-A3. `DEFAULT` meeting a
v0.2 file refuses the run rather than replacing the file."""
def test_the_default_predicate_owns_the_stamp_v1_made_it_write(tmp_path: Path) -> None:
"""V-A3 as V1 leaves it. Before V1 this asserted the opposite — `DEFAULT`
refused the O2 mapping outright and that reading died the moment commons
made `DEFAULT` WRITE that mapping: a profile that will not own its own
output fires the §3 collision gate on the files its own previous run wrote.
The emitter and the predicate are coupled through `OwnershipPolicy`
precisely so they cannot part company here.
What V-A3 protected is unchanged and is asserted below: ownership binds the
ACTOR, not the shape. A mapping is owned when it names this profile's actor
and refused when it names any other.
"""
path = tmp_path / "ingest-orders.md"
path.write_bytes(_stamped_concept(V0_2_STAMP))
assert _is_ingest_owned(path, "manifest") is False
assert _is_ingest_owned(path, "manifest", profile=DEFAULT) is False
assert _is_ingest_owned(path, "manifest") is True
assert _is_ingest_owned(path, "manifest", profile=DEFAULT) is True
def test_the_default_predicate_refuses_a_foreign_actor(tmp_path: Path) -> None:
"""The half of V-A3 that survives V1 intact, and the one that carries the
safety: another implementation's bundle, and §7's `human:` actor on curated
content, both stay unowned under `DEFAULT`. Presence of the key proves
nothing upstream writes `generated` on hand-authored files too.
"""
foreign = tmp_path / "ingest-orders.md"
foreign.write_bytes(_stamped_concept(f"{{ by: process:some-other-tool, at: {INGESTED_AT} }}"))
curated = tmp_path / "ingest-products.md"
curated.write_bytes(_stamped_concept(f"{{ by: human:jsmith@acme, at: {INGESTED_AT} }}"))
assert _is_ingest_owned(foreign, "manifest", profile=DEFAULT) is False
assert _is_ingest_owned(curated, "manifest", profile=DEFAULT) is False
def test_a_foreign_v0_2_actor_is_never_ingest_owned(tmp_path: Path) -> None:
@ -249,10 +285,14 @@ def test_sources_follows_generated_in_the_emitted_block() -> None:
]
def test_the_default_profile_emits_neither_sources_nor_a_v0_2_generated() -> None:
"""V-A6 at the unit level: the seven-key v0.1 block, byte for byte. The
golden suite proves the same thing end to end; this one localizes a failure
to the renderer rather than to a fixture diff.
def test_the_default_profile_emits_no_sources_and_the_o2_generated() -> None:
"""V-A6 at the unit level, as V1 amends it: the seven-key block byte for
byte. `generated` now carries commons' O2 mapping, and `sources` — which is
upstream v0.2's, not commons' is still absent. That pairing is the whole
point of keeping the two contracts on separate axes.
The golden suite proves the same end to end; this one localizes a failure to
the renderer rather than to a fixture diff.
"""
rendered = _concept(FileSource(id="golden-catalogue", root="fixture"), profile=DEFAULT)
@ -264,11 +304,12 @@ def test_the_default_profile_emits_neither_sources_nor_a_v0_2_generated() -> Non
"source_query: orders.csv\n"
f"ingested_at: {INGESTED_AT}\n"
f"ingest_manifest: {STAMP}\n"
"generated: true\n"
f"generated: {{ by: process:okf-ingest, at: {INGESTED_AT} }}\n"
"---\n"
"\n"
"Body.\n"
)
assert "sources:" not in rendered
def test_the_http_credential_reference_never_reaches_the_frontmatter() -> None:

View file

@ -106,7 +106,9 @@ def test_default_run_is_unchanged_by_the_new_parameter(file_setup: tuple[Path, P
materialize_bundle(manifest_path, explicit_dir, INGESTED_AT, profile=DEFAULT)
assert (explicit_dir / "ingest-orders.md").read_bytes() == implicit
assert (explicit_dir / "index.md").read_bytes() == index_implicit
assert b"generated: true" in implicit
# Not redundant with the equality above: it pins WHICH profile the implicit
# run used. Without it the two calls could agree while both being wrong.
assert f"generated: {{ by: process:okf-ingest, at: {INGESTED_AT} }}".encode() in implicit
def test_profile_is_keyword_only(file_setup: tuple[Path, Path]) -> None: