protocol: decouple the IM reply via santi-protocol and a transactional outbox #45

Merged
PerishFire merged 1 commit from split-protocol-reply into main 2026-07-21 06:44:02 +00:00
Owner

First step of the downstream-protocol design: what santi shares with a downstream consumer is a stable, transport-independent protocol, never its database. New crate santi-protocol holds the ReplyEvent contract + ReplyOutbox/ReplySink ports + dispatch_replies driver; the transport (outbox table now, MQ later) is an adapter behind the ports. Turn completion writes a self-contained ReplyEvent to a reply_outbox (schema v29) atomically with the turn; the service dispatches after completion (mirrors the error-outbox, latency preserved); the im consumer builds the reply from the event payload alone, reading none of santi's tables (at-least-once + idempotent via INSERT OR IGNORE on turn_id). By design, completion and delivery are no longer one cross-context tx: a downstream delivery failure no longer rolls the turn back (resilience gain; test rewritten). Follow-up: the ReplySink still lives in core's service, so core still crate-depends on im. 0 faults, core 0, 48 test groups green.

First step of the downstream-protocol design: what santi shares with a downstream consumer is a stable, transport-independent protocol, never its database. New crate santi-protocol holds the ReplyEvent contract + ReplyOutbox/ReplySink ports + dispatch_replies driver; the transport (outbox table now, MQ later) is an adapter behind the ports. Turn completion writes a self-contained ReplyEvent to a reply_outbox (schema v29) atomically with the turn; the service dispatches after completion (mirrors the error-outbox, latency preserved); the im consumer builds the reply from the event payload alone, reading none of santi's tables (at-least-once + idempotent via INSERT OR IGNORE on turn_id). By design, completion and delivery are no longer one cross-context tx: a downstream delivery failure no longer rolls the turn back (resilience gain; test rewritten). Follow-up: the ReplySink still lives in core's service, so core still crate-depends on im. 0 faults, core 0, 48 test groups green.
protocol: decouple the IM reply via santi-protocol + a transactional outbox
All checks were successful
guard / guard (pull_request) Successful in 5m27s
022f2ef777
The first step of the downstream-protocol design: what santi shares with a
downstream consumer must be a stable, transport-independent protocol, never
its database. New crate santi-protocol holds the ReplyEvent contract plus the
ReplyOutbox / ReplySink ports and the dispatch_replies driver; how events are
transported (a table today, a queue later) is an adapter behind the ports and
does not leak into the contract.

Turn completion no longer synchronously enqueues into im_inbox inside the
completion transaction (the old core->im edge). It now writes a self-contained
ReplyEvent to a reply_outbox table atomically with the turn (schema v29), and
the service dispatches the outbox after completion -- mirroring the existing
error-outbox pattern, so latency is preserved. The im consumer (deliver_reply)
builds the reply purely from the event payload, reading none of santi's tables.
Delivery is at-least-once; im's INSERT OR IGNORE on turn_id keeps it idempotent.

Consequence, by design: turn-completion and reply-delivery are no longer one
cross-context transaction. A downstream delivery failure can no longer roll a
turn back -- the turn completes and the reply stays pending in the outbox for
retry. The delivery_failure test is rewritten to assert this (it is a
resilience improvement: a flaky channel no longer fails agent turns).

Remaining (follow-up): the ReplySink still lives in core's service layer, so
santi-core still crate-depends on santi-im; moving the sink out (or letting im
consume fully independently) is the next step toward core being im-blind.
crates/ and adaptor/src/db gain fanout exemptions (workspace + substrate growth
from the split). 0 faults, core debt 0, 48 workspace test groups green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PerishFire deleted branch split-protocol-reply 2026-07-21 06:44:03 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
PerishFire/santi!45
No description provided.