packages feed

keiro-dsl-0.3.0.0: CHANGELOG.md

# Changelog

All notable changes to `keiro-dsl` are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/), and the package follows the
[Haskell Package Versioning Policy](https://pvp.haskell.org/).

## [Unreleased]

_No unreleased changes._

## 0.3.0.0 — 2026-07-14

No user-facing changes. `keiro-dsl` is released at 0.3.0.0 to stay in lockstep
with the rest of the Keiro package set.

## 0.2.0.0 — 2026-07-13

### Breaking Changes

- The process `saga` clause is now `saga <Aggregate> category "<camelCase>"`,
  replacing `saga <Aggregate> stream="<prefix>-" <> correlationId`. Categories are
  validated (`SagaCategoryIllegal`) against the same rules as
  `Keiro.Stream.category`: non-empty, not `$all`, no `-` (Kiroku's category/id
  boundary), no whitespace or control characters, and no `:` (reserved for the
  `wf:<name>` workflow stream family). Generated process and router fills now
  build saga streams with `entityStream` and a typed category constant instead of
  splicing a string prefix.
- `process` nodes must now declare node-level `rejected => <policy>` and
  `poison => <policy>` clauses (`halt`, `deadLetter`, or `skip`), and every timer
  `fire` disposition must carry an `on-ambiguous` arm alongside `on-ok`,
  `on-reject`, `on-error`, and `not-mine`. Mapping `on-ambiguous => Fired` is
  rejected (`AmbiguousMarkedBenign`): `CommandAmbiguous` means several aggregate
  edges matched, and is never a benign success.
- Identifier lexemes are restricted to ASCII, and the validator now enforces
  per-category Haskell hygiene: constructor-position names must be
  constructor-safe (`IdentNotConstructorSafe`), no identifier may be a Haskell
  keyword (`IdentHaskellKeyword`), and generated vertex constructors may not
  collide (`VertexCtorCollision`). Specs that previously scaffolded to
  uncompilable Haskell are now rejected at `check`.
- All numeric literal sites parse through `Integer` and fail with a positioned
  diagnostic when the value exceeds `maxBound :: Int`, instead of silently
  wrapping. `maxBound` itself still parses exactly.
- Duplicate singleton blocks and duplicate `goto` clauses are reported at their
  second occurrence rather than being silently accepted with a last-one-wins
  reading; a missing `goto` is now anchored to its transition.
- `Text` registers require a quoted initial, and a register whose type is an enum
  or the aggregate's vertex type must start at a declared constructor or state.
  The scaffolder refuses the run rather than emitting a broken initial.
- Validation is substantially stricter, so specs that checked under 0.1.0.0 may
  now be rejected: duplicate node, command, event, enum-constructor, enum-wire and
  id-prefix names; dangling aggregate, projection, timer, workflow, signal and
  operation references; non-total or unresolved `rule` domains; duplicate workflow
  replay labels; incomplete or shadowed disposition tables; duplicate and dangling
  status-map keys; emit/intake topic-affinity mismatch; workqueue
  `queueRef`/table/DLQ divergence; unresolved dispatch dedup queues and fields;
  invalid process timer ceilings; and write targets that are not registers.
- `keiro-dsl scaffold` now plans the entire module set before writing any byte,
  and refuses the run on module-path collisions, self-firewall breaches, or
  unlowerable spec content. It also refuses to overwrite a file on a `Generated`
  path that lacks the `@generated` banner; pass the new
  `--force-generated-overwrite` flag to override.
- `keiro-dsl diff` gained a `WARNING:` tier, and its change lines now read
  `<node> <facet> <subject>: <detail>` rather than always saying `event`. Only
  `BREAKING:` changes exit non-zero.

### New Features

- Added a first-class `readmodel` node declaring `table`, `schema`, a typed
  `columns` block, `version`, captured `shape`, `consistency`, `scope`, `feed`
  (`inline` or `subscription`), and `subscription`. The validator owns a closed
  column-type vocabulary (`text`, `int`, `bigint`, `bool`, `timestamptz`, `jsonb`,
  `numeric`), detects shape-hash drift against the declared columns, rejects
  `Strong` + `inline` (no subscription worker advances the cursor a strong read
  waits on), rejects `scope` without `Strong`, and rejects an `inline` model that
  no aggregate projection feeds. `scaffold` emits `ReadModel` and `ReadModelTable`
  generated modules plus `ReadModelHoles`. Aggregate `projection` consistency is
  now optional and must agree with the read-model node when one exists; a
  projection with no `readmodel` node warns that registration, schema identity,
  and rebuild helpers are unavailable.
- Query operations and PGMQ dispatch source/dedup read-model references now
  actually resolve against declared nodes — these were explicitly deferred no-ops
  in 0.1.0.0. Query `consistency` must be `Strong`, `Eventual`, or `PositionWait`,
  and a dispatch dedup field must be a column of the named model.
- Added the `router` node for stateless content-based routing: `input`, `key`,
  `resolve stable via read-model <name> row { ... }` (or `via hole`), `target`,
  `projections`, `dispatch-each`, a runtime-owned `dispatch-id` strategy keyed on
  target stream name and occurrence, and node-level `rejected`/`poison` policies.
  Validation resolves the target aggregate, its command and command fields, the
  key field, and the read-model reference, and confines dispatch bindings to the
  `input.` and `resolved.` scopes plus quoted literals. `scaffold` emits
  `Router`/`RouterHarness` generated modules with `RouterHoles`/`RouterValue`
  stubs, and `keiro-dsl new router` prints a starter.
- Added node-level `rejected` and `poison` worker policies on `process` and
  `router` nodes, reconciled against the per-dispatch `on-failed` arms: a dispatch
  declaring `DeadLetter` under a node that does not is a `PolicyContradiction`,
  divergent `on-failed` actions within one node are rejected because the runtime
  applies a single `RejectedCommandPolicy` to the whole failure group, and an
  unacknowledged `rejected => deadLetter` warns.
- Added aggregate `snapshot every <n>` / `snapshot on-terminal` with a captured
  `state-codec version=<n> shape-hash="..."` fixture, lowered into the generated
  aggregate modules and pinned against the live runtime. Intervals below 1, and
  empty or zero-version codec fixtures, are rejected.
- Added workqueue `ordering` (`unordered`, `fifo-throughput`, `fifo-round-robin`),
  `group key from <field> via <fn>`, and provisioning (standard, `unlogged`,
  partitioned). The validator rejects FIFO without a group key, a group key
  without FIFO, and an empty partition spec, and flags unlogged durability; the
  generated `QueuePolicy` is pinned to the live pgmq configuration types.
- Added intake `persist = full-envelope | dedupe-only`, lowered to the live
  `InboxPersistence` value and wired through `runInboxTransactionWith`.
- Added a durable-workflow evolution surface: guarded `patch <id> { ... }` blocks
  and a terminal `continueAsNew <SeedType>`, lowered into the workflow run
  options. Duplicate and malformed patch ids, and a non-terminal `continueAsNew`,
  are rejected.
- Added a `partial` token on `status-map`, so an intentionally incomplete
  event-to-status mapping is expressible instead of failing the totality rule.
- Publisher backoff accepts optional `max=` and `multiplier=`, and exponential
  backoff now lowers to `ExponentialBackoff ExponentialBackoffOptions{..}` with
  faithful duration units.
- Rebuilt `diff` on an exhaustive node-family registry: every `Node` constructor
  either has a differ or carries a recorded out-of-scope rationale, so a new node
  kind can no longer be silently treated as safe. Classification now covers
  aggregate decode evolution through command indirection (field type, removal,
  wire spelling, enum add/drop, schema-version regression, old-anchored upcaster
  continuity, undeprecation), contract topic/schema-version/discriminator/field/
  event changes, workqueue payload, identity, ordering and provisioning changes,
  process input and timer-window changes, intake decode posture, dedupe identity
  and persistence, emit mapping and ordering, publisher policy, workflow shape,
  body, patch and continue-as-new seed changes, read-model
  version/shape/feed/consistency evolution, projection and id-prefix re-keying,
  router stable-name changes, and dispatch retargeting.
- `scaffold` now writes a versioned per-context record
  (`keiro-dsl-scaffold-record.<context>.txt`) and reports still-present modules
  made stale by node, layout, or `--module-root` changes. It never deletes
  generated or hand-owned files.
- Diagnostics carry row-level source locations, so validator-owned rows
  (dispositions, status maps, timers, dispatches) are anchored precisely instead
  of at the enclosing node.

### Bug Fixes

- String literals now decode and re-render the closed DSL escape set, so topics,
  emit maps, and quoted field bindings survive a parse/pretty-print round trip
  instead of being corrupted.
- The scaffolder escapes payload literal splices, closing a template-injection
  path where a quoted spec literal could break out of the generated Haskell
  string. Its status-map and harness lowering is now total.
- Generated `Stream` and stream-category imports are emitted in the
  repository-standard post-qualified (`ImportQualifiedPost`) form.
- The self-firewall is derived from Keiki's exported surface as a single
  token-aware scan, rather than a hand-maintained substring list that both missed
  operators and produced false positives.

### Other Changes

- Added conformance suites that round-trip every node family, compile every
  `keiro-dsl new <kind>` starter, cold-start the new read-model, router, snapshot,
  queue-ordering, and workflow-rotation surfaces, and exercise the generated
  read-model and router modules against the live runtime.
- Test fixtures and conformance corpora resolve from either the package root or
  the repository root.

## 0.1.0.0 — 2026-07-05

Initial Hackage release.

### Breaking Changes

- Renamed the typed-spec file extension from `.kdsl` to `.keiro` before the first
  public release.

### New Features

- Added grammar, parser, pretty-printer, validator, diff engine, scaffold
  generator, harness emitter, and CLI for typed `.keiro` service specs.
- Added aggregate, process manager, durable timer, integration contract, inbox,
  publisher, PGMQ workqueue, workflow, and operation nodes.
- Added configurable module placement, build-wiring manifests, self-firewall
  checks, post-scaffold reports, per-iteration ergonomics, and `new <kind>`
  starter skeletons.
- Generated validated event streams compatible with Keiro's command boundaries.

### Bug Fixes

- Tolerated formatter comma style in scaffold conformance tests.