BBramaDocs

Brama runbook: startup, reachability and readiness

Startup and readiness

Five symptoms that appear before any model request succeeds: a caller asks a documentation site that publishes no gateway, the process refuses to start, /health says ok while nothing serves, /readyz answers 503, or a request from another machine is refused at the transport. Each entry quotes the sentence the product actually prints and names the repair. The error vocabulary itself is in errors; the rest of the runbook is at runbook.

The documentation site publishes a gateway only when its deployment declares one

The documentation site serves /docs and Brama's download under /download, redirects / to /docs, and sends every other path to its gateway forwarder. Whoever deploys the site chooses whether it also publishes a Brama gateway: setting BRAMA_GATEWAY_ORIGIN on the site's deployment to one credential-free HTTPS origin publishes the gateway running there, and each call is forwarded to it with its method, path, query, headers and body. With Stado, that origin is a public origin declared for the gateway with stado web origin declare, the origin of the URL stado web origin url /v1 prints.

Publication is off by default. A deployment that sets no origin publishes no API, and every path outside /docs and /download, /health and /readyz included, answers 404 with this body, the site, method and path filled in:

{"error":{"message":"<site> publishes no Brama gateway: its deployment sets no BRAMA_GATEWAY_ORIGIN, so POST /v1/chat/completions is not served here. Call the gateway your deployment runs, at the address it declares (with Stado: stado service directory connect brama). A deployment publishes its gateway on this site by setting BRAMA_GATEWAY_ORIGIN to that gateway's HTTPS origin. See /docs/runbook/startup-and-readiness#public-address",
 "type":"request_error","code":"api_not_published","retryable":false}}

The caller was configured with a site that publishes no gateway. Point it at the address of the gateway its deployment runs; a deployment placed by Stado gives each machine its own route:

stado service directory connect brama

A value that is not one credential-free HTTPS origin answers 500 with code gateway_origin_invalid, naming the value; an origin the forwarder cannot reach answers 502 gateway_unreachable with the transport error. Readiness is read from the gateway itself, as the entries below describe.

brama serve refuses to start

The sentence, verbatim (exit 1):

Server error: BRAMA_MODEL_ALIASES is required and is assembled by
src/release/bin/start-with-skarbiec from the sealed policy directory. Starting the
binary directly cannot obtain it: launch the gateway through that launcher, or
export the variable yourself. Restarting an unlaunched process will not
repair this.

The refusal names its own repair: managed configuration is generated by the launcher, and restarting the same bare invocation cannot change the answer. Start through src/release/bin/start-with-skarbiec; a standalone desktop deployment instead passes --local-credentials-stdin (configuration). A service host without Skarbiec sets BRAMA_LOCAL_CREDENTIALS_FILE (in the environment or in ~/.config/brama/service.env) to an owner-only provider-to-credential JSON file; the launcher then starts that standalone mode itself, says starting Brama without Skarbiec: provider credentials from <file> on stderr, and refuses a file that is not a regular, owner-only file. Other startup refusals in the same class — duplicate client tokens, malformed identities, an alias route with * or stray whitespace — also stop the process before it binds; the log names the offending entry.

An alias declares exactly one route, so a startup refusal about a route is a statement about that one destination. If the registry document itself is the thing being refused, repair it with brama routes migrate (cli/routes/migrate) and see routes and ledger.

/health is ok but nothing works

That is /health doing its job, not a contradiction: its body says "dependencies": "not_probed", and it answers ok from a gateway whose every credential redemption is being refused. The only readiness evidence is /readyz (architecture). Point deploy checks and uptime monitors at /readyz; treat a monitor on /health as a monitor of the process, nothing more.

/healthz is the same process-only check as /health. Neither waits for subscription inventory, credential redemption or provider model discovery. A healthy response does not establish that any route can serve.

A route has no live subscription

A request does not join subscription or model discovery. It reads the last completed background observation. If none has completed, it refuses with route <r>: no live subscription; discovery failed: <cause>, naming the operation still pending. If discovery failed, the refusal retains the failed operation and its reported cause, including a vault that cannot be opened. An empty trusted subscription catalog does not erase that failure.

Restore the named dependency before replaying the request. Later traffic starts another background observation while the previous failure remains visible; concurrent requests do not each start their own discovery. A failed discovery is not a provider generation timeout, and an already dispatched generation still follows the provider transport contract.

brama test --model <route> --agent-id <agent> --allow-provider-cost --json is an explicit live diagnostic: it discovers inventory before dispatch, and the best selector also discovers models. It may contact a provider and incur cost. Unlike service admission, this diagnostic waits for the discovery operation it was asked to perform.

/readyz answers 503

A readiness probe for one subscription reads that member's recorded credential and quota refusal before requesting its grant. Its diagnostic names the selected subscription and the retained cause, including the recorded quota reopening time when present. It does not claim that every other account failed because this member is unavailable, and a refused credential is not redeemed merely to repeat its recorded refusal.

reason retains the observed readiness problem. Inspect the corresponding fields rather than inferring account health from the HTTP status alone:

reason Meaning Check
no provider capability is configured zero direct providers — the gateway can route nothing on its own account launcher policy: required_provider_capabilities and the authority-owned capability routes table
a configured provider credential could not be obtained; the authorization chain is broken, not busy a capability or read grant refused just now denied[] names the providers; check broker socket, workload registry, proof key (concepts/capability)
an active subscription's credential did not redeem just now, so the next request that needs it will be refused whatever the catalogue lists a subscription is listed but its credential does not redeem unredeemable[], then brama subscription list for the refusal sentence
traffic can be served, but the vault holds a subscription account with incomplete routing metadata an account lacks routing identity metadata; brama:agent: is provenance, not a shared-pool routing gate unroutable_accounts[] identifies the actual missing brama:subscription, brama:provider: or brama:id: metadata
every credential was obtained, and at least one active subscription contributes no model: it cannot be routed to a redeemable account whose provider offers it no discoverable model unroutable[]; check provider model discovery and the account's plan

Readiness returns inventory_errors entries with operation and detail when the account census, boot-catalog comparison, standalone provider inventory or direct credential acquisition fails. local_provider_names identifies a failed standalone map read; provider_credential includes the affected provider and original redemption cause. Direct-provider rows also retain that refusal in reason. Installing standalone credentials fixes that backend for the process lifetime: a poisoned credential map does not switch discovery or final-use redemption to managed storage. An empty account/provider list is not a complete census when these errors are present. The response sets degraded:true and operator_action_required:true, and includes the causes in the overall reason. An otherwise working route remains ready:true; inventory diagnostics do not disable it. Desktop's Posture screen displays the same warning even while the gateway can serve traffic.

Qualify the actual endpoint with cargo test --test readiness-inventory -- --ignored --nocapture. Supply TEST_SOURCE_REVISION matching the qualification binary's embedded source revision, BRAMA_READINESS_URL, GATEWAY_SOURCE_REVISION, EXPECTED_READY, EXPECTED_READINESS_HTTP_STATUS, and EXPECTED_INVENTORY_ERROR naming an observed cause. The test refuses a mismatched qualification binary before contacting the gateway; the serving revision is checked independently. A refused census also requires its EXPECTED_INVENTORY_OPERATION. Use a real isolated gateway with the relevant unreadable vault, malformed boot catalog, unavailable standalone map or refused direct credential. A direct credential fixture additionally supplies EXPECTED_INVENTORY_PROVIDER and must expose the same cause in that provider's readiness row. The journey does not manufacture a provider, poison a lock, edit a deployment or restart it. For the healthy completed census, supply an empty expected error. Reports retain the test build, request, HTTP status, full returned body or actual transport/body-read failure, and serving revision under target/real-tests/readiness-inventory. This API journey does not qualify the native screen; inspect the same actual report in Posture separately.

configured_provider_capabilities identifies an incomplete provider inventory in both interim and final readiness reports. Its detail preserves the declared grant-route file and actual filesystem, JSON or object-shape failure, or the standalone-map or subscription-classification refusal. Qualify the final report with EXPECTED_INVENTORY_OPERATION=configured_provider_capabilities and the independently observed cause using the same readiness journey. A failed inventory read is never a successful empty provider pool. Adoption preview refuses the same failure before importing configuration; the administrative snapshot, process stats and authenticated deployment catalogue return 503 with that cause when they cannot construct their inventory.

configured_request_sign_agents in inventory_errors means the signing-agent declaration could not be read or decoded; it does not mean no agents were configured. The final readiness reason preserves that cause and Desktop Posture displays the same inventory warning. Use the readiness journey with this operation and the independently observed declaration error. Maintenance exposes the same failure in plan_usage.failed with operation and error rather than reporting a successful empty sweep. A working direct provider remains independently serviceable.

Waiting repairs none of these — every 503 here is an authorization or inventory statement, not load. The three subscription-shaped rows are worked through in credentials and subscriptions.

Requests from another machine answer 426

{"error":{"code":"secure_transport_required",
 "message":"HTTPS is required except for direct loopback requests", ...}}

The transport guard accepts loopback, the gateway's own bound address, peers in BRAMA_ENCRYPTED_PEER_IPS, and proxies in BRAMA_TRUSTED_PROXY_IPS whose forwarded headers state https — nothing else, and forwarded headers from an unlisted peer are never trusted (a forged X-Forwarded-Proto: https changes nothing; captured). Repair: front the gateway with the approved TLS terminator and list that terminator's peer IP, or call over the mesh hop that is already encrypted.