Skip to content

Render one ordered review queue on the dashboard#38

Open
kristofferR wants to merge 2 commits into
mainfrom
dashboard-parked-rounds
Open

Render one ordered review queue on the dashboard#38
kristofferR wants to merge 2 commits into
mainfrom
dashboard-parked-rounds

Conversation

@kristofferR

@kristofferR kristofferR commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Problem

The dashboard had two ways to be waiting for a fire slot. ## ⏳ Queue listed fire-eligible rounds; a round in awaiting_retry whose RetryAt had not passed fell out of QueuedRounds and was invisible. The first commit here added a separate "Parked" table for those. Rendering live fleet state showed that was the wrong cut:

## ⏳ Queue — 0 waiting        ### 🅿️ Parked — 2 not yet eligible
_Nothing fire-eligible._       …#480 retry 03:07   …#481 retry 03:06

Two lists, near-identical retry times, and nothing saying which goes first or how they relate.

They were never racing

NextEligible takes the lowest Seq among eligible rounds, Seq survives AwaitRetry untouched, and the FireSlot is a CAS admitting one fire fleet-wide. A cooling-down round is already queued, in order — crq just rendered it as a separate species of work.

The defect is the model: a round's position in line (Seq) and its permission to run (RetryAt) are independent properties, and crq rendered the first as a queue and the second as a lifecycle phase.

Change

State.Queue(now) is the single view: every round waiting for a fire — queued and awaiting_retry alike — ordered by (ReadyAt, Seq), the order they actually reach the slot. Each entry carries an absolute ready time and the gate holding it (cooling down / account blocked / slot busy).

## ⏳ Queue — 4 waiting

| # | PR | commit | ready | why | attempts | enqueued | host |
|--:|---|---|---|---|--:|---|---|
| 1 | carrier#201 | `0b996b365` | 2026-07-26 03:07 CEST | cooling down | 1 | 02:35 CEST | `cachyos` |
| 2 | coderabbit-queue#38 | `2ff562805` | 2026-07-26 03:07 CEST | cooling down | 1 | 02:23 CEST | `cachyos` |

A real bug fixed on the way. The parked table printed the round's own RetryAt, but DecideFire also gates on Account.BlockedUntil. If CodeRabbit extended the account window after a round parked, the dashboard promised a retry time the fire gate would refuse. ReadyAt now folds in the account block — the same max(...) State.AccountBlockedUntil already computes for the wait path.

## 🔬 In flight replaces the single In flight / Feedback wait summary rows, which showed one round each and so hid every reviewing round past the first plus any reserved round whose FireSlot Normalize had cleared. In flight (reserved|fired|reviewing) and Queue (queued|awaiting_retry) now partition Active() by phase, so "every active round is on the dashboard" holds by construction rather than by a catch-all.

RenderTitle counts the whole queue, so a state whose only work is cooling down reads 🐰 crq — 2 queued, never idle.

FireEligible, QueuedRounds, NextEligible, queue ordering, firing behaviour and the hidden crq:state block are untouched — this is a view, not a schema or a rule.

Tests

internal/state/dashboard_test.go is new to the package (dashboard rendering was untested): cooling-down-only renders no empty state and a correct header, genuinely-empty keeps _Nothing queued._ and the idle title, (ReadyAt, Seq) ordering including an elapsed RetryAt sorting among the ready rounds, the account block dominating a round's own RetryAt, slot busy, the Active() partition, and CRQ_TZ formatting.

gofmt -l . clean, go vet ./... and go test ./... pass. Verified against live fleet state with crq status (read-only); the crq-state issue was not hand-edited.

Note: crq preflight could not be re-run before this push — the CodeRabbit account was rate-limited and the autoreview daemon won each window. The branch's first push had a clean preflight, and this PR's own review covers the change.

A round in awaiting_retry whose RetryAt has not passed is correctly not
fire-eligible, so QueuedRounds excluded it — and then it vanished from the
dashboard entirely. Two PRs parked until 00:07Z rendered byte-identically to
an empty queue ("_Nothing queued._", title "idle"), so a reader concluded
their enqueue had been dropped.

Add parkedRounds: the active rounds that no other part of the dashboard
accounts for — not fire-eligible, and not named in the "In flight"/"Feedback
wait" rows. That also catches two neighbouring blind spots: every reviewing
round past the first (only reviewing[0] gets a row) and a reserved round whose
fire slot was cleared. Every active round now appears in exactly one of "In
flight", "Feedback wait", "Queue" or "Parked".

The queue heading gains a "· N parked" suffix and the empty-state text is
suppressed whenever work is parked; RenderTitle reports parked counts so a
parked-only state is never "idle". FireEligible/QueuedRounds and firing
behaviour are untouched — this is rendering only.

Adds internal/state/dashboard_test.go, the first test file in the package.
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5605287d-ccfc-4ff8-a35b-ea20f853f6e5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dashboard-parked-rounds

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 2ff5628052

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The dashboard had two ways to be waiting for a fire slot. "Queue" listed
fire-eligible rounds; a round in awaiting_retry whose RetryAt had not passed
fell out of QueuedRounds and needed a separate "Parked" table to be visible at
all. Rendering live fleet state showed why that is the wrong cut: two rounds
sat parked with near-identical retry times and nothing said which went first,
or how they related to the rounds listed above them.

They were never racing. NextEligible takes the lowest Seq among eligible
rounds, Seq survives AwaitRetry untouched, and the FireSlot admits one fire
fleet-wide — a cooling-down round is already queued, in order. What was wrong
is the model: a round's position in line (Seq) and its permission to run
(RetryAt) are independent properties, and crq rendered the first as a queue and
the second as a lifecycle phase.

State.Queue is the single view: every round waiting for a fire, ordered by
(ReadyAt, Seq) — the order they actually reach the slot. ReadyAt folds in the
account-wide quota block, which fixes a real bug: the parked table printed the
round's own RetryAt while DecideFire also gates on Account.BlockedUntil, so a
window CodeRabbit later extended left the dashboard promising a retry time the
fire gate would refuse. FireEligible, QueuedRounds and NextEligible are
untouched; this is a view, not a schema or a rule.

The single "In flight"/"Feedback wait" summary rows are replaced by an In
flight section listing every reserved/fired/reviewing round. Those rows showed
one round each, which hid every reviewing round past the first and any reserved
round whose FireSlot Normalize had cleared. In flight and Queue now partition
Active() by phase, so "every active round is on the dashboard" holds by
construction rather than by a catch-all — pinned by a test.
@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR kristofferR changed the title Show parked rounds on the dashboard Render one ordered review queue on the dashboard Jul 26, 2026
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 603cb0778a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/state/state.go
Comment on lines +665 to +666
case slotBusy:
e.Why = WaitSlotBusy

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not mark slot-blocked entries ready now

When another PR holds the fire slot, this branch sets Why to slot busy but leaves ReadyAt at zero, which the dashboard renders as ready: now. Such an entry cannot fire until the current holder releases the account-wide slot, so the new table presents contradictory and incorrect availability information; render the ready time as unknown/slot-dependent instead of now in this case.

AGENTS.md reference: AGENTS.md:L71-L73

Useful? React with 👍 / 👎.

Comment thread internal/state/state.go
Comment on lines +643 to +644
// MinInterval is deliberately NOT reflected: it is sub-minute pacing, so
// surfacing it would only churn DashboardSHA on every render.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the minimum interval in queue readiness

After the slot is released shortly following a fire, queued entries are rendered as ready: now even though DecideFire still rejects them until LastFired + MinInterval; this occurs with the default 90-second interval and can last arbitrarily longer when CRQ_MIN_INTERVAL is customized. Unlike a relative countdown, that absolute boundary is stable and would not churn the dashboard hash, so either include it in ReadyAt or avoid claiming the entry is ready now.

AGENTS.md reference: AGENTS.md:L84-L87

Useful? React with 👍 / 👎.

Comment on lines +159 to +160
case len(inFlight) > 0:
fmt.Fprintf(&b, "### 🟡 Awaiting feedback for %s#%d\n\n", inFlight[0].Repo, inFlight[0].PR)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish stranded reservations from feedback waits

When a round is reserved but has no matching FireSlot—the exact stranded case inFlightRounds now includes—slot is nil and this branch reports that crq is “Awaiting feedback.” A reserved round precedes command posting, so no feedback can arrive, and Pump cannot progress it without the slot; the same misleading state is also emitted by RenderTitle. Surface this as a stranded reservation or generic in-flight state rather than a feedback wait.

AGENTS.md reference: AGENTS.md:L54-L59

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant