Skip to content

test(conformance): reference-app RUN-conformance harness for web apps#103

Merged
tannevaled merged 5 commits into
mainfrom
conformance/webapp
Jul 2, 2026
Merged

test(conformance): reference-app RUN-conformance harness for web apps#103
tannevaled merged 5 commits into
mainfrom
conformance/webapp

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

What

A reference-app RUN-conformance harness for rbgo — the proof that the embedded interpreter can actually run real Ruby web apps end-to-end (run, not merely parse). It drives the Rack call(env) contract directly with a synthetic Rack environment (no TCP socket, no network), so it exercises routing → handler → model → view → response entirely through the pure-Go VM.

scripts/conformance/webapp/ stages real .rb apps through the public ruby.Run API and asserts the deterministic response each app prints.

Staged results

Stage App Result
1 Pure Rack lambda ->(env){[200,…,["hello #{PATH_INFO}"]]} GREENhello /x
2 Rack + ERB view (require "erb", ERB.new(…).result(binding)) GREEN — rendered HTML
3 Sinatra DSL (require "sinatra/base", get('/hi'){…}) GAPLoadError: cannot load such file -- sinatra/base
4 sqlite3 + ERB/JSON data route (in-memory seed → query → render) GREEN — HTML + JSON
4b ActiveRecord ORM data route GAPLoadError: cannot load such file -- active_record (PR #102 / bind/batch7)

A data-backed route is servable through rbgo today via the raw sqlite3 binding (stage 4): an in-memory SQLite DB seeded, queried per request, and rendered as both HTML (ERB) and JSON. The idiomatic ActiveRecord ORM form (stage 4b) is the only piece still missing, pending the go-ruby-activerecord binding.

Gap list for full Sinatra/Rack run-conformance

  • Sinatra — no sinatra/base: need a go-ruby-sinatra binding (Sinatra::Base, the get/post class-DSL, params, and the Rack #call adapter).
  • ActiveRecord — no active_record: the go-ruby-activerecord binding (PR Bind go-ruby-grape, go-ruby-rubocop, go-ruby-xslt and go-ruby-activerecord into rbgo as native modules #102) supplies ActiveRecord::Base / establish_connection / Schema.define / query interface; stage 4b flips to a hard assertion automatically once it lands.
  • require "rack" itself is a LoadError (rack is not a provided feature); the harness deliberately does not need it — the Rack contract is exercised in plain Ruby.

Design

  • Self-updating: the Sinatra and ActiveRecord stages feature-detect the require first — they assert the real response when the binding is present and otherwise record the exact missing feature and t.Skip. The suite is green today and lights up automatically when a binding lands.
  • Test-only package: no new production code, so the 100%-coverage gate (coverpkg=./internal/...) is unaffected.
  • CI-safe on all targets: apps embedded via go:embed (CWD-independent under the coverage job, on Windows, and under qemu on every 64-bit arch); deterministic and TZ-independent. gofmt/go vet clean; full vm suite green under TZ=UTC.

Do not merge — this is an exploratory baseline for review.

🤖 Generated with Claude Code

tannevaled and others added 5 commits July 2, 2026 23:12
…apps

Prove rbgo can *run* real Ruby web apps end-to-end (run, not just parse) by
driving the Rack call(env) contract directly with a synthetic Rack env — no
TCP socket, no network. scripts/conformance/webapp/ stages real .rb apps
through the public ruby.Run API and asserts the deterministic response:

  Stage 1  Pure Rack lambda                     -> GREEN
  Stage 2  Rack + ERB view                      -> GREEN
  Stage 3  Sinatra DSL (require sinatra/base)   -> GAP (no sinatra binding)
  Stage 4  sqlite3 + ERB/JSON data route        -> GREEN
  Stage 4b ActiveRecord ORM data route          -> GAP (go-ruby-activerecord, PR #102)

A data-backed route (in-memory sqlite3 seed + query + ERB/JSON render) is
servable through rbgo today via the raw sqlite3 binding (stage 4). The Sinatra
and ActiveRecord stages feature-detect the require: they assert the real
response when the binding is present and otherwise record the exact missing
feature, so the suite stays green now and lights up automatically when the
binding lands.

Test-only package: no new production code, so the 100%-coverage gate
(coverpkg=./internal/...) is unaffected. Apps embedded via go:embed so the
suite is CWD-independent under the coverage job, on Windows, and under qemu on
every 64-bit target. Deterministic and TZ-independent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…require

PR #102 landed the go-ruby-activerecord binding on main, so
`require "active_record"` now succeeds — but the binding does not yet implement
`ActiveRecord::Schema.define`, so stage 4b's route hard-failed with
`NoMethodError: undefined method 'define' for Module`.

Feature-detect the specific ORM capability the route uses, mirroring the
skip-until-present pattern of the Sinatra stage: a Ruby probe runs the exact
chain (establish_connection + Schema.define + create! + where(...).order.to_a)
inside a rescue and reports "READY" only when it all runs clean, else
"GAP: <ExceptionClass>: <message>". Stage 4b skips-with-gap when the ORM path is
incomplete and flips to a hard assertion automatically once the binding gains
the methods.

Recorded gap: NoMethodError: undefined method 'define' for Module
(ActiveRecord::Schema lacks .define).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled tannevaled merged commit 506e461 into main Jul 2, 2026
9 checks passed
@tannevaled tannevaled deleted the conformance/webapp branch July 2, 2026 22:08
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