Repository navigation
Dashboard: read devices, jobs, templates and schedules through the v1 client - #97
Merged
Merged
Conversation
… client The dashboard called the deprecated GET /api/devices, /api/devices/:id, /api/jobs, /api/jobs/:id and POST /api/jobs with hand-written response types. It now uses the generated client (dash/src/client.ts) for every read and change /api/v1 offers, so its types are the client's and a field the server drops fails check-api-v1 instead of blanking a column. - /api/v1 schemas state every field the dashboard reads (Beacon, Device, DeviceDetail, Job, JobDetail, Schedule), required where the handler always sends it. - listDevices and listJobs return the facets their filter menus are built from; listJobs takes has_error. - forward() carries X-Fleet-Token, so /api/v1 cancel and retry work on a collector with FLEET_DASH_TOKEN set (they were always 401 there). - scripts/check-dash-requests.ts fails the suite if dash/src calls a route deprecations.ts marks. Findings and every route /api/v1 does not offer stay on /api/*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
addisdev
marked this pull request as ready for review
October 16, 2026 02:55
Owner
Author
|
Self-review: v1 client transport keeps the dashboard's header behaviour; check-dash-requests guards against deprecated routes; the forward() X-Fleet-Token fix has a regression test. Composer enqueue via /api/v1 matches the documented posture (POST /jobs was never behind FLEET_DASH_TOKEN; FLEET_AUTH=tokens is the real gate). Checks green. Merging (LOOP-PLAN Phase 2.4, part of #83). |
# Conflicts: # CHANGELOG.md
addisdev
added a commit
that referenced
this pull request
Oct 16, 2026
… findings list facets; deprecate the older findings routes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 16, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LOOP-PLAN Phase 2 item 4. Part of #83 (Findings is not the only remaining exception, so this does not close it).
Summary
The dashboard no longer makes any request the deprecation headers mark. It reads devices, jobs, templates, schedules, the alert banner and health through the generated
/api/v1client (collector/dash/src/client.tswrapscollector/src/client/), and itsDevice,Job,DeviceDetail,JobDetail,DeviceList,JobListandScheduletypes are the generated ones. They are re-exported fromapi.ts, not redeclared.X-Fleet-Tokenfrom localStorage, read on every call (notAuthorization: Bearer), plusX-Fleet-Source: dash. A 401 on a change shows the same "paste a token" sentencemutate.tsuses. A strict-schema refusal lists eachschema_errorspath. The session cookie,/api/stream,<img>artifact links and the token banner work as before.schemas.ts) now state every field the dashboard reads: Beacon (mem_method,process_alive,busy), Device, DeviceDetail (counts,jobs,benchmarks), Job, JobDetail (locks,status_report, …) and Schedule (missed,next_run_in_s,template, …). Fields the handlers always send are marked required, socheck-api-v1fails if a handler stops sending one.listDevicesnow returnsfacets {pools, platforms, kinds}, andlistJobsreturnsfacets {status_counts, workloads, pools}and takeshas_error.openapi.jsonandapi.gen.tsare regenerated, so expect a conflict with the findings PR on those two files.forward()droppedX-Fleet-Token. WithFLEET_DASH_TOKENset and auth off, every/api/v1cancel and retry came back 401 whatever was sent, because they forward to the guarded/api/jobs/:id/cancel|retry. The header is now carried, andinner()maps a 401 tounauthorizedand a 403 toforbiddeninstead ofinternal.scripts/check-dash-requests.tsis a new suite step. It readsdash/srcand fails on any request that matchesSUCCESSORSindeprecations.ts(now exported). I checked that it fails on injectedfetch("/api/devices"),useApi(`/api/jobs/${id}`),`/api/jobs${q}`andmutate("POST", "/api/jobs").Changes you can see
POST /api/v1/jobs, so the spec is checked strictly. An unknown top-level field, or params outside the workload's manifest, is refused with the path named. The oldPOST /api/jobsaccepted it and the job failed later. The curl the composer shows now names/api/v1/jobs.source: dash(it was null).FLEET_DASH_TOKEN./api/v1/jobsdoes not check the guard, the same asPOST /jobs, which the guard's own comment says stays open. Cancel and retry are still guarded. This is a judgement call: say if you want the composer's enqueue guarded again. That would need the guard on/api/v1/jobs, which breaksfleetrand MCP against a guarded collector, because they send a bearer token.docs/api.md,docs/dashboard.md,AGENTS.mdand the CHANGELOG are updated.Still on
/api/*Findings (left untouched on purpose, waiting for findings in /api/v1):
GET /api/findings,/api/findings/:id,/api/findings/precision,POST /api/findings/:id/verdict(all inpages/Findings.tsx).Not in v1 yet:
/api/overview,/api/results/{bench,vision,ui,thermal,cold-start,drain,soak,recent},/api/evals*,/api/visual/*,/api/system,/api/locks,/api/executors,/api/events*,/api/enroll,/api/peers,/api/artifacts(list) and/api/artifacts/gc-candidates,/api/devices/:id/beacons(charts),/api/jobs/:id/mirrorand/mirror/status.GET /api/alerts): it shows per-state counts, whether a webhook is set and the thresholds, andlistAlertsreturns none of these. The banner moved to v1.GET /api/stream.POST|DELETE /api/session.PATCH /api/jobs/:id(priority),POST /api/jobs/preview-targets,PATCH|DELETE /api/devices/:id,POST /api/devices/:id/release-lock,POST /api/templates,DELETE /api/templates/:id,PATCH|DELETE /api/schedules/:id,POST /api/schedules/:id/run,POST /api/alerts/:id/ack|snooze,POST /api/power/:pool/:state,POST /api/system/{sweep,scheduler-tick,retention},POST /api/visual/baselines/accept,POST /api/artifacts/:sha/pin,DELETE /api/artifacts/:sha,POST /artifacts(upload).None of these carry a Deprecation header.
Not verified
npm run devfor the dashboard was not started. Theserver.fs.allowentry for../src/clientis from Vite's documented behaviour, not from running it.allDevicespages through, but no test covers more than one page).Test evidence (ultra, Node 24)
collector:CI=true npm test→EXIT=0. Every step passed: dashboard typecheck and build, "the dashboard calls no deprecated route" (ok — 62 requests in dash/src, none deprecated),gen:api --check, authALL PASS, lifecycleALL PASS, smokeALL PASS, api v1 contractALL PASS. That is 1284oklines and 0 FAIL. New checks:ok listJobs has_error=true finds the cancelled job, and only jobs with an errorok listJobs facets count every status, over the whole tableok listJobs facets name the workloadsok listDevices facets ignore the filterok its /api/v1 reads carry X-Fleet-Token toook as alice, via dashFLEET_DASH_TOKEN with auth off:ok cancel without the token is refused, as unauthorized,ok cancel with the token works,ok and so does retry. Run with theforward()fix reverted, the last two FAIL with401 X-Fleet-Token required.fleet:npm test→tests 81, pass 79, fail 0(2 skipped),EXIT=0.FLEET_DASH_TOKENset. Both runs wereALL PASS. It covers:has_error,status) and job detailsource: dash🤖 Generated with Claude Code