From 5029f5332d7f6e501616f7e5b895b6a4c52719b3 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 14 Jul 2026 22:36:36 +0800 Subject: [PATCH 1/6] feat(dashboard): expose exact-review pressure telemetry (#555) * feat(dashboard): expose exact-review pressure telemetry Co-authored-by: brokemac79 <255583030+brokemac79@users.noreply.github.com> * docs(dashboard): describe exact-review pressure telemetry Co-authored-by: brokemac79 <255583030+brokemac79@users.noreply.github.com> * feat(dashboard): render exact-review pressure Co-authored-by: brokemac79 <255583030+brokemac79@users.noreply.github.com> * chore: remove unreleased changelog entry --------- Co-authored-by: brokemac79 <255583030+brokemac79@users.noreply.github.com> Co-authored-by: brokemac79 (cherry picked from commit 41ea43be6d257f1fa48f0b7b9e45fc5f503e1b08) --- dashboard/exact-review-health.ts | 75 ++++++++++++++++++++++++++++++++ dashboard/exact-review-queue.ts | 29 +++++++++++- docs/live-dashboard.md | 16 +++++-- test/dashboard-worker.test.ts | 21 +++++++++ test/exact-review-health.test.ts | 74 ++++++++++++++++++++++++++++++- 5 files changed, 210 insertions(+), 5 deletions(-) diff --git a/dashboard/exact-review-health.ts b/dashboard/exact-review-health.ts index 470cb85c30..09816402ff 100644 --- a/dashboard/exact-review-health.ts +++ b/dashboard/exact-review-health.ts @@ -42,6 +42,25 @@ export type ExactReviewHandoffHealth = { phases: Record; }; +export type ExactReviewPressureStatus = "idle" | "congested" | "saturated" | "unknown"; + +export type ExactReviewPressureSummary = { + status: ExactReviewPressureStatus; + reason: + | "capacity_unavailable" + | "capacity_available" + | "no_ready_backlog" + | "no_admissible_backlog" + | "dispatcher_inactive" + | "handoff_unknown" + | "capacity_full_with_backlog"; + capacity: number; + active: number; + pending: number; + ready_pending: number; + admissible_pending: number; +}; + const PHASES: ExactReviewPhase[] = ["pending", "dispatching", "leased"]; export function summarizeExactReviewHandoff({ @@ -176,6 +195,57 @@ export function summarizeExactReviewHandoff({ }; } +export function summarizeExactReviewPressure({ + pending, + readyPending, + admissiblePending, + dispatching, + leased, + capacity, + dispatcherState, + handoffStatus, +}: { + pending: number; + readyPending: number; + admissiblePending: number; + dispatching: number; + leased: number; + capacity: number; + dispatcherState?: string; + handoffStatus?: string; +}): ExactReviewPressureSummary { + const safePending = nonNegativeInteger(pending); + const safeReadyPending = Math.min(safePending, nonNegativeInteger(readyPending)); + const safeAdmissiblePending = Math.min(safeReadyPending, nonNegativeInteger(admissiblePending)); + const safeCapacity = nonNegativeInteger(capacity); + const active = nonNegativeInteger(dispatching) + nonNegativeInteger(leased); + const common = { + capacity: safeCapacity, + active, + pending: safePending, + ready_pending: safeReadyPending, + admissible_pending: safeAdmissiblePending, + }; + + if (safeCapacity < 1) return { status: "unknown", reason: "capacity_unavailable", ...common }; + if (safeReadyPending < 1) return { status: "idle", reason: "no_ready_backlog", ...common }; + if (safeAdmissiblePending < 1) { + return { status: "idle", reason: "no_admissible_backlog", ...common }; + } + if (active < safeCapacity) return { status: "idle", reason: "capacity_available", ...common }; + if (dispatcherState !== "active") { + return { status: "unknown", reason: "dispatcher_inactive", ...common }; + } + if (!["healthy", "degraded", "stalled"].includes(String(handoffStatus || ""))) { + return { status: "unknown", reason: "handoff_unknown", ...common }; + } + return { + status: safeAdmissiblePending >= safeCapacity ? "saturated" : "congested", + reason: "capacity_full_with_backlog", + ...common, + }; +} + function exactReviewPhaseStartedAt( item: ExactReviewHealthItem, now: number, @@ -230,3 +300,8 @@ function finiteNumber(value: unknown, fallback: number) { const number = Number(value); return Number.isFinite(number) ? number : fallback; } + +function nonNegativeInteger(value: unknown) { + const number = Number(value); + return Number.isFinite(number) ? Math.max(0, Math.floor(number)) : 0; +} diff --git a/dashboard/exact-review-queue.ts b/dashboard/exact-review-queue.ts index 1c89a74460..624cc66b2e 100644 --- a/dashboard/exact-review-queue.ts +++ b/dashboard/exact-review-queue.ts @@ -1,5 +1,8 @@ import { stableJson } from "../src/stable-json.ts"; -import { summarizeExactReviewHandoff } from "./exact-review-health.ts"; +import { + summarizeExactReviewHandoff, + summarizeExactReviewPressure, +} from "./exact-review-health.ts"; type GithubAppJsonOptions = { method?: string; body?: BodyInit; errorLabel?: string }; const GITHUB_TIMEOUT_MS = 4500; @@ -3559,8 +3562,31 @@ function exactReviewQueueStats( publicationCapacity, ), }; + const readyPending = items.filter( + (item) => item.state === "pending" && item.nextAttemptAt <= now, + ).length; + const admissiblePending = exactReviewQueueAdmittedItems( + state, + now, + Number.MAX_SAFE_INTEGER, + targetCapacity, + publicationCapacity, + ).length; + const pressure = summarizeExactReviewPressure({ + pending: handoffHealth.phases.pending.count, + readyPending, + admissiblePending, + dispatching: handoffHealth.phases.dispatching.count, + leased: handoffHealth.phases.leased.count, + capacity, + dispatcherState: state.dispatcher?.state, + handoffStatus: handoffHealth.status, + }); return { + generated_at: handoffHealth.observed_at, pending: handoffHealth.phases.pending.count, + ready_pending: readyPending, + admissible_pending: admissiblePending, shed_since_reset: exactReviewShedSinceReset(state), dispatching: handoffHealth.phases.dispatching.count, leased: handoffHealth.phases.leased.count, @@ -3573,6 +3599,7 @@ function exactReviewQueueStats( oldest_leased_age_seconds: handoffHealth.phases.leased.oldest_age_seconds, handoff_health: handoffHealth, lanes, + pressure, next_wake_at: nextWakeAt === null ? null : new Date(nextWakeAt).toISOString(), dispatcher: { state: state.dispatcher?.state || "unknown", diff --git a/docs/live-dashboard.md b/docs/live-dashboard.md index 386349d517..cb6da7371b 100644 --- a/docs/live-dashboard.md +++ b/docs/live-dashboard.md @@ -149,6 +149,8 @@ is absent or a cache event lands in another Cloudflare colo. apply-ready candidate count and an estimated number of cursor windows to revisit the close queue; scheduled cadence time is explanatory only because successful windows can dispatch immediate continuations +- exact-review queue backlog, retry-ready backlog, target-admissible backlog, + and pressure classification from the current durable queue snapshot The Worker fetches job details only for the bounded active-run set, limits that GitHub fanout to 12 concurrent requests, and caches each run's jobs for 60 @@ -287,9 +289,17 @@ workflow state, check time, and retry time so an intentional pause cannot look like occupied executor capacity. Re-enabling the workflow does not require a queue mutation; the next status check resumes normal admission. -The same endpoint exposes `handoff_health` plus oldest timestamps and ages for -the pending, dispatching, and leased phases. New dispatch and claim transitions -carry explicit phase timestamps. Rows written by an older deployment derive +The same endpoint exposes `generated_at`, `ready_pending`, +`admissible_pending`, `pressure`, `handoff_health`, and oldest timestamps and +ages for the pending, dispatching, and leased phases. `ready_pending` excludes +retry-delayed items. `admissible_pending` further excludes ready items blocked +by their target's exact-review cap. `pressure` is a deterministic observation +from that same queue snapshot: it reports `congested` or `saturated` only when +capacity is full, the dispatcher and handoff telemetry are known, and +target-admissible backlog remains. The snapshot adds no GitHub API fanout, and +no workflow, planner, admission, continuation, or dispatch decision consumes +the pressure value. New dispatch and claim transitions carry explicit phase +timestamps. Rows written by an older deployment derive their phase start from the active dispatch or execution lease; a stale timestamp left by a rollback cannot override that newer lease, and a wholly unknown legacy age stays non-alarming. A claim is degraded after one third of the dispatch diff --git a/test/dashboard-worker.test.ts b/test/dashboard-worker.test.ts index 35ffc9ec00..f9080c0de9 100644 --- a/test/dashboard-worker.test.ts +++ b/test/dashboard-worker.test.ts @@ -744,7 +744,10 @@ test("dashboard status reads the exact-review handoff model from the durable que }); assert.ok(status); + assert.match(status.generated_at, /^\d{4}-\d{2}-\d{2}T/); assert.equal(status.pending, 2); + assert.equal(status.ready_pending, 1); + assert.equal(status.admissible_pending, 1); assert.equal(status.dispatching, 0); assert.equal(status.leased, 2); assert.equal(status.handoff_health.status, "healthy"); @@ -778,6 +781,8 @@ test("dashboard status reads the exact-review handoff model from the durable que assert.equal(typeof status.lanes.review.oldest_pending_at, "string"); assert.equal(status.lanes.review.oldest_pending_key, "openclaw/gogcli#597"); assert.equal(typeof status.lanes.review.next_attempt_at, "string"); + assert.equal(status.pressure.status, "idle"); + assert.equal(status.pressure.reason, "capacity_available"); assert.equal(await exactReviewQueueStatusSnapshot({}), null); }); @@ -6140,6 +6145,9 @@ test("dashboard hero treats apply and exact-review handoff health as attention", reconcilers: { running: 1, waiting: 0 }, }, exact_review_queue: { + pending: 4, + ready_pending: 3, + admissible_pending: 2, lanes: { review: { pending: 4, @@ -6199,6 +6207,15 @@ test("dashboard hero treats apply and exact-review handoff health as attention", }, }, }, + pressure: { + status: "congested", + reason: "capacity_full_with_backlog", + capacity: 28, + active: 28, + pending: 4, + ready_pending: 3, + admissible_pending: 2, + }, handoff_health: { status: "healthy", message: "Dispatch-to-claim handoffs are within the expected window.", @@ -6335,6 +6352,8 @@ test("dashboard hero treats apply and exact-review handoff health as attention", assert.match(elementFor("exact-review-handoff").innerHTML, /Dispatching/); assert.match(elementFor("exact-review-handoff").innerHTML, /2 of 28 exact-review slots open/); assert.match(elementFor("exact-review-handoff").innerHTML, /health-badge healthy/); + assert.match(elementFor("exact-review-handoff").innerHTML, /pressure congested/); + assert.match(elementFor("exact-review-handoff").innerHTML, /4 total · 3 ready · 2 admissible/); assert.match(elementFor("exact-review-lanes").innerHTML, /Review admission/); assert.match(elementFor("exact-review-lanes").innerHTML, /52 review admission slots open/); assert.match(elementFor("exact-review-lanes").innerHTML, /Result publication/); @@ -6396,6 +6415,7 @@ test("dashboard hero treats apply and exact-review handoff health as attention", status.recent.apply_health.items = []; status.exact_review_queue.handoff_health.status = "stalled"; + status.exact_review_queue.pressure.status = "saturated"; status.exact_review_queue.handoff_health.message = "A dispatched review has not been claimed within the expected handoff window."; context.renderDashboard(status, ""); @@ -6403,6 +6423,7 @@ test("dashboard hero treats apply and exact-review handoff health as attention", assert.equal(elementFor("hero-dot").className, "hero-dot red"); assert.match(elementFor("hero-headline").textContent, /^Needs attention/); assert.match(elementFor("exact-review-handoff").innerHTML, /health-badge stalled/); + assert.match(elementFor("exact-review-handoff").innerHTML, /pressure saturated/); Object.assign(status, { exact_review_queue: null }); status.diagnostics.exact_review_queue_error = "exact-review queue timed out"; diff --git a/test/exact-review-health.test.ts b/test/exact-review-health.test.ts index f2e0422d46..a995b3a7c7 100644 --- a/test/exact-review-health.test.ts +++ b/test/exact-review-health.test.ts @@ -1,7 +1,10 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { summarizeExactReviewHandoff } from "../dashboard/exact-review-health.ts"; +import { + summarizeExactReviewHandoff, + summarizeExactReviewPressure, +} from "../dashboard/exact-review-health.ts"; const NOW = Date.parse("2026-07-13T02:00:00.000Z"); const DISPATCH_LEASE_MS = 10 * 60_000; @@ -198,3 +201,72 @@ test("exact-review handoff health derives legacy leased age from its execution l assert.equal(health.phases.leased.oldest_at, "2026-07-13T01:59:20.000Z"); assert.equal(health.phases.leased.oldest_age_seconds, 40); }); + +test("exact-review pressure distinguishes available, congested, and saturated capacity", () => { + const base = { + pending: 4, + readyPending: 4, + admissiblePending: 4, + dispatching: 4, + leased: 60, + capacity: 64, + dispatcherState: "active", + handoffStatus: "healthy", + }; + + assert.deepEqual(summarizeExactReviewPressure({ ...base, leased: 59 }), { + status: "idle", + reason: "capacity_available", + capacity: 64, + active: 63, + pending: 4, + ready_pending: 4, + admissible_pending: 4, + }); + assert.equal(summarizeExactReviewPressure({ ...base, admissiblePending: 3 }).status, "congested"); + assert.equal( + summarizeExactReviewPressure({ ...base, pending: 64, readyPending: 64, admissiblePending: 64 }) + .status, + "saturated", + ); +}); + +test("exact-review pressure preserves non-dispatchable and unknown states", () => { + const base = { + pending: 5, + readyPending: 5, + admissiblePending: 5, + dispatching: 4, + leased: 60, + capacity: 64, + dispatcherState: "active", + handoffStatus: "healthy", + }; + + assert.equal( + summarizeExactReviewPressure({ ...base, readyPending: 0 }).reason, + "no_ready_backlog", + ); + assert.equal( + summarizeExactReviewPressure({ ...base, admissiblePending: 0 }).reason, + "no_admissible_backlog", + ); + assert.deepEqual( + summarizeExactReviewPressure({ + ...base, + pending: 2.9, + readyPending: 9, + admissiblePending: 8, + dispatcherState: "paused", + }), + { + status: "unknown", + reason: "dispatcher_inactive", + capacity: 64, + active: 64, + pending: 2, + ready_pending: 2, + admissible_pending: 2, + }, + ); +}); From 4f249c3136589e36c28d5c54855a942ca3f8618c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 14 Jul 2026 16:52:34 +0200 Subject: [PATCH 2/6] style(dashboard): format pressure proof summary (cherry picked from commit a4c5cc0a6e7d57dddc5e54f5c1331db6aa9f42c7) --- docs/proof/openclaw-bay/proof-summary.json | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/docs/proof/openclaw-bay/proof-summary.json b/docs/proof/openclaw-bay/proof-summary.json index 78a29d49a5..912c89a3cf 100644 --- a/docs/proof/openclaw-bay/proof-summary.json +++ b/docs/proof/openclaw-bay/proof-summary.json @@ -126,10 +126,7 @@ { "name": "repository filter isolates selected repo", "status": "PASS", - "visible_keys": [ - "openclaw/clawhub#3058", - "openclaw/clawhub#97002" - ] + "visible_keys": ["openclaw/clawhub#3058", "openclaw/clawhub#97002"] }, { "name": "drawer exposes safe GitHub links", @@ -164,12 +161,7 @@ { "name": "preview tide follows explicit visual phases", "status": "PASS", - "phases": [ - "incoming", - "crest", - "receding", - "idle" - ] + "phases": ["incoming", "crest", "receding", "idle"] }, { "name": "reduced-motion tide is brief and non-spatial", @@ -359,12 +351,7 @@ } ], "tide_isolation": { - "phases": [ - "incoming", - "crest", - "receding", - "idle" - ], + "phases": ["incoming", "crest", "receding", "idle"], "before_keys": [ "openclaw/clawhub#97002", "openclaw/clawsweeper#97003", From cc59805cf1616c83a4c057439d117b667c97c083 Mon Sep 17 00:00:00 2001 From: brokemac79 Date: Fri, 17 Jul 2026 13:36:23 +0100 Subject: [PATCH 3/6] feat(dashboard): align Bay queue telemetry --- dashboard/bay-page.ts | 38 +++- dashboard/exact-review-queue.ts | 123 +++++++++- dashboard/worker.ts | 14 +- .../openclaw-bay/fixtures/02-forward.json | 184 ++++++++++++++- docs/proof/openclaw-bay/run-proof.mjs | 213 +++++++++++++++++- test/dashboard-worker.test.ts | 130 ++++++++++- 6 files changed, 662 insertions(+), 40 deletions(-) diff --git a/dashboard/bay-page.ts b/dashboard/bay-page.ts index 8488cc74a7..a383829cd2 100644 --- a/dashboard/bay-page.ts +++ b/dashboard/bay-page.ts @@ -86,6 +86,7 @@ dialog{border:0;padding:0;margin:0 0 0 auto;width:min(580px,94vw);height:100vh;m @media(max-width:1100px){.masthead{height:auto;min-height:72px;flex-wrap:wrap;padding:10px}.nav{order:3;width:100%;overflow:auto}.tools{grid-template-columns:1fr}.tide-panel{width:auto}.beach{overflow:auto}.beach-inner{min-width:1080px}.terminal-stack{min-width:170px}.title-row p{display:none}} @media((max-width:820px) and (orientation:portrait)),(max-width:600px){.masthead{min-height:0;gap:7px;padding:8px 11px}.brand{min-width:0}.brand small,.demo-chip,.brush-control>span{display:none}.nav{order:0;flex:1;width:auto;justify-content:flex-end;gap:1px}.nav a{padding:7px 8px;font-size:10px}.brush-control{gap:4px}.brush-control button{padding:6px 8px;font-size:10px}.hero{padding:10px 12px 8px}.title-row{align-items:center;gap:7px;flex-wrap:wrap}.title-row h1{font-size:clamp(29px,9vw,37px)}.title-row p{display:none}.live-chip{padding:4px 7px;font-size:10px}.overall-average{order:4;flex-basis:100%;margin-left:0;align-self:flex-start;padding:6px 9px}.overall-average strong{font-size:12px}.overall-average small{font-size:8px}.tools{margin-top:8px;gap:7px}.finder{padding:7px;flex-wrap:wrap;gap:6px}.finder label{font-size:8px}.finder input{width:auto;min-width:0;flex:1;padding:7px 8px}.finder-status{flex-basis:100%;min-width:0;padding-left:1px}.tide-panel{width:100%;padding:7px 9px}.repo-bar{max-height:72px;overflow:auto;padding-bottom:2px}.repo-bar>span{flex-basis:100%}.beach{min-height:0;overflow:hidden;background-color:#efd8a8;background-image:linear-gradient(180deg,rgba(248,236,204,.08),rgba(106,72,37,.1)),url('/bay-assets/bay-background-portrait.webp?v=1');background-size:100% 100%,cover;background-position:center,center top;background-attachment:scroll,fixed}.beach:after{background:linear-gradient(90deg,rgba(54,34,18,.1),transparent 30%,transparent 74%,rgba(21,104,113,.12))}.beach-inner{min-width:0;min-height:0;padding:142px 13px 0}.stage-grid{grid-template-columns:1fr!important;gap:0;height:auto}.lane-lines{display:none}.stage{min-height:195px;border:0}.stage:before{content:"";position:absolute;z-index:1;left:5%;right:5%;bottom:0;height:10px;border-bottom:3px dashed rgba(103,69,36,.43);filter:drop-shadow(0 2px 0 rgba(255,239,196,.65));transform:rotate(var(--lane-divider-tilt,-.4deg))}.stage:nth-child(even):before{--lane-divider-tilt:.55deg}.stage:after{right:auto;left:50%;bottom:-7px;width:72px;height:14px;transform:translateX(-50%) rotate(-1.8deg)}.stage:nth-child(even):after{transform:translateX(-50%) rotate(2deg)}.stage h2{top:8px;bottom:auto}.stage-body{inset:52px 10px 24px}.overflow-note{bottom:3px}.station{left:2%;top:22px;transform:scale(.78);transform-origin:left top}.master{z-index:15}.terminal-stack{position:relative;right:auto;top:auto;bottom:auto;width:auto;min-width:0;margin:28px 13px 24px;display:grid;grid-template-columns:1fr;gap:18px}.terminal-stack:before{display:none}.pool{min-height:205px!important;flex-grow:0!important;flex-basis:auto!important}.pool.completed{min-height:340px!important}.pool h2{top:12px}.pool-body{inset:54px 12px 16px}.sample-note{position:relative;left:auto;right:auto;bottom:auto;margin:0 13px 12px;padding-bottom:5px}.chat-overlay{z-index:90}.overlay-speech{width:min(220px,calc(100vw - 28px))}.overlay-speech.answer{width:min(250px,calc(100vw - 28px))}} @media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition:none!important}.beach.tide-active .wave{animation:none!important;transform:translate3d(2%,0,0);opacity:.44}.beach.tide-active .tide-wet-sheen{animation:none!important;opacity:.3}.beach.tide-active .tide-wet-gleam{animation:none!important;opacity:.32}.beach.preview-tide-cleared .pool .critter{opacity:.2;transform:none;filter:grayscale(.15)}} +.bay-control-board{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;margin-top:8px}.bay-control-card{min-width:0;padding:8px 10px;border:1px solid rgba(83,66,43,.18);border-radius:10px;background:rgba(255,252,245,.84);box-shadow:0 5px 15px rgba(48,45,34,.06)}.bay-control-card h2{margin:0;color:#6f604d;font:800 8px ui-monospace,monospace;letter-spacing:.12em;text-transform:uppercase}.bay-control-summary{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin-top:4px}.bay-control-summary strong{font:800 16px ui-monospace,monospace;color:#264f51;letter-spacing:-.04em}.bay-control-summary span{font-size:9px;color:var(--muted);text-align:right}.bay-control-charts{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:6px}.bay-control-chart{min-width:0}.bay-control-chart small{display:block;margin-bottom:2px;color:#6f604d;font:800 7px ui-monospace,monospace;letter-spacing:.06em;text-transform:uppercase}.bay-control-chart svg{display:block;width:100%;height:28px;overflow:visible}.bay-control-grid{stroke:rgba(70,88,78,.16);stroke-width:1}.bay-control-line{fill:none;stroke:#df552f;stroke-width:2.1;stroke-linejoin:round;stroke-linecap:round}.bay-control-line.rate{stroke:#6859c7}.bay-control-point{fill:#df552f;stroke:#fffaf0;stroke-width:1.1}.bay-control-point.rate{fill:#6859c7}.bay-control-rate{margin-top:5px;color:#287456;font-size:9px;font-weight:800;line-height:1.3}.bay-control-rate.rising{color:#b74331}.bay-control-rate.collecting{color:var(--muted);font-weight:650}.bay-handoff{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px;margin-top:7px}.bay-handoff div{min-width:0}.bay-handoff span{display:block;color:var(--muted);font:800 7px ui-monospace,monospace;text-transform:uppercase;letter-spacing:.08em}.bay-handoff strong{display:block;margin-top:2px;font:800 13px ui-monospace,monospace;color:#294a4b}.bay-handoff-status{display:inline-block;margin-top:7px;padding:3px 5px;border-radius:999px;background:#e8f4ea;color:#287456;font:800 8px ui-monospace,monospace;letter-spacing:.05em;text-transform:uppercase}.bay-handoff-status.degraded,.bay-handoff-status.stalled{background:#fff0e9;color:#a5402c}.bay-control-empty{margin:6px 0 0;color:var(--muted);font-size:10px}@media(max-width:900px){.bay-control-board{grid-template-columns:1fr 1fr}.bay-control-card:last-child{grid-column:1/-1}}@media((max-width:820px) and (orientation:portrait)),(max-width:600px){.bay-control-board{grid-template-columns:1fr;margin-top:7px}.bay-control-card:last-child{grid-column:auto}.bay-control-summary strong{font-size:15px}} @@ -103,6 +104,7 @@ dialog{border:0;padding:0;margin:0 0 0 auto;width:min(580px,94vw);height:100vh;m
Waiting for the first tide…Terminal pools clear together at 20 outcomes
0 / 20
Repository waters
+
@@ -164,12 +166,13 @@ dialog{border:0;padding:0;margin:0 0 0 auto;width:min(580px,94vw);height:100vh;m