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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 6 additions & 8 deletions .agents/skills/adr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ pointing at it.
`docs/adr/architecture/` for a decision about the compiler's own structure
(its `normative:` pointer names a `docs/architecture.md` or
`docs/architecture-rules.md` heading); `docs/adr/deferred/` only for
delivery or co-testing direction work, never for a v1 decision. While
`emf/` exists, a Java-side decision goes to `emf/docs/adr/` instead, using
the same numbering sequence.
2. **Take the next number.** Check `docs/adr/README.md`'s register **and**
`emf/docs/adr/README.md`'s, even when writing to the root register: the
sequence is estate-wide and a number already used in either register is
the fastest way to fail the register-integrity check.
delivery or co-testing direction work, never for a v1 decision.
2. **Take the next number.** Check `docs/adr/README.md`'s register: the
sequence is estate-wide, a number already used in it is never taken again,
and the next number is the highest the register holds plus one (which is
the fastest way to fail the register-integrity check).
3. **Write the frontmatter.** `tier: premise` (a falsifiable claim, no
`rests-on`) or `tier: decision` (names only premises in `rests-on`, never
another decision: a decision-to-decision dependency is prose, in `## Why`,
Expand All @@ -38,7 +36,7 @@ pointing at it.
here: that belongs in the chapter the `normative:` pointer names, and this
record links to it instead.
5. **Add the register row**, in the numeric position its section of
`docs/adr/README.md` (or `emf/docs/adr/README.md`) already sorts by, with
`docs/adr/README.md` already sorts by, with
the title and claim matching the file exactly.
6. **Cite it correctly everywhere else you touch.** Never a bare `ADR-NNNN`
or bare number: always a Markdown link. A decision that changes is
Expand Down
9 changes: 4 additions & 5 deletions .agents/skills/spec-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ next.
`expected/dependencies.json`, `expected/resolved.json`,
`<input>.diagnostics.json`, `rendered/`, `expected/descriptor.json`.
Written and reviewed by hand, never regenerated by CI
([`docs/architecture.md#the-parity-contract`](../../../docs/architecture.md#the-parity-contract)).
([`docs/architecture.md#the-oracles`](../../../docs/architecture.md#the-oracles)).
A tool may propose a candidate; the committed file is the reviewed copy of
it, canonical JSON (RFC 8785), byte for byte.
- **The diagrams**, under `spec/v1/diagrams/`: one drawn SVG per chapter, the
editable draw.io source embedded, one palette, colour carrying the layer.
- **The TypeScript declarations.** A model change lands in the TypeScript
production implementation first; `emf/` catches up in a pull request of its
own ([`AGENTS.md`](../../../AGENTS.md#boundaries)). Nothing regenerates an
implementation and its oracle files together
([`AGENTS.md`](../../../AGENTS.md#boundaries)). Nothing regenerates an
oracle.

## Steps
Expand All @@ -50,8 +50,7 @@ next.
needs, or updating the pointer in the same commit if a heading moves.
3. Update or add the worked example(s) the change bears on, and hand-write
the oracle files it touches.
4. Update the TypeScript declarations against the same oracle files; leave
`emf/` as it is.
4. Update the TypeScript declarations against the same oracle files.
5. Run `npm run lint:adrs` and `npm run lint:links`.

## Claiming a ticket
Expand Down
3 changes: 0 additions & 3 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,3 @@
# change that lands without its ADR is the drift this repository exists to stop.
/docs/adr/ @JorisJonkers-dev/maintainers
/spec/ @JorisJonkers-dev/maintainers

# The model-driven implementation, deleted at its sunset.
/emf/ @JorisJonkers-dev/maintainers
4 changes: 2 additions & 2 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Paths CodeQL does not analyse. Build output and generated sources are not
# code anyone wrote here; the model-driven build (emf/) generates Java from its
# genmodel and Xtext grammar into target/ and src-gen/.
# code anyone wrote here; generated code lands in target/, src-gen/ and
# xtend-gen/.
'name': 'deploy-kit CodeQL'

'paths-ignore':
Expand Down
78 changes: 0 additions & 78 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@
- 'name': 'ADR contract'
'run': 'npm run lint:adrs'

# The coursework implementation's register, linted as its own root.
# Deleted with emf/ (emf/docs/adr/emf/0107).
- 'name': 'ADR contract (emf)'
'run': 'node scripts/lint-adrs.ts emf'

# Relative links and heading anchors across every Markdown file git does not ignore.
# The ADR domain move rewrote about a hundred references outside the
# decision set, and nothing checked them.
Expand Down Expand Up @@ -496,79 +491,6 @@
'security-events': 'write'
'uses': './.github/workflows/codeql.yml'

# The model-driven implementation under emf/ (docs/adr/emf/0107): its own
# Maven build, JDK and gates, deleted with the directory at its sunset. Every gate
# it runs is listed in emf/docs/rules.md; the thresholds are in emf/pom.xml.
# test/emf-wiring.test.ts proves this step names a real build.
#
# The model-driven build under emf/ (Maven and Tycho) runs its tests and its
# 100% JaCoCo gate on every change to its sources or to this workflow. Any
# other change skips its steps: a model change lands in TypeScript first and
# moves the oracles, and the model-driven build catches up in its own change. Its 100% PIT gate takes too long for every change, so it runs
# periodically: on the nightly run and on a dispatch. It is not one of
# Pipeline Complete's needs.
'emf':
'name': 'Model-driven build'
'if': "!startsWith(github.head_ref, 'release-please--')"
'runs-on': 'ubuntu-latest'
'timeout-minutes': 60
'permissions':
'contents': 'read'
'steps':
# A pull request checks out its merge commit and a push to main the
# squashed commit; either way the first parent is main before it.
- 'uses': 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7.0.1
'with':
'fetch-depth': '2'
- 'name': 'Decide whether the change reaches the model-driven build'
'id': 'scope'
'shell': 'bash'
'env':
'EVENT': '${{ github.event_name }}'
'run': |
set -euo pipefail
mutation='false'
if [ "${EVENT}" = 'workflow_dispatch' ] || [ "${EVENT}" = 'schedule' ]; then
needed='true'
mutation='true'
elif git diff --name-only HEAD^1 HEAD | grep -qE '^(emf/|\.github/workflows/ci\.yml$)'; then
needed='true'
else
needed='false'
fi
echo "needed=${needed}" >> "$GITHUB_OUTPUT"
echo "mutation=${mutation}" >> "$GITHUB_OUTPUT"
- 'name': 'Nothing the build reads changed'
'if': "steps.scope.outputs.needed != 'true'"
'run': 'echo "No model-driven build: this change reaches neither emf/ nor this workflow."'
- 'uses': 'actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6' # v6.0.1
'if': "steps.scope.outputs.needed == 'true'"
'with':
'distribution': 'temurin'
'java-version-file': 'emf/.java-version'
'cache': 'maven'
# Tycho caches p2 bundles in the Maven repository too, so the target
# platform is part of the key.
'cache-dependency-path': |
emf/**/pom.xml
emf/emf.target
- 'name': 'Verify'
'if': "steps.scope.outputs.needed == 'true'"
'working-directory': 'emf'
'shell': 'bash'
'env':
'MUTATION': '${{ steps.scope.outputs.mutation }}'
'run': |
set -euo pipefail
if [ "${MUTATION}" = 'true' ]; then
./mvnw -B -ntp verify
else
./mvnw -B -ntp verify -DskipPitest=true
fi
- 'name': 'Summary'
'if': "always() && steps.scope.outputs.needed == 'true'"
'run': 'emf/scripts/summary.sh >> "$GITHUB_STEP_SUMMARY"'

# Two jobs land here together, for issue #33. Neither gates: neither joins
# `pipeline-complete`'s `needs` below, per
# docs/adr/architecture/0064-a-gate-is-a-script-or-a-named-job.md's own rule
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# CodeQL static analysis: JavaScript, TypeScript, the workflow logic, and the
# model-driven implementation's Java under emf/.
# CodeQL static analysis: JavaScript, TypeScript, and the workflow logic.
#
# Every language is analysed without a build (`build-mode: none`), so Tycho and
# p2 resolution can never break the scan. Generated sources and build output
# Every language is analysed without a build (`build-mode: none`), so builds
# can never break the scan. Generated sources and build output
# are ignored through .github/codeql/codeql-config.yml.
#
# A gate, not a report. ci.yml calls this workflow on every pull request and on
Expand Down Expand Up @@ -37,7 +36,6 @@
'include':
- 'language': 'javascript-typescript'
- 'language': 'actions'
- 'language': 'java-kotlin'

'steps':
- 'uses': 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7.0.1
Expand Down
8 changes: 4 additions & 4 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ spec/
.github/actions/
.github/codeql/

# The model-driven implementation's stage goldens are canonical JSON its own
# writer produces, compared byte for byte, so prettier must not reflow them.
emf/bundles/cli/src/test/resources/stages/

# Scratch. `.tmp/` is a working directory, not a deliverable, and its contents
# are whatever a tool last dropped there.
.tmp/

# Local working artifacts, not deliverables.
.playwright-mcp/
.scratch/
66 changes: 15 additions & 51 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ this file stays a pointer. Everything below is repository-specific.
## What this repository is

`deploy-kit` holds the deployment model (`spec/v1`), its decision record
(`docs/adr/`), and the compiler that renders it: a TypeScript production
implementation under `src/` and, for the length of a
university course, a model-driven implementation under `emf/`. Start at
(`docs/adr/`), and the compiler that renders it: a TypeScript implementation
under `src/`. Start at
[`README.md`](README.md) for the shape of the model, or
[`docs/adr/README.md`](docs/adr/README.md) for why each rule is what it is.

Expand All @@ -46,10 +45,6 @@ every rule a tool enforces on it.
- Vitest for the suite, ESLint (`strictTypeChecked`, with type information)
and Prettier for style, dependency-cruiser for the module graph, Stryker for
mutation testing.
- `emf/` is a second, separate stack: Maven and Tycho on JDK 21, building Ecore, Xtext, OCL, QVT-Operational and
Acceleo. It has its own `AGENTS.md` equivalent in
[`emf/docs/architecture.md`](emf/docs/architecture.md); this file only
routes an agent into it, per [the parity contract](#the-model-driven-implementation-under-emf).

## Setup

Expand Down Expand Up @@ -107,7 +102,7 @@ Coverage is a ratchet
([0063](docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md)): the thresholds
in `vitest.config.ts` sit on what the suite reaches, over an explicit include
list, and only ever rise. Mutation testing holds the same shape with a break
score in `stryker.config.json`. Neither covers `emf/`, which measures itself.
score in `stryker.config.json`.

## Code style

Expand Down Expand Up @@ -138,11 +133,10 @@ tool runs it.
enforcement. Changing what `spec/v1` says the model means. Anything that
touches release, publishing or rulesets.
- **Always:** land a model change in TypeScript and in the oracle files it
affects, in one pull request. `emf/` follows in a pull request of its own,
held to the same oracle files by its own build. Check both ADR registers
before taking a number.
- **Never:** generate one implementation from the other, regenerate an oracle
file in CI, or add a root dependency on anything under `emf/`. Push to
affects, in one pull request. Check the ADR register before taking a
number.
- **Never:** regenerate an oracle
file in CI. Push to
`main` or force-push a shared branch. Edit a version or `CHANGELOG.md` by
hand. Supersede an ADR or annotate it with an amendment note: a decision
that changes is rewritten, in its one record, in the pull request that
Expand Down Expand Up @@ -193,7 +187,7 @@ above instead of restating them.

| skill | what it does |
|---|---|
| [`adr`](.agents/skills/adr/SKILL.md) | Writes a decision record to this repository's own ADR contract: the right domain directory, the next estate-wide number (checking both registers while `emf/` exists), the frontmatter, premises only in `rests-on`, an Alternatives table, the register row, and an anchor that resolves. |
| [`adr`](.agents/skills/adr/SKILL.md) | Writes a decision record to this repository's own ADR contract: the right domain directory, the next estate-wide number, the frontmatter, premises only in `rests-on`, an Alternatives table, the register row, and an anchor that resolves. |
| [`spec-change`](.agents/skills/spec-change/SKILL.md) | Edits a spec chapter as one change: its anchors, the ADRs that point at it, `CONTEXT.md`'s vocabulary, the worked examples, the rendered trees, the oracle files, the diagrams, and both implementations' declarations. |
| [`gate-triage`](.agents/skills/gate-triage/SKILL.md) | Goes from a failing CI job or a quoted rule id to its ledger row and the ADR that decided it, so a red gate resolves to the document that explains it rather than a guess. |
| [`new-rule`](.agents/skills/new-rule/SKILL.md) | Adds a rule ledger row, its enforcement and a failing fixture that proves it, in one change, per [0066](docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md). |
Expand Down Expand Up @@ -252,48 +246,18 @@ both. See [`docs/agents/domain.md`](docs/agents/domain.md).
structure, normative for code.
- [`docs/architecture-rules.md`](docs/architecture-rules.md) and
[`docs/requirements.md`](docs/requirements.md): the rule ledger and the
behaviour ledger, two different questions kept in two different documents.

## 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 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). A model change lands in
TypeScript first, and `emf/` catches up in a pull request of its own, held to
the same oracle files:

- **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, which runs the build with its tests and coverage gate
on every change to `emf/`, its mutation gate nightly, and is needed by no
gate; the `emf` ADR lint step; and CodeQL's `java-kotlin` entry), `test/emf-wiring.test.ts`
with its ledger rows, the `emf` domain in `scripts/lint-adrs.ts` and its test, the release-please and Renovate
configuration, and
[`docs/architecture.md#the-parity-contract`](docs/architecture.md#the-parity-contract).
- **Never generate one implementation from the other.** Both are tested,
separately, against committed oracle files under `spec/v1/examples/`.
- **A model change lands in TypeScript first.** `emf/` may trail `main` between
catch-ups, and its `OracleDistanceTest` shows how far; the links, meaning
and codes lints skip it.
- EMF decisions live in [`emf/docs/adr/`](emf/docs/adr/README.md), numbered
from the root's sequence. Check both registers before taking a number, and
lint with `node scripts/lint-adrs.ts emf`.
behaviour ledger, two different questions kept in two different documents.## MDE coursework material

`docs/mde/` holds a university course's reports, frozen as delivered: one
directory per task, plus [`docs/mde/README.md`](docs/mde/README.md), which
says which directory mirrors which task. The course's own assignment text
(`assignment.md`, `practicals.md`) and the course-material submodule are
retired later, on #354, once the grade is recorded.

`deploy-config-schema` is the repository this one replaced. `deploy-kit`
renders and delivers the whole estate, so it is archived: read it for
history, never as a source of truth.

## MDE coursework material

`docs/mde/` holds a university course's reports: one directory per task, plus
[`docs/mde/assignment.md`](docs/mde/assignment.md), the course's own task text,
which says what each task requires and hands in, and
[`docs/mde/practicals.md`](docs/mde/practicals.md), what each practical session
asks. [`docs/mde/README.md`](docs/mde/README.md) says which directory mirrors
which task.

The course's own hand-outs (the lecture decks, the background reading and the
index over them) are **not in this repository**. They are third-party works, so
they live in the private repository `JorisJonkers-dev/mde-course-material`,
Expand Down
11 changes: 2 additions & 9 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@ and *layer 3* for its members.
**Metamodel**: the definition of the language a model is written in, and
nothing else. A metamodel is a model whose instances are models, so the word is
never used for a layer, a document, an abstraction level or the pipeline as a
whole. The production implementation declares its languages as Zod schemas in
`src/model/`;
the model-driven implementation under `emf/` has two hand-written Ecore
metamodels, a source and a target, and generates the Deliverable Set as files
with no metamodel of its own. One word, `metamodel`, unhyphenated.
whole. The implementation declares its languages as Zod schemas in
`src/model/`. One word, `metamodel`, unhyphenated.

**Project Intent**: layer 1. What a project's repository authors by hand:
requirements, never mechanisms. Two kinds of file, a project file and one env file
Expand Down Expand Up @@ -789,10 +786,6 @@ for a DNS name, an ADR decision domain, and the core ring of the compiler's
hexagon.

**Bootstrap.** The bootstrap set and the bootstrap order, and nothing else.
The first build of the model-driven implementation under `emf/` is the **EMF
scaffold** (its Maven build, gates and CI job, with no EMF dependency), and its
first change that depends on the modelling tools is the **walking skeleton**,
which proves each tool runs headless.

**Config.** Avoid. Env files carry *configuration*; the platform's facts and
policies are *Platform Intent*; an Application's authored document is *Project Intent*.
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ document or one gate. A change is bigger than that shape when it:
- adds a gate (its npm script and its CI job, in the same pull request;
[0064](docs/adr/architecture/0064-a-gate-is-a-script-or-a-named-job.md)), or
- changes what `spec/v1` says the model means, in which case it lands with
the ADR that decides it, in TypeScript first (`emf/` catches up in a pull
request of its own), and with every oracle file the change touches.
the ADR that decides it and with every oracle file the change touches.

`AGENTS.md`'s Boundaries section states which of these an agent may do on its
own and which need to be asked about first.
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ lands, the **compiler** that turns that model into deployable artifacts.
| [`spec/v1/diagrams/`](spec/v1/diagrams/README.md) | One drawn diagram per chapter, as an SVG with the editable draw.io diagram embedded. One palette; colour carries the layer. |
| [`spec/v1/examples/minimal/`](spec/v1/examples/minimal/README.md) | The smallest complete Application: one project, one Application, one Process, 31 authored lines reaching 12 objects. |
| [`spec/v1/examples/`](spec/v1/examples) | Worked examples: real Applications from this estate, written in the model. |
| [`emf/`](emf/README.md) | The model-driven implementation: a Java build on Ecore, Xtext, OCL, QVT-Operational and Acceleo, held to parity with the production implementation and deleted after the course. |
| [`scripts/`](scripts/) | The gates: the ADR contract, links, manifests and layer boundaries. TypeScript that Node runs directly ([tooling](docs/architecture.md#tooling)). |

## The shape of the model
Expand Down
Loading
Loading