Apply task evidence end to end
Traceability
- Spec ID:
2026-09-01-task-evidence-upload-end-to-end - Status: Implemented
- Refs:
2026-09-01-task-evidence-upload,2026-09-01-organization-harness-dashboard
Intent
Close the gap between the two halves that already existed: better-harness upload plan prepared a reviewable packet but could never send it, and the Dashboard rendered an upload section whose input was a hard-coded empty array. Nothing carried evidence from one to the other, and the page itself showed a single snapshot taken when its server process started.
This spec makes the loop real and keeps every existing consent boundary. The prepared plan remains the only thing that names a destination, the packet contract is unchanged, and applying a plan is a separate, explicit command rather than a side effect of preparing one.
Acceptance Scenarios
- AC-1 — Apply is explicit and plan-directed:
better-harness upload apply --plan <file>posts a validated plan to the endpoint recorded inside that plan. The destination cannot be supplied or overridden on the command line, so applying cannot redirect evidence somewhere the reviewed plan did not name.--helpreturns without reading the plan or using the network. - AC-2 — Receipts are verifiable: the destination returns a
better-harness.task-evidence-upload-receipt/v1whose body is bound by a canonical SHA-256 digest.applyrejects a receipt whose digest, destination, or organization does not match the applied plan, and reports a rejected or unreachable destination as a failure with no receipt. - AC-3 — Idempotent acceptance: the packet digest is the storage key and the idempotency key. Sequential or concurrent re-application of the same plan reports one
acceptedresult andduplicatethereafter, preserves the first acceptance time, and leaves exactly one stored record. - AC-4 — The destination validates before it stores: the local
/api/uploadroute requires JSON and rejects an invalid or tampered plan, a plan addressed to another endpoint, an oversized body, and an organization outsideBETTER_HARNESS_UPLOAD_ORGANIZATIONSwhen that is configured. A rejected request stores nothing. - AC-5 — Accepted evidence reaches the Dashboard: the collector reads stored records from the uploads directory and projects their packets into
evidencePackets. A record that cannot be parsed or validated is reported as an unavailable source rather than silently dropped. - AC-6 — Data is current: the collected input is reused for a bounded refresh window (
BETTER_HARNESS_REFRESH_MS, default 30s) and recollected after it, aged from the end of a collection rather than its start. A failed collection is not cached. Evidence written after the server started appears without restarting the process. - AC-7 — Every analyzable host is collected: session evidence defaults to all supported session platforms rather than two,
BETTER_HARNESS_PROVIDERSnarrows that set, and asset inventory covers only hosts with an inventory adapter so an unsupported host is skipped instead of reported as a failure. - AC-8 — A session limit actually bounds work: an unset limit analyzes every eligible session with
all-eligible; a configuredBETTER_HARNESS_SESSION_LIMITswitches tolatest-nso the limit applies instead of being ignored. - AC-9 — Observed context usage is shown:
contextUsagefrom the analyzed host is carried into the Dashboard input when its status isobserved, and is absent otherwise.
Input and Output Contract
upload apply consumes a prepared plan and produces:
{
"kind": "better-harness.task-evidence-upload-receipt",
"schemaVersion": 1
}carrying acceptedAt, state (accepted or duplicate), the plan's destination, a receiptId, the packetDigest and planDigest it answers, and a receiptDigest over that body.
The destination stores one better-harness.task-evidence-upload-record/v1 per packet digest, holding the receipt and the plan it accepted. The uploads directory is BETTER_HARNESS_UPLOADS, or <workspace>/.better-harness/uploads.
Non-goals
- Authentication, tenancy, RBAC, approval workflow, or a deployed control plane. The bundled endpoint is a local destination for the local Dashboard.
- Protobuf/Buf ingestion, PostgreSQL, or object storage.
- Changing the task evidence input, packet, or plan contracts.
- Automatic upload: preparing a plan still never sends anything, and applying one is always a separate command.
- Live push or websocket refresh. The page recollects on request within a bounded window.
Plan and Tasks
- Extend the upload contract with a digest-bound receipt, its validator, and a content-addressed storage key.
- Add
upload applyto the capability CLI with an injectable fetch, a bounded timeout, receipt verification against the applied plan, and stable diagnostics; register it in the root CLI. - Add a local upload store shared by the destination route and the collector, with idempotent writes and reporting reads.
- Add the
/api/uploadroute handler that validates before it stores. - Replace the collector's empty packet list with stored records, widen its provider default, make its limit meaningful, and carry observed context usage.
- Replace the Dashboard's permanent process-lifetime cache with a bounded refresh window behind a testable seam.
- Cover the chain with focused tests: contract, store, CLI, collector, the real route handler over a loopback port, and a browser run whose evidence is applied through the real CLI.
Test and Review Evidence
- AC-1, AC-2, AC-3:
npx vitest run test/cli/task-evidence-upload.test.mjscovers plan-directed posting, idempotency-key headers, receipt mismatch, rejected and unreachable destinations, tampered plans, and receipt tampering. - AC-3, AC-4, AC-5:
npm test -w @qoder-ai/harness-uiruns the upload store tests, including concurrent applies, and an end-to-end test that drives the real CLI against the real route handler over a loopback port, then projects the stored packet into the Dashboard model. Wrong media types, endpoint mismatches, tampering, and disallowed organizations are rejected before storage. - AC-6, AC-7, AC-8: focused cache, collector-argument, refresh-window, and workspace-resolution tests in
packages/harness-ui/test/local-data.test.mjs. - AC-5, AC-9:
npm run harness-ui:test:browserapplies fixture evidence throughupload planandupload applyagainst the running Dashboard in its global setup, then asserts the applied task is visible on the page.