Repository navigation
docs: add four tested problem guides - #87
Conversation
Developers search for a problem, not for a virtual actor library. Four
guides now start from one: race conditions in Rails, running jobs in
order for each customer, expiring reservations, and saving state and
queuing work together. Each one reproduces the failure, shows the plain
Rails fix first (a unique index, a conditional update, row and
optimistic locks, a sequence number, Sidekiq capsules, Solid Queue
concurrency limits, a transactional outbox), and only then shows an
actor where ordering, durable state, reminders, and recovery are needed
together. Codex with GPT-6 Astra wrote the prose from briefs that held
only verified facts and cited sources.
Every code block in a guide is a file under examples/guides/, and the
tests in test/guides/ prove each claim. Each test was watched to fail
first, and each guard in the examples was removed once to confirm that
a test fails without it. A document test fails when a guide does not
embed the current example files, contains an em dash or an en dash, or
links to a missing file.
The concurrency helper limits the threads that act at once to the free
connections in the pool. On PostgreSQL with the default pool of five,
ten waiting synchronous callers otherwise held every connection and the
actor turn could not get one ("could not obtain a connection from the
pool within 5.000 seconds").
Active Job joins the development and test bundle for the job examples,
pinned to the Rails line in compatibility runs.
|
Docs7 for cardmagic/solid-objects-ruby
Commit 1 finding is inline on the changed files. |
|
Review found three gaps in the guide examples, and Rails 7.1 and 7.2 found two in the tests. - EventTickets and SeatInventory now store each deadline and check it in the operation, so a hold past its deadline cannot be confirmed or extended and frees its seats even when the expiry reminder has not run. The reminder only cleans up. New tests travel past the deadline without delivering a reminder; both failed before the change. - SeatInventory rejects a seat count that is not a positive integer. A hold for -5 seats had added five seats to the show. - LedgerAccount kept the last 100 entry IDs in state, so a repeated entry after 100 newer entries changed the balance again. Each entry now writes a ledger_entries row through a commit action in the same transaction, with a unique index, and apply checks that row first. A test applies 102 entries and repeats the first; it failed before. - On Rails 7.1 and 7.2, ActiveJob::TestHelper ignores a queue adapter assigned inside the test, so the lost-job test raised nothing. It now replaces perform_later for that test. - On Rails 7.1 SQLite, two workers that registered their processes at the same time raised "database is locked". The test now creates both workers before the threads start. - The Sidekiq snippet no longer carries the commented-out weighted line. Codex with GPT-6 Astra revised the three affected guides from change lists, and the guides embed the new example files.
|
@greptileai Please review the latest commit, bc462f4. It addresses each finding:
The commit also fixes two Rails 7.1 and 7.2 test failures from CI:
Validation:
|
A retry with the same buyer and hold ID after the deadline creates a fresh hold. When the scheduler had already queued the old expiry, that expiry removed the fresh hold, because expire checked only the hold ID. The reminder now passes the stored deadline, and expire releases a seat only when the hold ID and the deadline both match, as SeatInventory does. A new test retries after the deadline and then delivers the old expiry; with the deadline check removed, it fails.
GitHub runners hit the Docker Hub pull rate limit for anonymous pulls (toomanyrequests) on the Redis, PostgreSQL, and MySQL service containers. The ECR Public mirror serves the same official images without that limit.
|
@greptileai Please review the latest commit, 8f077a1.
Validation: |
| - **Retries:** Two identical holds and two identical confirmations sell one seat. | ||
| - **Confirmation after expiry:** The actor rejects the confirmation with the code `no_hold`. | ||
| - **Past the deadline, before the reminder runs:** The test moves the clock 11 minutes forward and delivers no reminder. The actor rejects the confirmation with `no_hold`, and another buyer holds the seat. | ||
| - **A retry with the same hold ID after the deadline:** the test moves the clock 11 minutes forward. The retry creates a fresh hold, and then the old expiry arrives. The fresh hold stays. |
There was a problem hiding this comment.
Grammar and spelling: After the bold colon the sentence starts with a lowercase 'the'; capitalize it like the other bullets.
Why
Developers search for a problem ("Rails race conditions", "Sidekiq jobs in order per user", "reserve tickets for 15 minutes", "after_commit job lost"), not for a virtual actor library. These guides answer those problems. Each one shows the plain Rails fix first and recommends Solid Objects only where it adds value. They will be published at
/ruby/race-conditions,/ruby/ordered-jobs,/ruby/expiring-reservations, and/ruby/transactional-outboxon solidobjects.dev.What changed
docs/guides/race-conditions.md, "Prevent race conditions in Rails".docs/guides/ordered-jobs.md, "Run jobs in order for each customer in Rails".limits_concurrency, and a sequence number with a row lock.docs/guides/expiring-reservations.md, "Expiring reservations in Rails".docs/guides/transactional-outbox.md, "Save state and queue work together in Rails".docs/agents.mdlist the guides.Code and tests
Every code block in a guide is a file under
examples/guides/. The tests intest/guides/(43 runs) prove each claim the guides make.test/guides/guide_documents_test.rbfails in three cases: a guide does not embed the current example files verbatim (without therbs_inlineheader line), a guide contains U+2013 or U+2014, or a relative link points to a missing file.Observed failures.
LoadError: cannot load such file -- .../examples/guides/.... The document test failed withErrno::ENOENTbefore the guides existed.retry_on, and the entry dedupe;reject(replaced by araise), the seat check, the extension reschedule and limit, andunschedule;placeguard, and the effect idempotency key.could not obtain a connection from the pool within 5.000 seconds. The helper now limits the threads that act at once to the free connections. Each file passed on a fresh local PostgreSQL 17 database. MySQL was not run locally; CI covers it.Dependency change
activejobjoins the development and test group. Compatibility runs pin it with~> RAILS_VERSION.0, andbundle lock --update --printresolves 7.1.6 and 8.0.5.1 forRAILS_VERSION=7.1and8.0. The default lock addsactivejob 8.1.3.1andglobalid 1.4.0. No other gem changes. The runtime gemspec is unchanged.Copy
Codex CLI with GPT-6 Astra (
codex exec -m gpt-6-astra, read-only sandbox) wrote the prose from four briefs. The briefs held the outline, the verified facts with sources (checked October 9, 2026), and the ASD-STE100 and no-dash rules. Codex wrote{{EMBED path}}placeholders, and a script replaced them with the exact tested files. Every claim was checked againstdocs/correctness.md,docs/architecture.md,docs/operations.md,docs/reminders.md, and the cited pages.Hand edits to the Codex copy.
expiring-reservations.md: "An actor for each reservation does not stop two reservations from the same stock." became "An actor for each reservation cannot prevent an oversold show. Two reservations can take the same stock." The verb was missing.race-conditions.md: "SQL retains pending work" became "SQL keeps the unfinished work".Citations, all checked October 9, 2026:
enqueue_after_transaction_commit.Effects
authorization_context:.Validation
bundle exec rake: 916 runs, 0 failures, 0 errors, 28 skips. Standard Ruby and RuboCop found no offenses in 301 files. RBS validates, Steep found no type errors, and Brakeman found no warnings.bundle exec ruby -Itest test/guides/<file>for each guide test againstSOLID_OBJECTS_DATABASE_URL=postgresql://localhost/solid_objects_guides_test(a fresh database for each file): every file passed.