Authoring · 11 of 17
Migrating from YAML
In this chapter: the bridge is crossed, the Primmel packages are the single source of truth and the YAML trees are generated artifacts. What that means for an author day to day, the regeneration discipline that keeps every derived tree honest, the gates that prove it, and what remains of the post-release program. Read this before touching
data/<rec>/by hand, for domain content, you almost never should.
Status markers: ● exists in the running system · ◐ partial · ○ planned.
Paths are relative to the oimlsmart/smart repository.
11.1 Two trees, one direction
Every Recommendation in this volume exists twice in the repository:
primmel-packages/oiml-<rec>/, the PRL package. ● This is the source of truth. All domain content, subjects, requirements, tests, forms, processes, roles, state machines, quantity registers, edition manifests, is authored here in the Primmel language (Volume I), with clause-URN provenance on every element, exactly as chapters 2–7 describe (the provenance blocks are PRLsource { doc clause }constructs).data/<rec>/, the YAML tree. ● Fully generated for its package-covered files,cd browser && npm run gen:dataregenerates it from the package (browser/scripts/regenerate-data.ts, wired intonpm run build/validate/dev). Never edit a generated file by hand: each generated tree carries a machine-writtenGENERATED.mdlisting the exact generated set, and the drift guard (npm run test:ssot) fails on any hand-edit, the next regeneration silently wins anyway.
The hand-authored remainder of a data tree is app configuration, not
Recommendation content: the standard.yaml / layer.yaml manifests,
workflow / gateway / approval / certificate-template config, evaluation
dimensions and profiles, navigation, obligation, value-types, parts,
redirects, sample data, notes, the sources-prd/ extracts and coverage
declarations, and the ANR / documents / examples payloads. Those stay
YAML-authored by design (§11.6, the app-config question).
Alongside the four rec packages (oiml-r60, oiml-r91, oiml-r129,
oiml-r144) the release ships the shared packages the recs compose:
oiml-smart-core (the Tier-1 content every rec shares), the seven
oiml-smart-module-* packages (chapter 7, §7.5), the oiml-cs scheme
reference package (Volume IV), and the four ISO/IEC CASCO foundation
packages, seventeen packages in all. Every layer package regenerates its
own YAML tree (data/core/, data/oiml-cs/, data/iso-iec-*/,
data/modules/*) by the same discipline; a rec package never duplicates
content it consumes from a layer, its layers.prl include record
pulls the layer’s .prl files in verbatim.
The package manifest is the package’s identity card
(primmel-packages/<pkg>/package.primmel): id, kind core|module|rec,
title, version, editions, baseUrn, the uses composition list,
provides/requires capability tokens, and the edition-lifecycle
facets (supersedes, validity, status) that Volume I, chapter 13
specifies. primmel check C77–C80 validates them. The manifest and its
sibling projection files (.primmel-allowlist.prl, sources-prd/*.json,
value-types.prl, layers.prl) are the residual YAML→PRL projections of
the hand-authored app config, generated by the authoring aid, kept
byte-honest by the drift guard (§11.3).
11.2 What the v3 model adds, the author’s view
The v3 kernel is described in Volume I; this is the checklist of what changes for a Recommendation author moving from the YAML era:
- The subject is first-class (Volume I, ch. 2). The instrument model
is a
subjectwith an IS/HAS/DOES anatomy: identity/design aspects (is), exhibited aspects (has), and processes (does). Classification dimensions, attribute definitions (origin/scope/ category), capability mixins, behaviors, and condition sets hang off the same construct the round-trip maps tomodel/*.yaml. - Facets, not conventions. Three classification facets authored in
the YAML era as plain keys are machine-checked facets in the package:
activity_kind(the ISO/IEC 17000 activity-archetype register),segregation:(machine-checkable non-involvement, 17065), andscheme_type:(the oiml-cs layer’stype_1aself-classification, 17067), Volume IV, chapters 1–2. - Quantities are typed (Volume I, ch. 6).
value_typeand units resolve against the package’s quantity register;primmel checkC32–C34 enforces INV-1 (no bare numbers) and quantity-kind coherence. - Promises and artifacts (Volume I, ch. 2; tasks 08/09).
Manufacturer claims on characteristics and artifact definitions have
kernel constructs (
is.promises,artifact_definition). - Operational state (task 07). The instrument’s
off/warming/ready/measuring/fault machine is a
state_machineofkind operational, family-separated from the lifecycle machines (check C38); tests gate on states via preconditions. - Set-valued dimensions (task 11). R 144’s multi-component gas mixtures classify with set values, not single tokens.
- Packages compose with
uses(Volume I, ch. 8; task 05). A rec consumes core + modules + the CASCO/CS reference packages topologically, with no-redefine semantics: reference upstream ids, never restate them (check C27–C31). - Editions are package metadata (Volume I, ch. 13; task 28).
supersedes/validity/statuslive on the manifest, never in subject models, andprimmel diffgives the structural model diff that powers the release changelog (§11.5).
11.3 The regeneration discipline
One content, one source, several derived trees, and machine-enforced proof that none of them drifts. The pipeline and its gates:
primmel-packages/oiml-<rec>/ (PRL — the source of truth, edited by you)
│ scripts/regenerate-data.ts (PRL → YAML, the primary generator)
▼
data/<rec>/ (YAML — GENERATED, committed; never hand-edited)
│ the standards registry composes layers + rec
▼
the app builds and runs from the YAML trees
│
│ SMART_STANDARDS_SOURCE=primmel (the direct path):
│ scripts/build-primmel-cache.ts <rec>
▼
browser/.cache/primmel/oiml-<rec>/ (the build-consumable tree)
Three disciplines make this safe:
-
The codecs are construct-symmetric.
browser/build/yaml-to-prl.tsandbrowser/build/prl-to-yaml.tsmap every shared construct both ways;prl-round-trip.test.tsproves the YAML → PRL → YAML′ fixed point over the whole tree, andprl-fidelity.test.tsproves a hermetic 3-package build. Both regeneration paths share the.prlfile-layout doctrine (browser/build/prl-layout.ts): one YAML twin per declaring.prlfile, so the file slugs the linker resolves against survive the round trip. -
Equivalence and idempotence are gates.
npm run test:round-trip(the TODO.refactor/16 gate) builds the app from the YAML tree and from the packages and asserts the generated data is identical, then mutates one requirement inside the package and asserts the mutation propagates: the PRL tree is a real source, not a shadow.npm run test:ssot(the drift guard) proves the regeneration itself is clean in BOTH directions: every generated YAML file byte-identical to a fresh regeneration from the committed packages, and every package byte-identical to a rebuild from the hand-authored app config (the authoring aid). A hand-edit to a generated file, or an app-config edit never migrated into the packages, fails loudly with the file named. -
The exclusions ship in the package, documented. A small, named set of content has no PRL construct yet. It is not silently dropped, it ships inside the package as YAML payloads under
payload/, extracted by the authoring aid and composed back into the generated trees by the generator and the cache build (drift fails loudly):payload/attributes-pair-list.yaml, thepair_listblocks (R 144’sinterfering_components);payload/symbols-formula-notes.yaml, R 60-2’s annex formula notes;payload/formulas-variants.yaml, engine-facing formula variants that share acalculations.yamlid (the calculation construct holds one expression per id);payload/conditions-common-test.yaml, thecommon_test_conditionsregister.
Separate from the payloads, three more surfaces stay outside the PRL content by design: the app config listed in §11.1 (hand-authored YAML); the certificate print projections (
model/promises.yaml’scertificate:block) and the typed slot registries (model/identity.yaml,model/aspects.yaml), app-facing surfaces with no construct yet; and the YAML-only layer content (the OIML-CS framework model, abstract-process registers, activity archetypes, functional approach, scheme types, theUNSHIPPED_PROVIDESdoctrine of AGENTS.d/10: aprovidestoken is advertised only when its content actually ships as PRL).Each exclusion is a codec or app-config gap with an address, not a semantic difference: the round-trip gate proves the app’s generated data identical from either source.
A note on rec overlays: a rec file that overlays a layer file
(entities/workflow.yaml, the skeleton-materialized forms of R 129,
R 144’s cgm-point subform) regenerates as the minimal merge-delta over
the layers-only composition (browser/build/overlay-delta.ts), with the
fixpoint merge(layers, delta) ≡ package content asserted per file. The
hand-authored delta discipline of the YAML era (“never complete an
overlay by hand”) is now mechanical.
11.4 The gates that hold the line
Run these constantly; the release runbook runs them all from the packages.
| Gate | Command | What it proves |
|---|---|---|
| Package lint | primmel check --strict --audit <pkg> |
17 packages, 0 errors; the KNOWN/STALE allowlist discipline (a stale allowlist entry is an error, the list only shrinks); coverage budgets enforced (C55/C72) |
| Check-all | browser/src/__tests__/prl-check-all.test.ts |
the 6 composition-relevant packages at all four lint levels, all 17 at default and --strict --audit, built hermetically |
| SSOT drift guard | cd browser && npm run test:ssot |
data trees ≡ regeneration from the packages; packages ≡ rebuild from the app config, byte-clean both directions |
| Round-trip | cd browser && npm run test:round-trip |
YAML-source ≡ primmel-source build output + PRL-mutation detectability |
| App gates | npx vue-tsc --noEmit, npx astro check, npx vitest run, npm run build, npm run validate, npm run test:e2e |
the platform itself (AGENTS.md command gates) |
| From-packages proof | cd browser && npm run test:from-packages |
the release gate: every gate above run from the committed packages only, lint, the drift guard, cache regeneration, round-trip, build, type checks, tests, validation, coverage reports, the headless e2e suite, and a file-drop mutation proof |
The last row is the acceptance contract made executable: a clean checkout builds the entire system from the packages, every gate green, in about four minutes.
11.5 What changes in your daily workflow
Primmel-native authoring (the default):
- Author in
primmel-packages/oiml-<rec>/per chapters 2–7, withsource { doc clause }provenance on new content. - Regenerate the YAML trees:
cd browser && npm run gen:data(wired intonpm run build/validate/dev, so you usually build). Commit the package change AND the regenerated data trees together , the two trees move in one commit. - Run the gates:
npm run test:ssot,bin/check(vue-tsc + astro check + round-trip), thennpx vitest run,npm run validate. - Before a release:
npm run test:from-packages, the full proof from the packages.
The YAML-draft aid (for bulk drafting or the YAML-fluent):
- Draft the content in
data/<rec>/YAML, the schemas and your editor tooling still work there. - Migrate the draft into the package:
cd browser && npx tsx scripts/build-prl-package.ts <rec>, the authoring aid emits the.prlconstructs and extracts any payload-class exclusions (pair_list, formula notes, formula variants, the common-test register) intopayload/*.yaml. - Review the
.prldiff, regenerate (npm run gen:data), gates. From here the package is the only place the content is edited.
Reading a diff for review. The changelog of any change is
machine-computable: primmel diff <old-package-dir> <new-package-dir>
(a git worktree or git archive gives you the old tree). The v3
release’s own changelog (docs/releases/v3-changelog.md, regenerated by
scripts/v3-changelog.ts) is built exactly this way from the pinned
YAML-era baseline.
What you never do: edit a GENERATED.md-listed file by hand;
hand-tune browser/.cache/** (100 % derived); add content to a generated
file “for the app alone” (author it in the package, or as a package
payload when no construct exists, the payload compose fails loudly on
drift, that is the point).
11.6 What remains of the post-release program
The flip landed in three of the v2 plan’s phases:
- Phase A, packages able to be authoritative (●, the v3 release): the from-packages proof stands on the committed packages alone.
- Phase B, YAML becomes generated output (●, this flip): the data
trees regenerate from the packages byte-clean; the drift guard holds
both directions; authoring is Primmel-native with the YAML-draft aid
for migration. What remains inside phase B:
- codec homes for the §11.3 payload classes,
pair_list,formula_notes, the formula engine variants,common_test_conditions, plus the process/gateway/approval inverse mappings, the promises certificate projection, and the identity/aspect slot registries, each is a grammar/codec task; when one lands its payload file retires; - the textual
includetransport retired in favor ofusescomposition in the load path (AGENTS.d/10: the two are never mixed in one load today, the rec packages include layer files verbatim); - the app-config question answered in full, how much of workflow/certificate/navigation YAML is model content (gains a construct) vs platform configuration (stays YAML by design).
- codec homes for the §11.3 payload classes,
- Phase C, new content authored Primmel-native only (◐, de facto
current for the four recs): new Recommendations author in
.prlfrom the start; the YAML tree is what the generated TypeScript is: derived, committed, never edited.
The rule of this chapter: edit Primmel, regenerate, let the gates prove every derived tree honest.