Repin Rails releases to the August profile - #10
Conversation
The successor server contract advances its target, analyzer, and compiler identities together while retaining the sketch/0.19 Plan format. Keep newly initialized Plans and synthetic compilation fixtures aligned with that contract.
Technical reviewA twelve-line repin, so the review is mostly about whether it is complete and whether it targets something real. Both hold
The profile it repins to is genuinely landed rather than anticipated: firstdraft/firstdraft#250 is merged, and The repin is also complete. No The other The minimum-Node run is worth keeping in the habitThe body verifies on both the pinned 24.18.0 and the Same result on a Node 22 line. Testing the floor rather than only the pinned version is the thing most projects skip, and this repository has been consistent about it since #5. One thing to carry forward, not a findingThis is a hard swap. The CLI now writes and validates That is correct today, because there is no released CLI and no production data, so nothing exists that is pinned to the old identity. It is worth noting only because the same change made after release would strand every existing Plan: the client would refuse the identity its own earlier version wrote. I raised the server-side half of this on firstdraft/firstdraft#250, where a Project persisted with the old profile has no clean path forward. The client half is the mirror image. Whenever this pair does get released, the transition will want a window where both identities are accepted rather than a same-day cutover on both sides. Nothing to change in this PR. Recording it because a coordinated repin is exactly the moment the question is cheap to think about and expensive to discover later. |
Lesson: changing a value that two codebases shareThis pull request changes one string from The ordering problemTwo codebases agree on an identifier. The server writes it, the client validates it. You want to change it. There are two orders and both are wrong on their own: Client first. The CLI starts sending Server first. The server starts expecting The second is worse and it is the common one, because server deploys feel safer than client releases. What makes this PR safeTwo things, neither of which generalizes. The server side landed first, and the client repin references a merged commit rather than a hope. That is the right order for the first half. And critically, nothing is deployed. No released CLI exists, so there is no old client sending the old identity. No production Plans exist, so there is no stored data pinned to the old value. A hard swap is fine when the set of things that could break is empty. Verify that it is, rather than assuming. What you do when it is not emptyThe standard answer is to make the change in three deploys instead of one. It is usually called expand and contract, and the shape is always the same: Expand. Teach the reader to accept both. Deploy. Now the server handles ACCEPTED_PROFILES = ["rails-sketch/2026-07", "rails-sketch/2026-08"].freezeMigrate. Change the writer to emit the new value. Deploy. Backfill stored data. Old clients still work, because the reader still accepts their value. Contract. Once nothing emits the old value and nothing stored has it, drop it from the accepted set. Three deploys, and no window where a working client is refused. You have done this without naming it if you have ever renamed a database column safely: add the new one, write both, backfill, read from the new one, drop the old one. Same shape. The rule underneath is that a rename is a create, a migrate, and a delete, and they cannot be the same deploy. The bit people forget: stored data has a version tooDeploys are not the only thing that lags. Rows do. If a record was written with the old identity and nothing migrates it, that record is now unreadable by the new code, even after every client and server is upgraded. There is no deploy you can do to fix it, because the problem is in the data. So the contract step has two preconditions, not one: nothing emits the old value, and nothing stores it. The second usually needs a migration and is the one that gets skipped, because in development the database is small and gets rebuilt often. That is precisely the case I flagged on the server side of this change, where a Project written with the old profile has no path forward. It costs nothing to fix now and would be genuinely painful after release. The habitBefore changing a shared value, list what could still be carrying the old one:
If that list is empty, change it and move on, like this PR. If it is not, you want expand and contract, and you want the migration for stored values before you drop the old identity. The version string is easy. The things holding it are the work. |
Summary
rails-sketch/2026-08target profileBoundary
The Foundation Plan format remains
firstdraft.foundation-plan.sketch/0.19. This changes release identities only; it does not widen the CLI protocol or add iOS-specific commands.Verification
PATH="/Users/sandbox2/.asdf/shims:$PATH" npm run checkPart of firstdraft/firstdraft#133.