From 1c5863c4b6f605bbe7582a8c94c06417679ca082 Mon Sep 17 00:00:00 2001 From: huangrt01 Date: Fri, 26 Jun 2026 01:04:19 +0800 Subject: [PATCH] feat: add dashboard budget governance contract --- .../dashboard/smoke/frontstage-route-smoke.ts | 6 ++ .../src/data/goal-channel-frontstage.ts | 7 ++ apps/dashboard/src/views/frontstage-page.tsx | 48 ++++++++++++ docs/README.md | 4 + docs/dashboard-budget-governance-contract.md | 78 +++++++++++++++++++ ...ontstage-dashboard-interaction-baseline.md | 2 + 6 files changed, 145 insertions(+) create mode 100644 docs/dashboard-budget-governance-contract.md diff --git a/apps/dashboard/smoke/frontstage-route-smoke.ts b/apps/dashboard/smoke/frontstage-route-smoke.ts index ca0b7c60..faac91ad 100644 --- a/apps/dashboard/smoke/frontstage-route-smoke.ts +++ b/apps/dashboard/smoke/frontstage-route-smoke.ts @@ -63,6 +63,8 @@ includes(dataSource, 'schema_version: "goal_channel_projection_v0"', "goal chann includes(dataSource, "goalChannelProjectionSchema", "goal channel zod schema"); includes(dataSource, 'mode: "read_only"', "read-only mode"); includes(dataSource, 'claimed_by: "codex-side-bypass"', "side-agent claim fixture"); +includes(dataSource, 'scheduler_rrule: "FREQ=MINUTELY;INTERVAL=3"', "scheduler cadence fixture"); +includes(dataSource, 'pause_policy: "control-plane policy only"', "pause policy fixture"); includes(dataSource, "raw_or_private_material_omitted", "source warning fixture"); includes(statusSource, "goal_channel_projection: goalChannelProjectionSchema", "status projection parser"); includes(statusSource, "local_dashboard_api", "local dashboard API status parser"); @@ -94,6 +96,10 @@ includes(frontstageSource, "read-only default", "read-only default copy"); includes(frontstageSource, "Write affordances require explicit loopback opt-in", "loopback opt-in copy"); includes(frontstageSource, "TanStack Query", "TanStack Query copy"); includes(frontstageSource, 'data-testid="frontstage-operations-strip"', "operations signal strip"); +includes(frontstageSource, 'data-testid="frontstage-budget-governance"', "budget governance panel"); +includes(frontstageSource, "Budget & Governance", "budget governance panel title"); +includes(frontstageSource, "Cadence changes, final checks, and monitor-only polls are no-spend.", "no-spend governance copy"); +includes(frontstageSource, "Audit through todo ids, run history, and quota spend events.", "budget evidence audit copy"); includes(frontstageSource, 'data-testid="frontstage-goal-select"', "goal selector"); includes(frontstageSource, "resolveFrontstageOpsStatusUrl", "ops status URL resolver"); includes(frontstageSource, "statusContractFreshnessIssue", "schema freshness gate"); diff --git a/apps/dashboard/src/data/goal-channel-frontstage.ts b/apps/dashboard/src/data/goal-channel-frontstage.ts index fbe66632..8a12df7d 100644 --- a/apps/dashboard/src/data/goal-channel-frontstage.ts +++ b/apps/dashboard/src/data/goal-channel-frontstage.ts @@ -155,7 +155,14 @@ export const sampleGoalChannelProjection: GoalChannelProjection = { }, quota: { allowed_slots: "10", + cadence_class: "active_work", + latest_evidence_ref: "run:validated_progress_fixture", + no_spend_for_cadence_change: true, + override_policy: "fresh quota guard required", + pause_policy: "control-plane policy only", reason: "synthetic fixture has quota", + scheduler_reset_token: "fixture-reset-token", + scheduler_rrule: "FREQ=MINUTELY;INTERVAL=3", spend_policy: "spend after validated writeback", spent_slots: "2", state: "eligible", diff --git a/apps/dashboard/src/views/frontstage-page.tsx b/apps/dashboard/src/views/frontstage-page.tsx index f13c45a3..7cc4827f 100644 --- a/apps/dashboard/src/views/frontstage-page.tsx +++ b/apps/dashboard/src/views/frontstage-page.tsx @@ -1568,6 +1568,38 @@ function FrontstageRoute({ : filterTodosByQuery(projection.agent_todos, normalizedTodoQuery); const visibleTodoCount = filteredUserTodos.length + filteredAgentTodos.length; const totalTodoCount = projection.user_todos.length + projection.agent_todos.length; + const budgetGovernanceRows = [ + { + label: "budget", + value: quotaUsed, + helper: `quota state: ${stringifyScalar(projection.quota.state)}`, + tone: statusTone(stringifyScalar(projection.quota.state)), + }, + { + label: "cadence", + value: stringifyScalar(projection.quota.scheduler_rrule ?? projection.quota.cadence_class ?? "scheduler hint"), + helper: `reset token: ${stringifyScalar(projection.quota.scheduler_reset_token ?? "not projected")}`, + tone: "info", + }, + { + label: "spend rule", + value: stringifyScalar(projection.quota.spend_policy), + helper: "Cadence changes, final checks, and monitor-only polls are no-spend.", + tone: "success", + }, + { + label: "controls", + value: stringifyScalar(projection.quota.override_policy ?? "preview gated"), + helper: stringifyScalar(projection.quota.pause_policy ?? "writes require CLI or loopback opt-in"), + tone: "warning", + }, + { + label: "evidence", + value: stringifyScalar(projection.quota.latest_evidence_ref ?? projection.source_refs.latest_run_generated_at ?? "run history"), + helper: "Audit through todo ids, run history, and quota spend events.", + tone: "neutral", + }, + ] satisfies Array<{ label: string; value: string; helper: string; tone: BadgeTone }>; return (
+ +
+ {budgetGovernanceRows.map((row) => ( +
+
{row.label}
+
+ {row.value} +
+
+ {row.helper} +
+
+ ))} +
+
+