Skip to content

Day 5 (Rails slice): real Layer 2 via bin/rails routes#12

Merged
dadachi merged 1 commit intomainfrom
feat/day5-layer2-rails-routes
Apr 21, 2026
Merged

Day 5 (Rails slice): real Layer 2 via bin/rails routes#12
dadachi merged 1 commit intomainfrom
feat/day5-layer2-rails-routes

Conversation

@dadachi
Copy link
Copy Markdown
Contributor

@dadachi dadachi commented Apr 21, 2026

Summary

Fills the runLayer2 stub with a real implementation for Rails. Strategy: bin/rails routes boots Rails fully (loads gems, resolves the class graph, compiles routes) and exits. No server spawn, no DB churn, no background processes.

How it works

Three subprocess steps, each auto-wrapped with mise exec -- when mise is on PATH:

  1. bundle check — skip fast-path if gems satisfied
  2. bundle install — only if check fails (first run or Ruby version change)
  3. bin/rails routes — the Layer 2 assertion; exit 0 = pass

Why mise

Node's spawn doesn't trigger mise's directory-scoped Ruby auto-switching. Without mise exec, the subprocess inherits the agent's default Ruby — may not match the generated project's .ruby-version — and bundler hard-fails. With mise exec, mise reads the .ruby-version from the subprocess's cwd and resolves correctly. If mise isn't installed, the wrapper falls back to a direct command (agent logs still report what was actually run).

Type reshape

  • Layer2Input — dropped healthPath, added timeoutMs (default 5 minutes).
  • Layer2Result — dropped port and healthStatus (we're not booting a server). Added command, exitCode, durationMs. stderrTail is only emitted on failure.

Perf on clinic-queue (freshly generated, clean gem cache)

Scenario Duration
Cold (full bundle install) 23.6s
Warm (bundle check passes) 1.3s

Warm pace is demo-speed — well within the 20-second beat-5 budget.

Test plan

  • npm run ci — 5/5 green
  • Cold Layer 2 run against ./out/clinic-queue/railspass: true, exitCode: 0, 23.6s
  • Warm second run — pass: true, 1.3s
  • iOS + Android Layer 2 — separate PRs (needs xcodebuild + ./gradlew wrappers)
  • Wire Layer 2 into the judge sub-agent — judge currently stubs all three layers; real integration is the next PR

What's not in this PR

  • iOS Layer 2 — would use xcodebuild -scheme <Slug> -destination '...iPhone 17...' build (~60-90s fresh, faster on rebuild)
  • Android Layer 2 — would use ./gradlew assembleDebug (slow first run, fast on rebuild)
  • Judge integration — currently runJudge stub doesn't invoke runLayer1/2/3. Real integration involves passing domain.slug + worker outputs into the judge.

Fills the runLayer2 stub. Strategy: `bin/rails routes` boots Rails
fully (loads gems, resolves the class graph, compiles routes) and
exits. No server spawn, no DB churn, no background processes to
clean up — matches the spirit of "runtime check" without the
operational cost.

Three subprocess steps, each via `mise exec --` when mise is on
PATH (auto-detected):

  1. bundle check  — skip (fast path) if gems are satisfied
  2. bundle install — only runs when check fails (first-ever run
     or Ruby version change)
  3. bin/rails routes — the actual Layer 2 assertion; exit 0 = pass

mise wrapping is required because Node's spawn() doesn't trigger
mise's directory-scoped Ruby switching. Without `mise exec`, the
subprocess inherits the agent's default Ruby (may not match the
generated project's .ruby-version) and bundler hard-fails on the
mismatch. With `mise exec`, mise reads .ruby-version from cwd and
resolves correctly.

Perf on clinic-queue (freshly generated, clean gem cache):
  cold:  23.6s (full bundle install)
  warm:   1.3s (bundle check pass + routes)

Layer2Input + Layer2Result reshaped: dropped the port / healthStatus
fields (we're not booting a server) and added exitCode + command +
durationMs to report what actually ran. Updated smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dadachi dadachi merged commit 0a446d8 into main Apr 21, 2026
1 check passed
@dadachi dadachi deleted the feat/day5-layer2-rails-routes branch April 21, 2026 23:20
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