QA Surfaces
JobCache's QA platform follows the same three-worker shape used everywhere else in the repo: API for state, MCP for agents, UI for humans. The shape is intentional — every product (CV, JobCache, future ones) has the same operator interface for QA evidence, so an agent that knows one knows them all.
The three workers
| Worker | Host | Role |
|---|---|---|
jobcache-qa-api |
api.qa.jobcache.corbet.ch |
Workflow state, queue records, trigger allowlist enforcement |
jobcache-qa-mcp |
mcp.qa.jobcache.corbet.ch |
MCP tool surface for agents — same operations as the UI |
jobcache-qa-ui |
qa.jobcache.corbet.ch |
SvelteKit dashboard: Queue view, per-item drill-down, manual triggers |
The API is the source of truth. The MCP forwards calls to it through a service binding. The UI uses the API as its own backend. There is no parallel state path.
Triggering QA work
QA executions are not free — they consume CI quota, scrape quota, and LLM tokens. The trigger endpoint is allowlisted at the API:
- The list of permitted workflow IDs is in the API's environment.
- A trigger request for an unknown workflow ID returns
403, not404, to make the allowlist behaviour explicit. - The UI's trigger page mirrors the same allowlist server-side so a forged client cannot bypass it.
This applies symmetrically to human triggers (from the UI) and agent triggers (from the MCP). Agents do not get a wider surface than humans.
The Queue view
Every trigger request creates a CockroachDB-backed queue item projected through /queue/[workflowId]. The row carries:
- Workflow ID and trigger source (human, MCP agent, CI)
- Start / finish timestamps
- Status (queued / running / passed / failed / cancelled)
- Evidence references (workflow URL, packages, logs)
- Operator notes, when added later
The table is append-only for the same reason operator_actions is: the queue item is the evidence. If an item is misclassified, a follow-up row corrects the misunderstanding; the original row stays.
Device architecture QA
Distributed device work adds more evidence surfaces to the same QA platform:
contract fixtures, fake devices, canary tasks, duplicate assignment checks,
quarantine and rollback checks, resource-policy compliance, and the
zero-server-compute guardrail. The day-zero gate list lives in
jobcache/wiki/content/architecture/device-qa.md.
Do not add a trigger allowlist entry for a device gate until the matching
CircleCI job or pinned spec dispatch exists. Unknown or placeholder device gates
should fail closed instead of being silently mapped to runner_smoke.
The broker path in broker-flow.md is the QA spine for
distributed ingest. QA should prove capability reports, lease assignment,
observation submission, current ad payload cells, and device-trust updates with
fake devices before an Adapter is allowed to run broadly. The CareerVector
bottom-up path adds one mandatory proof: a workspace job.create/job.update
that carries a public-ad Observation must commit the private workspace op and
the D1 jobcache_commands submit_observation row in the same batch, and the
drain must apply that Observation through submitObservation without direct
Cockroach access from CareerVector or post-commit best-effort HTTP from /ops.
Current ops visibility maps that spine into GET /devices as brokerPath.
The summary is deliberately cheap: it only rolls up the rows already read for
the device fleet panel and MCP tool.
| Spine step | Ops field | Backing proof |
|---|---|---|
| Device capability allowed now | brokerPath.capability |
jobcache/ops/api/src/routers/devices.test.ts |
| Broker lease assignment | brokerPath.lease |
jobcache/ops/api/src/routers/devices.test.ts |
| Accepted Observation / current cells | brokerPath.observation and facts |
jobcache/ops/ui/src/lib/api-ops-client.test.ts |
| Device trust evidence | brokerPath.trust |
jobcache/ops/api/src/routers/devices.test.ts |
Why the MCP exists
An agent that can drive QA from outside the UI gives us the parity we promise everywhere else: anything the operator can do from the dashboard, an agent can do over MCP with the same auth posture and the same allowlist. The MCP tools are intentionally a strict subset of the UI's surface — discovery and triggering, not retrospective editing.
See also
jobcache/wiki/content/architecture/device-qa.md— day-zero QA contract for distributed devices.jobcache/wiki/content/architecture/broker-flow.md— broker/observation path for distributed ingest.jobcache/qa/api/README.md— route reference (if/when added).jobcache/qa/ui/src/routes/queue/— UI for the Queue view.qa/behaviours/jobcache-qa-surfaces.feature— QA-side behaviours that VERIFY this surface.