Roda on Spinel

thunderbong2 pts0 comments

Roda on Spinel

At RubyConf on Thursday I argued that there is no<br>server — that Rails is a<br>declarative spec, the compiler is the query planner, and the deployment<br>target is the execution plan. Afterwards, Jeremy Evans asked me the<br>question that keeps a thesis honest: could you do<br>Roda too?

It's the right question precisely because Roda is Rails' opposite number.<br>Rails is macros all the way down — has_many, validates,<br>resources — declarations a compiler can read off the page. Roda has no<br>routes file at all. Routing is a tree of plain Ruby: the request<br>threads down r.on and r.is matchers, interior nodes load state and<br>can abort the whole subtree, and the leaf that matches writes the<br>response. Sequel models validate in an ordinary def validate method<br>body. If Roundhouse's intermediate representation were secretly<br>Rails-shaped, this is where it would show: imperative Ruby that does<br>its work instead of declaring it.

So I asked Claude to write up an honest assessment, and posted it as<br>roundhouse#67. What<br>happened next is worth narrating, because the collaboration structure<br>mattered as much as the compiler work.

Jeremy keeps the oracle

Three weeks ago I wrote that maintaining the<br>oracle is the human job in<br>this way of working: extending the standard's coverage where it's blind,<br>deciding how it computes truth, overruling it when a passing artifact<br>should still die. In every episode so far, that keeper was me. The part<br>of this story I most want on the record is that here, it isn't. For this<br>spike, the keeper's seat belongs to Jeremy — he decides whether it<br>lives, dies, or needs to be tweaked — and each of the keeper's powers<br>got exercised by him, visibly, in the issue thread.

He extended the spec where it was blind. My assessment imagined<br>responses at the leaves of the routing tree; Jeremy pointed out they<br>return from any node — access-control checks abort whole subtrees — and<br>that interior nodes routinely set state their sub-branches share. The<br>exemplar we then built,<br>roda-sequel-blog, bakes<br>both seams in deliberately, an article-and-comments blog<br>domain-identical to the Rails fixture Roundhouse already compiles so the<br>two could be diffed through one pipeline.

He decided how correctness gets computed. His line-by-line review made<br>the exemplar more idiomatic and less Rails-shaped — set_fields with<br>an allow-list instead of strong-parameters cosplay, next unless @article = Article[id] as the interior abort, r.post true for path<br>termination. Where a choice existed between mirroring Rails and writing<br>what a Roda developer would actually write, we took the second on his<br>word — and that matters, because "idiomatic Roda" is precisely the kind<br>of behavior my earlier post flagged as the referenced oracle's edge:<br>there is no running system you can query for it. The reference here is a<br>person. Then the app grew an eighteen-check test suite of its own — the<br>full route surface, valid and invalid input, flash across redirects, the<br>hidden-_method form override, both 404 paths, HTML escaping — and that<br>suite became the contract: a transpiled version of this application<br>must pass it unchanged. The oracle was fixed, and blessed by the<br>framework's author, before the first line of compiler code existed.

And he holds the verdict. The plan — CRuby target first as the<br>correctness substrate, native binary second — got his sign-off before<br>anything was built, and the results now sit in the issue awaiting his<br>read. What I kept for myself is the other half of the earlier post's job<br>description: keeping a reachable target in front of the agent, one hold<br>at a time. The division turns out to be natural — the domain's author<br>keeps the standard; the project's owner keeps the route.

A few hours, wall clock

From the first<br>commit — the<br>vendored fixture and a mapping table — to the native binary was a few<br>elapsed hours, spread over a Monday morning. The routing tree linearized: each<br>root-to-leaf path through the matchers became one route, and the interior<br>next unless guard became a synthesized before-filter on both<br>controllers that needed it, with exactly the only: scoping the<br>equivalent Rails app declares by hand. Sequel's imperative validate<br>body turned out to be a closed vocabulary that reads as declarations.<br>The Sequel dataset spellings — Article[id], eager, with_pk —<br>normalized to the one query dialect the rest of the pipeline already<br>speaks. This is the first Futamura projection again, at smaller scale:<br>Roda's per-request walk down the routing tree is interpretation, and<br>specializing the app against static route structure makes the<br>interpreter disappear.

The transpiled app passes all eighteen checks — same runs, same seventy<br>assertions as the source app, both runs now CI gates. But the result I<br>was actually after was the diff. The two blogs are the same app in two<br>dialects, so their compiled forms should converge, and they do: of 130<br>lowered methods with shared names, 93 are byte-for-byte identical ,<br>and every one of the 37 that...

roda rails compiler jeremy keeps routing

Related Articles