Skip to main content

Release & Adoption Plan — July 2026

Status: APPROVED & IN EXECUTION (decisions approved by @justin808 2026-07-04) Owner: @justin808

Execution log​

  • 2026-07-03: triage labels applied to all open issues/PRs.
  • 2026-07-04: R1 done (PR #210 merged). R2 done (PR #168 rebased as PR #219, merged; obsolete Rails 4.2 commit dropped). R5 done (GitHub Releases v1.16.0–v1.20.0 backfilled; repo now shows v1.20.0 as Latest). R3 in review (PR #225). All 7 close-candidates closed with pointers, plus #24 and #11 closed per decision. Every remaining open issue now carries an "Agent Implementation Spec" section. New task issues: #220 (M1 migration guide), #221 (M2 README), #222 (A1+A2 agent docs), #223 (A3 doctor), #224 (M3 outreach, gated).
  • Remaining for v1.21.0 (as recorded 2026-07-04; superseded by the next entry — the current 1.21.0 plan is section 7): merge PR #225, then a maintainer runs rake release[1.21.0] (RELEASING.md) and publishes the GitHub Release.
  • 2026-07-11: the release above shipped as v1.20.1 (patch number chosen by the maintainer; contents unchanged: #205, #207, #210, #219). Every task gated on "after v1.21.0 ships" (#226, #228, #224, #197, #209) was treated as gate-satisfied from this date. (Superseded by the 2026-09-03 entry, which renumbered 1.21.0: only #226 is in flight on that basis. Section 7 re-gates #228, #224, #197 and #209 to the renumbered 1.21.0, so the repo rename and the outreach comment must not start until that release ships.) PR #243 later landed #185 delivery 1.
  • 2026-09-03: release triage. PR #191 closed as superseded (release task already reworked on master), #155 closed per its auto-close disposition, #241 root cause recorded (missing DOCS_DISPATCH_APP_ID/DOCS_DISPATCH_APP_KEY secrets), PR #249 adds the missing #243 changelog entry, and wave 1 of the next release started as one coordinated batch: #185 remaining deliverables, #13 security default, #226 alias gem. Release plan in section 7.

Decisions (2026-07-04, @justin808)​

  1. v1.21.0 scope and R1/R2 merge order — approved, executed.
  2. Seven close-candidates — approved, closed.
  3. #24 (gem split) and #11 (rename) — closed.
  4. Naming & docs site — RESOLVED 2026-07-04, twice refined (ADR-0001 → ADR-0002): public brand is E2E on Rails; e2eonrails.com purchased and canonical (supersedes testing.shakastack.com); repo renames to shakacode/e2e-on-rails right after v1.21.0 ships; e2e_on_rails wrapper now (#226); the gem flip is 2.0, scheduled right after the v1.22 line. Full rationale: docs/roadmap/2026-07-e2e-on-rails-naming-decision.md.
  5. Outreach (M3) — approved in principle; post only after v1.21.0 + hardening (#185) + migration guide (#220) ship. Draft lives in #224.
  6. #191/#193 (release task, RuboCop) — after v1.21.0.

Audience: maintainers and coding agents. Every task below is written to be implementable by an agent without additional context. Facts were verified on 2026-07-03; re-verify anything marked VERIFY before acting on it.


1. Current state (verified 2026-07-03)​

FactValue
Gem namecypress-on-rails (repo renamed to cypress-playwright-on-rails)
Latest RubyGems release1.20.0 (2025-10-21)
Lifetime downloads6,412,456
GitHub stars / forks453 / 61
Latest GitHub Releasev1.15.0 (2023-07-05) — 5 versions behind RubyGems
Unreleased commits on master7 (notably Rails 8.1 compat fix #207, generator whitespace fix #205)
Open issues / PRs21 / 6 (all triage-labeled as of 2026-07-03)

The competitive moment (why now)​

testdouble/cypress-rails is effectively dormant:

  • Last commit to main: 2024-09-06 (v0.7.1). Last maintainer activity of any kind: Nov 2024.
  • Broken on Rails 7.2+ (testdouble/cypress-rails#164, 31 comments): ConnectionPool#lock_thread= was removed in Rails 7.2. The only fix is 0.8.0.rc1, which was never finalized and causes state-reset failures / Puma hangs for some users. Users are on personal forks or stuck.
  • 1.19M lifetime downloads (0.8.0.rc1 alone has 189k — an active, stranded CI user base).
  • No Playwright support, none planned. Justin Searls publicly moved to Playwright for Rails browser testing (justin.searls.co, June 2024).

cypress-on-rails v1.19.0 already shipped the parity features those users would need: cypress:open/cypress:run rake tasks, automatic server start/stop, before_server_start/after_server_start/after_transaction_start/after_state_reset/before_server_stop hooks, transactional test mode, the /cypress_rails_reset_state endpoint, and CYPRESS_RAILS_HOST/CYPRESS_RAILS_PORT env vars. What's missing is hardening (issue #185), a migration guide, and marketing.

⚠️ Strategic caveat: cypress-rails died from a fragile transactional-server implementation under multi-threaded Puma. Our equivalent (merged in v1.19.0 via PR #179) has known robustness gaps tracked in #185 and #186. Harden before marketing the migration path — attracting refugees onto a launcher that hangs would repeat the failure we're recruiting from.

ShakaStack fit (from shakastack.com research)​

  • shakastack.com pitches "Ship modern React in Rails — fast, and prove it" (Build → Deploy → Prove) and claims "the most agent-capable stack". The Prove phase currently only covers performance (ShakaPerf). E2E correctness — this gem — is absent from shakastack.com and shakacode.com.
  • react_on_rails already dogfoods this gem (its dummy-app E2E suite runs Playwright via cypress-on-rails: react_on_rails/spec/dummy/e2e/README.md) — an untold story.
  • Ecosystem conventions this repo doesn't yet follow: AGENTS.md (contributor agents) + AGENTS_USER_GUIDE.md (users' agents) + llms.txt (react_on_rails has all three), a doctor diagnostic task (react_on_rails/shakapacker have one), a brief top-level README with docs links (ours is 821 lines with the consulting block above the fold).

2. Triage results (labels applied 2026-07-03)​

New labels created: documentation, security, needs-info, close-candidate, needs-rebase, needs-decision, priority: high, priority: medium, priority: low, agent-ready, cypress-rails-parity, ci-infra.

PRStateAction
#210 Don't override RAILS_ENVApproved, CI green, mergeableMerge now. Ships in v1.21.0
#168 Playwright response.json() fixApproved but conflicting, +6/−3Rebase, re-run CI, merge. Ships in v1.21.0 (task R3)
#213 Claude workflowConflicting; superseded by merged #211/#212/#214/#215Close as superseded
#193 RuboCopChanges requested, largeKeep; land after v1.21.0 to avoid churn (issue #197 tracks follow-ups)
#191 Release task conflictConflicting, CI red, changes requestedRebase or close/redo small; only touch alongside the release (task R6)
#173 README: run server in test envConflicting; overlaps #210 and #157Decide docs stance on test-env (task M4), then rebase or close

Issues — close candidates (resolved by shipped releases or stale)​

IssueWhy closableClose message should point to
#152 Auto-start rails serverShipped in v1.19.0 (rake tasks + managed server)CHANGELOG 1.19.0, docs/
#153 Initialization hooksShipped in v1.19.0 (all 5 hooks it asked for)CHANGELOG 1.19.0
#112 Integration tests Rails 6/7CI now covers Rails 6.1–8.x example apps; Rails 4/5 dropped in 1.18.0.github/workflows/ruby.yml
#92 Stub outgoing requestsVCR middleware shipped in 1.18.0 covers thisdocs/VCR_GUIDE.md
#183 v1.19.0 release discussionRelease shipped 2025-10-01—
#146 Webpack compilation errorStale (2023), Cypress-side config, no repro—
PR #213Superseded (see above)merged #211–#215

Agent instruction: when closing, post a comment naming the release that resolved it and the doc to read; invite reopening if the shipped feature doesn't cover the reporter's case. Do not close silently.

Issues — keep open, prioritized​

PriorityIssueNotes
high#185 server/state-reset hardeningPrerequisite for migration campaign (task H1)
high#13 RCE mitigation / middleware securityLong-standing adoption blocker; see task H3
medium#186 follow-ups from PR #180 reviewSmall, agent-ready
medium#114 transactional fixturesPartially addressed by v1.19 transactional mode; remaining: document + benchmark vs database_cleaner
medium#157 test-env reloadingDocs task M4; related to merged #210
medium#78 TypeScript typingsagent-ready, task A4
medium#80 Devise login helper, #81 ActionMailer email viewingGood v1.22+ features, agent-ready
low#113 split experimental options, #197 RuboCop staging, #209 LefthookHousekeeping
needs-info#175 VCR route 404, #155 MySQL errorAsk for repro; auto-close in 30 days if silent
needs-decision#24 gem split (2019), #11 gem rename (2019)Maintainer decision; recommend closing both as "won't do — stability is the brand"

3. Release plan​

v1.21.0 — "current & compatible" (superseded 2026-09-03)​

Superseded for the 1.21.0 line by section 7, which is the authoritative plan; this block is kept as the July 2026 plan of record. Its contents shipped as v1.20.1 on 2026-07-11, so the 1.21.0 in section 7 is a different, renumbered release — release it from section 7, never from the tasks below.

Goal: flush 9 months of unreleased fixes, restore release hygiene, signal active maintenance to anyone comparing us with cypress-rails.

Contents: Rails 8.1 compat (#207), generator whitespace (#205), PR #210 (RAILS_ENV respected), PR #168 (Playwright JSON response fix).

Tasks (each independently implementable; IDs referenced below):

  • R1 — Merge PR #210. ✅ DONE 2026-07-04.
  • R2 — Rebase + merge PR #168. ✅ DONE 2026-07-04 as PR #219 (fork rejected maintainer push; obsolete Rails 4.2 Gemfile commit dropped).
  • R3 — CHANGELOG pass. ✅ DONE 2026-07-04 (PR #225): #201/#203 entry moved under ## [1.20.0]; Unreleased now lists #205, #207, #210, #219.
  • R4 — Release. ✅ DONE 2026-07-11 — shipped as v1.20.1, not 1.21.0 (patch number chosen by the maintainer; contents unchanged). The renumbered 1.21.0 release runs from section 7's maintainer steps, not from here.
  • R5 — Backfill GitHub Releases. ✅ DONE 2026-07-04 for v1.16.0–v1.20.0; repo now shows v1.20.0 as Latest (was v1.15.0 · 2023). v1.20.1's release was created as part of R4.
  • R6 — Fix the release task (PR #191's goal). ✅ RESOLVED 2026-09-03: R4 did not hit the duplicate-task conflict and #191 was closed as superseded (the release task was already reworked on master).

v1.22.0 — "the cypress-rails magnet" (superseded 2026-09-03)​

Superseded for scope by section 7, which is authoritative for what ships when: H1–H3 and M1/M2/M4 were pulled forward into the 1.21.0 waves. Read the tasks below as the specs they always were, not as a v1.22 work list — each one now records where it actually landed.

Theme: harden the server/transactional path, then actively convert cypress-rails users.

  • H1 (issue #185) — server & state-reset hardening. (→ 1.21.0 wave 1.) priority: high. Scope from the issue: spawn-failure error handling, SIGTERM→SIGKILL escalation with timeout, port-detection retry, process-group cleanup, and tests for lib/cypress_on_rails/server.rb + lib/cypress_on_rails/state_reset_middleware.rb. Acceptance: new specs covering each failure mode; multi-threaded Puma smoke test in one example app (this is the exact failure mode that killed cypress-rails — see testdouble/cypress-rails#164).
  • H2 (issue #186) — PR #180 review follow-ups. (→ 1.21.0 wave 2.) Small.
  • H3 (issue #13) — security hardening. (→ 1.21.0 wave 1.) ⚠️ Two verified facts constrain the design (2026-07-05 review): (1) the gem's own default is unsafe — Configuration#reset sets use_middleware = true unconditionally; the !Rails.env.production? guard exists only in the generated initializer template, so apps configured by hand get the middleware in every environment. Fixing that library default is part of H3. (2) An auth hook already exists: before_request runs at the top of Middleware#handle_command, the generated initializer shows a 403 example, and README §"Authenticate CypressOnRails" documents secret-token auth with it. H3 must first evaluate hardening/documenting before_request (or building middleware_token as thin sugar over it) rather than shipping a second, overlapping auth mechanism. Full spec in issue #13.
  • M1 — docs/MIGRATE_FROM_CYPRESS_RAILS.md. (→ 1.21.0 wave 2, #220.) The centerpiece. Structure:
    1. Why (dormant since 2024, Rails 7.2+ broken, no Playwright — with links);
    2. Concept map table (their env vars/hooks/reset endpoint → ours; most map 1:1 since v1.19.0);
    3. Step-by-step swap (Gemfile, generator, initializer);
    4. What you gain (factories from JS, appEval, scenarios, VCR, Playwright);
    5. Honest trade-offs (middleware security model + mitigation from H3). Acceptance: a real cypress-rails example app converted by following only the guide, committed under specs_e2e/ as a CI job if practical.
  • M2 — README repositioning. (→ 1.21.0 wave 3, optional; issue #221.) Add "Migrating from cypress-rails" link near the top; add a short comparison table; move the ShakaCode consulting block below the fold (match current react_on_rails/shakapacker style); add badges (gem version, downloads, CI).
  • M3 — Outreach (human, not agent): (→ post-release, not in the gem; issue #224.) ShakaCode blog post ("cypress-rails is stuck on Rails 7.1 — here's the maintained path, with Playwright"), a respectful comment on testdouble/cypress-rails#164 pointing to M1, Reddit/r/rails + Rails Discord, changelog.com pitch.
  • M4 — Test-env docs (issue #157, PRs #173/#210). (→ 1.21.0 wave 2.) Document the two supported modes (dev-env with ENV['CYPRESS'] vs test-env with code reloading enabled) in README + docs/; then close #157 and resolve #173.

v1.23.0 — "agent-native E2E" (target: +2–3 months)​

Theme: make this the E2E layer AI agents reach for — aligned with ShakaStack's "most agent-capable stack" claim. E2E-with-app-state-control is uniquely agent-friendly: an agent can seed state via app_commands, run one spec headlessly, and get a deterministic pass/fail without clicking around.

  • A1 — AGENTS.md (contributor-facing; mirror react_on_rails/AGENTS.md structure; reuse shakacode/agent-workflows seams).
  • A2 — AGENTS_USER_GUIDE.md + llms.txt (user-facing: how an agent in a host app should install, generate, seed state, run one test headlessly, interpret failures; publish llms.txt wherever docs land per S2).
  • A3 — rails g cypress_on_rails:doctor or rake cypress_on_rails:doctor. Checks: middleware mounted? install_folder exists & matches config? VCR middleware on if vcr commands present (would have prevented issue #175)? server bootable? Print actionable fixes. Convention match: react_on_rails doctor / shakapacker doctor.
  • A4 (issue #78) — TypeScript declarations for cy.app* commands, shipped via generator or @types/-style package. agent-ready.
  • A5 — machine-readable failure output. Ensure middleware errors return structured JSON (error class, message, backtrace head) so agents can self-correct; document in A2.
  • Candidates from backlog as capacity allows: #80 (devise helper), #81 (mailer deliveries endpoint), #114 (document/benchmark transactional mode vs database_cleaner).

4. ShakaStack integration (parallel track, mostly non-repo work)​

  • S1 — shakastack.com: add cypress-playwright-on-rails as a Projects card and extend "Prove" to two legs: prove it's fast (ShakaPerf) + prove it works (this gem). Owner: whoever edits shakastack.com (site repo UNKNOWN — locate first).
  • S2 — docs site (DECIDED 2026-07-04, ADR-0002): publish to e2eonrails.com (purchased; apex is docs + landing, no docs. subdomain, no defensive domain variants). IA from the naming doc: /getting-started, /cypress, /playwright, /factory-bot, /fixtures, /scenarios, /app-commands, /migration/from-cypress-on-rails. Stand it up once #221 (README/docs split) lands; publish llms.txt (#222) there.
  • S3 — cross-promotion: react_on_rails already uses this gem for its E2E suite — write that up (blog or docs page "How React on Rails tests itself with Playwright"), link from react_on_rails docs and AGENTS_USER_GUIDE.
  • S4 — naming (DECIDED 2026-07-04, ADR-0001 + ADR-0002; #11/#24 closed): public brand E2E on Rails ("The Rails test bridge for Cypress and Playwright"). Sequence: v1.21.0 releases under the current names → repo renames to shakacode/e2e-on-rails + README hero rebrand → v1.22 campaign runs under the new brand with gem 'cypress-on-rails' still the install → 2.0 = the gem flip (e2e_on_rails canonical, cypress-on-rails shim, module E2eOnRails), scheduled right after v1.22. Scope note (2026-09-03): M1/M2/M4 moved into 1.21.0, so the doc work ships before the rename; what runs under the new brand is the M3 outreach (#224), not the docs. See docs/roadmap/2026-07-e2e-on-rails-naming-decision.md, ADR-0002, and CONTEXT.md.

5. Open decisions​

All six original decision points were resolved on 2026-07-04 (see the Decisions section at the top of this document). Still genuinely open:

  1. Final sign-off on the M3 outreach comment text before posting (draft in issue #224; gated on v1.21.0 + #185 + #220 shipping).

6. Suggested agent execution order (superseded 2026-09-03)​

Superseded for the 1.21.0 line by section 7 below, which is the authoritative order; this block is kept as the July 2026 plan of record.

R4(human release) # only v1.21.0 step left
repo rename + README hero (post-v1.21.0, ADR-0002)
#226 alias gem → H1 → H2 → H3 → M1 → M2 → M4 # v1.22: hardening before marketing
2.0 flip (right after v1.22): e2e_on_rails canonical, cypress-on-rails shim
A1 → A2 → A3 → A4 → A5 # agent-native layer (issues #222/#223/#78)
S1–S3 in parallel (site/marketing, human-led); docs site = e2eonrails.com

Every task above states its issue/PR, files, and acceptance criteria; tasks labeled agent-ready on GitHub carry the same contract. When in doubt: small PRs, bundle exec rubocop clean, CHANGELOG entry per user-visible change, files end with newline.


7. Release plan: 1.21.0 (added 2026-09-03)​

Theme: the "cypress-rails magnet" line from section 3, renumbered because v1.20.1 consumed the v1.21.0 slot. Ship it as 1.21.0 (minor: new middleware_token, server_shutdown_timeout, and the alias gem; the use_middleware default change is documented as a behaviour change).

Scope, in merge order​

Every PR in every wave passes the repository review gate from .agents/agent-workflow.yml (green Ruby workflow on the PR, local bundle exec rake evidence, all review threads resolved). The column below lists what is required in addition.

WaveTargetsAdditional gate before merge
1 (running)#185 remaining, #13, #226QA evidence per PR; maintainer risk decision for security/runtime/release-surface PRs
2#220 migration guide, #186 follow-ups, #157 environments doc, #175 VCR docs, #244 streaming guide (also exercises #241)#185 merged first for #186/#220; docs secrets configured so trigger-docs-site can succeed
3 (optional for 1.21.0)#114 state-management doc, #221 README splitstandard gate only

Post-release, not in the gem: #228 repo rename (in-place, maintainer click), the #224 outreach comment, and the PR #193 RuboCop rebase (then #197, #209).

Maintainer steps, in order​

  1. Add repository secrets DOCS_DISPATCH_APP_ID and DOCS_DISPATCH_APP_KEY (GitHub App installed on shakacode/e2eonrails-com with Contents: write) so docs merges publish. Verify with the next docs/** merge (#241).
  2. Post autonomous-merge-risk-decision:v1 comments on the wave-1 PRs that the eligibility gate flags for human review (the coordinator supplies the exact envelope per PR head). Neither that envelope nor the gate is defined in this repo; both live in the private coordination backend named in .agents/agent-workflow.yml.
  3. Decide wave 3 before stamping: either take #114/#221 into 1.21.0 or defer them to the next release. After every wave included in 1.21.0 has merged — waves 1 and 2, plus wave 3 when it is included: /update-changelog release PR, then merge it. Nothing user-visible may merge between that PR and the release, or its entry lands under the new Unreleased section instead of ## [1.21.0].
  4. Immediately before releasing, re-verify that e2e_on_rails is still unclaimed on RubyGems, as ADR-0001 requires for the first publish. Check ownership, not the search index: gem owner e2e_on_rails must report that the gem does not exist. A name whose versions were all yanked is absent from gem search -r -e output yet still belongs to its original owners. If the name has been taken, stop and decide the fallback name before running the release.
  5. From clean master: bundle exec rake "release[,true]" (dry run shows both gems once #226 lands), then bundle exec rake release.
  6. First publish of e2e_on_rails: the release task pushes it after the main gem; if that first push needs RubyGems ownership setup, run gem push alias_gem/pkg/e2e_on_rails-1.21.0.gem manually once, then bundle exec rake "sync_github_release[1.21.0]". The release task only syncs the GitHub Release after publishing returns cleanly, so a failure recovered by hand skips that step; do not rerun rake release once the tag exists.
  7. Then #228: rename the repo in place and open the URL-sweep PR.

Definition of done for 1.21.0​

  • CHANGELOG ## [1.21.0] lists #243, #185 follow-ups, #13, #226, and every user-visible doc from each included wave with [PR N] credit links.
  • rake release dry run green; tag v1.21.0 on RubyGems with both gems.
  • GitHub Release notes synced from the changelog section.
  • README security section and migration guide published at e2eonrails.com — only if wave 3 is included, since S2 stands the site up once #221 lands. The #220 migration guide markdown ships in wave 2 either way.