Skip to content

Phase 6 — Panel frontend hardening (rides 0.19.0)#320

Merged
rennf93 merged 51 commits into
fix/scan-background-enginesfrom
fix/scan-panel-frontend
Jul 7, 2026
Merged

Phase 6 — Panel frontend hardening (rides 0.19.0)#320
rennf93 merged 51 commits into
fix/scan-background-enginesfrom
fix/scan-panel-frontend

Conversation

@rennf93

@rennf93 rennf93 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Phase 6 — Panel frontend hardening (rides 0.19.0)

Sixth phase of the 2026-07-06 full-codebase-scan fix program. Ten verified panel-frontend findings + an accept-as-is comment, all under the existing ## [0.19.0] CHANGELOG section. Stacks on Phase 5 (fix/scan-background-engines, PR #319) — base is fix/scan-background-engines; merge #319 first.

Fixed

  • C4 (7f825736, 377e65b5) — panel /ws/system WebSocket is now shared across consumers (one ref-counted socket per URL in a module-level registry, fanning messages + state to all subscribers) instead of one socket per useWebSocket mount. useA2ALiveStream + useRateLimitWebSocket now share one /system socket. Long-tail reconnect: exponential backoff capped at WS_RECONNECT_MAX_INTERVAL=30s with no max-attempts freeze (the old WS_MAX_RECONNECT_ATTEMPTS=3 dead-cap that terminal-disconnected at attempt 4 is gone). A pong-timeout watchdog force-closes a dead socket at WS_PONG_TIMEOUT_MS=60s of no pong. 377e65b5 is the fix-wave: discriminating long-tail-retry tests (each FAILS on a gate-only revert AND a cap-only revert), the dead "freeze" if-block deleted, and manual disconnect() evicts the shared conn.
  • H15 (d1ae1ea4) — video-post-queue captions derive per render (editedX ?? post.x_caption ?? ""), mirroring x-post-queue.tsx:64-65. A CEO in-flight caption edit is no longer clobbered by a background refetch reinitializing useState(post.x_caption ?? "").
  • H16 (f2fbf15e) — settings page Save wired to settingsApi.update (persist + invalidateQueries(["settings"]) read-back); each control tracks edits ?? server ?? default per the transcript-retention-card.tsx pattern. The Save button was previously decorative.
  • H17 (1e2bc8f2) — tasks page passes single-select status/team + limit: 500 to useTasks (server-side filter via /tasks/summary); multi-select (>1) status/team + task_type/project/product stay client-side (backend doesn't accept them). Was fetching the whole backlog with { q } only. DTO imported as TaskApiFilters to avoid the TaskFilters React-component name collision.
  • H18 (15fba310, 2e839ebf) — useAgents roster re-derives on live-status change: a statusEpoch derived from the orchestratorStatus.agents snapshot (${agent_id}:${state} joined) joins the useAgents queryKey, so the existing 10s useOrchestratorStatus poll invalidates the cached 5-min roster immediately. Keyed on the live snapshot, not the roster (circular → never changes). No refetchInterval added. 2e839ebf drops the H18: spec-ref from the production comment.
  • M40 (daf98181, a41223d7) — useMetrics reads agent counts from the useAgentStatus 10s poll cache (queryClient.getQueryData(dashboardKeys.agentStatus()) + fetchQuery cold-cache fallback) instead of issuing its own redundant 60s getAgentStatus() fetch. Writer + reader share the exact same key (verified no mismatch). a41223d7 drops the M40: spec-ref + tightens the comment.
  • M41 (2470b045) — scorecard refetchInterval 60s → 5min (extracted SCORECARD_REFETCH_INTERVAL = 300_000 at module scope; both useMemberScorecard + useOrgScorecard use it). Scorecard data changes slowly; 25 req/min → 5.
  • M42 (d68a371f) — feature-flag off-transitions (true→false) confirm via Radix AlertDialog before the mutation fires; on-transitions stay immediate. Pending state tracks all in-flight toggles in a Set<string> (onMutate add / onSettled delete, immutable copies, error-path clear) — each row locks independently, replacing the old single-key toggleMutation.variables?.key check that showed the wrong row as pending under rapid toggles.
  • M43 (43a8f57c) — X/TikTok credentials clear-behind: emptying all four fields when credentials exist (isClearing = noneFilled && has_credentials) now confirms via AlertDialog before the destructive clear. Normal save (any field filled) stays immediate. Both cards symmetric; the confirm handler uses confirm-time form values (react-query re-binds mutationFn each render, no stale closure).
  • M44 (46ecb310) — rate-limit store syncFromApi merges by freshest hitAt (existing.hitAt >= entry.hitAt → keep existing) instead of wholesale-replacing; an out-of-order older snapshot no longer regresses the displayed freshest hit. Omitted entries retained per the brief. A2A page invalidates a2aLiveKeys.all on /ws/system reconnect via a useEffect that fires only on a false → true transition (prevConnected ref, initial-mount skipped, no storm).

Accept-as-is

  • L32 (fd496fbe) — the proxy.ts cookie-presence check is a UX redirect to /login, NOT a security boundary (the API /api/* enforces auth independently). Accept-as-is architecturally; a one-line clarifying comment added so a future reader doesn't mistake it for a control. No behavior change, no CHANGELOG bullet.

CHANGELOG

  • (fd496fbe) — Phase 6 entries appended under the existing ### Fixed of ## [0.19.0]. No new version section. CHANGELOG base blob verified bdc08a18 before edit.

End-of-branch fix wave

  • (1f0acb61) — two stale-comment cleanups from the opus whole-branch review: deleted the misleading 3-line "pin attempts at the floor" comment in connection.ts (the code never pins reconnectAttempts, only caps the delay — the ponytail one-liner already says this), and tightened the tasks/page.tsx:163 lead-in from "Fetch all tasks…" to "Fetch tasks (server-filtered for single-select) + client-side multi-select extras". Comment-only, no behavior/test change.

Verification

  • pnpm lint + pnpm typecheck — clean.
  • pnpm vitest run — 47 files / 304 tests pass.
  • Per-task reviews: Tasks 1–11 each Approved (sonnet reviewers); Tasks 1, 5, 6 had fix subagents for comment-only findings (spec-ref drops + comment tightening), all controller-adjudicated or re-reviewed Approved.
  • Whole-branch opus review: SHIP — no Critical/Important; cross-task interactions all compose (WS shared-socket registry + pong watchdog + backoff cap form one coherent layer; H18/M40/M44 operate on different queryKey families with no collision; AlertDialog confirm pattern consistent across feature-flags + X/TikTok credentials; edited ?? serverValue pattern consistent with existing references); TDD spot-checks (H15, M40, C4 long-tail) each fail on pre-fix for the right reason; binding constraints verified across all 15 commits (signed, no co-author, no @ts-ignore/eslint-disable added, no spec refs in production code, AGPL-3.0 only, no new dependencies — Radix AlertDialog was already in the project). One Minor dismissed (cosmetic prettier reflow of buildPair test signature — prettier-compliant, reverting fights the formatter).

Model note

Implementers ran on sonnet; per-task reviews on sonnet; whole-branch review on opus. kimi-k2.7-code:cloud is not routable in this harness (flagged to CEO; accepted).

🤖 Generated with Claude Code

rennf93 added 15 commits July 7, 2026 03:12
…block + evict dead shared conn on manual disconnect

Finding 1 (Critical, websocket.test.ts): the two long-tail-retry tests fired onopen between close cycles, which reset reconnectAttempts to 0 each cycle, so they passed under the pre-fix 3-attempt gate. Rewrote both to NEVER fire onopen between closes, so attempts accumulates: test 1 asserts state stays 'reconnecting' past attempt 3 (old gate would flip 'disconnected' terminal); test 2 asserts a new socket is constructed within 30000ms at attempt 7 where uncapped 5000*1.5^7 ~= 85s (old uncapped code would leave the timer unexpired). Verified both FAIL on a reverted old-shape connection.ts and PASS on the fixed code.

Finding 2 (Important, connection.ts): the 'if (raw >= cap) this.reconnectAttempts = exp' block was a no-op (exp was just read from the same field) and the unconditional increment afterwards grew the counter regardless. Deleted the dead block; kept the Math.min cap on the delay. Replaced the misleading ponytail comment with an accurate one: delay is capped, counter grows unbounded but delay is bounded.

Finding 3 (Important, use-websocket.ts): manual disconnect() tore down the shared conn for all subscribers but left the dead (manualClose=true, never reconnects) entry in _sharedSockets, so a later mount hit the reuse branch, attached a subscriber, replayed 'disconnected', and never called connect(). Added a urlRef and _sharedSockets.delete(url) in the manual disconnect callback so a later mount reopens a fresh conn.
@github-project-automation github-project-automation Bot moved this to Backlog in RoboCo Kanban Jul 7, 2026
@github-actions github-actions Bot added documentation Docs, README, CHANGELOG, governance files area: panel Touches panel/ (Next.js control panel) labels Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Thanks for opening your first pull request on RoboCo!

Quick checklist before review (most of these are enforced by CI, but worth a glance):

  • make quality — ruff format check, ruff check, mypy, pytest (≥80% coverage), and the rest of the gate
  • Panel changes pass pnpm lint and pnpm exec tsc --noEmit (run from panel/)
  • No # noqa / # type: ignore shortcuts; pre-existing violations in touched files are fixed
  • Added an entry under ## [Unreleased] in CHANGELOG.md
  • Signed the CLA (the bot will prompt you on this PR)
  • Signed your commits — master requires verified signatures (SSH signing setup)
  • Updated any affected docs under docs/

See CONTRIBUTING.md for the full workflow and the Code of Conduct for the community standards we follow.

Welcome aboard — a maintainer will review shortly.

rennf93 added 14 commits July 7, 2026 06:35
…ep so live cost reflects Anthropic cache spend
@rennf93 rennf93 self-assigned this Jul 7, 2026
@rennf93 rennf93 moved this from Backlog to In review in RoboCo Kanban Jul 7, 2026
rennf93 added 3 commits July 7, 2026 08:25
[phase9] Auth hardening: bound agent tokens (iat/exp) + JWT jti revocation
[scan-fix] Phase 8: LLM providers / usage / billing
[Phase 7] schemas/conventions/MegaTask/API fixes (15 findings, scan-fix program)
@github-actions github-actions Bot added dependencies pyproject.toml / uv.lock or panel package manifests area: api Touches roboco/api/ (FastAPI routes, schemas, app) area: services Touches roboco/services/ (business logic, side effects) area: db Touches roboco/db/ or roboco/models/ area: alembic Touches alembic/ (database migrations) tests Test suite changes area: gateway Touches roboco/services/gateway/ (Choreographer, verb surface) area: orchestrator Touches roboco/runtime/ (agent spawner, dispatch loops) labels Jul 7, 2026
@rennf93 rennf93 merged commit 342c142 into fix/scan-background-engines Jul 7, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in RoboCo Kanban Jul 7, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area: alembic Touches alembic/ (database migrations) area: api Touches roboco/api/ (FastAPI routes, schemas, app) area: db Touches roboco/db/ or roboco/models/ area: gateway Touches roboco/services/gateway/ (Choreographer, verb surface) area: orchestrator Touches roboco/runtime/ (agent spawner, dispatch loops) area: panel Touches panel/ (Next.js control panel) area: services Touches roboco/services/ (business logic, side effects) dependencies pyproject.toml / uv.lock or panel package manifests documentation Docs, README, CHANGELOG, governance files tests Test suite changes

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant