diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b7133..61161fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## Unreleased + +- Align the use-case claims with the Ruby gem. The README table sold per-key + rate limits, while the Ruby fit guide called a rate limiter an anti-pattern. + Both projects now draw one line: a low-rate quota that a reminder refills + fits, because each check is one durable ordered message, and a limiter that + every request touches does not. +- Point the high-QPS reader at [Solid Objects Pro](https://solidobjects.pro/) + from the rate-limit sentence in the README and `docs/fit.md`, and name what + it adds for that shape: grouped commits and ephemeral operations. The README + states that it ships for the Rails gem today and that the Node build is in + development. +- Move the early-release caveat off the first screen. It is now a `Status` + section at the end of the README, with a table-of-contents entry, which + matches where the Ruby gem keeps the same statement. The first screen keeps + the transaction caveat, because that one changes whether a reader should + install anything. +- State the workflow limit next to the workflow row instead of only in + `docs/fit.md`. A workflow fits when one entity owns the mutable state and its + mailbox holds the step order. A durable execution engine that replays named + steps from a step log is a different tool. + ## 0.14.3 - 2026-08-25 - Rewrite the first screen around the objection a reader actually has. The diff --git a/README.md b/README.md index 8df68c3..4879462 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,6 @@ durable actor state in the origin's private file system, and its offline writes can replay onto a Node **or Rails** backend over one shared wire contract. See [Solid Objects in the browser](#solid-objects-in-the-browser). -> **Early release:** the correctness core has automated coverage. That coverage -> includes the supported databases, the Chromium browser client, the browser -> runtime, process recovery, and the packaged artifacts. The TypeScript -> implementation is still new. There is one deployed first-party reference -> application. There is no measured scale and no third-party production use -> yet. Read the -> [delivery boundaries](#delivery-boundaries) before you use it for important -> data. - > **Not a replacement for SQL transactions:** when one row update inside one > transaction solves the problem, use that and install nothing. Solid Objects > earns its cost when the critical section outlives the transaction: a hold that @@ -56,6 +47,7 @@ contract. See [Solid Objects in the browser](#solid-objects-in-the-browser). - [Operations](#operations) - [Design provenance](#design-provenance) - [Documentation](#documentation) +- [Status](#status) - [License](#license) ## The programming model @@ -177,7 +169,7 @@ committed state are the same argument. Not worth it for a plain counter, a single-row update inside one transaction, a stateless job, bulk ingestion or a data-parallel pipeline, CPU-heavy work, a large JSON document that belongs in normalized rows, globally placed edge -state, or a global rate-limit counter that every request touches. One hot +state, or a rate-limit counter that every request touches. One hot identity is serialized on purpose, so making everything one identity makes a queue. Split an identity only when the domain can tolerate independent ordering and transactions. @@ -221,15 +213,26 @@ Durable Objects: | Multiplayer, presence, or collaboration | Room, session, or document | Joins, moves, and edits commit in order; subscribers refresh from committed state | | Reservations and expiring holds | Show, resource, or stock item | Availability checks and holds cannot interleave; a durable reminder can release an old hold | | Checkout and account workflows | Cart, order, account, device | The current step, retries, and effect results return to the same ordered mailbox | -| Per-key rate limits | API key, account, or device | Token checks and decrements are serialized; a reminder can refill the bucket | +| Quotas and expiring limits | API key, account, or device | Low-rate quota checks and decrements are serialized; a reminder can refill the bucket | | Stateful agent sessions | Agent session | Messages and tool results apply in order and pending work survives a worker exit | The common shape is one durable coordination boundary with an application defined identity. Work for that identity is serialized, while unrelated rooms, -carts, accounts, or sessions can progress concurrently. A single global rate -limiter or another very hot identity is a poor fit because it becomes an -intentional bottleneck. If one ordinary row transaction solves the problem, -prefer that. See [Choosing Solid Objects](docs/fit.md) for the longer guide. +carts, accounts, or sessions can progress concurrently. Any very hot identity is +a poor fit, because it becomes an intentional bottleneck. + +Two of those rows have a limit. A quota fits when one identity checks it a few +times per minute, because each check is one durable ordered message with a +retained history row. A limiter that every request to that identity touches +does not fit here. That high-QPS shape is what +[Solid Objects Pro](https://solidobjects.pro/) targets. + +A workflow fits when one entity owns the mutable state and its mailbox holds +the step order. A durable execution engine that replays named steps from a step +log is a different tool. + +If one ordinary row transaction solves the problem, prefer that. See +[Choosing Solid Objects](docs/fit.md) for the longer guide. ## Measured behavior @@ -540,6 +543,16 @@ TypeScript package in the deployed Node and SQLite topology above. - [Contributing](CONTRIBUTING.md) - [Security policy](SECURITY.md) +## Status + +**Early release:** the correctness core has automated coverage. That coverage +includes the supported databases, the Chromium browser client, the browser +runtime, process recovery, and the packaged artifacts. The TypeScript +implementation is still new. There is one deployed first-party reference +application. There is no measured scale and no third-party production use yet. +Read the [delivery boundaries](#delivery-boundaries) before you use it for +important data. + ## License Solid Objects is released under the [MIT License](MIT-LICENSE). diff --git a/docs/fit.md b/docs/fit.md index f7ce9ac..6b31f31 100644 --- a/docs/fit.md +++ b/docs/fit.md @@ -37,8 +37,16 @@ history, and no actor-state migration contract. identities. - Compute and state must be automatically placed close to clients at the edge. - The team wants a managed control plane to place, scale, and recover workers. +- A rate limiter sits on the request path, and every request touches the same + identity. A low-rate quota that a reminder refills is a different case and + fits, because each check is one durable ordered message. For the high-QPS + limiter, see [Solid Objects Pro](https://solidobjects.pro/): grouped commits + coalesce concurrent writes into one insert, and ephemeral operations keep + loss-tolerant calls out of the durable journal. It ships for the Rails gem + today, and the Node build is in development. - Durable workflow replay across named steps is more important than a mutable - object with ordered operations. + object with ordered operations. The runtime redelivers an ordered message and + retries it. It does not replay a function from a step log. ## Model identities deliberately