RFD 0022 β Spock as a framework: one project, one command, two languages
Status: accepted and implemented for the initial framework host (2026-07-15). Spock and Uhura semantics remain separate. The unresolved long-term state problem stays in RFD 0023; the safe client-live/backend-pinned policy in Section 12.1 is the implemented contract, not a placeholder auto-migration scheme.
0. The question
At decision time, the installed spock command took a .spock file as its
unit of work. The SpockβUhura composition proof had a different unit:
- one Spock authority program;
- one optional Uhura client project; and
- composition knowledge then carried by a shell script, two process lifecycles, and duplicated port configuration.
The temporary two-process proof ran both runtimes against the Instagram
example and made the framework hostβs replacement inventory concrete. It
accepted one .spock program and one Uhura project root, built two binaries
and the Uhura web application, required separately built Uhura Wasm artifacts,
bound two ports, waited for health, and coordinated shutdown. The Uhura
provider repeated the Spock port in uhura.toml.
βSpock as a frameworkβ should mean:
spockbecomes the installed project-level front door;- Spock remains the authority language and authority runtime;
- Uhura remains the client/experience language and runtime;
- a composition host loads them as one coherent project; and
- absorbing Uhura means absorbing discovery, distribution, lifecycle, diagnostics, linking, and hosting β not semantic ownership.
This document recorded that direction before either runtime was reshaped and now governs the resulting host. It deliberately does not solve development database reload; pretending that question is a host implementation detail would bake an accidental answer into the framework boundary. RFD 0023 owns it.
In scope
- the project as the new unit of work;
spock.tomland canonical project layout;- the public command ecosystem;
- logical crate and host responsibilities;
- one-origin serving and the existing web products;
- compatibility with file-oriented Spock commands; and
- the build/repository boundary around the Uhura submodule.
Out of scope
- backend reload, state migration, state rebase, and reset semantics (RFD 0023);
- deployment, production process supervision, and remote environments;
- generalized monorepo or microservice orchestration;
- multiple authority databases or distributed transactions;
- merging either languageβs grammar, IR, checker, or state machine; and
- replacing explicit provider/link contracts before a linker is designed.
1. The boundary composition must preserve
The existing responsibility split remains the load-bearing rule:
| Concern | Owner |
|---|---|
| Durable product truth, constraints, policy, and guarded operations | Spock language/runtime |
| UI-session state, experience transitions, semantic presentation, and service requests | Uhura language/runtime |
| Project discovery, cross-artifact linking, hosting, lifecycle, and combined diagnostics | Spock framework layer |
| Layout, paint, native widget mechanics, and device integration | Renderer/host drivers |
No authoritative fact may live in both Spock and Uhura. The framework layer may compose checked artifacts and route requests between them; it may not reinterpret either source language or invent compatibility that their public contracts do not prove.
The current repository boundary also remains intentional:
- Uhuraβs canonical source remains its own repository, included at
uhura/as a git submodule; - Uhura remains independently buildable and testable;
spock-runtimedoes not acquire UI-session or renderer behavior;- the combined host consumes the versioned
uhura-hostlibrary boundary; and - the standalone
uhuracommand remains useful to contributors and for isolated language work even though it is not the public framework front door.
βClientβ is the project-topology word. Calling Uhura ui would be misleading:
Uhura owns a language, checker, deterministic state machine, Editor, Play
runtime, provider ports, and renderer-neutral semantics β not merely a bundle
of visual assets.
2. Vocabulary
The name βSpockβ now appears at several layers. Use these terms precisely:
- Spock language β
.spocksource, its checker, contract IR, and authority semantics. - Spock runtime β materializes and serves one checked authority contract.
- Uhura β the client/experience language, checker, headless runtime, Editor, and Play surfaces.
- Spock framework β the project manifest, public CLI, composition/link layer, combined host, and distribution envelope.
- Spock project β one
spock.toml, one required backend entry, and zero or one client root in the first version. - Project generation β one coherent checked backend artifact, host routing table, binding to backend development state, and, when a client is configured, the matching integrated Uhura Play artifact. Uhura Editor may publish a newer static read model with explicit freshness independently. In the first implementation, its backend generation is pinned for the process lifetime; RFD 0023 studies later activation models.
This vocabulary prevents two opposite mistakes: shrinking Spock back to only
the language when discussing the installed product, and growing
spock-runtime into an unbounded application framework.
3. The project is the new unit of work
The exact minimal full-stack starter generated by spock new is:
my-app/βββ spock.tomlβββ backend/β βββ app.spockβββ client/ # omitted by --backend-only βββ uhura.toml βββ app/home/ β βββ page.uhura β βββ page.examples.uhura βββ catalog/base.toml βββ fixtures/ βββ empty.toml βββ scripts/empty.tomlProjects add optional seed assets and richer Uhura directories such as components, surfaces, ports, providers, and styles only when the application needs them. The initial starter does not invent empty structure or a lockfile.
app.spock is the conventional backend name, not main.spock:
- it already appears in examples, command tests, and the composition proof;
- a declarative authority contract is an application boundary, not a procedural entry function; and
- the manifest still permits another filename when a project needs one.
The first manifest should be small and topological:
version = 1
[project]name = "my-app"
[backend]root = "backend"entry = "app.spock"
[client]root = "client"This spelling is the version-1 schema. Unknown keys are errors so a misspelled root cannot silently select a different project. The responsibilities are:
spock.tomlis required for project/framework commands.- Exactly one Spock backend entry is required in the first version.
- The Uhura client is optional; when configured, its root contains its own
uhura.toml. - Every path is relative to the project root, normalized, and forbidden from escaping it.
spock.tomldescribes composition topology. It does not duplicate Uhuraβs catalogs, ports, fixtures, assets, provider profiles, or language settings.- Start with singular
[backend]and[client]. Named arrays create unearned multi-authority and multi-client semantics. - Internal ports and absolute provider URLs do not belong in the minimum committed schema. A one-origin host can derive relative endpoints.
The framework manifest is therefore the master composition config, while
uhura.toml remains the master client-language config. βMasterβ must not
mean βcopy every subsystem setting upward.β
4. Empty authority is valid, but explicit
Even a project that currently uses only Uhura must carry the configured
backend/app.spock. It may be empty or comment-only. This gives every Spock
project one invariant and makes adding authoritative behavior later an edit,
not a project-topology conversion.
The user guidance can be simple:
This project has no backend contract yet. Keep
backend/app.spockempty until it does.
Do not scaffold a fake table merely to satisfy GraphQL. An empty authority means βno authoritative capabilities,β not βinvent a placeholder data model.β The host should still be able to serve project health and the configured client. Contract metadata remains present, while GraphQL is absent with a structured 404 because an empty authority advertises no GraphQL capability.
This is current framework behavior. The Spock runtime recognizes that an empty
authority has no GraphQL operation-root field and skips schema construction;
the framework environment advertises graphql_path: null, while the combined
fallback returns a structured 404 for /graphql/v1. No fake query field or
placeholder table is introduced.
5. The command ecosystem
The recommended public surface is:
| Command | Unit | Meaning |
|---|---|---|
spock new <name> | new project | Create the selected canonical project template, always including the manifest and required backend. |
spock init [path] | existing directory | Adopt existing sources without moving or overwriting them. |
spock check [path] | project | Check backend, client, manifest, and every currently provable provider/link contract as one result. |
spock dev [path] | project | Rebuild client source live; observe backend changes as restart-required while keeping the active backend pinned. |
spock start [path] | project | Check once and serve one fixed combined generation with no source watcher. |
spock run <file.spock> | Spock program | Preserve the standalone authority/file escape hatch. |
spock build, spock gen | artifact | Preserve existing language artifacts; project-aware variants are a separate design. |
5.1 new and init are different
spock new is the create-a-project command. It owns the canonical template
and fails if its destination already contains conflicting files.
spock init is adoption. It creates only missing framework files, discovers
an unambiguous existing .spock entry and uhura.toml, never moves user
sources, never silently overwrites them, and fails with choices when discovery
is ambiguous. Adopting an Uhura-only directory creates the required empty
backend entry and points spock.toml at it; it does not invent a placeholder
table or relocate the Uhura project.
RFD 0020 recorded spock init [name] as the original general first-run gap.
This accepted RFD refined that spelling in the implementation: new creates a
named project; init adopts a directory. The distribution requirement remains
intact.
5.2 dev and start are different
spock dev means saved-source observation, current diagnostics, coherent
candidate ordering, last-good retention, and browser generation events. It
keeps the active backend and its state pinned after startup. A structural
backend edit is reported but never applied until an explicit restart.
spock start means a fixed generation: resolve, check, construct, bind, and
serve without watching or automatic replacement. The name does not imply that
the prototype runtime is production-ready.
5.3 Language escape hatches remain
spock run app.spock, spock check app.spock, spock build app.spock, and
the current spock gen forms remain valuable for language development, CI
fixtures, backend-only experiments, and compatibility with the published
command.
Directory or omitted targets select project mode; an explicit .spock target
retains file mode. Project discovery starts at the explicit directory or the
current directory and walks upward to the nearest spock.toml. It never walks
past a discovered nested project. Every manifest path is relative, rejects
absolute paths, prefixes, and .., and must resolve inside the canonical
project root; a symlink that resolves outside the root is an error.
Uhura-only expert operations such as formatting and deterministic traces need
a later namespace decision. spock client fmt and spock client trace are
better candidates than placing every subsystem command at the global top
level, but this RFD does not lock them.
6. Logical crate and host topology
Do not create spock-framework-cli, and do not demote the existing crate to
spock-language-cli. There should be one public command and one crate that
owns its argument parsing: spock-cli.
The recommended responsibility topology is:
crates/βββ spock-langβββ spock-runtimeβββ spock-projectβββ spock-hostβββ spock-cli # [[bin]] name = "spock"
uhura/ # unchanged git submodule boundaryβββ crates/ βββ uhura-core, uhura-check, ... βββ uhura-host βββ uhura-cliThe dependency/ownership direction is:
spock-cli βββ spock-project ββ manifest, discovery, paths, scaffolding βββ spock-host βββββ project generations, routes, listener, lifecycle βββ spock-project ββ validated layout/config types and path rules βββ spock-runtime ββ one authority contract/database/API router β βββ spock-lang βββ uhura-host βββββ reusable Editor/Play host service
uhura-cli ββ uhura-host # standalone contributor/subsystem commandspock-project
Owns spock.toml parsing and version diagnostics, the validated project
layout/configuration model, root discovery, portable paths, scaffold templates,
and adoption planning. Each language subsystem owns its captured semantic-input
type and coherent capture rules; spock-project must not duplicate Uhuraβs
established project-capture rules. It owns no filesystem watcher, HTTP listener,
or live database.
spock-host
Owns the combined HTTP listener, route-collision policy, project-generation
construction and activation, lifecycle, shutdown, status/events, and the
coordination needed by both dev and start. For dev, that includes
filesystem observation, monotonic source-revision assignment, and coherent
cross-subsystem capture orchestration; the language subsystems still enumerate
and capture their own semantic inputs. The host consumes spock-projectβs
validated layout/configuration model and normalized path rules; the CLI also consumes that
crate directly for new, init, and project discovery. spock-host is
clearer than spock-dev-server: it serves fixed generations too. It is clearer
than spock-framework, which names the product concept rather than a concrete
responsibility.
The host orchestrates whatever state capability RFD 0023 selects; it need not own the state ABI mapper or rebase laws itself. Those may belong beside the runtime or in a later focused crate once their boundary is understood.
spock-runtime
Continues to implement one Spock authority generation. It exposes constructible service/router boundaries, but it must not become the project manifest reader, Uhura host, or master process supervisor.
uhura-host
Is extracted inside the submodule from the original uhura-cli::cmd::dev
behavior. It owns reusable Uhura Editor/Play state and routes without binding
its own mandatory listener or returning CLI-specific exit codes. uhura-cli
remains the standalone listener and contributor entrypoint over it.
The root consumes uhura-host through a direct path dependency into the
initialized submodule. This deliberately ends the βcomplete public binary
builds from a core-only checkoutβ property: framework source builds and npm CI
must initialize submodules. Uhura keeps its separate workspace and lockfile.
7. One host and one origin
One public listener and one browser origin are required. The allocation is:
/ Uhura Editor, or redirect to Studio without a client/play Uhura Play/assets/* explicit Uhura browser assets/api/editor/* Editor model and events/api/play/* Play artifacts, events, assets, and Wasm/~studio Spock Studio/~project/environment typed same-origin provider environment/~project/status authoritative status snapshot/~project/events project status invalidations/~health combined readiness/~contract Spock contract/graphql/v1/rest/v1/*/storage/v1/*One origin gives the product:
- one process lifecycle and advertised URL;
- relative provider endpoints rather than committed localhost ports;
- no cross-origin configuration for the integrated path;
- one place to detect route collisions; and
- a possible atomic project-generation switch rather than two independently advancing servers.
The standalone Uhura command still owns a tiny_http listener. The framework
instead consumes listener-free uhura-host routing through spock-hostβs Axum
fallback, so the public framework process now binds one Axum listener. The
temporary two-process proof was retired once the combined lifecycle became the
canonical contributor path.
The combined host emits no cross-origin CORS grant by default. Its own Studio, Editor, Play, and provider traffic is same-origin; the contributor Vite loop uses a proxy. The standalone language server retains its explicitly permissive local-development CORS behavior. Any future framework allowlist is an explicit host configuration decision, not an ambient wildcard.
8. Both web products remain
The web playgrounds are not a reason to avoid the framework. They are separate tools with separate authority:
- Spock Studio inspects authoritative contract, rows, personas, and protocol behavior.
- Uhura Editor presents checked client previews and authoring diagnostics.
- Uhura Play runs the experience and its provider link.
- GraphiQL remains a backend protocol tool.
They should be mounted separately, not collapsed into a single frontend or renamed as though they did the same work. Each subsystem retains ownership of its web source and browser-facing protocol.
The distributed build now builds the shared Uhura sidecar first, derives the exact raw manifest SHA-256, and compiles that identity into every native binary; Spock Studio remains a per-target embedded build. RFD 0020βs release workflow verifies each asset family, the executable-to-sidecar binding and exact inventory, and installed Editor/Play/Wasm routes on all supported operating systems. Node and Vite remain build-time dependencies; neither running server needs a Node process.
The release and source-build policy is also settled: building the framework assets from source requires the initialized Uhura submodule. The npm package carries the already-built sidecar whose manifest identity is compiled into its binaries. An ordinary source binary has no packaged identity and therefore fails closed if an executable-relative sidecar appears; source and test runs must opt into their local trust boundary with both explicit asset-root overrides. A missing submodule cannot silently produce an empty Editor or Play.
9. Configuration and linker ownership
The composition pipeline is:
backend/app.spock ββ> checked Spock contract βββ ββ> composition/link resultclient/uhura.toml ββ> checked Uhura program ββββspock.toml identifies the composition inputs and topology. Runtime host policy
remains in CLI options and defaults; the manifest must not redefine either
language. Uhuraβs required ports and Spockβs exported surface should eventually
meet at a versioned linker/provider boundary.
The current application-owned TypeScript provider is a valid explicit adapter and remains the integration proof. Some of that code is opaque to todayβs language checkers. Project checks should validate every declared contract they can prove and report the remaining adapter seam as unchecked, rather than claiming a static link proof. A future linker may validate or generate more of this seam, but the framework RFD cannot assume that contract exists before its own design document and conformance tests.
When a client is configured, the host should supply same-origin endpoint configuration to integrated Play at runtime. A committed Uhura profile can still carry absolute URLs for standalone or remote-provider work; the local framework path should not require the developer to keep two port declarations synchronized.
10. Lifecycle
Fixed start
- Discover and validate
spock.toml. - Capture the declared project files.
- Compile/check the backend and any configured client.
- Validate every currently declared/checkable provider contract and report opaque adapter seams.
- Construct one immutable project-generation binding to its selected state.
- Bind the public listener only after the generation is valid.
- Serve that artifact/state binding unchanged until shutdown; ordinary application requests may still mutate the selected database.
Watched dev
- Capture one coherent saved project snapshot.
- Compare the observed backend inputs and manifest topology with the active
fingerprints; report any difference as
restart_requiredwithout building or activating a backend candidate. - Prepare any configured client candidate against the one active backend.
- Reject stale/out-of-order client work.
- Publish a valid client candidate or retain the last-good Play generation when the candidate is rejected.
- Publish current diagnostics, changed backend inputs, and active-versus- observed freshness separately.
When a client is configured, Uhura Editor may still publish the latest static
render and diagnostics while Play remains bound to the active backend. Client
publication continues while a backend restart is required. Both modes fail
before binding when the initial backend is invalid. start also fails for an
invalid configured client. dev may bind with current Editor diagnostics and
no Play generation, then activate the first valid client save.
No watched backend candidate exists in this implementation. Whether a future candidate retains a database, creates a new world, rebases state, or requires a reset is the subject of RFD 0023.
11. Alternatives considered
Add spock-framework-cli
Rejected as the working recommendation. It creates two possible owners of the same public command, forces artificial dispatch between them, and encodes a distinction the installed product is trying to remove.
Rename the existing crate to spock-language-cli
Rejected. Language behavior already has homes in spock-lang and
spock-runtime; the CLI should become thinner, not fork into another user
surface. It also creates compatibility and publishing churn for no semantic
gain.
Put Uhura into spock-runtime
Rejected. The authority runtime and composition host have different responsibilities and different state. This would erase the boundary the two languages were created to preserve.
Keep the shell script and two public ports
Retained only as a proof and transition oracle. It cannot provide one origin, project-level diagnostics, one packaged command, or atomic combined generations.
Merge repositories or Cargo workspaces
Rejected as a premise. Composition does not require giving up Uhuraβs submodule, independent build, or public contract boundary.
Call the client root ui
Rejected. It understates Uhuraβs language, state, and host responsibilities.
Absorb uhura.toml into spock.toml
Rejected. It duplicates semantic authority, harms standalone checking, and turns the composition manifest into a grab bag. Point to the client root; leave the client contract there.
12. Accepted first implementation
The accepted framework shape is:
- One installed/public command:
spock. spock-cliremains its crate and binary owner.- A required
spock.toml, one required backend, and an optional client. backend/app.spockis conventional and may represent an empty authority.- Project vocabulary is backend/client, not backend/UI.
new,init,dev, andstarthave distinct roles.- Add
spock-projectandspock-hostresponsibility crates. - Extract a reusable
uhura-hostinside the submodule. - Preserve Studio, Editor, Play, and GraphiQL as separate surfaces.
- One listener and one origin.
12.1 Client-live, backend-pinned dev
The first spock dev activates exactly one valid backend generation. Client
changes may build and publish immutable last-known-good Uhura generations
against that active backend. A .spock change, referenced seed-asset change,
or backend/topology change in spock.toml is observed and reported as
restart_required, but never constructs, opens, reseeds, or swaps a backend
inside that process. Returning all backend inputs and topology bytes to their
active fingerprints clears the warning without touching the database.
Client publication continues while a restart is required and explicitly names the active backend generation. A rejected client attempt retains the previous Play generation. Applying a backend edit requires an explicit process restart; while v0 load remains destructive, the CLI must say that restart reconstructs state from seed. The one future activation marker belongs at this disposition seam:
TODO(RFD-0023): replace restart-required with off-path backend candidateconstruction and an explicit activation policy after development-worldsemantics are accepted. Never reopen or mutate the active world here.spock start has no watcher and serves one fixed generation. Both modes
require a valid backend before binding. A configured invalid client also makes
start fail before binding; dev may bind backend tools plus current Editor
diagnostics with Play unavailable, and the first valid client save activates
Play.
Before named-state ownership or database opening, preparation re-resolves the
project topology and recaptures backend and client fingerprints. Any content
change, capture instability, or safe in-project root-symlink retarget makes the
whole attempt unstable; start never binds a snapshot assembled across saves.
Once a client attempt becomes observable as building, its lifecycle always
finishes it as published or rejected and then invalidates project status. A
newer project observation rejects a now-ineligible build immediately, including
when the new topology removes the client. The coordinator transition is proven
off to the side before Uhura installation, so a publication error leaves the
last-good client untouched and cannot strand the status machine waiting for
another filesystem event.
12.2 Routes and empty authority
The stable route ownership is:
/ Uhura Editor when configured; otherwise redirect to /~studio/play Uhura Play when a client is configured; otherwise 404/assets/* Uhura browser assets with a client; otherwise 404/api/editor/* Editor state/events with a client; otherwise 404/api/play/* Play artifacts/events/Wasm with a client; otherwise 404/~studio Spock Studio/~contract active Spock contract/~personas, /~whoami Spock development identity/graphql/v1 GraphQL when the authority derives fields/rest/v1/* REST and RPC/storage/v1/* storage/~project/environment integrated provider host environment/~project/status authoritative project status snapshot/~project/events project status invalidation events/~health aggregate host readinessThe framework owns final fallback, cross-origin policy, body limits, and
collision checks; the accepted same-origin default installs no CORS grant.
Unknown protocol paths return protocol 404/method responses, never SPA HTML.
An empty or comment-only backend is valid. It serves contract metadata and the
configured client, but /graphql/v1 is absent with a structured 404 because
there is no GraphQL capability to advertise.
12.3 State and process ownership
The first framework release defaults to an in-memory database. --db PATH
selects an explicitly disposable named database that is still reconstructed
from seed on each process start. Before touching a named database, its WAL,
SHM, or mutable framework state, the host holds an exclusive OS advisory lock
for the process lifetime. The lock is released by closing its handle, including
after abnormal process termination; correctness never depends on deleting a
sentinel file or guessing whether a PID is stale.
.spock/dev/ is reserved for ignored framework development state. In-memory
hosts do not serialize unrelated processes through a project-wide lock because
they share no mutable database.
The advisory object lives under the reserved sibling
.spock-named-state-locks/ namespace, never at a valid database path. The host
normalizes and locks the database directory entry, then passes that exact path
to destructive bootstrap; a symlink or alternate parent spelling therefore
cannot make locking and opening select different worlds.
12.4 Build, assets, and provider environment
The root workspace consumes uhura-host by direct path from the initialized
Uhura submodule. A full source build therefore requires recursive submodules;
Uhura remains a separate workspace with its own lockfile. The tested framework
toolchain is exactly Rust 1.92.0 with Cargo resolver 3. This is an exact build
pin, not a lower MSRV promise.
The npm package carries one shared, platform-independent Uhura web/Wasm sidecar
tree plus a versioned manifest of protocol versions, commits, hashes, and
sizes. The release asset job hashes the exact manifest bytes before the native
matrix runs; every distribution executable captures that SHA-256 and rejects a
different executable-relative manifest before parsing it. The manifest then
provides per-file integrity and compatibility checks over the immutable served
snapshot. This authenticates the sidecar only relative to a trusted executable:
it does not sign the package, protect replacement of both artifacts, or cover a
compromised release workflow. The explicit paired test/source override is
deliberately unanchored local input; uhura-host never searches a source tree at
runtime. Spock Studio stays embedded initially. Canonical scaffold bytes are
embedded in spock-project, so spock new does not need a checkout.
Integrated Play receives framework-owned facts from
/~project/environment using protocol spock-host-environment/1:
{ "protocol": "spock-host-environment/1", "mode": "dev", "project_generation_id": 1, "backend_generation_id": 1, "authority": { "graphql_path": "/graphql/v1", "rpc_path": "/rest/v1/rpc", "storage_path": "/storage/v1" }}authority.graphql_path is a capability, not merely a conventional URL. It is
null for an empty/comment-only backend because that active generation has no
GraphQL operation root. A provider that recognizes this environment must keep
using its integrated RPC and storage paths and report GraphQL as unavailable;
it must not reinterpret the deliberate null as a reason to contact the
standalone fallback configured in uhura.toml.
Uhura providers may prefer this same-origin environment and fall back to their committed absolute configuration in standalone mode. The framework does not merge or rewrite arbitrary provider JSON.
12.5 Status, events, and readiness
/~project/status uses protocol spock-project-status/1. Its snapshot names
the mode and observed revision/fingerprint; active project, backend, and client
generation IDs; active and observed backend fingerprints; backend freshness
(active or restart_required); client state (absent, building, active,
cold_invalid, or rejected_last_good); the latest client attempt separately
from the generation serving bytes; Editor freshness; changed input paths;
diagnostics; and aggregate readiness/degradation. An active clientβs
source_fingerprint identifies the exact captured Uhura source snapshot, not a
digest of toolchain-derived browser artifacts. IDs are monotonic within one
host session and are not presented as durable identities across restart.
/~project/events uses SSE event protocol spock-project-event/1. Events are
monotonic invalidations containing the session event ID and authoritative
status URL; publication updates artifacts and status before broadcasting. The
host does not promise unbounded event replay. On initial connection, reconnect,
an unknown Last-Event-ID, or a detected gap, the client fetches the current
status snapshot. Project, Editor, and Play event hubs belong to the host
session and survive client-generation swaps. One four-stream admission budget
covers all three event surfaces. Saturation returns 503 with Retry-After: 1;
disconnect, shutdown, or stream completion returns its permit.
/~health returns 200 once the listener and backend generation are active.
Restart-required, cold-invalid client state, and retained-last-good client
failures are reported as degraded but ready; they do not make working APIs
unready. Before backend activation it returns 503. Fixed start never binds
with an invalid configured component.
12.6 Scaffolding and budgets
spock new NAME defaults to a minimal full-stack project: the exact v1
manifest, an empty backend/app.spock, and a self-contained Uhura starter
with no required remote provider. --backend-only omits [client] and the
client tree. spock init adopts existing roots without moving or overwriting
them; ambiguity is an error with choices.
Initial release budgets on the recorded reference machine are: source
start/dev readiness within 5 seconds and no more than twice the pre-framework
backend startup baseline; valid client publication p95 within 1.5 seconds;
idle observer CPU at or below 2%; a 250-revision soak with RSS growth at most
25 MiB and file-descriptor/thread growth at most three; shutdown and port
rebind within 2 seconds; and a packed all-platform npm artifact at most 25 MiB.
Still deferred are backend world reuse/rebase/migration, Play state-preserving
HMR, automatic provider TypeScript build supervision, multiple backends or
clients, a published uhura-host crate, and the native-event versus polling
observer optimization.
13. Implementation record
The sequence was completed in the intended dependency order:
uhura-host,spock-project, and the immutable backend-generation seam landed independently.- The pinned Uhura submodule and direct Cargo dependency were integrated atomically while Uhura retained its separate workspace and lockfile.
spock-hostcomposed one listener and fixed-generationstart.devadded client-live/backend-pinned observation with the single in-code RFD 0023 TODO at the backend disposition seam.- The public CLI added project-wide
check,new, andinitwhile retaining explicit.spockfile workflows. - RFD 0020βs npm workflow added the shared Uhura web/Wasm sidecar, four native launchers, exact package guards, and installed cross-platform route smokes.
The ordering remains part of the design: the combined host owns immutable artifacts and lifecycle, but it has no API that replaces the active backend. That makes the current doctrine mechanically visible instead of relying on a watcher convention.
14. Acceptance evidence
spock new demoproduces the documented, project-checkable shape;--backend-onlyomits the client.spock inituses create-new writes, publishes the manifest last, and never overwrites or silently relocates existing sources. On Unix, retained parent handles let rollback remove exact invocation-owned files; created directories are preserved and reported becausemkdircannot atomically return an ownership handle. On Windows, retained root, directory, and file leases block replacement through commit; failure handling is deliberately non-mutating and reports every known creation as a residual rather than risking deletion or overwrite through a replace-capable rename.- Planned paths reject Windows device aliases, alternate-data-stream syntax, trailing-dot/space aliases, and case- or Unicode-normalization-equivalent duplicate destinations before filesystem mutation.
- Empty-authority full-stack and backend-only projects check and start.
uhura/examples/instagramis the canonical non-empty full-stack proof: one checked-inspock.tomlcomposes its seeded Spock backend and complete Uhura client without flattening either subsystemβs configuration or asset plane.- For a full-stack project, one public port serves the configured Spock APIs, Studio, Uhura Editor, Play, status, environment, health, browser assets, and Wasm. Backend-only client routes return structured 404 responses.
- Valid, invalid, and recovered client saves prove last-known-good publication;
a client generation can publish while backend status is
restart_requiredand remains bound to the active backend generation. - Editing and then exactly reverting backend inputs changes only observation status; backend generation and world identity remain unchanged.
- Real-browser acceptance covers Editor, Play navigation, hard-reloaded Play, and Studio with no console warnings or errors.
- Root and independently runnable Uhura Rust gates, plus the Uhura
browser/provider gate, pass in their respective workspaces. The first
0.5.0npm release dry run passed its four-target build and macOS/Linux/Windows installed-package verification on 2026-07-15 (Actions run 29379605382); that workflow remains the authoritative full-matrix integration proof. - The local package-topology smoke contains exactly 21 files and the release workflow rejects a packed artifact above 25 MiB. Release CI remains authoritative for the four real platform binaries.
spock run app.spockremains valid and shares the named-state safety lock.
15. Related documents
- RFD 0006 β language identity, static runtime, and IR reload architecture.
- RFD 0009 β the existing
spock run --watchdirection. - RFD 0010 β client/codegen ownership; Uhura is not generated client code.
- RFD 0015 β Spock Studioβs embedded same-origin host.
- RFD 0020 β the npm-distributed
spockbinary and asset build. - RFD 0023 β saved-source reload and authoritative development state.
- Uhura RFC 0001 β the language/runtime ownership boundary.
- Uhura RFC 0002 β coherent saved-source capture and last-known-good publication.
- Uhura specification β current Uhura contract authority.