The smoke tests¶
make validate checks every configuration without starting anything (Validation and CI). The smoke tests are the other half: they run against a started stack, send telemetry, a gateway request and an application's requests through it, and find each where it should land. CI runs them on every pull request, and you run them after changing a service, an image or a version.
Both are scripts/smoke, and need no provider key: the gateway's model replies are mocked.
make smoke¶
make smoke checks the profiles in PROFILES, the same variable make up reads, so check what you started:
It runs one set of checks per profile, and a database check when a profile keeps data in PostgreSQL. Each check is retried every 3 seconds until it passes or SMOKE_TIMEOUT (120 seconds by default) runs out, and every failure is reported before it exits non-zero.
observability¶
It sends a trace, a metric and a log through the Collector's gRPC port with telemetrygen, as the service stackr-smoke with a run id, and finds:
- the trace in Tempo, by a TraceQL search on the run id
- the metric in Prometheus as
stackr_smoke_total, which also checks Prometheus's name translation - the log in Loki
- Tempo's span metrics for the service, and the Collector's own metrics, in Prometheus
- Grafana's four data sources healthy, and the Collector health dashboard provisioned
The database¶
Over db-init's own connection to the adapter (its host, admin role and networks, as make configures them), it checks that db-init created Langfuse's database and the gateway's, for whichever of those profiles run. With local Supabase, it also checks that Supabase's API answers.
langfuse¶
It sends a trace with a known id to the Collector's HTTP port, and finds it in Langfuse through the public API, /api/public/v2/observations, and in Tempo. That checks the Collector's route to Langfuse, its credentials and Langfuse's ingestion, end to end. It needs observability too.
gateway¶
- The proxy loaded both guardrails,
pii-maskandprompt-injection, and serves both model groups,defaultandfast. - On a new key of the
stackr-smoketenant (the teamtenant-stackr-smoke, the only one allowed mocked replies), a mocked request with atraceparentmust be routed todefault, masked bypii-maskand priced, and the key's spend must be recorded. prompt-injectionmust block an injection attempt with HTTP 400.- With
observability, the proxy's spans must continue the caller's trace in Tempo, and withlangfuse, the trace must be in Langfuse.
The key is deleted at the end.
make smoke-app¶
It runs an application from the template beside the whole stack:
- It generates an application with both libraries and evals from this checkout, locks its dependencies, and creates a key on the
stackr-smoketenant for it. - It starts the application in its app profile, on port
SMOKE_APP_PORT(8800 by default), with telemetry, Langfuse and mocked model replies, and waits for it to be healthy. - A request without a token must be refused with 401.
- It creates a user of the tenant
stackr-smokewith local Supabase's admin API, and signs them in. - As that user, it posts a message to the notes agent (artifactr) and opens a ticket for the triage agent (reflexr). Each agent's model request goes through the gateway on the tenant's key.
- For each agent, the turn or run must end successfully, and its trace must be in Tempo, with the gateway's spans in it, and in Langfuse.
- The completed turn and the succeeded run must be counted in Prometheus, as
artifactr_turns_totalandreflexr_runs_total, for the run's own workspace.
At the end it removes the application, its image and volumes, the key, the user and the application's schema. It needs local Supabase, whose Auth signs the user in, so it fails on the postgres adapter. Building the application's image fetches the libraries from GitHub, so it needs the network.
In CI¶
CI's smoke job starts the stack three ways, each on a fresh runner, and runs make smoke against it:
| Run | Profiles | Database |
|---|---|---|
| observability | observability |
None |
| everything on local Supabase, and an application | observability langfuse gateway, then make smoke-app |
Local Supabase |
| everything on PostgreSQL | observability langfuse gateway |
Plain PostgreSQL |
It installs the Supabase CLI version pinned in versions.env, and starts Supabase without the services the smoke tests don't use (SUPABASE_START_FLAGS). When a run fails, it prints every container and the last 200 lines of each service's logs, and it always ends with make reset.