Live bounded journey — operator runbook
The "live bounded journey" lane (Lane G) drives the full CareerVector pipeline against real AI providers with real workspace state, capturing a sanitized evidence bundle. It is the only end-to-end test that proves the actual product works — every other test layer (unit, contract, mocked browser journey) uses provider doubles or curated fixtures.
It is not part of default CI. It runs only on explicit operator opt-in.
When to run it
Three legitimate triggers:
- Before a release that touches the pipeline (extract, enrich, evaluate, tailor, render).
- After a provider cascade change (new provider, new model, new fallback ordering).
- After a structural change to workspace mutation paths (op catalog version bump, new sub-doc, schema migration).
Do not run it as a smoke check; the synthetic lane is faster and free.
Opt-in
The spec aborts loudly if any of the three opt-in variables are missing or incorrect:
export CV_LIVE_JOURNEY=1
export CV_LIVE_PROVIDER_OPT_IN=1
export CV_LIVE_MAX_COST_CHF=0.50 # your ceiling in CHF
Each must be set exactly. The cost cap is enforced — the spec aborts mid-run if cumulative provider spend exceeds it.
Additionally, supply at least one provider key. Groq is the default:
export GROQ_API_KEY=$(grep -oE 'gsk_[A-Za-z0-9_]+' ~/.agent/secrets/groq.md | head -1)
Any of the cascade's other providers (Cerebras, Gemini, OpenAI, …) also work
if their env var is set; see lib/domain/src/providers-config.ts.
Running
Against a local dev server:
bun --filter @cv/ui dev # in another shell
# wait for the dev server to come up
CV_LIVE_JOURNEY=1 \
CV_LIVE_PROVIDER_OPT_IN=1 \
CV_LIVE_MAX_COST_CHF=0.50 \
GROQ_API_KEY=gsk_... \
bun --filter @cv/ui playwright test e2e/journey-real/ --project=chromium --reporter=list
Against a deployed worker (Cloudflare quota policy — see
wiki/content/runbooks/CI-CD.md §22):
PLAYWRIGHT_BASE_URL=https://careervector.corbet.ch \
CV_LIVE_JOURNEY=1 \
CV_LIVE_PROVIDER_OPT_IN=1 \
CV_LIVE_MAX_COST_CHF=0.50 \
GROQ_API_KEY=gsk_... \
bun --filter @cv/ui playwright test e2e/journey-real/ --project=chromium --reporter=list
Evidence output
Each run writes a sanitized bundle to:
ui/test-results/journey-real/<runId>/
evidence.json ← machine-readable JourneyEvidence (validated against schema)
summary.md ← human-readable digest
ui/e2e/helpers/live-capture.ts is the sanitizer. It removes anything matching
api_key, token, secret, password, credential, authorization,
cookie, set-cookie. It also refuses to write the bundle if any string in
the evidence still contains a known provider key prefix (sk-, gsk_, AIza,
ant-, Bearer , …). That refusal is the final safety net — if it ever
fires, audit the evidence object before retrying.
Cost expectations
One full pipeline pass against Groq's llama-3.3-70b-versatile consumes
roughly:
| Stage | LLM calls | Tokens (~) | Cost (~) |
|---|---|---|---|
| Extract | 1 | 1500 in / 500 out | < CHF 0.001 |
| Enrich (commute, salary) | 1 | 800 in / 200 out | < CHF 0.001 |
| Evaluate | N per dimension | N × 500 in / 200 out | < CHF 0.005 |
| Tailor (CV) | 1 | 2000 in / 600 out | < CHF 0.002 |
| Tailor (CL) | 1 | 1500 in / 600 out | < CHF 0.002 |
Total per run: well under CHF 0.05 for a default 4-dimension workspace on Groq. A CHF 0.50 cap leaves headroom for one full run plus diagnostic retries.
What to do if the lane fails
- Read
summary.mdfirst — it lists which steps passed and which failed. - Open
evidence.jsonfor the failed step'sdetailsblock. - If the failure is a 429 or a provider 5xx, the cascade is meant to fall over. Investigate the cascade chain in the Models tab, not the journey itself.
- If the failure is a schema mismatch (extract returned wrong shape,
evaluate returned malformed scores), capture the failing prompt + response
into a new
wiki/content/studies/entry and propose a curated fixture delta for the synthetic lane. - Never copy a live provider response into the repo verbatim — that's
captured-evidence-as-fixture which we explicitly reject (see
wiki/content/studies/wiki-engine-spike.mdfor the broader knowledge-base reasoning).
Hard prohibitions
- This lane never runs in default CI. Verified by
tools/quality/src/bucket.rs(journey-livebucket blocks--exec). - The opt-in variables are never committed to
.circleci/config.yml,.env.example, or any test fixture. They live only in the operator's shell environment. - The evidence bundle is never committed to the repo (it's under
test-results/which is gitignored). Share it via direct file transfer or paste into the wiki manually, with another sanity scan.