Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
ef30b5d
Basic CCC store and message
ismasan Feb 20, 2026
6758e11
Read and append with consistency guard
ismasan Feb 20, 2026
8737661
Add consumer group support with partition-based offset tracking
ismasan Feb 20, 2026
8772eb6
Return ConsistencyGuard from claim_next for optimistic concurrency
ismasan Feb 20, 2026
ac0b674
Use Message.to_conditions for type-aware guard conditions
ismasan Feb 20, 2026
a77102b
Cache payload_attribute_names at define time
ismasan Feb 20, 2026
6581cbc
Update partition plan with implemented semantics
ismasan Feb 21, 2026
0342f2c
Add YARD comments to CCC::Store methods
ismasan Feb 21, 2026
bd3be9f
Add YARD comments to CCC::Message, QueryCondition, ConsistencyGuard
ismasan Feb 21, 2026
0444e2a
Add causation_id, correlation_id, and #correlate to CCC::Message
ismasan Feb 21, 2026
ff63b2a
Add replaying flag to claim_next based on highest acked position
ismasan Feb 21, 2026
732fd2c
Return ClaimResult Data struct from Store#claim_next
ismasan Feb 21, 2026
8c17f0f
Add CCC reactor abstraction layer (Decider, Projector, Router)
ismasan Feb 21, 2026
50ac8c9
Fix causation chain: reactions correlate with event, not command
ismasan Feb 21, 2026
9ddceba
Support simple Consumer-only reactors without Decider/Projector
ismasan Feb 21, 2026
58a3b80
Add CCC.load for synchronous reactor state loading with AND-filtered …
ismasan Feb 21, 2026
11d0614
Add CCC background dispatch infrastructure (Worker, Dispatcher, notif…
ismasan Feb 21, 2026
28c63b7
Add CCC stale claim reaper with worker heartbeats
ismasan Feb 21, 2026
0cce1b5
Add CCC::Supervisor as top-level process entry point
ismasan Feb 21, 2026
0f5e311
Add CCC::Configuration and module-level API (config, configure, regis…
ismasan Feb 21, 2026
2fbf355
Add StoreInterface to guard CCC::Configuration#store= assignment
ismasan Feb 21, 2026
ee383e3
StateStored and EventSourced projectors for CCC
ismasan Feb 22, 2026
d48dc4e
Add CCC error handling parity with SequelBackend
ismasan Feb 22, 2026
9b9bc46
Error logging
ismasan Feb 22, 2026
381cbf7
CCC::Command and CCC::Event subclasses with their own registries
ismasan Feb 22, 2026
9253938
Add CCC.handle! for synchronous command handling in web controllers
ismasan Feb 22, 2026
432caeb
Add CCC module README with API docs and usage examples
ismasan Feb 28, 2026
926fd12
Accept #group_id objects in CCC Store consumer group methods
ismasan Feb 28, 2026
ce82396
Syntax
ismasan Mar 11, 2026
0e1901c
Design refs not in repo
ismasan Mar 11, 2026
7e579ae
Fix missing vars
ismasan Mar 11, 2026
84ea18f
Add #dispatch helper to CCC::Decider, allow resolving message classes…
ismasan Mar 11, 2026
68df28d
Add CCC scheduled message support
ismasan Mar 11, 2026
7251e03
Document CCC retries and backoff
ismasan Mar 11, 2026
dc5058c
New 'failed' consumer group status, and ErrorStrategy#on_fail
ismasan Mar 12, 2026
189b81a
fail status for CCC consumer groups
ismasan Mar 12, 2026
c6c5be2
Add CCC::Store#stats for monitoring and debugging
ismasan Mar 12, 2026
d523210
Include error_context in CCC::Store#stats and document stats API
ismasan Mar 12, 2026
949bb51
Add CCC::Store#read_correlation_batch for tracing causal chains
ismasan Mar 12, 2026
5c21da5
Add YARD examples to CCC::Store#read_partition
ismasan Mar 12, 2026
d6dc34e
Add CCC::Store#read_all for paginating the global event log
ismasan Mar 12, 2026
52450ef
CCC::Topology
ismasan Mar 12, 2026
039db1f
Falcon integration for Sourced::CCC with deferred configuration (to r…
ismasan Mar 12, 2026
59c3ceb
Add CCC::Falcon::Environment and Service with post-fork setup, update…
ismasan Mar 12, 2026
822d932
Revert "Add CCC::Falcon::Environment and Service with post-fork setup…
ismasan Mar 12, 2026
55be5e0
Falcon support
ismasan Mar 12, 2026
0f499d1
Remove CCC::Configuration#register
ismasan Mar 12, 2026
b0fd092
Support Sequel migrations, install store tables from migration
ismasan Mar 12, 2026
8daadae
Document CCC Sequel migration support
ismasan Mar 12, 2026
3938e9f
handle_batch -> handle_claim
ismasan Mar 12, 2026
fad69ed
Make reactors support .handle_batch
ismasan Mar 12, 2026
6d0c253
no need for argument
ismasan Mar 12, 2026
b6f034e
Replicate with_reactor RSpec helper for CCC
ismasan Mar 12, 2026
f92f298
Lazy-load CCC::Store
ismasan Mar 12, 2026
e20bc1c
Update offsets in a transaction to avoid locking on SQLite's single w…
ismasan Mar 12, 2026
3076cef
Add CCC::CommandContext for building commands from raw attributes
ismasan Mar 13, 2026
95a3314
Add order: :desc option to Store#read_all for reverse-chronological b…
ismasan Mar 13, 2026
cd92ea1
Return ReadAllResult from Store#read_all with Enumerable, to_enum, an…
ismasan Mar 13, 2026
67c3d9d
Change QueryCondition to support compound attrs with AND semantics
ismasan Mar 13, 2026
7bb9685
Extract condition_position_subqueries to deduplicate query_messages a…
ismasan Mar 13, 2026
bb0c9de
Change partition_values from Array to Hash for self-documenting key a…
ismasan Mar 13, 2026
064f01e
Fix composite partition false positives in find_and_claim_partition
ismasan Mar 13, 2026
19fb368
Add index on offsets(consumer_group_id, claimed) for faster partition…
ismasan Mar 13, 2026
78d5ad7
Logline
ismasan Mar 13, 2026
b03b4d4
CCC::Sync.after_sync actions run after the DB transaction
ismasan Mar 14, 2026
68f55ce
Document
ismasan Mar 14, 2026
c4137bb
Add missing specs for CCC::Message
ismasan Mar 14, 2026
c3a7825
Add specs for CCC::Message#with_payload
ismasan Mar 14, 2026
e911969
Add per-message and `any` callback hooks to CCC::CommandContext
ismasan Mar 14, 2026
5fdcf72
Support multiple message types in CommandContext.on
ismasan Mar 14, 2026
2c06711
Allow multiple `on` blocks per command type in CommandContext
ismasan Mar 14, 2026
36db6d1
Run CCC::CommandContext hooks in context of instance
ismasan Mar 14, 2026
fa9a31d
Lazy offset discovery in CCC::Store#claim_next
ismasan Mar 15, 2026
8c31b49
Replace CROSS JOIN with streaming iteration in find_and_claim_partition
ismasan Mar 15, 2026
e16b897
Order discovery results by min_pos to prevent skipping partitions
ismasan Mar 15, 2026
b8afa24
Use CTEs in discovery and fetch queries to halve key_pairs JOINs
ismasan Mar 15, 2026
c1831be
Skip caught-up offsets in find_and_claim_partition
ismasan Mar 15, 2026
dd4d40f
Add timing logs to CCC::Router for profiling
ismasan Mar 15, 2026
bc8f029
Short-circuit idle polls in claim_next via types_max_pos check
ismasan Mar 15, 2026
6fc497e
Add scaling benchmark with HTML charts
ismasan Mar 15, 2026
999f77b
Add scenario descriptions to scaling benchmark charts
ismasan Mar 15, 2026
1b3659f
Skip offset scan when undiscovered messages exist
ismasan Mar 15, 2026
bd5af3d
Remove known_keys Set from discovery — rely on INSERT OR IGNORE
ismasan Mar 15, 2026
85c2e9b
Add Store#append benchmark as baseline for eager offset creation
ismasan Mar 16, 2026
c556cad
Optimise append: eliminate redundant SELECT queries
ismasan Mar 16, 2026
0153cfa
Fix claim_next short-circuit and add eager offset creation
ismasan Mar 16, 2026
6afd4a8
Scaling bench
ismasan Mar 16, 2026
7b6303f
Bench results
ismasan Mar 16, 2026
4af46ab
Fix idle poll regression: replace broken min/max short-circuit with c…
ismasan Mar 16, 2026
935c0a5
Add consumer group lifecycle hooks via Router
ismasan Mar 16, 2026
939910a
Make CCC::Store#read_all from_position inclusive
ismasan Mar 17, 2026
985568a
Add CCC::Store#read_offsets for paginated offset inspection
ismasan Mar 17, 2026
d568007
Remove logging
ismasan Mar 18, 2026
f3af89a
Rename from_position: to after_position: in CCC::Store#read call stack
ismasan Mar 18, 2026
af56568
Add CCC::Message::Registry#all for recursive enumeration
ismasan Mar 18, 2026
c184ac5
Add conditions filter to CCC::Store#read_all
ismasan Apr 14, 2026
c2a54a4
Encapsulate Dispatcher setup and spawning into class level CCC::Dispa…
ismasan Apr 14, 2026
003548d
Remove redundant names
ismasan Apr 14, 2026
23a3433
PositionedMessage#to_message and Message.===
ismasan Apr 15, 2026
109ee36
Make all #handle_batch signatures the same so that GWT helpers work f…
ismasan Apr 15, 2026
9985ffa
Re-implement DurableWorkflow for CCC
ismasan Apr 15, 2026
235b365
Implement CCC::DurableWorkflow#handle_batch and rewrite tests to use …
ismasan Apr 15, 2026
d0e0540
Promote CCC to top-level Sourced namespace
ismasan Apr 15, 2026
05bf988
Simplify
ismasan Apr 15, 2026
582e163
Improve README
ismasan Apr 15, 2026
053a75c
Untrack examples/app
ismasan Apr 15, 2026
931d53a
Untrack bench files
ismasan Apr 15, 2026
e1a6a78
Ignore bench/ for now
ismasan Apr 15, 2026
d95dd57
Update CLAUDE.md to reflect CCC APIs
ismasan Apr 15, 2026
42135c3
Update README
ismasan Apr 15, 2026
e76d3b1
Style tweaks
ismasan Apr 16, 2026
f621f7b
Defer reactions in Decider.handle_batch
ismasan Apr 16, 2026
03fd28f
Move correlation into Actions::Append/Schedule
ismasan Apr 16, 2026
1ae600e
Sourced.load(upto:) loads history up to specific position number
ismasan Apr 24, 2026
cda8e6a
Dispatcher.spawn_into(task) => Dispatcher.start(task)
ismasan Apr 30, 2026
f5388b1
Block error strategy config
ismasan May 7, 2026
f00978f
Make ErrorStrategy take multiple on_fail and on_retry callbacks
ismasan May 14, 2026
b342d82
Make ErrorStrategy callbacks take keyword args. Also optional #report…
ismasan May 14, 2026
9698454
Log any error dispatching error strategy callbacks
ismasan May 14, 2026
f869a0d
Make Configuration#error_strategy mutable, only freeze on Sourced.setup!
ismasan Jun 4, 2026
f429d24
Remove Falcon support
ismasan Jun 4, 2026
573e04a
Re-register router reactors on setup!
ismasan Jun 4, 2026
e2188f2
Support multiple Sourced.configure blocks
ismasan Jun 4, 2026
bd065f1
Require new Sourced::Message gem.
ismasan Jun 6, 2026
5ffebee
Nicer Sourced::Store#inspect
ismasan Jun 8, 2026
b40b977
Add arm64-darwin-25 platform
ismasan Jun 17, 2026
6c6cd09
Reactor.queue_mode causes acked messaged to be deleted
ismasan Jul 9, 2026
b26d1c1
Make Sourced a durable-messaging runtime for third-party reactors
ismasan Jul 9, 2026
60394eb
Simplify
ismasan Jul 9, 2026
689471c
Fix index-basis resolution and drained-offset reaping
ismasan Jul 9, 2026
dac1f9b
Require exclusive for all id-partitioned reactors
ismasan Jul 9, 2026
8fd4689
Update CLAUDE.md for signal actions, duck-typed reactors, delete-on-a…
ismasan Jul 10, 2026
a557c3d
Rename magic message-id partition key from :id to :__id
ismasan Jul 10, 2026
b47b89b
Remove the delivery_mode column; derive reset guard from exclusive
ismasan Jul 10, 2026
3dbd8d2
Hard dependency on sequel and sqlite3. Sourced::Store requires it.
ismasan Jul 10, 2026
f0cb5dd
Make Store#append schedule future messages (#created_at > now). Remov…
ismasan Jul 11, 2026
e23b595
Index by message ID regardless.
ismasan Jul 11, 2026
1d1b331
Document scheduling-via-append, reactor protocol, and delete-on-ack q…
ismasan Jul 11, 2026
4075bf0
Merge pull request #52 from ismasan/queue_mode
ismasan Jul 11, 2026
ffc0d8f
Use IMMEDIATE transactions to avoid BUSY_SNAPSHOT
ismasan Jul 13, 2026
c8aaafe
Store#transaction(&) handles immediate mode for us. Revert PRAGMA app…
ismasan Jul 13, 2026
6b6e1e4
Don't apply the nil-claim short-circuit on the eager offset path
ismasan Jul 13, 2026
02b4f0b
Collapse find_and_claim_partition into a single query
ismasan Jul 13, 2026
4c1dc73
Restore an O(1) idle claim gate via trigger-invalidated scan versions
ismasan Jul 13, 2026
fadad78
Keep SQLite planner statistics fresh: Store#optimize! at boot + perio…
ismasan Jul 13, 2026
b0dc23e
WiP message codecs
ismasan Aug 7, 2026
4ba14ba
Store uses Plumb::Codec::JSON to decode/encode into DB, transparently
ismasan Aug 8, 2026
1cdef79
Make Plumb::Codec::JSON the global, non-configurable codec
ismasan Aug 10, 2026
3dc7d3d
Work with latest Sourced::Message's built-in message codecs, and late…
ismasan Aug 10, 2026
e8e535e
Merge pull request #54 from ismasan/codecs
ismasan Aug 10, 2026
ff71030
Add link to Rubyforum page
ismasan Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ logs/
pkg
.DS_Store
.claude
bench/

58 changes: 58 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,63 @@
## [Unreleased]

### Changed

- `Sourced::Store::MessageCodec` is now a subclass of `Sourced::Message::JSONCodec`, which
lives in the **sourced-message** gem and is shared with Sidereal. It keeps its
payload-only behaviour by overriding three private seams, and gains a per-class pair
cache, `compiled?`, `recompile!`, `.reset!` and `.clear_pairs!`.
- `#encode_payload` is now `#encode` (the base class's name; it still encodes only the
payload and still returns `nil` for a message declared without one).
- `#compile!` is idempotent — call `#recompile!` to pick up message types or encoders
registered since the last compile.
- Encoding or decoding an uncompiled type raises
`Sourced::Message::JSONCodec::UnregisteredTypeError` instead of `Plumb::Codec::NoEntryError`.
- `EncodeError` / `DecodeError` now descend from `StandardError` rather than
`Sourced::Error`. `Store::MessageCodec::EncodeError` still resolves, by inheritance.

### Added

- **Message codecs.** Messages are declared with native Ruby types (`Date`, `Time`,
`Symbol`, `BigDecimal`, `URI`, `Range`, …) and `Plumb::Codec::JSON` translates them to
and from the store's JSON columns. Apps register encoders for their own value types
directly on it (`Plumb::Codec::JSON.encoder MoneyEncoder`), before `Sourced.setup!`.
- `Sourced::Store::MessageCodec` — the SQLite store's serializer, namespaced under and
owned by it. It registers each message class's payload type in a Plumb codec instance
keyed by message type string, built and frozen at `setup!`; the
envelope is the store's own business. The format is global and needs no configuring; a
future store with a different layout owns a different serializer, or none. A message
type the store can't persist raises `Plumb::TypeError` at `setup!` — the app fails to
boot rather than raising on the first append.
- `Sourced::Types::JSONData` — any JSON value, recursively — for payload attributes
whose shape isn't known up front.

### Fixed

- `Date` and `Time` payload attributes never round-tripped through the store: they
were written via `#to_s` and read back as Strings, producing invalid messages. This
affected `DurableWorkflow`'s `WaitStarted#at`.
- Scheduled messages recorded `scheduled_at` metadata via `Time#to_s` rather than ISO 8601.
- A message's `created_at` was stored at whole-second precision in the log while the
scheduled-message blob kept microseconds. Both now come from the encoded message, at
microsecond precision.

### Changed

- `Configuration::StoreInterface` requires `setup!` instead of `install!` / `installed?`.
A store prepares itself however it needs to at boot; creating tables is one store's
answer, not the contract. `Sourced::Store#setup!` creates its tables and compiles its
serializer; `install!` / `installed?` remain public for scripts and tests.

- Reading a message whose stored payload no longer satisfies its schema raises
`Sourced::Store::MessageCodec::DecodeError` instead of silently producing an invalid
message. Appending an invalid message raises `Store::MessageCodec::EncodeError`.
- Reading a message whose type isn't registered raises
`Sourced::Message::UnknownMessageError` instead of returning a base
`Sourced::Message` with its payload silently dropped.
- `DurableWorkflow` workflow context and step outputs are typed `Types::JSONData`
rather than `Types::Any`: values must be JSON-native, checked at append time
rather than silently coerced to Strings on the way back out.

## [0.1.0] - 2024-09-27

- Initial release
291 changes: 206 additions & 85 deletions CLAUDE.md

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ group :development do
end

group :test do
gem 'dotenv'
gem 'pg'
gem 'rspec', '~> 3.0'
gem 'sequel'
gem 'sqlite3'
Expand Down
27 changes: 19 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ PATH
specs:
sourced (0.0.1)
async
plumb (>= 0.0.17)
plumb (= 0.2.0.beta.2)
sequel
sourced-message
sqlite3

GEM
remote: https://rubygems.org/
Expand All @@ -23,8 +26,8 @@ GEM
io-event (~> 1.11)
metrics (~> 0.12)
traces (~> 0.18)
bigdecimal (3.1.8)
concurrent-ruby (1.3.4)
bigdecimal (4.1.2)
concurrent-ruby (1.3.8)
console (1.34.3)
fiber-annotation
fiber-local (~> 1.1)
Expand All @@ -33,11 +36,15 @@ GEM
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.5.1)
dotenv (3.1.4)
et-orbi (1.4.1)
tzinfo
fiber-annotation (0.2.0)
fiber-local (1.1.0)
fiber-storage
fiber-storage (1.0.1)
fugit (1.13.0)
et-orbi (~> 1.4)
raabro (~> 1.4)
io-console (0.7.2)
io-event (1.14.2)
irb (1.14.0)
Expand All @@ -57,12 +64,12 @@ GEM
parser (3.3.7.1)
ast (~> 2.4.1)
racc
pg (1.5.8)
plumb (0.0.17)
plumb (0.2.0.beta.2)
bigdecimal
concurrent-ruby
psych (5.1.2)
stringio
raabro (1.5.0)
racc (1.8.1)
rainbow (3.1.1)
rake (13.2.1)
Expand Down Expand Up @@ -101,27 +108,31 @@ GEM
ruby-progressbar (1.13.0)
sequel (5.84.0)
bigdecimal
sourced-message (0.2.1)
fugit
plumb (= 0.2.0.beta.2)
sqlite3 (2.8.0)
mini_portile2 (~> 2.8.0)
sqlite3 (2.8.0-arm64-darwin)
stringio (3.2.0)
timecop (0.9.10)
traces (0.18.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.2.0)

PLATFORMS
arm64-darwin-23
arm64-darwin-24
arm64-darwin-25
x86_64-linux

DEPENDENCIES
debug
docco!
dotenv
logger
pg
rake (~> 13.0)
rspec (~> 3.0)
rubocop
Expand Down
Loading