Packages
All five packages are released together at the shared version 0.2.0.0.
| Package | Hackage | Tag |
|---|---|---|
keiro-core |
https://hackage.haskell.org/package/keiro-core-0.2.0.0 | keiro-core-0.2.0.0 |
keiro |
https://hackage.haskell.org/package/keiro-0.2.0.0 | keiro-0.2.0.0 |
keiro-pgmq |
https://hackage.haskell.org/package/keiro-pgmq-0.2.0.0 | keiro-pgmq-0.2.0.0 |
keiro-migrations |
https://hackage.haskell.org/package/keiro-migrations-0.2.0.0 | keiro-migrations-0.2.0.0 |
keiro-dsl |
https://hackage.haskell.org/package/keiro-dsl-0.2.0.0 | keiro-dsl-0.2.0.0 |
What's Changed
A major release across the package set. The headline changes are the relocation
of Keiro's framework tables into a dedicated keiro PostgreSQL schema, stricter
replay-contract validation on the Keiki 0.2 core, durable dead letters for
rejected dispatches, and a substantially expanded keiro-dsl spec surface
(read models, routers, snapshots, queue ordering, and workflow evolution).
Breaking Changes
- Keiro's framework tables moved out of the
kirokuschema into a new,
dedicatedkeiroPostgreSQL schema that Keiro creates and owns. Every
runtime query is now schema-qualified (keiro.keiro_snapshots,
keiro.keiro_timers,keiro.keiro_outbox, …) and no longer depends on
search_path.keiro-coreexports the newKeiro.Schema.keiroSchemaas the
single source of truth for the name. Existing databases must run the
keiro-migrationsbootstrap, which creates the schema and relocates the
tables; application SQL that read barekeiro_*relations must be re-qualified. runCommandWithSql,runCommandWithSqlEvents,
runCommandWithProjections, and the process-manager/router runners now
requireKirokuStoreResourceso transactional appends can apply Kiroku's
configuredenrichEventhook. Acquire the store withwithKirokuStoreand
interpretStorewithrunStoreResource; plainrunCommandis unchanged.- Read-model queries no longer auto-register missing registry rows. Applications
must callregisterReadModelat projection startup; unknown models now return
ReadModelUnregisteredwithout mutating the registry. ReadModelnow requires astrongScope :: StrongScopefield. Use
EntireLogfor all-stream subscriptions orCategoryHead categoryfor a
category subscription so unrelated traffic cannot holdStrongreads behind.ReadModelnow also requires aschema :: Textfield naming the PostgreSQL
schema its data table lives in. Keiro does not rewritequery; qualify the
application's SQL withqualifiedTableNameorKeiro.Connection.qualifyTable.
The field is Haskell-level wiring only and is deliberately not persisted in the
keiro.keiro_read_modelsregistry.AsyncProjectionnow requiresreadModelName, naming the registry row that
fences writes during a rebuild.PMCommandResult.PMCommandFailednow carries the targetStreamNamealongside
itsCommandError, so worker policy can identify the failing target.WorkerOptionsgains arejectedCommandPolicy :: RejectedCommandPolicyfield,
andShardedWorkerOptionsgainshandlerRetryDelay :: RetryDelayand
retryPolicy :: RetryPolicy. Record construction must supply them; the
defaultWorkerOptionsanddefaultShardedWorkerOptionsdefaults are unchanged
in behavior.applyAsyncProjectionnow returnsAsyncApplyOutcome(AsyncApplied,
AsyncDuplicate, orAsyncFenced) and live workers must not checkpoint a
fenced event. Rebuild replayers useapplyAsyncProjectionUnfencedbetween the
new atomicstartRebuildand guardedfinishRebuildhelpers.keiro-migrationsnow exports a nativepg-migratecomponent and composes
Kiroku through an explicit component dependency instead of a combined Codd
migration-set API.- Router deterministic command ids are now derived from the resolved target
stream name and same-stream occurrence rather than the target's list position.
A transition point-probe recognizes legacy positional ids for stable resolver
output and may be removed in a later release. If both the deployment version
and resolver output change between attempts, a target command may be
dispatched at most one extra time across that one-time upgrade window. runWorkflow,runWorkflowWith, and the child-workflow runtime now require
Error StoreErrorin their effect rows so post-commit workflow snapshot
failures can be caught without leaving the typed error channel.mkEventStreamnow rejects snapshot codecs that cannot encode their initial
state and register file. Snapshot-enabled streams built from
emptyRegFilemust initialize every slot before validation.- Keiro now requires post-MP-16 Keiki 0.2. Stream validation runs the new
head-recoverability, inversion-ambiguity, unguarded-input-read, and
state-changing-silent-edge checks; any warning makesmkEventStreamreject
the stream at startup. HydrationReplayFailednow carries a typedHydrationReplayReasonalongside
the failing stream version. The reasons distinguish no inverting edge,
ambiguous inversion, queue mismatch, and a truncated multi-event chain.
CommandErroralso gainsCommandAmbiguous, carrying matched edge indices.- A command matching multiple transitions is now reported as
CommandAmbiguousinstead ofCommandRejected. Process managers and routers
halt on this aggregate-definition bug, while generated timer dispositions
route it through their on-error arm rather than benign on-reject handling. - The
hydration_replay_failedtelemetry class is replaced by four
reason-specificerror.typevalues, andcommand_ambiguousis new.
Dashboards keyed on the old hydration class must be updated. validateEventStreamWithandmkEventStreamWithnow force-enable Keiki's
head-recoverability and state-changing-epsilon checks. Caller-supplied
options may only strengthen validation at Keiro's durable boundary; use the
explicitly unsafemkEventStreamUncheckedonly for tests and emergency
forensics, never production streams.keiro-dsl: the processsagaclause is now
saga <Aggregate> category "<camelCase>", replacing
saga <Aggregate> stream="<prefix>-" <> correlationId;processnodes must
declare node-levelrejectedandpoisonpolicies; every timerfire
disposition must carry anon-ambiguousarm; identifiers are restricted to
ASCII and checked for Haskell hygiene; and numeric literals exceeding
maxBound :: Intare rejected instead of silently wrapping. Validation is
substantially stricter overall, so specs that checked under 0.1.0.0 may now be
rejected. Seekeiro-dsl/CHANGELOG.mdfor the full list.keiro-dsl:scaffoldnow plans the whole module set before writing any byte
and refuses to overwrite aGeneratedpath lacking the@generatedbanner
(override with--force-generated-overwrite).diffgained aWARNING:tier
and reformatted its change lines; onlyBREAKING:changes exit non-zero.
New Features
- Durable dispatch dead letters. New
Keiro.DeadLetter,
Keiro.DeadLetter.Schema, andKeiro.DeadLetter.Replaymodules let
process-manager and router workers park a rejected dispatch instead of halting.
RejectedCommandPolicyselectsRejectedHalt(the default),
RejectedDeadLetter(persist to the newkeiro.keiro_dead_letterstable and
acknowledge), orRejectedSkip.replaySubscriptionDeadLettersre-runs a
caller-supplied handler over the rows Kiroku parked inkiroku.dead_letters
without deleting or mutating those Kiroku-owned rows. - New
Keiro.Connectionmodule for application read-model and projection tables:
qualifyTable,quoteIdentifier,withProjectionSchema,
keiroConnectionSettings, and the opt-inensureProjectionSchema. The store
connection'sschemastayskirokubecause it drives theLISTEN/NOTIFY
channel; a projection schema is reached by qualification and/or
extraSearchPath. - Acknowledgement-aware sharded subscriptions:
runShardedSubscriptionGroupAck
withShardAck,ShardDelivery, andShardEventHandler, plus per-event retry
and dead-letter dispositions.runShardedSubscriptionGroupremains as the
compatibility wrapper. - New telemetry:
keiro.dispatch.deadlettered,keiro.subscription.deadlettered,
keiro.snapshot.encode.failures,keiro.snapshot.decode.failures,
keiro.snapshot.read.hits,keiro.snapshot.read.misses, and
keiro.snapshot.apply.divergence.Keiro.Telemetry.kirokuEventBridgeinstalls
on Kiroku'seventHandlerto observe the terminal retry-exhaustion signal. keiro-dslgained a first-classreadmodelnode (typed columns, shape-hash
drift detection, consistency/scope/feed validation) and arouternode for
stateless content-based routing, both with generated runtime modules and typed
holes. Query operations and PGMQ dispatch dedup references now genuinely resolve
against declared read models — they were deferred no-ops in 0.1.0.0.keiro-dslgained aggregatesnapshotpolicies with a captured state-codec
fixture, workqueueorderingand provisioning (FIFO, group keys, unlogged,
partitioned), intakepersistposture, and durable-workflow evolution via
guardedpatchblocks and terminalcontinueAsNew.diffwas rebuilt on an
exhaustive node-family registry, so a new node kind can no longer be silently
classified as safe.keiro-migrationsappended0018, creatingkeiro.keiro_dead_letters.
Bug Fixes
- Sharded subscription readers now acknowledge each event only after its handler
returns. A shed or rebalanced bucket's checkpoint can no longer cover an
unprocessed event. keiro-dslstring 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. The scaffolder also escapes payload literal splices, closing a
template-injection path where a quoted spec literal could break out of the
generated Haskell string.
Other Changes
- Command hydration now detects stream-version gaps caused by Kiroku
per-stream truncation and returnsHydrationGapDetectedunless a snapshot
covers the hidden prefix. - Transactional command runners now apply Kiroku's configured
enrichEvent
hook before event preparation, so persisted events and the
runCommandWithSqlEventscallback observe the same enriched metadata as
plainrunCommand. - The shared PostgreSQL test fixture now provisions templates through the
native Kiroku/Keiro migration plan. Codd transition and remediation tests are
retained behind the manuallegacy-codd-toolsflag. - Router and process-manager duplicate-event rejections are now confirmed
against the intended target stream before being treated as benign.
Unconfirmed cross-stream or id-less collisions surface as command failures,
causing workers to halt instead of silently dropping a dispatch. - Aggregate snapshot encoding is forced before the store write. An
ErrorCall
from a partial state encoder or uninitialized register is swallowed after the
event append and counted instead of escaping a successful command. - Workflow snapshot writes after steps, completion, and continue-as-new
rotation are advisory: store failures are swallowed and counted after the
journal append commits. - Added
keiro.snapshot.encode.failures,
keiro.snapshot.decode.failures,keiro.snapshot.read.hits, and
keiro.snapshot.read.misses; snapshot lookup APIs now retain miss and decode
reasons while compatibility wrappers preserve the previousMaybesurface. - Corrected snapshot documentation: version non-regression applies within one
codec version and shape hash, while an incompatible codec can replace a newer
row to permit rollback. Upgrade notes cover the full-replay miss caused by
Keiki EP-78's stable shape hash. - Kiroku 0.3/0.2, Keiki 0.2, and pg-migrate 1.0 now resolve from Hackage; their
obsolete Git package overrides and local Cabal overlay are no longer needed. RunCommandOptions.verifyReplayOnAppenddefaults on. Both command append
paths replay each just-committed batch from the pre-command state, count an
unreplayable batch throughkeiro.snapshot.apply.divergence, and attach a
bounded typed reason tokeiro.replay.divergencewithout turning an already
committed command into a reported failure.- No-op commands now report
CommandResult.globalPosition = Nothinginstead
of exposing Kiroku's per-stream-read sentinelGlobalPosition 0. Appended
commands continue to report the real store-assigned position. - Exported additional runtime helpers so custom workers can reuse the framework's
classification logic:commandErrorClass,isRejectionClass,
decideForFailures,DispatchFailure,confirmBenignDuplicate,
deterministicRouterCommandId,ReadModel.categoryHeadPosition,
ReadModel.qualifiedTableName,StrongScope, andRebuildError. - Documented previously implicit runtime contracts: the inbox deduplication window
closes whengarbageCollectCompletedremoves a completed row; outbox
created_atis transaction-start time, soPerKeyHeadOfLineand
PerSourceStreamordering is best-effort unless the caller serializes same-key
enqueues; the default timer worker has no attempt ceiling and requeues claims
leftFiringfor five minutes; and process-managercorrelatejoins across
streams must be order-insensitive. - Added upper bounds alongside the move to Hackage:
keiki >=0.2 && <0.3,
keiki-codec-json >=0.2 && <0.3, andkiroku-store >=0.3 && <0.4. keiro-dsladded conformance suites that round-trip every node family, compile
everykeiro-dsl new <kind>starter, and cold-start the new read-model, router,
snapshot, queue-ordering, and workflow-rotation surfaces against the live
runtime.