Skip to content

feat: widen the Project Intent metamodel to every worked example, with its descriptor and JSON Schema - #113

Merged
ExtraToast merged 1 commit into
mainfrom
feat/84-widen-project-intent
Sep 15, 2026
Merged

ExtraToast merged 1 commit into
mainfrom
feat/84-widen-project-intent

Conversation

@ExtraToast

Copy link
Copy Markdown
Contributor

Closes #84 (parent #78). Second of three pull requests rewriting #77; #85 adds the refusals and closes #38.

What this branch does

The Project Intent language is now whole in both implementations: every worked example parses, and both write the same canonical intent, the same descriptor, byte for byte.

  • The metamodel covers chapter 10's layer 1: engine, sidecars, dependsOn, assets, volumes, replicas, writablePaths, grants (on the Application and on the Process), the placement dimensions (arch, site, disk, gpu, capabilities), route-level audience and redirectTo, and the probe forms.
  • A union in the language is a union in both models. A probe is HTTP or TCP; a probe policy is a block or the word none; a grant is a KV, database or transit grant. Java models each as an abstract class with its concrete cases, TypeScript as a Zod union; the descriptor shows them as the same thing.
  • spec/v1/examples/expected/descriptor.json: every class with its features (types, required, many, map), every closed vocabulary with its literals. TypeScript builds it from the Zod schemas through z.toJSONSchema() and a normaliser; Java walks the EPackage reflectively. The two agreed on the first run.
  • spec/v1/schemas/project-intent.schema.json: generated from the input variant of the schema and committed, with a test that regenerates it and fails on a diff. RULE-043 moves from pending to enforced.
  • auth, data and knowledge gained expected/intent.json, written from the production parser, reviewed, and matched by the model-driven one.

Decisions worth naming

The three worked examples gained the document header. Chapter 10 states apiVersion and kind, and minimal and the refusal fixtures carry them, but auth, data and knowledge started at schemaVersion. They now match the chapter.

stateful is gone from the authored examples. #38 deletes it from the language; the object kind derives from lifecycle and volumes. The prose that still mentions it (chapter 10, chapter 20, the rendered-tree READMEs) is rewritten in #85, where #38 closes.

The block token source grew a fold. auth's replicas.reason is a folded scalar, so the token source now turns the lines under >, >-, | or |- into one scalar token, with the indentation stripped. A # indented inside the block is content; one at or left of the key is a comment.

A grant that names an engine names it first. The three grant shapes are told apart by engine, which an unordered group cannot look ahead for. The subset requires the key first, which every example already does.

The discriminator is its own vocabulary. SecretEngine becomes DatabaseEngine and TransitEngine, one literal each, so the Ecore enumeration and the Zod literal describe the same feature and the descriptor agrees. The kv arm carries no engine at all, as the chapter says.

Optional attributes are unsettable in Ecore. An enumeration's first literal is its default, so an optional contentPolicy: strict was indistinguishable from an absent one and vanished from the intent. Unsettable features carry "not written" as a state.

One equivalent mutant is disabled with its reason. z.toJSONSchema(..., { io: "input" }) produces the same document as the output variant until a field has a platform default, so no test can tell the option apart. The option stays; the mutant is named and skipped.

Verification

  • ./mvnw clean verify in emf/: 102 tests, line coverage 100.0%, mutation score 100.0% (232 of 232).
  • npm run verify: 447 tests, src/ at 100% statements, branches, functions and lines; Stryker 378 of 378 killed (2 ignored, as above). Ratchet raised to statements 98.6, branches 93.8, functions 100, lines 98.51, with README.md matching.
  • Both implementations produce minimal, auth, data and knowledge's expected/intent.json and the shared descriptor.json byte for byte; each suite keeps its negative case.

What this does not do yet

The refusal fixtures and their diagnostics oracles, the OCL invariants, and the removal of stateful from the prose (#85, which closes #38). References within a document are still names rather than model references (#39), and the Platform document is #41.

@ExtraToast ExtraToast added type: feature New user-facing or operator-facing capability. area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: build Gradle, npm, packaging, or local build tooling. component: tests Unit, integration, system, or contract test concern. labels Sep 15, 2026
@ExtraToast ExtraToast self-assigned this Sep 15, 2026
@ExtraToast
ExtraToast merged commit 663beb8 into main Sep 15, 2026
19 checks passed
@ExtraToast
ExtraToast deleted the feat/84-widen-project-intent branch September 15, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: deploy homelab-deploy, deploy-v2, manifests, and rollout flow. component: build Gradle, npm, packaging, or local build tooling. component: tests Unit, integration, system, or contract test concern. type: feature New user-facing or operator-facing capability.

Projects

None yet

1 participant