| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
The correctness doc promises at-least-once execution and tells external systems to hold stable idempotency keys, but nothing in the repository showed that duplicate arriving anywhere. A contract clause nobody can watch fire is decoration. This adds the artifact that fires it on demand and shows the documented remedy absorbing it. examples/at_least_once stages one actor turn whose effect writes to an external sink file. The first effect worker crashes between the sink write and the acknowledgement. A second worker runs ProcessRegistry.cleanup_dead after the liveness threshold, reclaims the released effect, and delivers again. With deduplication off the sink reads 2, both deliveries carrying the same context.id at attempts 1 and 2. With a guard on that id the sink reads 1. The actor state commits exactly once in both runs, which is the sharpest line of the proof: the state machine kept its exactly-once story while the outside world saw two. bundle exec rake at_least_once runs it, CI runs it in the SQLite job, and docs/correctness.md links it from the handler idempotency section it makes observable. The sink module carries unit coverage for both guard modes. This is the Ruby counterpart of solid-objects-js#26.
|
CI reproduced the proof on Ubuntu in the sqlite job, so the crash timing is not a macOS artifact: "duplicate": { "state_commits": 1, "sink_deliveries": 2, "same_effect_id": true, "attempts": [1, 2] }
"remedy": { "state_commits": 1, "sink_deliveries": 1 }
sqlite job log. All checks pass. |
Sorry, something went wrong.
Greptile flagged the JS counterpart for reading every failure as an empty sink, which lets the deduplication phase forget the effect id and still pass. The Ruby sink already rescues only Errno::ENOENT, and the Ruby effect worker already fails when no effect became claimable, so neither defect exists here. Both properties were incidental until now. These two tests make them deliberate: a truncated JSON file and a path that is a directory must raise rather than read as a first run. Widening the rescue to StandardError fails both.
|
Greptile reviewed the JS counterpart (cardmagic/solid-objects-js#26) and raised two P2 findings. I checked both against this PR:
Both properties were incidental rather than pinned, so b8ea47a adds two tests: a truncated JSON file and a path that is a directory must raise instead of reading as a first run. Widening the rescue to StandardError fails both: AtLeastOnceSinkTest#test_refuses_to_read_a_damaged_sink_as_an_empty_one: JSON::ParserError expected but nothing was raised. AtLeastOnceSinkTest#test_refuses_to_read_an_unreadable_sink_as_an_empty_one: Errno::EISDIR expected but nothing was raised. Restored, the file reads 5 runs, 9 assertions, 0 failures. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Why
docs/correctness.md promises at-least-once execution and tells external
systems to hold stable idempotency keys. Nothing in the repository showed that
duplicate arriving anywhere. A contract clause nobody can watch fire is
decoration, so this adds the artifact that makes it fire on demand, and shows
the documented remedy absorbing it.
This is the Ruby counterpart of
solid-objects-js#26,
which implements
solid-objects-js#23.
Same proof, same shape, same numbers.
No runtime code changes. This is an example, a unit test, a CI step, and two
lines of prose.
What the demo does
bundle exec rake at_least_once runs examples/at_least_once/demo.rb against
a temporary SQLite file:
commit.
file, then calls Process.exit!(1) between the sink write and the
acknowledgement. The sink holds the delivery; the effect row never
completes.
SolidObjects::ProcessRegistry.cleanup_dead (production runs this on
dead_process_cleanup_interval), reclaims the released effect, and delivers
again.
Phase one runs the sink with deduplication off. Phase two repeats the same
crash with a guard on the stable effect id.
{ "duplicate": { "state_commits": 1, "sink_deliveries": 2, "same_effect_id": true, "attempts": [1, 2] }, "remedy": { "state_commits": 1, "sink_deliveries": 1 } }The state commit happens exactly once in both phases. That is the sharpest
line of the proof: the actor kept its exactly-once story while the outside
world saw the delivery twice, and only a consumer-side guard on context.id
collapsed it.
The crash point
context.id is stable across attempts and context.attempt reads 1 then 2,
which is exactly what an external consumer needs in order to deduplicate.
Observed failures
The sink test was written first. With examples/at_least_once/sink.rb absent,
bundle exec rake test TEST=test/unit/at_least_once_sink_test.rb:
A missing file is a weak failure, so the guard was also removed from a
complete sink. The unit test then failed on the assertion under test rather
than on load:
The demo is not self-fulfilling either. With the same guard removed,
bundle exec rake at_least_once fails at the remedy phase:
Restoring the guard turns all three green.
Files
Wiring
observable.
docs/roadmap.md is untouched. The gem's claims about itself did not move;
this makes an existing claim observable.
Effects
authorization inside its own process.
Validation