Skip to content

Track cross-repo Gateway operator control-surface rollout #3512

Description

@marcusrbrown

Summary

Track the cross-repo rollout for the Gateway operator control surface across fro-bot/agent, fro-bot/dashboard, marcusrbrown/infra, and this control-plane repo.

Project matrix: Gateway operator control-surface rollout

Current state

The GitHub Project matrix is the structured source of truth. This issue body is the human-readable rollup; comments are the audit log.

Shipped / closed:

  • fro-bot/agent#907 is closed. The gateway producer spine is complete on main at operator contract v1.5.0.
  • fro-bot/agent#1033 is merged and released as v0.78.0. Agent releases have since advanced to v0.85.0. The deployed gateway is pinned to v0.83.0 and runs operator contract v1.6.0 live (dashboard.fro.bot/operator/health returns {"ok":true,"contractVersion":"1.6.0"}). The v1.5.0v1.6.0 cutover is complete: main, the latest release (v0.85.0), and the deployed gateway (v0.83.0) all carry contract v1.6.0.
  • fro-bot/agent#1111 is merged. Operator-initiated run cancellation is code-complete on main: POST /operator/runs/:runId/cancel cancels a queued or executing run, auto-rejects any pending tool approval through the single settlement gate, posts a cancellation notice to the run's origin Discord thread, and reconciles a per-repo lock stranded by a crash mid-cancel on startup recovery. This closes the one functional gap in the operator surface (previously launch/list/stream/approve but no stop). It bumped the operator contract to v1.6.0 (additive route + response type, MINOR), and is now released in v0.83.0 (2026-07-04) and deployed — the running gateway carries the cancellation route and contract v1.6.0.
  • fro-bot/agent#1109 is merged. Fixes a latent bug where run-state thread_id was written empty at admission and never persisted, which broke discord approval-scope resolution (scopeIdFor) and startup recovery thread-notes. Repaired at the root by persisting the live thread_id at run adoption; web/GitHub surfaces (scoped on run_id) were unaffected.
  • fro-bot/agent operator push notifications shipped across six PRs (#1152, #1157, #1160, #1162, #1163, #1165) and released in v0.85.0 (2026-07-11). The gateway is now the authoritative owner of operator push subscriptions, VAPID dispatch, and the notification lifecycle (pending approvals, failed runs, logout deactivation), with a durable subscription store, a connect-time SSRF guard on the relay path, and coarse lifecycle audit events. Push is disabled-by-default (active only when VAPID config is present) and adds only /operator/push/* REST routes — it deliberately does not bump OPERATOR_CONTRACT_VERSION, since additive REST is invisible to the dashboard's SSE ready-frame drift gate, so v0.85.0 carries contract v1.6.0 unchanged. Not yet deployed (the deployed pin is v0.83.0); production enablement additionally requires VAPID secret provisioning.
  • fro-bot/dashboard#108 is closed (COMPLETED). It scoped the browser half of operator push (consent UI, PushManager handoff, service-worker notification rendering/click handling); the gateway server half is the v0.85.0 push feature above. Any remaining browser-side push consumption is dashboard-repo work.
  • fro-bot/agent#929 shipped the web operator surface foundation.
  • fro-bot/agent#931 shipped the operator listener topology.
  • Unit 3 work landed across fro-bot/agent#932, #934, #936, #939, and #944.
  • Unit 7 was cut and superseded by GET /operator/repos; raw binding records must not reach the browser.
  • marcusrbrown/infra#579, #580, and #581 are closed.
  • fro-bot/dashboard#24, #25, #26, #39, #47, #53, #59, and #81 are closed.
  • fro-bot/dashboard#48 is closed as superseded. The dashboard already consumes canonical approval settle frames (settled:true) and must not invent deadline-specific copy unless a future gateway contract exposes a deadline reason or timestamp.
  • fro-bot/dashboard#122 is merged. The PWA is now operator-first: / renders the operator shell, the user-facing monitoring UI is suspended from the active frontend, and /api/monitoring survives behind operator auth as a server-side snapshot endpoint.

Tracker automation:

  • fro-bot/.github#3514 installed the scheduled Gateway Rollout Tracker workflow.
  • fro-bot/.github#3517 made tracker comments deterministic and idempotent with a Project/issue-state preflight.
  • The latest settled tracker snapshot is c112ff2769bfd1abf3d7311fba5686f098a2bed5b7821a7d45c0d4c7c6be58a6.

Still open / not yet complete:

  • fro-bot/.github#3512 — this tracker issue. Keep it open until live dashboard/operator verification (browser-session flows) and the push deploy/enablement tail are complete. The gateway-side deployed-version and contract-match gates are now satisfied.
  • Gateway live capability verification — the deployed gateway (v0.83.0) now runs contract v1.6.0 and carries run cancellation (#1111) and the thread_id persistence fix (#1109), both released in v0.83.0 and live. What remains is end-to-end verification of the live operator capability flows (launch, run listing, run stream, repo listing, approvals, run cancellation) and OAuth/session/CSRF/logout behavior against the deployed gateway — this is browser-session operator verification (dashboard-repo work), not gateway-side.
  • Operator push deploy + enablement (v0.85.0) — the push feature is released in v0.85.0 but not yet deployed (the deployed pin is v0.83.0). Production enablement additionally requires VAPID secret provisioning (marcusrbrown/infra) and the dashboard browser half (consent UI, PushManager, service worker). Push is disabled-by-default, so deploying v0.85.0 without VAPID config is inert on the push surface.
  • Dashboard consumption of the v1.6.0 contract — the dashboard already pins OPERATOR_CONTRACT_VERSION at v1.6.0 (the cutover landed with the deployed gateway; the exact-match drift gate is satisfied on both sides). The remaining dashboard-side UI work — the Cancel button consuming POST /operator/runs/:runId/cancel and per-kind failureKind failure copy — is tracked at fro-bot/dashboard#179.
  • Phase-1 monitoring tail — the user-facing monitoring UI is intentionally suspended by fro-bot/dashboard#122, not relocated or fallback. The remaining verification is to ratify that suspension as a deliberate decision and to verify R8 against the surviving /api/monitoring server-side endpoint and the monitoring-v1 cache-purge path, per docs/plans/2026-06-15-001-feat-monitoring-dashboard-phase-1-plan.md.

Cross-repo dependency matrix

Workstream Item State Notes
Agent fro-bot/agent#907 Done Producer spine closed at contract v1.5.0.
Agent fro-bot/agent#1033 Released v0.78.0 published; releases since advanced to v0.85.0; deployed gateway pinned at v0.83.0, running contract v1.6.0 live.
Agent fro-bot/agent#1111 Deployed Operator run cancellation; bumped operator contract v1.5.0v1.6.0; released in v0.83.0 and live.
Agent fro-bot/agent#1109 Deployed Persists run-state thread_id at adoption; repairs discord approval-scope resolution + recovery thread-notes; released in v0.83.0.
Agent Operator push (#1152/#1157/#1160/#1162/#1163/#1165) Released Gateway-owned push subscriptions, VAPID dispatch, connect-time SSRF guard, lifecycle audit; released in v0.85.0 (contract unchanged at v1.6.0). Not yet deployed; needs VAPID secrets + dashboard browser half for enablement.
Dashboard Cancel UI (fro-bot/dashboard#179) Open Cancel button consuming POST /operator/runs/:runId/cancel + per-kind failureKind copy. The v1.6.0 pin cutover is already complete (dashboard and deployed gateway both at v1.6.0).
Dashboard Push browser half (fro-bot/dashboard#108) Done Closed COMPLETED; scoped consent UI / PushManager / service-worker rendering. Gateway server half shipped in v0.85.0.
Dashboard fro-bot/dashboard#48 Done Closed as superseded by canonical settled:true approval settle-frame behavior.
Dashboard fro-bot/dashboard#122 Done PWA operator-first; monitoring UI suspended, /api/monitoring endpoint survives behind operator auth.
Infra marcusrbrown/infra#579 Done Operator listener reverse-proxy topology.
Infra marcusrbrown/infra#580 Done Operator auth/config secrets.
Infra marcusrbrown/infra#581 Done Same-origin hosting path decision.
Control plane fro-bot/.github#3512 Open Coordination issue stays open until deploy/live verification and security/R8 checks are done.

Remaining rollout tasks

  1. Confirm the deployed gateway is running a release that includes the current operator contract. Done (re-verified 2026-07-11 at v0.83.0 / contract v1.6.0). The contractVersion health-body field (shipped since #1096) now makes this a one-line probe:
    • dashboard.fro.bot/operator/health returns {"ok":true,"contractVersion":"1.6.0"} — the running gateway reports contract v1.6.0 directly.
    • marcusrbrown/infra pins the gateway to fro-bot/agent v0.83.0 (apps/gateway/upstream.json, pin bump 7b9bffd7b, 2026-07-04); version.ts at tag v0.83.0 declares OPERATOR_CONTRACT_VERSION = '1.6.0' and the tag carries the #1111 cancellation route and #1109 thread_id fix.
    • The deploy asserts the running droplet image digest equals the CI-built digest and fails closed on mismatch.
    • Not yet advanced to v0.85.0 (operator push); that deploy is gated on VAPID secret provisioning and is inert on the push surface without it.
  2. Complete live operator verification before marking the rollout complete:
    • dashboard.fro.bot/operator/health returns healthy.
    • / and /operator remain auth-gated.
    • gateway-origin operator routes deny as expected when reached from the wrong boundary.
    • launch, run listing, run stream, repo listing, approval, and run cancellation flows work against the deployed gateway.
    • OAuth/session/CSRF/logout behavior is verified end-to-end.
    • redaction/denylist behavior is checked against production-shaped data.
  3. Phase-1 plan's operational/security tail:
    • ratify the monitoring-UI suspension from fro-bot/dashboard#122 as a deliberate decision, not a missing or fallback surface.
    • R8 verification against the surviving /api/monitoring endpoint and the monitoring-v1 cache-purge path: zero private repo names or node_id leaks in SSR, API, logs, or cache; fail closed on metadata failure. Verified in code (2026-06-28). All four leak surfaces pass with pinned tests: SSR renders no repo identity pre-auth; /api/monitoring is auth-gated with a strict DTO whitelist (internal identity fields never emitted) and Cache-Control: no-store; every aggregator logger call routes through safeRepoLogIdentity/safeRepoErrorContext; /api/* is service-worker NetworkOnly (never cached) and monitoring-v1 is purged on logout; metadata failure fails closed (no fresh query, no partial identity). One low-severity nit filed: /api/status lacks no-store (fro-bot/dashboard#125). The residual node_id-format gap is tracked at fro-bot/.github#3525. Production-shaped runtime confirmation against a live snapshot with both public and denylisted repos is still owed.
    • infra security posture: App key is file-mounted, container hardening is in place, secrets are absent from logs. Verified in code (2026-06-28). App private key is file-mounted (container receives a path via *_FILE, never key material in env; O_NOFOLLOW read); secrets are delivered via SSH stdin (never argv) with redaction on failure; the deploy asserts the running image digest fails closed on mismatch. Two gaps filed: gateway container hardening (fro-bot/agent#1053, closed 2026-06-28cap_drop: ALL + no-new-privileges shipped on main; read-only rootfs + non-root user deferred pending a tmpfs-mount audit), and there is no dedicated GitHub App key revocation runbook (marcusrbrown/infra#711).
    • post-merge security review for the dashboard and infra surfaces.
  4. Keep the Project matrix current; use this issue for audit comments only when state actually changes.

Risks to keep visible

  • Same-origin cookie boundary: do not rely on cross-site browser cookies between dashboard and Gateway origins.
  • Auth/session duplication: dashboard's existing session is not Gateway operator auth.
  • SSE proxy buffering: reverse proxy must support long-lived streams without buffering.
  • Approval settlement: the UI must dismiss settled prompts without inventing settlement reasons the gateway does not send.
  • Binding enumeration: dashboard repo selection must not expose raw binding records or private-repo identity.
  • Announce ingress separation: existing /v1/announce HMAC route must remain distinct from browser operator control.
  • Operator contract drift (exact-match, fail-closed): the dashboard's drift gate breaks every operator run stream at the ready frame on any OPERATOR_CONTRACT_VERSION skew. The v1.5.0v1.6.0 cutover is complete and matched on both sides, so this is currently satisfied. It stays a live risk for any FUTURE contract bump — a gateway release/deploy carrying a new contract version and the dashboard's pin bump must land in the same deploy window. v0.85.0 (push) is deliberately contract-neutral (v1.6.0 unchanged), so deploying it carries no drift risk.
  • Suspended-surface drift: with the monitoring UI gone, the surviving /api/monitoring endpoint and its cache-purge path must stay watched so a removed thing does not become an unwatched thing.

Acceptance criteria

  • The Project matrix is current and reflects all shipped/closed rollout items.
  • fro-bot/dashboard#48 is closed as superseded by canonical settle-frame behavior.
  • The deployed gateway's operator contract version is verified and matched by the dashboard pin before live rollout claims are made. Satisfied: the deployed gateway (v0.83.0) runs contract v1.6.0 live and the dashboard pin is at v1.6.0 — the exact-match drift gate holds on both sides.
  • Production operator flows are verified live, including auth, CSRF, repo/run surfaces, SSE, approvals, and privacy boundaries.
  • R8/privacy verification, infra security posture, revocation runbook, and post-merge security review are complete.
  • This issue links the cross-repo issues and records state transitions without performing implementation directly from the tracker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions