Commit Graph

1633 Commits

Author SHA1 Message Date
saravanakumardb1
2bd97791c9 feat(fleet): resilient PR merge on ship (inline attempt + background retry)
The corporate proxy intermittently 407s GitHub's API, so a single gh pr merge can
fail transiently. Try once inline (fast path), then retry in the background with
backoff (3s/8s/20s/45s) without blocking the ship; mark prState=merged when one
lands. Best-effort throughout.
2026-05-31 16:13:52 -07:00
saravanakumardb1
740335a149 feat(fleet): Ship can also merge the linked PR (gh pr merge)
On ship (Ship button / operator action / autoship PATCH), when the run has an open
PR and FLEET_SHIP_MERGES_PR=1, the coordinator squash-merges it via gh (best-effort,
where gh is authed) and marks the run prState=merged. UI button reads 'Ship & merge
PR' when an open PR exists; Ship refreshes runs.
2026-05-31 16:08:28 -07:00
saravanakumardb1
37d049eb69 fix(tracker-web): telemetry ingest auth (X-Install-Token) + show cost as approx
- telemetry proxy attaches an X-Install-Token (derived from the payload, with a
  fallback) so the backend ingest auth gate stops returning 401 on browser beacons.
- job-detail Cost shows ~$x.xx approx when the figure is estimated (token-based).
2026-05-31 15:58:26 -07:00
saravanakumardb1
696ee4189e feat(fleet): track + show PR status (open/merged) on the run
Runs now carry prState (open when the PR is opened, merged when auto-merge
succeeds), reported on lease release. Job-detail Runs table shows a status badge
next to the PR link.
2026-05-31 13:56:33 -07:00
saravanakumardb1
e9c1714c13 feat(tracker-web): factory dropdown routes job to the selected factory's product
New Job form: pick a Factory (2 hardcoded for this machine) -> the job is submitted
to that factory's product (submitJob productId override) and the dashboard view
switches to it so the job is visible. Confirmation shows factory + product.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 06:28:28 -07:00
saravanakumardb1
c239abeec9 feat(fleet): per-repo verify + auto-merge options for PR jobs
Add job-level verify (command run in the PR checkout before opening the PR) and
autoMerge (squash-merge the PR once opened). Surfaced in the New Job form as a
Verify-command field + Auto-merge checkbox (PR mode only); confirmation now shows
PR-mode/repo. More repos added to the dropdown.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 06:17:19 -07:00
saravanakumardb1
2adddce754 feat(tracker-web): hardcoded repo dropdown for PR-mode jobs (base=main)
MVP: the New Job form picks a PR target from a fixed dropdown of local repos; base
branch is fixed to main. Empty selection = no PR (plain job).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 05:36:50 -07:00
saravanakumardb1
d350159025 Merge feat/fleet-pr-deliverable: PR deliverables for fleet jobs 2026-05-31 05:27:16 -07:00
saravanakumardb1
883cf329e5 feat(fleet): PR deliverables — jobs target a repo, factory opens a PR, link recorded
Make "shipped" produce a real artifact. A job can now carry an optional repo
(owner/name or clone URL) + baseBranch; the factory's PR mode runs the agent in an
isolated checkout, opens a PR, and records the link.

Backend:
- SubmitJobSchema + FleetJobDoc: optional repo/baseBranch (recorded on submit).
- FleetRunDoc: optional prUrl/branch.
- ReleaseLease report carries prUrl/branch -> stored on the run.
- +2 coordinator tests.

UI (tracker-web):
- New Job form gains optional Repo + Base branch fields (and fixes the priority
  options to the valid critical/high/medium/low; "normal" was rejected by the API).
- Job detail Runs table shows a PR ↗ link from run.prUrl.
- fleet-client: submitJob repo/baseBranch; FleetRun prUrl/branch; OperatorAction +ship.

Docs: FLEET_CONTROL_PLANE.md "PR deliverable (PR mode)" section.

Verified: tsc clean; fleet suite 182; tracker-web 230.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 05:27:11 -07:00
saravanakumardb1
8b9ca4fee2 Merge feat/fleet-ui-submit-job: submit fleet jobs from the dashboard 2026-05-31 04:53:28 -07:00
saravanakumardb1
176b778a1f feat(tracker-web): submit fleet jobs from the dashboard
Add a collapsible 'New Job' form on the fleet jobs page (task body, priority,
capabilities) wired to a new fleet-client submitJob() -> POST /fleet/jobs, with
inline success/error and auto-refresh. Also add 'ship' to the OperatorAction type
for parity with the coordinator. The existing job-detail 'Ship' button already
drives the human-gate testing -> shipped transition.

Verified: tsc clean; tracker-web suite 230/230.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:53:23 -07:00
saravanakumardb1
c773742658 Merge fix/command-palette-undefined-key 2026-05-31 04:47:45 -07:00
saravanakumardb1
de7e0dcb84 fix(command-palette): guard keydown with undefined key (no crash)
Some keydown events (autofill, IME/composition, certain extensions) arrive with
e.key === undefined, crashing the hotkey handler at e.key.toLowerCase(). Guard
e.key (and hotkey.key) before comparing. +1 test (undefined-key keydown is
ignored without throwing). 27 pass.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:47:40 -07:00
saravanakumardb1
60989d7b62 Merge fix/fleet-run-result-on-ship: run result mirrors shipped + docs 2026-05-31 04:31:51 -07:00
saravanakumardb1
bcdb5dcdf3 fix(fleet): run result mirrors a shipped job + document testing->shipped
A job can reach `shipped` via autoship PATCH, the `ship` operator action, or a
terminal lease release, but the run-level `result` was left at whatever the
factory last reported (e.g. `review`), so the dashboard showed a shipped job with
a non-terminal run result.

- Add markLatestRunShipped(): on any transition to `shipped`, set the latest run
  result to `shipped` (+ endedAt if unset). Idempotent, best-effort.
- Wire it into patchJobFenced (ungated; budget accrual stays flag-gated) and the
  `ship` operator action.
- Document the testing->shipped paths (factory autoship vs `ship` operator action)
  and the run-mirroring in docs/GIGAFACTORY/FLEET_CONTROL_PLANE.md.

Tests: +2 (patchJobFenced->shipped and operator ship both set run.result=shipped).
Fleet suite 180 pass; tsc clean.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:31:46 -07:00
saravanakumardb1
f7740f13e9 Merge fix/tracker-web-test-env: stable DOM env + Node-25 localStorage fix 2026-05-31 04:12:50 -07:00
saravanakumardb1
06d7d881a0 fix(tracker-web): stable test DOM env + working localStorage (Node 25)
product-context.test.tsx failed with "localStorage.clear is not a function".
Root cause: Node 25 ships a global `localStorage` Web Storage stub that is
non-functional without --localstorage-file, and it shadows the test DOM
environment's storage. The two DOM tests also relied on `jsdom`, which was only
present transitively (not a tracker-web dependency) while the rest of the
monorepo standardizes on happy-dom.

- Add happy-dom as a tracker-web devDependency; switch the two `@vitest-environment
  jsdom` tests (product-context, command-menu) to happy-dom.
- Add vitest.setup.ts that installs a real in-memory Web Storage over Node 25's
  non-functional stub when the active localStorage/sessionStorage lacks the
  Storage API; wire it via test.setupFiles.

Verified: full tracker-web suite 230/230 (was 228/2).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:12:34 -07:00
saravanakumardb1
eb702137de Merge chore/types-node-25: bump @types/node 22 -> 25 2026-05-31 04:03:12 -07:00
saravanakumardb1
8fe26027e7 chore(deps): bump @types/node 22 -> 25 (dev types)
Verified: full workspace build (tsc) green across all packages/services/dashboards;
fleet+items tests pass. Compile-time only.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:02:56 -07:00
saravanakumardb1
fa419e3b80 Merge chore/stripe-v20-migration: Stripe SDK 17 -> 20 + API migration 2026-05-31 04:00:32 -07:00
saravanakumardb1
3022e634b8 feat(billing): migrate to Stripe SDK v20 (API shape changes)
Bump stripe 17 -> 20 and adapt to the breaking API changes:
- PromotionCode: coupon moved under `promotion` ({ type: 'coupon', coupon }).
  mapPromo now reads p.promotion.coupon; create now passes
  promotion: { type: 'coupon', coupon: id } instead of a top-level coupon.
- Subscription.current_period_end removed (now per subscription item). Add
  getSubscriptionPeriodEnd() = max(items[].current_period_end) and use it in the
  customer.subscription.updated webhook handler.
- Update the promos route test fixture to the new promotion.coupon shape.

Verified: platform-service build (tsc) clean; promos (14) + stripe/subscriptions/
billing tests pass; full suite 1692/1692.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:00:13 -07:00
saravanakumardb1
58ed096ac8 Merge chore/dep-bumps-majors: happy-dom 20, lint-staged 16, @fastify/cors 11, bcryptjs 3 2026-05-31 03:51:31 -07:00
saravanakumardb1
0079274bff chore(deps): bump bcryptjs 2 -> 3 (+ @types/bcryptjs 3)
Verified: auth + platform-service build (tsc, default import still resolves);
packages/auth (31) + platform-service auth/api-key (65) pass (hash/compare work).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 03:46:19 -07:00
saravanakumardb1
66a4a74aa6 chore(deps): bump @fastify/cors 10 -> 11
Verified: fastify-core + platform-service build (tsc); createServiceApp boot smoke
handles a CORS preflight (OPTIONS -> 204 with access-control-allow-origin).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 03:44:54 -07:00
saravanakumardb1
168bff6e27 chore(deps): bump lint-staged 15 -> 16 (pre-commit tooling)
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 03:43:42 -07:00
saravanakumardb1
83745b2fee chore(deps): bump happy-dom 18 -> 20 (test env)
Verified: UI package suites (ui, dashboard-components, data-table, react-auth)
+ tracker-web all green; no new failures.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 03:42:57 -07:00
saravanakumardb1
4c974b94e3 Merge chore/dep-bumps-safe: bump @azure/cosmos, jose, @typescript-eslint/parser 2026-05-31 03:28:56 -07:00
saravanakumardb1
808f615124 chore(deps): bump @azure/cosmos, jose, @typescript-eslint/parser
Applied fresh on current main (the matching dependabot branches were 350-430
commits behind and would have conflicted on the lockfile):
- @azure/cosmos 4.9.1 -> 4.9.3
- jose 6.1.3 -> 6.2.3 (mcp-server stays on the 5.x line: 5.9.6 -> 5.10.0)
- @typescript-eslint/parser 8.0 -> 8.60.0

Verified: full workspace build green; platform-service suite 1684 pass (only the
pre-existing single-fork migration-isolation flake, passes isolated); tracker-web
228 pass (only the pre-existing happy-dom product-context failures). No new
regressions. Major bumps (fastify/cors, happy-dom, lint-staged, stripe,
types/node) deferred for separate review.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 03:28:40 -07:00
saravanakumardb1
a528ffea1d Merge fix/fleet-phase3-hardening: budget authz, idempotent accrual, cycle detection, artifact cleanup 2026-05-31 02:46:18 -07:00
saravanakumardb1
1503ef2e19 fix(fleet): Phase 3 hardening — budget authz, idempotent accrual, cycle detection, artifact
Re-applies 4 defects merged with Phase 3 (still present on main), ported from the
stale reference branch and adapted to current main.

FIX 1 (BLOCKER): all 5 budget routes (GET/burndown/PUT/pause/resume) read
productId from the URL with no caller check, so a caller for product A could
read or modify product B budget. Add requireOwnProduct() -> 403 on mismatch.

FIX 2: stop tracking services/platform-service/.data/platform-events.json (the
EVENT_BUS_FILE runtime log); gitignore .data/.

FIX 3: accrueSpend was definition-only (budgets never accrued) and not
idempotent. Add accruedRunIds to FleetBudgetDoc; accrueSpend(productId, costUsd,
runId) no-ops on a seen runId; wire it into patchJobFenced on stage shipped,
flag-gated + best-effort + idempotent via jobId:leaseEpoch. Accrue the run ACTUAL
insights.costUsd so spentUsd and costBurndown agree.

FIX 4: submitChildren cycle detection is now batch-aware — rejects duplicate
child keys and walks each child declared deps across BOTH the unpersisted batch
and existing jobs, rejecting child-self, child-parent and sibling cycles.

Tests: +2 budget-authz (403 on all 5 verbs), +3 accrual (idempotent runId, ship
accrues insights.costUsd once, flag-off no accrual), +5 cycle detection. Gates
green: tsc/build, fleet+items (204), full suite (only the unrelated single-fork
migration-isolation file flakes, passes isolated). Flags stay default-OFF.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 02:45:52 -07:00
saravanakumardb1
c1aad8a819 fix(tracker-web): do not send Content-Type on bodyless fleet proxy POSTs
Operator actions (ship/requeue/cancel) are bodyless POSTs. The proxy always set
Content-Type: application/json, so the backend rejected them with
FST_ERR_CTP_EMPTY_JSON_BODY (500). Only declare the JSON content type when a
body is actually forwarded. Fixes the fleet dashboard action buttons.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 01:50:11 -07:00
saravanakumardb1
32e426d423 feat(fleet): run-insights reporting + ship action; complete the lifecycle
Make the Agent Gigafactory fully drivable end-to-end via the API:

- lease/release now accepts `insights` (model/tokens/cost) + `result`, recorded
  on the current run with endedAt — factories report cost/token metrics on
  completion (previously no API existed; runs stayed insights:{}).
- add `ship` operator action so a job in `testing` (where the review gate left
  no lease holder) can reach the terminal `shipped` stage. Idempotent.
- operatorAction now retries on optimistic-concurrency conflict with backoff
  (mirrors submitReview) so a ship right after approve survives real-Cosmos
  read-after-write lag instead of a spurious 409.

Tests: +2 coordinator (ship idempotent, release records insights) and +2 route
integration (gated submit->...->ship->metrics; release-with-insights). 170 pass.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 01:49:59 -07:00
saravanakumardb1
939c7b4621 fix(tracker-web): include productId in login (LoginSchema requires it)
The login form posted {email,password} but platform-service LoginSchema
requires productId, so real logins returned 400 (only the mocked e2e passed).
Send the selected product (tracker_selected_product) or the default PRODUCT_ID.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 01:21:58 -07:00
saravanakumardb1
2253f888c7 feat(tracker-web): per-run cost/token/time metrics + log download; fix fleet proxy
Job detail Runs table now shows Duration, Model, Tokens (in/out + cached) and
Cost per run, plus a per-job totals header (cost / tokens / wall-time). Artifacts
get a view/download button via a fresh signed URL. Also fix the fleet API proxy
to forward to /api/fleet/* (backend mounts fleet under /api) so a live backend
resolves; previously it returned 404 and only the mocked e2e passed.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 01:19:57 -07:00
saravanakumardb1
8158efacf7 chore(local-llms): refresh chat-history snapshot (mirrors verified diff-free)
Ran refresh.sh; only .last-refresh.log changed — all mirrored repo docs/
workflows already match their source bytes, confirming the .prettierignore
fix ended the formatter churn. Future refreshes now only move the periodic log.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-30 23:32:42 -07:00
Saravanakumar D
6d66355a22 feat(scripts): add Cosmos DB cost report tooling (.sh + .ps1)
Reports billed cost, RU by database, RU by container drill-down, and
storage for the cosmos-mywisprai account. Auto-detects serverless vs
provisioned billing mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 23:30:22 -07:00
saravanakumardb1
cad75b1c02 chore: stop prettier churn on __LOCAL_LLMs mirrors + refresh snapshot
Add .prettierignore excluding __LOCAL_LLMs/ (and dist/build/generated). Those
are mirrored copies refreshed by the chat-history sync; prettier was rewriting
them on every commit, fighting the generator and producing permanent diff
churn. Also commits the latest refresh snapshot in its native format.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-30 23:25:34 -07:00
saravanakumardb1
e0a904c7ea fix(cosmos): support composite indexes; add fleet_jobs (priorityOrder, createdAt)
Azure Cosmos cannot serve a multi-field ORDER BY without a matching composite
index (the local emulator is lenient, real Cosmos returns HTTP 400). The fleet
listJobs() query orders by (priorityOrder, createdAt), which broke
GET /api/fleet/metrics and /api/fleet/jobs on real Cosmos.

- ContainerConfig gains an optional `compositeIndexes` field
- container init applies it on create AND reconciles it onto existing
  containers (createIfNotExists never updates an existing index policy)
- fleet_jobs declares the (priorityOrder ASC, createdAt ASC) composite index

Verified live against Azure Cosmos: both endpoints now return 200.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-30 23:07:06 -07:00
saravanakumardb1
c1f85050a0 chore(local-llms): update WINDSURF chat-history, env audit, and workflow logs
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-30 22:25:13 -07:00
Saravanakumar D
20bcbd9f19 docs(gigafactory): uppercase GIGAFACTORY folder + add index README
Rename docs/gigafactory/ to docs/GIGAFACTORY/ and update the cross-repo
source-of-truth references in the fleet README and types.ts comment. Add an
index README listing the platform docs and pointing to the canonical spec in
learning_ai_devops_tools. Docs/comment only; no behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 21:22:21 -07:00
Saravanakumar D
fc000c4c20 docs(gigafactory): consolidate gigafactory docs into docs/gigafactory/
Move ROADMAP_COMPLETION_AUDIT.md, TASKS_TO_COMPLETE.md,
gigafactory-phase3-progress.md and FLEET_CONTROL_PLANE.md under
docs/gigafactory/ so the scattered Gigafactory docs are easy to discover.
Update intra-doc and cross-repo source-of-truth references (fleet README
and types.ts comment) to the new agent-queue/docs/gigafactory/ path.
Pure docs/comment move; no behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 21:07:20 -07:00
Saravanakumar D
0799f69c30 feat(fleet-web): harden budget bar, surface SSE polling, allow checkpoint in patchJob
- budget page: guard spend bar against missing/zero ceiling (no NaN width);
  show an explicit "no ceiling set" state. Add pure budgetUsagePct() helper.
- job detail: replace silent live/poll toggle with an explicit stream-mode
  badge (Live vs Polling) so operators see when SSE degrades to polling.
- fleet-client: extend patchJob to carry optional checkpoint/blockedReason
  matching the server PatchJobSchema; add FleetCheckpoint type.
- tests: unit cover budgetUsagePct + patchJob checkpoint forwarding; e2e
  asserts the polling indicator appears when the stream is unavailable.
- ci: add a Gitea Playwright e2e job that runs the fleet control-plane specs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 20:35:05 -07:00
saravanakumardb1
3de2a797b9 docs(cheatsheets): document longrun helper in long-running-jobs guide 2026-05-30 19:26:06 -07:00
saravanakumardb1
5df580d999 docs(cheatsheets): add long-running/overnight jobs cheat sheet 2026-05-30 19:20:08 -07:00
Saravanakumar D
932951dbaf docs: update roadmap audit to reflect completed Phase 3 slices
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 19:05:33 -07:00
Saravanakumar D
4ac499f301 feat: add multi-reviewer human gate (review-policy routing)
Implements the §14 Phase 3 review gate. requestReview() routes a building
job into the review stage (fencing any worker), carrying a normalized policy
(requiredApprovals + reviewer allowlist) and clearing prior decisions.
submitReview() records one decision per reviewer (last-write-wins, identity-
normalized), advances the job to testing once distinct approvals reach the
quorum, and treats any reject as a veto that returns the job to queued for
rework. Adds POST /fleet/jobs/:id/review/request and POST /fleet/jobs/:id/review,
a typed client, and a review-gate card on the job-detail page.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 19:04:24 -07:00
Saravanakumar D
c9c2c174db feat: add fleet metrics + alerting (GET /fleet/metrics)
Adds coordinator.fleetMetrics() computing queue depth, stage histogram,
oldest-queued age (starvation signal), factory health and seat utilization,
plus derived alerts (no_live_capacity, all_factories_down, queue_starvation,
saturated, stale_factories). Exposed via GET /fleet/metrics and surfaced as a
metrics+alerts panel on the fleet overview. Thresholds injectable for tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 18:51:59 -07:00
Saravanakumar D
d780739cbe test: add fleet control-plane Playwright e2e coverage
New e2e/fleet.spec.ts with a method- and URL-aware /api/fleet/** mock that
holds mutable state so operator actions and budget toggles reflect in
follow-up GETs. Covers: fleet overview (factory cards + recent jobs), jobs
table + stage filter, job detail requeue (stage building->queued) with the
SSE-driven Live badge, and budget pause/resume. All 4 specs green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 18:44:53 -07:00
Saravanakumar D
ea42602407 feat: add resumable SSE live event stream for fleet jobs
Backend: GET /fleet/jobs/:id/events/stream emits a snapshot (seq > Last-Event-ID)
then long-polls the append-only event log, closing after a bounded window so
EventSource-style clients reconnect cleanly. Honors Last-Event-ID resume,
keepalive comments, and a terminal error frame.

Frontend: subscribeJobEvents uses fetch streaming (to send auth + product
headers) with parseSseFrames, Last-Event-ID resume, reconnect backoff, and a
fatal-on-error-frame fallback to polling. Job detail page subscribes live
(deduped by seq), falls back to 4s polling on failure, and shows a Live badge;
refresh() now merges events so a slow snapshot can't clobber streamed ones.

Tests: +3 route (snapshot, resume cursor, append-after-connect), +5 client
(parseSseFrames x2, subscribe deliver/error/resume/error-frame). fleet 150, web 222.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 18:38:50 -07:00
Saravanakumar D
1ae15a7755 docs: mark cost burndown complete
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 18:25:46 -07:00