Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ what gets fixed.
Before changing anything under `docs/adr/` or `spec/v1/`:

- Read [`docs/adr/README.md`](docs/adr/README.md) for the register, the citation
rule and the project table, and `docs/adr/model/0003`–`0006` for the model's
rule and the domain table, and `docs/adr/model/0003`–`0006` for the model's
premises.
- `docs/adr/` carries **one directory per project**: `model/` (v1 model,
- `docs/adr/` carries **one directory per decision domain**: `model/` (v1 model,
pointers into `spec/v1`), `architecture/` (the compiler's own structure,
pointers into `docs/architecture.md`), `deferred/` (not linted). Numbers run
in one estate-wide sequence, so never reuse a number from another project.
in one estate-wide sequence, so never reuse a number from another domain.
- Run `npm run lint:adrs`. It enforces frontmatter schema, register integrity,
qualified citations (a bare `ADR-` token outside a link fails), normative
anchors resolving against real headings in `spec/v1`, and content shape.
Expand All @@ -55,17 +55,18 @@ Delivery mechanics and co-testing are **defined separately**: see
applier, a prune pass, a field manager or a co-test gate in `spec/v1`; state the
model-level rule and point at the deferred set.

### The coursework implementation under `emf/`
### The model-driven implementation under `emf/`

The MDE course requires the compiler to be built with Ecore, Xtext, OCL,
QVT-Operational and Acceleo, so `emf/` holds a second, hand-written Java
QVT-Operational and Acceleo, so `emf/` holds the model-driven implementation:
a second, hand-written Java implementation beside the TypeScript production
implementation (Maven and Tycho, JDK 21, no Eclipse IDE to build, but
loadable in Eclipse for the course's examiners). It is deprecated
from the day it lands and deleted at its sunset:

- **The root stays TypeScript.** Every pom, module, check, ledger and decision
of the Java side lives under `emf/`. The root references it only from CI
(the `emf` job and the `emf` ADR lint step), the `emf` project in
(the `emf` job and the `emf` ADR lint step), the `emf` domain in
`scripts/lint-adrs.ts` and its test, and
[`docs/architecture.md#the-parity-contract`](docs/architecture.md#the-parity-contract).
- **Never generate one implementation from the other.** Both are tested,
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ lands, the **compiler** that turns that model into deployable artifacts.
| --- | --- |
| [`CONTEXT.md`](CONTEXT.md) | The vocabulary. One term, one meaning; also the naming authority for code. |
| [`docs/architecture.md`](docs/architecture.md) | Normative for code structure, the way `spec/v1` is normative for the model. |
| [`docs/adr/`](docs/adr/README.md) | The decision surface, one directory per project. Machine-checked. |
| [`docs/adr/`](docs/adr/README.md) | The decision surface, one directory per decision domain. Machine-checked. |
| [`docs/adr/model/`](docs/adr/model/) | The v1 model: 8 premises carrying falsifiable claims, 43 decisions resting on them. |
| [`docs/adr/architecture/`](docs/adr/architecture/README.md) | The compiler's own structure. Pointers resolve against `docs/architecture.md`, not `spec/v1`. |
| [`docs/adr/deferred/`](docs/adr/deferred/README.md) | Delivery and co-testing decisions, defined separately from the model. Direction work, not v1. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ folders after the layers is not decoration. It means a reviewer reading
`src/domain/resolved/` are looking at the same thing, and a rule that lands in
the wrong ring is visible as a wrong import rather than as a wrong idea.

The two runtimes in [chapter 30](../../../spec/v1/30-deliverables.md#adapters) (five fragment producers in the Project repository, eleven central adapters over
The two runtimes in [chapter 30](../../../spec/v1/30-deliverables.md#adapters) (five fragment producers in the project repository, eleven central adapters over
the union) are the reason to be careful here. They differ in *what documents
they receive*, not in what an Application means. One core with two use-cases keeps
the invariants in one place; two applications would put them in a third package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ rests-on: ["0003", "0006"]

# Two hand-written implementations meet at committed oracle files, and neither is generated from or tested against the other

> **Amended 2026-09-14.** Aligned with the revised project proposal
> ([#102](https://github.com/JorisJonkers-dev/deploy-kit/pull/102)): the TypeScript code is the production implementation and `emf/` the
> model-driven implementation. They are compared on validation, dependency
> resolution, errors and generated resources. `resolved.json` binds the
> production implementation only, because the model-driven target metamodel
> holds the Resolved Deployment and the typed resources as one model; a new
> dependency-edge oracle carries the part of resolution both must agree on.

## Rests on
The three layers give three points where a run's state is a complete, closed
document, and pinned inputs make each of those documents a function of the
Expand Down
45 changes: 31 additions & 14 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,26 +188,41 @@ clean tree is untested: nothing proves it would fail.

## The parity contract

This compiler has a second implementation. The model-driven engineering course
this repository is coursework for requires Ecore, Xtext, OCL, QVT-Operational
and Acceleo, so a Java implementation lives under [`emf/`](../emf/README.md)
This compiler has two implementations. The TypeScript code under `src/` is the
**production implementation**. The model-driven engineering course this
repository is coursework for requires Ecore, Xtext, OCL, QVT-Operational and
Acceleo, so a **model-driven implementation** in Java lives under
[`emf/`](../emf/README.md)
until its sunset condition holds
([0105](adr/architecture/0105-two-implementations-meet-at-committed-oracles.md)).
Everything about that implementation, its build, its checks and its decisions,
lives inside `emf/`. What lives here is the contract both implementations
answer to, because the contract outlives the second implementation.
answer to, because the contract outlives the model-driven implementation.

Neither implementation is generated from the other, and neither is the oracle
for the other. Each is tested on its own against committed oracle files, and
agreement between the two follows from both agreeing with the oracle.

| oracle | where | compared as |
|---|---|---|
| the parsed Project Intent | `spec/v1/examples/<case>/expected/intent.json` | canonical JSON, byte for byte |
| the Resolved Deployment | `spec/v1/examples/<case>/expected/resolved.json` | canonical JSON, byte for byte |
| the Deliverable Set | `spec/v1/examples/<case>/rendered/` | the existing golden tree, byte for byte |
| the diagnostics of a refused case | `<input>.diagnostics.json` beside the refused input in `refusals/` or `negative/` | a set of `(code, path)` pairs |
| the metamodel's structure | `spec/v1/examples/expected/descriptor.json` | canonical JSON, byte for byte |
The two are compared on what the project proposal names: validation, dependency
resolution, errors and generated resources. They are not required to agree on
anything else. In particular their intermediate models differ: the production
implementation keeps the Resolved Deployment and the typed object model its
adapters build as two things, while the model-driven implementation has one
target metamodel holding both, because a model-to-text template reads one model.

| oracle | where | compared as | binds |
|---|---|---|---|
| the parsed Project Intent (validation) | `spec/v1/examples/<case>/expected/intent.json` | canonical JSON, byte for byte | both |
| the diagnostics of a refused case (errors) | `<input>.diagnostics.json` beside the refused input in `refusals/` or `negative/` | a set of `(code, path)` pairs | both |
| the resolved dependency edges (dependency resolution) | `spec/v1/examples/<case>/expected/dependencies.json` | canonical JSON, byte for byte | both |
| the Deliverable Set (generated resources) | `spec/v1/examples/<case>/rendered/` | the existing golden tree, byte for byte | both |
| the source metamodel's structure | `spec/v1/examples/expected/descriptor.json` | canonical JSON, byte for byte | both |
| the Resolved Deployment | `spec/v1/examples/<case>/expected/resolved.json` | canonical JSON, byte for byte | production only |

**The dependency edges** are, per Application, every dependency edge after
resolution: the consumer, the provider Application and Surface, the address the
consumer is given, and the policy peers that allow the connection. It is the
part of resolution both implementations must agree on before either renders.

**Canonical JSON** is RFC 8785 (JSON Canonicalization Scheme): keys sorted,
numbers in their shortest form, no insignificant whitespace. An absent
Expand All @@ -218,8 +233,10 @@ optional field is absent, never `null`.
points at the authored value it derives from. Messages and hints are free per
implementation; the code and the path are the contract.

**The descriptor** lists every class of every layer with its features, each
**The descriptor** lists every class of the source metamodel (Project Intent
and the platform data it is resolved against) with its features, each
feature's type and multiplicity, and every closed vocabulary with its literals.
Target structures are compared through what they generate, not structurally.
The TypeScript side builds it from the Zod schemas with Zod's native
`z.toJSONSchema()` and a normaliser; the descriptor's shape is fixed here, not
by either source format.
Expand All @@ -231,8 +248,8 @@ of the model's validation, whichever implementation happens to enforce it.

**Behaviour rows.** A row of the [behaviour ledger](requirements.md) whose
behaviour is the model's own (parse, validate, resolve, render) is proved in
both implementations. The row names the TypeScript test; the Java witness for
the same id is listed inside `emf/`, and `emf/`'s own gate fails when a model
both implementations. The row names the TypeScript test; the model-driven witness
for the same id is listed inside `emf/`, and `emf/`'s own gate fails when a model
row has no witness there.

An oracle file changes in the pull request that changes the behaviour it
Expand Down
2 changes: 1 addition & 1 deletion docs/mde/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ One directory per deadline, named after the course's own task numbering.

| Directory | Deliverable | Overleaf project | State |
|---|---|---|---|
| [`task-0-proposal/`](task-0-proposal/) | Task 0 — project description, the proposal that must be approved before work starts | `6aa2ba0c3920baa59ec20901` | re-mirrored 2026-09-14, after the joint-implementation revision |
| [`task-0-proposal/`](task-0-proposal/) | Task 0 — project description, the proposal that must be approved before work starts | `6aa2ba0c3920baa59ec20901` | re-mirrored 2026-09-14, after the simplification in #102 |
| `task-1-metamodelling/` | Task 1 — domain analysis, modelling decisions, the two metamodels and their diagrams, example models | — | not started |
| `task-2-transformations/` | Task 2 — the model-to-model transformation, its rules and limitations, evidence it runs | — | not started |
| `task-3-code-generation/` | Task 3 — the model-to-text transformation, the generated code, evidence it loads | — | not started |
Expand Down
9 changes: 5 additions & 4 deletions emf/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# emf: the coursework implementation
# emf: the model-driven implementation

Everything under this directory is the second implementation of the
deploy-kit compiler, built with the Eclipse Modeling Framework toolchain the
Everything under this directory is the model-driven implementation of the
deploy-kit compiler, the second implementation beside the TypeScript production
implementation, built with the Eclipse Modeling Framework toolchain the
model-driven engineering course at the University of Twente requires: Ecore,
Xtext, OCL, QVT-Operational and Acceleo. It is **deprecated from the day it
lands**: it exists for the length of the course and is deleted when its sunset
Expand All @@ -14,7 +15,7 @@ ledgers and its decisions all live here, so the sunset is deleting this
directory and the few root lines that name it, listed in
[the architecture](docs/architecture.md#scope-and-sunset).

The one thing this implementation shares with the TypeScript compiler is the
The one thing this implementation shares with the production implementation is the
[parity contract](../docs/architecture.md#the-parity-contract): the committed
oracle files under `spec/v1/examples/` that both are tested against, separately.

Expand Down
6 changes: 3 additions & 3 deletions emf/docs/adr/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Decision register: the coursework implementation
# Decision register: the model-driven implementation

The decisions that shape the EMF implementation under `emf/`. Every one is
deleted with this directory
([0107](emf/0107-emf-is-coursework-scoped-and-self-contained.md)), and none of
them can change what the model means: the model's decisions are in
[`docs/adr/`](../../../docs/adr/README.md), and the contract this
implementation shares with the TypeScript compiler is
implementation shares with the production implementation is
[0105](../../../docs/adr/architecture/0105-two-implementations-meet-at-committed-oracles.md).

The contract every ADR here satisfies is the root register's, unchanged:
Expand Down Expand Up @@ -35,7 +35,7 @@ taking a number, check both registers.
|---|---|---|
| [0107](emf/0107-emf-is-coursework-scoped-and-self-contained.md) | The EMF implementation is coursework-scoped, lives entirely under `emf/`, and is deleted when two conditions hold | open |
| [0108](emf/0108-maven-and-tycho-against-a-pinned-target-platform.md) | Maven builds `emf/`, with Tycho resolving p2-only bundles against a pinned target platform, on JDK 21, with no Eclipse IDE | open |
| [0109](emf/0109-ecore-metamodels-are-hand-written-per-document.md) | Each model document has a hand-written Ecore metamodel, and its Java is generated at build time | open |
| [0109](emf/0109-source-and-target-metamodels-are-hand-written.md) | The source and target metamodels are hand-written in Ecore, and their Java is generated at build time | open |
| [0110](emf/0110-constraints-are-complete-ocl-named-by-code.md) | Constraints are Complete OCL invariants named by the diagnostic code they emit | open |
| [0111](emf/0111-xtext-parses-the-authored-yaml-into-the-metamodel.md) | The Xtext grammar parses the authored YAML files themselves, into the imported metamodel | open |
| [0112](emf/0112-qvto-derives-the-resolved-deployment.md) | QVT-Operational derives the Resolved Deployment | open |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ rests-on: ["0106"]
> **Amended 2026-09-14.** No Eclipse IDE is needed to build, and CI never
> uses one. The projects must still be loadable in Eclipse Modeling Tools for
> the course's examiners, as the Task 0 proposal now promises: they import as
> existing Maven projects, the metamodels open and the example models validate
> against the OCL constraints, and committed launch configurations run the
> existing Maven projects, the metamodels open, the Xtext-generated editor
> reports OCL constraint violations while editing, and committed launch
> configurations run the
> QVT-Operational transformation and the Acceleo generator. Keeping that
> working is part of this decision; the Maven build stays the only path CI
> checks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ normative: docs/architecture.md#metamodels
rests-on: ["0106"]
---

# Each model document has a hand-written Ecore metamodel, and its Java is generated at build time
# The source and target metamodels are hand-written in Ecore, and their Java is generated at build time

> **Amended 2026-09-14.** Aligned with the revised project proposal
> ([#102](https://github.com/JorisJonkers-dev/deploy-kit/pull/102)). This decision originally gave each model document its own package: Project
> Intent, Platform Intent, Resolved Deployment and Deliverable Set. The
> proposal defines two metamodels, so there are two packages: a source
> metamodel holding Project Intent and the Platform document, and a target
> metamodel holding the Resolved Deployment with its typed Kubernetes and
> extension resources. The descriptor covers the source metamodel only.

> **Amended 2026-09-14.** Vocabulary renamed by
> [0116](../../../../docs/adr/model/0116-project-application-process.md): Domain is now Project,
Expand All @@ -17,9 +25,11 @@ rests-on: ["0106"]

## Rests on
Resting on [0106](0106-the-model-is-expressible-in-the-emf-toolchain.md), the
claim is that Project Intent, Platform Intent, the Resolved Deployment and the
Deliverable Set each fit one Ecore package whose structure, exported as the
parity descriptor, equals the structure the Zod schemas in `src/` declare.
claim is that the source metamodel (Project Intent, with the Platform document
it is resolved against) fits one Ecore package whose structure, exported as the
parity descriptor, equals the structure the Zod schemas in `src/` declare, and
that the target metamodel (the Resolved Deployment with its typed resources)
fits a second package the templates can walk.
False if: the descriptor exported from Ecore cannot equal the committed
descriptor without a type, multiplicity or vocabulary that the TypeScript side
does not have. Settled by: the descriptor parity suite green in both
Expand All @@ -32,9 +42,14 @@ the transformation maps between its packages, and the templates walk it. It is
written by hand because the course grades authored metamodels and because
generating it from Zod would make its structure unfalsifiable against Zod.

One package per document follows the model's own layering
([0003](../../../../docs/adr/model/0003-three-layer-meta-model.md)), with
Platform Intent separate because it is a separately authored document.
The proposal defines two metamodels, a source and a target, and the course
grades them as such. The model's three layers
([0003](../../../../docs/adr/model/0003-three-layer-meta-model.md)) still hold:
the Deliverable Set is the generated files, so it has no metamodel, and the
target metamodel carries layer 2 together with the typed resources the files
are written from, because an Acceleo template reads one model. The Platform
document is part of the source package because the transformation resolves a
Project against it.
Cross-document references are Ecore references, so the transformation navigates
them rather than joining strings.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ rests-on: ["0106"]

# Constraints are Complete OCL invariants named by the diagnostic code they emit

> **Amended 2026-09-14.** Aligned with the revised project proposal
> ([#102](https://github.com/JorisJonkers-dev/deploy-kit/pull/102)). The same Complete OCL constraints also run in the Xtext-generated editor,
> which marks each violation while a source file is edited. Diagnostics in the
> build keep the code and JSON Pointer contract; the editor shows the code as
> the message.

## Rests on
Resting on [0106](0106-the-model-is-expressible-in-the-emf-toolchain.md), the
claim is that every constraint in the constraint ledger is expressible as an
Expand Down
Loading
Loading