keiro-dsl-0.6.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]
## 0.6.0.0 — 2026-07-31
### Breaking Changes
- `DiagnosticCode` gains `AggregateTypeUnknown`,
`AggregateTypeUnsupportedAtUse`, `AggregateRegisterInitialInvalid`,
`AggregateGuardTypeMismatch`, `AggregateGuardCapabilityUnsupported`,
`WorkspaceLanguageVersionMismatch`, and `SourceLanguageDeclarationChanged`.
The additions are append-only, but exhaustive matches must be extended.
- `DiagnosticCode` also gains the nominal-check codes
`NominalMissingIngredient`, `NominalInvalidHaskellSource`,
`NominalInvalidQualifiedName`, `NominalInvalidIdentity`,
`NominalInvalidIdPrefix`, `NominalUnsupportedRepresentation`,
`NominalEmptyEnumRepresentation`, `NominalMissingInitialValue`, and
`NominalNameCollision`, plus the nominal diff codes
`NominalBindingChanged`, `NominalFixturesChanged`,
`NominalCanonicalTypeChanged`, `NominalInitialChanged`,
`NominalRepresentationChanged`, and `NominalIdDecoderTightened`.
- `DiagnosticCode` gains `AggregateExpressionRootUnknown`,
`AggregateExpressionRootAmbiguous`, `AggregateExpressionPathInvalid`,
`AggregateExpressionPathUnsupported`, `AggregateExpressionLiteralNeedsType`,
`AggregateExpressionLiteralInvalid`,
`AggregateExpressionOperandTypeMismatch`,
`AggregateExpressionOperatorUnsupported`,
`AggregateExpressionBooleanRequired`,
`AggregateExpressionGuardBoolRequired`,
`AggregateExpressionWriteTargetUnknown`,
`AggregateExpressionWriteTypeMismatch`,
`AggregateTransitionOwnershipConflict`, and
`CollectionExpressionUnsupported`. The additions are append-only, but
exhaustive matches must be extended.
- The public expression AST gains located arithmetic, scalar literals, explicit
roots/paths, and transition implementation ownership. Exhaustive matches over
`Expr`, `TypeExpr`, or transition implementation must be extended.
- Aggregate command/event fields now use the located `AggregateField` type and
aggregate register types use `TypeExpr` instead of a raw `Name`. The library
requires the exact-Integer/total-Natural `keiki >=0.6 && <0.7` and
`keiki-codec-json >=0.6 && <0.7` releases.
### New Features
- Adds language version 2 syntax for binding direct aggregate IDs, enums, and
nominal scalar wrappers to consumer-owned Haskell types. Version 1 and
legacy-unversioned sources reject these declarations at source-language
dispatch. The `pretty` command is an explicit alias for canonical parsing and
rendering.
- Adds the public total `Keiro.Codec.Nominal` binding/fixture API, a checked
nominal registry, generated prefix-safe `KindID` codecs, closed private enum
representations, built-in scalar codecs, create-once binding skeletons, and
context-level nominal scalar projections. Consumer-owned registers retain
the existing consumer-JSON snapshot cache boundary.
- Nominal consumer provenance is fingerprinted and diff-visible, persisted in
additive `nominal-mapping` scaffold/workspace rows, and included in generated
package requirements. Bound-ID adoption at an existing event use reports a
named decoder-tightening historical-read advisory and targeted replay audit.
- Adds a compiled nominal conformance ring with binding laws, pinned wire bytes,
malformed/wrong-prefix ID and unknown-enum rejection, snapshot and canonical
identity checks, projection agreement, forward/replay parity, mutation gates,
and a compile-fail partial-inverse fixture.
- Adds authoritative version-2 scalar aggregate expressions. Guards and writes
accept typed `reg.`/`cmd.` roots, required structural scalar paths, all scalar
literal families, exact `Integer` `+`/`-`/`*`, and total `Natural`
`+`/monus/`*`. Machine-`Int` arithmetic, coercion, division/remainder, Time
arithmetic, predicate-valued Bool writes, and collection expressions fail
before scaffolding.
- Adds generated per-aggregate `Expressions` and `Transducer` modules. Every
version-2 transition is exclusively generated-owned or explicitly
`implementation hole`; Hole transitions retain a generated structural
envelope, require a per-transition `FoldVersion`, and expose conservative
ownership/predicate-verification reports where opaque terms remain
unverified. Version-1 generated output remains frozen.
- Adds a compiled scalar-expression conformance service with a 360-case oracle,
concrete/symbolic/replay/snapshot agreement, all scalar literal families,
Natural `2 - 5 = 0`, required structural projection identity, and eight
mutation sentinels for arithmetic, authority, envelope, fold-version, and
verification drift.
- Adds an explicit source-language contract. A first-significant-clause
`language keiro-dsl 1` preamble selects the frozen released v1 parser before
body parsing; unsupported future versions fail at that boundary. Unversioned
input remains readable as `legacy-unversioned` with effective version 1 and
is never silently rewritten by parse/pretty.
- Adds `Keiro.Dsl.LanguageVersion`, provenance-preserving parsing/rendering,
`keiro-dsl inspect FILE --format=json`, and canonical per-member workspace
inspection. Workspace composition compares effective versions before graph
merge while keeping the merged `Spec` semantic.
- Single-file and workspace scaffold records now carry additive source-language
rows, report provenance drift, and interpret missing rows from older records
as legacy. Source-aware diff reports declaration-only changes with an
all-compatible vector and no-semantic-action remedy; generated bytes, fold
fingerprints, and replay impact remain unchanged.
- Every `new <kind>` skeleton and ordinary checked-in `.keiro` fixture now
declares version 1. Dedicated legacy, future, malformed, zero, duplicate, and
misplaced fixtures preserve compatibility and rejection coverage. Automated
upgrades remain deferred to IR-5.
- Adds `Keiro.Dsl.AggregateType`, the single resolution and capability policy
used by aggregate validation, Haskell lowering, imports, packages, JSON and
snapshot samples, fold fingerprints, diffs, replay impact, and scaffold
refusals.
- Direct aggregate `Time` and `Natural` fields and registers now check,
scaffold, compile, encode, snapshot, and replay. `Time`/`UTCTime` normalize
to `Time` and lower to exact `UTCTime` constructors; Natural accepts only
non-negative integral initials. Equality and ordering are checked against
Keiki's released symbolic capabilities. Version 1 retains the original
no-arithmetic grammar; version 2 adds only the exact/total arithmetic listed
above.
- Direct aggregate `Json` and container shapes now parse far enough to receive
a located remediation toward `mapped structural`, and malformed scalar
initials, mismatched comparisons, and unsupported ordering fail during
`check`. Generated imports and Cabal dependencies remain type-directed and
minimal.
## 0.5.0.0 — 2026-07-31
### Breaking Changes
- `DiagnosticCode` gains nine constructors:
`WorkspaceMemberUnreadable`, `WorkspaceMemberParseFailed`,
`WorkspaceContextMismatch`, `WorkspaceAuthorityConflict`,
`WorkspaceDuplicateDeclaration`, `WorkspaceDuplicateNodeName`,
`WorkspacePathCollision`, `OwnershipMoved`, and `WorkspaceAuthorityChanged`.
Additions are append-only, but exhaustive matches over the type must be
extended.
- `Keiro.Dsl.ScaffoldRun.Refusal` gains `GoldenRootDivergence`, raised only by
the workspace path when a golden payload fixture sits beside a member that
the one workspace golden root lacks.
- `Keiro.Dsl.ScaffoldRun.WriteDisposition` gains `Unchanged`, produced only by
the workspace write path when a Generated module's bytes already match.
- `Keiro.Dsl.DiffReport.Remedy` gains `RemedyRescaffoldWorkspace`.
No behaviour of the single-file path changed: it keeps its context-keyed
record and manifest names, its report bytes, and its `Overwritten`
disposition, and no existing generated bytes moved.
### New Features
- Adds **service workspaces**: a `.keiro-workspace` manifest names a service and
lists its member `.keiro` files, and `keiro-dsl check <manifest>` validates
them as one service contract. Shared ids, enums, rules, and mapped structural
types resolve once across all members, so an aggregate in one file may use a
declaration or feed a read model owned by another. A single `.keiro` file is
unchanged and behaves as a one-member workspace.
Membership is a set: member paths are normalized and canonically sorted, so
listing order changes neither the parsed manifest nor any output. Composition
refuses, before producing a graph, when members declare different contexts,
when a member's `module`/`layout` clause contradicts the manifest authority,
when a shared declaration or node is owned by two members (identical
duplicates never silently merge), or when two members claim generated module
paths that collide under case folding. One diagnostic can cite several files:
the primary location keeps the established
`<file>:<line>: error[<Code>]: <message>` shape and each further location
follows as an indented `note:` line.
`check --emit`, `--explain-bindings`, `--coverage-report`, and
`--fail-on-opaque` all work against the merged whole-service graph, and
`keiro-dsl parse <manifest>` round-trips the manifest canonically.
Dispatch is by file extension, so every single-file branch is unchanged.
New `Keiro.Dsl.Workspace` module; `Keiro.Dsl.Validate.nodeIdentity` is now
exported. Recorded as ADR-14.
- **Whole-workspace scaffolding.** `keiro-dsl scaffold <manifest> --out DIR`
emits the complete generated module set for every member in one invocation,
with unchanged flags. The set is emitted once from the merged spec, so the
structural projection facade and the replay-audit assembly are produced
exactly once from the complete graph, and every existing refusal gate runs
over the whole set. Both preflights — golden fixtures stranded beside a
member, and Generated paths lacking the `@generated` banner — are evaluated
across the whole workspace before the output directory is created, so a
failure in any member leaves the tree, the record, and the build manifest
byte-for-byte untouched.
History is workspace-keyed (`workspace.<service>`, a name a context can never
collide with), and each record row carries its producing member, so an
aggregate moved between member files is reported as an ownership move with
zero stale churn and zero content change. A Generated module whose bytes
already match is reported `(unchanged)` rather than rewritten, making
idempotence observable. Ownership is attributed structurally through the new
`scaffoldStructuralOwners` and `bindingSkeletonOwners` seams in
`Keiro.Dsl.Scaffold`, never by parsing the human-readable `origin` string.
New `Keiro.Dsl.WorkspaceRecord` and `Keiro.Dsl.WorkspaceScaffold` modules;
`Keiro.Dsl.ScaffoldRun` now exports the gates and helpers the workspace path
reuses (`pureRefusals`, `missingGeneratedBanners`, `staleAgainst`,
`constraintPlan`, `mappingDrift`, `newBindingObligations`,
`obligationKindLabel`, `renderMappingIdentity`) so the two paths cannot
diverge on what counts as a refusal.
- **Adoption of pre-workspace output.** The first whole-workspace scaffold into
a directory that already holds per-context output imports what is
attributable, reports everything, and claims nothing silently. A file is
claimed only with evidence — `record` when a legacy per-context record for
this workspace's effective context lists it, or `banner` when it sits at a
planned Generated path carrying the `@generated` banner while no surviving
record lists it. Hole paths are never claimed; everything else is listed as
unclaimed and left untouched, and a bannerless file at a planned Generated
path still refuses the run. Nothing is deleted or renamed: the superseded
legacy record gains one appended `superseded-by:` line that its own v1 parser
ignores. The migration report is persisted once as
`keiro-dsl-migration-report.workspace.<service>.txt`. New
`Keiro.Dsl.WorkspaceAdoption` module; recorded as ADR-15.
- **Whole-workspace diffing.** `keiro-dsl diff <manifest> --since <rev>`
composes the historical workspace from the manifest and member blobs at that
revision through the same loader and diffs it against the working tree as one
service. Membership deltas are covered, and when the manifest itself does not
exist at the old revision an adoption baseline is composed from the current
membership and flagged in the report.
Findings from the merged graph are annotated with the member file and line
that own the changed declaration and each use site, so a shared declaration's
blast radius is visible across files. The report carries workspace metadata
(service identity, manifest, `since`, old and new membership, adoption-baseline
flag), and replay-impact and coverage output are merged across members. Owner-map
and manifest-authority changes are reported as the non-blocking consumer-build
advisories `OwnershipMoved` and `WorkspaceAuthorityChanged`, classified
independently of wire evolution so they never mask a real wire finding.
The `keiro-dsl/diff-report/1` JSON schema is preserved: single-file reports
keep their original bytes, and workspace inputs add a top-level `workspace`
object plus optional per-finding `declaration` and `useSites` keys, which
version-1 readers ignore. New `Keiro.Dsl.WorkspaceDiff` module; new
`Keiro.Dsl.DiffReport` exports `OwnedSite`, `WorkspaceChange`,
`WorkspaceMeta`, `WorkspaceDiffReport`, and `workspaceDiffReport`. ADR-4 is
amended with the composed-workspace diff boundary.
## 0.4.0.1 — 2026-07-28
### Other Changes
- Adds PVP upper bounds to every dependency that previously carried a lower
bound only, so `cabal check` reports no packaging warnings. No API or
behaviour change from 0.4.0.0, which was tagged but never published.
## 0.4.0.0 — 2026-07-28
### New Features
- Structural scaffolding now creates hand-owned binding/fixture/initial
skeletons grouped by their declared owner modules, persists granular hole
obligations for non-overwriting re-scaffold reports, derives `Generic` for
private shape types, and provides `check --explain-bindings` for deterministic
package/module/signature/use-site reports.
- Adds `Keiro.Dsl.CodecCompare`, a historical-codec comparison engine that
classifies RFC 8785 canonical-JSON parity between a declared codec and a
historical one, reports structured migration differences and declared-versus-
observed branch coverage gaps, and writes stable reports atomically.
`scaffold --codec-comparison MAPPED-NAME --comparison-out FILE` emits a
non-production comparison module and runner for one structural mapped type.
- Adds `Keiro.Dsl.Coverage` and reporting-only `--coverage-report FILE` on both
`check` and `diff`, recording structural and opaque mapped-root coverage as
JSON. `check --fail-on-opaque` fails when a private persisted root still
contains an opaque boundary; `diff --fail-on-opaque-increase` fails when a
change adds a named opaque boundary. Without the flags, coverage is purely
informational.
- Adds checked `mapped structural` and `mapped opaque` declarations with a
resolved, total type-expression graph. Validation rejects recursive,
ambiguous, non-injective, or incomplete mappings; recursive diff findings
carry six-surface compatibility vectors and complete command/event/register
use-site paths.
- Structural consumer-type scaffolding now emits private
`Generated.<Context>.Structural.Shape.*` wire representations, generates
structural codecs from declared keys/defaults/tags, delegates opaque values
only at their declared JSON boundary, imports consumer types into aggregate
domains, and exposes eligible total scalar getters through a narrow Keiki
0.4 `StructuralProjections` witness facade.
- Scaffold preflight now reports consumer packages/modules, refuses consumer
modules inside the generated namespace before writing, includes consumer
requirements in manifests, persists canonical structural/opaque mapping
identities as forward-compatible JSON rows, and reports mapping drift on
subsequent runs. Mapped register wire/binding/initial identities now
participate in the aggregate fold fingerprint.
- Generated harnesses exercise both structural binding laws, declared codec
policy and current payload goldens, enum/union/optional fixture coverage,
canonical projection witness agreement, and forward-versus-replay equality
over every mapped and scalar register. The committed structural conformance
suite includes opaque-boundary checks and three falsifying mutations.
- `Keiro.Dsl.ReplayImpact` and `diff --replay-impact-out FILE`. Diffs now
print whether stored-data replay is unchanged and can emit a stable JSON
affected set for targeted auditing. New aggregates, events, transitions,
and syntactically proven guard loosenings are replay-neutral; changed
decode/fold surfaces identify conservative event types and whether
snapshot-bearing streams must be included.
- Scaffolding now emits one context-wide
`Generated.<Context>.ReplayAudit` module. Its typed target list includes
every aggregate, validates discovered stream names against the generated
category, and documents the replay-neutral/targeted/full deployment tiers.
- `diff` now emits non-breaking, coded advisories when a router resolve or
dispatch surface, process handle surface, or unversioned process-timer
payload changes. The advisories explain the subscription drain and
dead-letter procedure needed to avoid mixed old/new deterministic fan-out
during a deployment.
- First-class replay-only transitions for guard evolution (plan 143). A
`replay-only` prefix on a transition line marks it as serving inversion
only: the parser accepts it, the pretty-printer round-trips it, and the
scaffolder lowers it to `B.replayOnly` (keiki's `ReplayOnly` edge mode) in
the transducer skeleton. New validator rules: `ReplayOnlyEmitsNothing`
(error — a replay-only transition with no emit can invert nothing) and
`ReplayOnlyCommandStillLive` (warning — no live sibling for the (source,
command) pair; the fuller procedure is event retirement). A deprecated
event may keep being emitted by a replay-only transition — replay-only
transitions are not the write path.
- `diff` computes the guard-tightening remedy (`AggGuardTightened`
advisory): on any live-transition guard change without a replay-only twin,
it prints a paste-ready `replay-only` twin whose guard is the removed
region `old ∧ ¬new`, negation eliminated inside the guard grammar by the
new total `Keiro.Dsl.Grammar.complementExpr` (De Morgan, comparison
flipping, `x == false` for bare boolean atoms). The twin carries the old
transition's writes/emits/goto and re-parses as-is; it is printed, never
auto-applied.
- `Keiro.Dsl.PrettyPrint.renderTransition` renders one transition in
concrete `.keiro` syntax (used by the advisory).
- Requires `keiki >=0.4 && <0.5`, including `EdgeMode` and the typed structural
projection contracts.
## 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.