Rails Core composition
Status: Implemented for the pinned Rails Core and the bounded Capabilities and Domain the Compiler emits.
Every generated Rails application starts from one pinned Foundation Rails Core archive. The Compiler loads that
archive as values, adds renderer output for the selected Capabilities and Domain, and checks path ownership before
anything is written. Core paths are immutable unless an explicit registry transfers one path to one named renderer.
A dependency plan projects one complete Gemfile and Gemfile.lock from a qualified universe without network
access. The Compiler also writes the application's README, AGENTS, and UI documents, substitutes the application
identity into Core's configuration, and verifies that no reusable-Core identity token remains. The
Rails target profile states the Core, Capabilities, and Domain concept, and the
Compiler owner owns rendering and packaging.
On this page
- Core pin
- Dev Container
- Path ownership
- Dependency projection
- Application documents
- Identity and configuration
Core pin
The prototype bundles the current Rails Core pin (repository-only) as a
deterministic compressed Git archive. The only released tag, v0.1.0, predates material fixes, so this is recorded as
an exact revision rather than a release.
In pre-alpha mode, a Core repin may repair the current target profile's constant, route, and inflection census in
place only after complete local re-extraction and review of the active-pin surfaces. The
machine reference (repository-only) names that profile.
Cross-platform hosted reproduction on both profile platforms is the landing gate. The dangerous-attribute registry was
re-extracted from Core 9181b05043977f95fb1ead1012a2b1478363eb67 for the September 16 naming correction and
reproduced locally and in hosted CI. No retained-Project
migration or coexistence machinery is added; a profile repair starts a new Project or an explicit fork. A later
package update should move the same loading boundary to a verified Core release asset.
Moving the pin is an explicit maintenance operation. It verifies the archive digest, embedded revision, root,
regular-file count, uncompressed bytes, and lockfile digest; regenerates the maximal dependency universe when Core
inputs change; refreshes exact output characterizations; and reruns current-pin profile compatibility and
generated-app qualification. Review changed Core commands, dependencies, and UI APIs against the complete
application README, AGENTS, and UI templates so their operating guidance stays accurate. Reconcile relevant facts;
those templates need not copy Core's contributor prose. A repin removes the superseded archive and dependency pairs
unless code, tests, or a frozen profile name them; Git history keeps their bytes. User compilations remain
network-free. The loader
verifies the compressed-byte SHA-256 and Git
revision in the global PAX header before it exposes file values. It accepts regular files and directories, rejects
links and special entries, strips one required root, reduces Git's executable bit to 0644 or 0755, and passes
the complete file set through OutputManifest.
The profile workflow automatically compares every changed active archive with the frozen compatible surfaces on
arm64 Darwin and x86-64 Linux through script/verify_rails_target_profile_compatibility. The default Actions token
cannot read the private sibling Core repository, so script/release check reads Core main through gh on the
release operator's machine instead. When the pin lags, it warns and lists the missing commits. Merging a Core pull
request approves adopting it in the next Compiler release unless the pull request is labeled for separate approval;
see owner sign-off (repository-only).
Dev Container
The generated Dev Container selects PostgreSQL client 18 to match its PostgreSQL 18 service. It omits the unused Active Storage media feature; applications adding image variants or previews choose and install their processor. The Dev Container adoption (repository-only) records the exact package and qualification boundary. That adoption changed the Compiler release while retaining its Plan, API, Analyzer, and target profile.
Path ownership
All Core paths are immutable by default. CorePathRegistry contains only explicit path-to-renderer ownership
transfers. A registered replacement is required from that exact renderer owner; an absent replacement, a different
claimant, or any undeclared collision fails. The default registry transfers nine paths. Five concrete renderers own
config/application.rb, config/database.yml, config/locales/en.yml, render.yaml, and README.md;
application-document renderers own AGENTS.md and UI.md; the schema renderer owns db/schema.rb; and the
application-global renderer owns app/controllers/application_controller.rb. The active application plan adds the
Domain-routes and main-navigation Web transfers that Web files and routes
describes, plus unconditional Gemfile and Gemfile.lock transfers to their separate generic renderers. Account
qualification changes dependency-plan and ApplicationController content without changing global file ownership. It
also changes the generic Domain-routes and main-navigation outputs through shared semantic evidence. The Account-self
renderer owns only app/controllers/accounts_controller.rb, app/views/accounts/show.html.erb, and its locale. The
Web families do not claim Core's application layout. Core retains the layout and responsive navigation. The task plan
preflights every selected task-backed transfer, and CoreComposer enforces the planned owner during composition.
Dependency projection
RailsDependencyPlan receives the complete sealed Project, exact compilation input, and base rendering context.
Each selected contributor supplies one internal immutable identifier, direct-requirement set, complete Gemfile block,
prerequisite list, and source identities. Policy requires Account. The planner orders contributors, rejects duplicate
or conflicting claims, coalesces shared identical requirements, and checks every contributor against its digest-gated
universe entry, including its prerequisite list. Every contributed requirement must also be a direct dependency of
the maximal lock, not merely a reachable specification. Account, Normalization, Policy, and State Machine are the
current entries. Normalization contributes pinned strip_attributes only when an emitted Field requests trim.
This is a linear contributor registry, not a table of contributor combinations.
The empty selection returns Core's exact Gemfile and Gemfile.lock without starting the projector. A nonempty
selection inserts the qualified blocks once into the exact Core Gemfile. It starts one isolated service-Ruby 4.0.6
subprocess with only the checked-in Bundler 4.0.10 package, an empty Bundler configuration, fixed locale and time,
private home and temporary directories, and an explicit environment allowlist. Bundler runs lock --local --print;
Compilation inherits no proxy, Bundler, Ruby, credential, or ambient gem paths and has no resolution route to the
network.
The lock verifier parses Core, the maximal universe, and the candidate. It requires exact direct dependencies,
remote, platforms, Bundler version, reachable specifications, and checksums. ApplicationTaskPlan retains the one
result in its derived rendering context. The two dependency renderers only emit that retained pair. Six baseline
snapshots retain the previous lockfile bytes and compose Gemfiles against the selected Core. A focused regression
projects the six additional normalization-bearing selections and verifies that only strip_attributes is added.
The standalone qualifier checks seven pairs, including the maximal universe, twice under hostile parent settings.
Production selection consults no overlay contract or bytes.
The maximal universe is an upper bound for the current contributor registry, not a permanent gem census. Adding Money, Position, or Counter contributors under Issue #418 requires regenerating and requalifying the universe. The same dependency advance must requalify Issue #570's target namespace facts. Optional library methods must remain qualified by the selected dependency rather than restrict apps that do not load it. Package provenance, qualification, and runtime installation live in the vendor owner (repository-only) and packaging decision (repository-only).
Application documents
The Compiler writes complete application-facing README, AGENTS, and UI documents. The README starts with the
application display name and a small replaceable product-description paragraph. Operational instructions derive
from the selected emitted clients and retained Rails source, and concrete test-coverage omissions remain visible.
It does not turn Plan subjects or gaps into a feature catalogue. The user's agent can replace the paragraph from
retained design context after inspecting the emitted source and gaps; no narrative Plan field is required.
Setup, runtime, preview helpers, and application tests work independently of removable .firstdraft/ context.
Core's changelog, contributor guide, and root composition document are omitted; they describe Core maintenance
rather than the application's history or operation. The Core path registry rejects replacement claims for these
paths. Useful UUID generator, Dev Container, and Codespaces guidance belongs in the
application README; UI retains reusable component and native geometry guidance; DEPLOY keeps its existing
Account-sensitive operational guidance. License-required third-party notices remain. The minimal CLAUDE.md
adapter stays @AGENTS.md; removing it would require separate first-session agent-discovery qualification.
Identity and configuration
The identity renderers derive the Rails module, database prefix, display name, and Render service name from
Project#application_key and Project#name. README is a full-file renderer: its title is escaped, single-line
application display text; its iPhone and Android preview links use the same selected-client projections as the
emitted clients and guides. Requested but ungenerated clients receive no preview instructions. README preserves
the private Codespaces port default and routes temporary remote-preview exceptions and cleanup to the selected
guide. It no longer relies on exact Core prose markers or carries a historical forwarded-host receipt as instruction.
Other identity renderers read verified Core files through RenderingContext and return complete replacements.
The module name uses the declared target's camelization rather than mutable Designer inflections. Identity
derivation rejects a Project with another target/profile. CoreTemplate validates exact marker counts before one
atomic in-memory substitution and verifies replacement counts; JSON quoting and YAML-printable filtering keep
valid display text valid in nested Ruby/YAML source. Files retain Core modes. No renderer patches a materialized
file or consumes another renderer's output.
The application-configuration renderer substitutes the application namespace in Core's ordinary Rails configuration. The CSP baseline (repository-only) retains Rails' commented initializer and standard layout helper without custom middleware or nonce wiring.
The composition identity test (repository-only) requires complete Rails output to contain no bare reusable-Core identity token. README and AGENTS carry application guidance; historical Core provenance sentences are no longer exceptions. Replacement values preserve the original file modes, and required third-party notices remain.