Repository navigation
Description
Parent
What to build
Narrowed 2026-10-01. This ticket is the registry and the OCL statements. Making each code a real refusal (one check per code in
check/, in both implementations, with fixtures) is #204.
Every error code the specification defines becomes a registry entry, the constraint ledger the parity contract names, with a greppable CONS-NNN id, its code, its context (the metamodel class it constrains, the composed union, or a transformation), its kind (schema, document, composition, render, or a property of a function), its OCL placement (invariant, derived value, or precondition), its specification anchor, its fixtures and its tests. The registry is the list the spec error-code test from #30 reads. The rule tables in the chapters are checked against it.
Resolved in this ticket:
- One rule, one code.
E_DUPLICATE_ROUTE_MATCHstays andE_DUPLICATE_ROUTEgoes.E_DUPLICATE_HOSTstays andE_DUPLICATE_APEXgoes; its message names the apex.E_PROVIDER_WITHOUT_COORDINATESstays andE_UNMANAGED_SURFACE_WITHOUT_COORDINATESgoes, since edges resolve against providers, not the unmanaged register, after 0095. 0018, 0090 and 0093 are amended to match. E_RELEASE_UNIT_NO_READINESSgets a home. Chapters 20 and 50 cite it as a chapter-40 invariant, and chapter 40 neither lists it nor keeps release-unit invariants. It becomes a document-level rule on the Application, and chapters 20 and 50 point at it.- A refusal that hides a derivation names the derived value: the eligible node set before
E_PLACEMENT_UNSATISFIABLE, staleness beforeE_PARTICIPANT_STALE. - Every rule that can be evaluated on one parsed document is proved to fire by a refusal fixture.
The OCL statement per entry
Merged from the ticket that used to be #45, so that all 61 codes are read once rather than twice.
Each entry gains a normative statement in Essential OCL, written against the metamodels, using no @pre and no message expressions. The TypeScript implementation is tested by the entry's fixtures, so the specification and the code meet at the fixture.
The statement is specification notation, not tool input: spec/v1 stays independent of any EMF tool. The Complete OCL invariants under emf/ are the executable Java-side counterpart, each named by its code and held to the same statement and fixture. The ledger's column naming the OCL invariant lives inside emf/, so the root ledger has no EMF column to delete at the sunset.
- Entries that are properties of a function rather than of a model (render determinism, no ambient reads, no input outside the working directory) are marked as such and point at the double render, not at an OCL statement.
- A rule that compares two composition runs (
E_CONTRACT_TOO_EARLY) is stated as a precondition on composition, not as an invariant on one snapshot. - Rules that navigate across documents (34 of the 61) name the composed union as their context.
- The statements are rendered into the chapters' rule tables, so they are what the Task 1 report cites.
Writing the statements surfaces facts the metamodels leave implicit. This ticket adds the one known now: cutover: rolling is refused over storage that cannot surge, and "every claim is ReadWriteOnce on local-path" is a substrate fact no document states. Platform Intent states it, and the rule reads it.
Parity
Every refusal fixture this ticket adds or keeps carries a committed <input>.diagnostics.json: the set of (code, path) pairs, with paths as JSON Pointers. Diagnostics compare as a set, never an ordered list, because OCL does not fix evaluation order. Each ledger row names the TypeScript check that enforces it; the Java counterpart ticket adds the Complete OCL invariant for every row and emf/'s check that no row lacks one.
Acceptance criteria
- Every
E_token in the specification, the decision records and the tests resolves to exactly one registry entry; an unknown token fails. - Each document-level rule has a refusal fixture that emits exactly its code.
- No rule has two codes; the three retired codes appear only in historical notes.
- A registry entry without a specification anchor, or a rule table row without an entry, fails.
- Every registry entry has an Essential OCL statement, or a marker saying why it is not a model constraint.
- Each statement uses only the Essential OCL subset.
- The cutover rule reads the storage fact from Platform Intent, and a Platform document stating a surge-capable storage class changes the outcome of its fixture.
- Every ledger row has a
CONS-NNNid, and every refusal fixture has a committeddiagnostics.jsonwhose set equals what the TypeScript implementation emits.
Activity
[-]Register every model rule with its context, placement and fixture[/-][+]Register every model rule with its context, placement, OCL statement and fixture[/+]feat: read the Platform document and refuse what it and the project f…
ExtraToast commentedon Oct 9, 2026
Closed by the map's Decide the fate of the open work that predates the map: course-driven work whose reason ends with the grade (#344) and with
emf/(#347). Any residue is listed on that ticket's resolution as a rewrite input.