Skip to content

Repin Rails releases to the August profile - #10

Merged
raghubetina merged 1 commit into
mainfrom
codex/rails-profile-202608
Jul 31, 2026
Merged

Repin Rails releases to the August profile#10
raghubetina merged 1 commit into
mainfrom
codex/rails-profile-202608

Conversation

@raghubetina

Copy link
Copy Markdown
Contributor

Summary

  • initialize new Plans against the landed rails-sketch/2026-08 target profile
  • validate August analyzer, compiler, and target provenance in compilation responses
  • keep the package smoke server aligned with the successor server contract

Boundary

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 check
  • type checking, ESLint, and Prettier passed
  • 111 tests passed on pinned Node 24.18.0
  • package-content check and packed-package HTTP smoke passed
PATH="/Users/sandbox2/.asdf/shims:$PATH" ASDF_NODEJS_VERSION=22.0.0 npm test
  • 111 tests passed on the minimum supported Node 22.0.0

Part of firstdraft/firstdraft#133.

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.
@raghubetina

Copy link
Copy Markdown
Contributor Author

Technical review

A twelve-line repin, so the review is mostly about whether it is complete and whether it targets something real.

Both hold

npm run check exits 0 with 111 tests, matching the body.

The profile it repins to is genuinely landed rather than anticipated: firstdraft/firstdraft#250 is merged, and rails-sketch/2026-08 is present on that repository's main. Repinning a client to a server identity that has not shipped is the usual way this goes wrong, and it did not happen here.

The repin is also complete. No rails-sketch/2026-07 remains anywhere in the tree, and all five surviving references are 2026-08:

5 rails-sketch/2026-08

The other 2026-07 strings a naive search turns up are test timestamps like 2026-07-30T12:00:00.000Z, which are unrelated fixture dates.

The minimum-Node run is worth keeping in the habit

The body verifies on both the pinned 24.18.0 and the engines floor. I could not reproduce the exact 22.0.0 build, which is not installed here, so I ran the suite on 22.14.0 instead:

# tests 111
# pass 111
# fail 0

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 finding

This is a hard swap. The CLI now writes and validates 2026-08 and no longer recognises 2026-07 at all.

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.

@raghubetina

Copy link
Copy Markdown
Contributor Author

Lesson: changing a value that two codebases share

This pull request changes one string from rails-sketch/2026-07 to rails-sketch/2026-08 in five places. Twelve lines. It is also the kind of change that takes production down, so it is worth understanding why this one is safe and when the same change is not.

The ordering problem

Two 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 2026-08. The server does not know that identity yet and rejects everything. Broken until the server ships.

Server first. The server starts expecting 2026-08. The old CLI is still sending 2026-07. Broken until every user upgrades, which for a CLI is never, because you do not control when people run npm update.

The second is worse and it is the common one, because server deploys feel safer than client releases.

What makes this PR safe

Two 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 empty

The 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 2026-07 and 2026-08.

ACCEPTED_PROFILES = ["rails-sketch/2026-07", "rails-sketch/2026-08"].freeze

Migrate. 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 too

Deploys 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 habit

Before changing a shared value, list what could still be carrying the old one:

  • deployed servers
  • installed clients you do not control
  • rows in your database
  • cached payloads, queued jobs, signed tokens
  • other teams' code you forgot depends on you

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.

@raghubetina
raghubetina merged commit 121272c into main Jul 31, 2026
4 checks passed
@raghubetina
raghubetina deleted the codex/rails-profile-202608 branch July 31, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant