Skip to content

[Spec 927] Needs Attention: surface PRs via the universal pr gate; delete gateless builder-derived fallbacks - #928

Merged
waleedkadous merged 32 commits into
mainfrom
builder/spir-927
May 29, 2026
Merged

[Spec 927] Needs Attention: surface PRs via the universal pr gate; delete gateless builder-derived fallbacks#928
waleedkadous merged 32 commits into
mainfrom
builder/spir-927

Conversation

@waleedkadous

Copy link
Copy Markdown
Contributor

Closes #927.

What

Reworks the dashboard's Needs Attention surface so PR-readiness keys on the universal pr gate instead of fragile builder-state derivations. Net −45 LOC (3 SPIR phases) — mostly deletion.

Needs Attention = (A) ∪ (B):

  • (A) open PRs whose linked builder has a pending pr gate → PR rows only (never a builder standing in for a PR; a cache-missed/merged PR yields no row).
  • (B) gate rows for genuine human gates: spec / plan / dev / verify-approval.
  • plus the existing unaffiliated/human-PR (REVIEW_REQUIRED) fallback.

How (by phase)

  1. server-derivation (packages/codev, packages/types): derivePrReady reduced to the requested_at-aware pr-gate-pending check (drops the bugfix && verified fallback and the pr_ready_for_human field dependency — kills the Terminal state 'verified' over-promises: split back into 'complete' (phases done) vs 'verified' (verify-approval passed) #919 sticky-field hazard). verify-approval → "verify review" added to GATE_LABELS; detectBlockedSince unified on Object.keys(GATE_LABELS).
  2. dashboard-surfacing (packages/dashboard): deleted the builder-emit branch; if (b.prReady) continue; makes PR-ready builders surface only as PR rows; affiliated PRs use the gate timestamp (createdAt only for unaffiliated); verify styling (gateKindClass + .attention-kind--verify).
  3. remove-dead-projection (packages/codev, packages/types): removed recentlyMergedIssueIds end-to-end. Retained fetchRecentMergedPRs (still feeds the recentlyClosed PR-link map).

Shared-infra / VSCode blast radius (cc area/vscode — @amr)

pr stays in the shared GATE_LABELS/detectBlocked* so VSCode (tree/toast/status-bar) is unchanged; the "no builder stand-in" rule is dashboard-local. New: verify-approval now surfaces as a blocked builder in VSCode via the gate-toast generic fallback (added a builders.test.ts regression-guard). Open question for Amr: is that the desired VSCode UX, or do you want a dedicated GATE_ACTIONS "Verify" action? (additive follow-up — not a blocker.)

Verification

  • porch build + tests green at every phase; dashboard NeedsAttentionList 13/13; VSCode builders.test.ts type-checks (Electron run = area CI).
  • Render-verified the new --verify styling in headless chromium against the built CSS: .attention-kind--verifyrgb(234,179,8) (--status-waiting, == PR row), distinct from spec and from an unstyled control.
  • 3-way CMAP per phase (Gemini/Codex/Claude); all REQUEST_CHANGES addressed.

Relationships

See codev/reviews/927-needs-attention-surface-prs-vi.md for the full review, consultation history, and lessons.

Needs Attention: surface PRs via the universal pr gate; delete gateless
builder-derived fallbacks. Grounds the issue's direction in the current
overview.ts / NeedsAttentionList code and surfaces the verify-approval,
recentlyMergedIssueIds, and derivePrReady-form decisions.
3-way: Gemini APPROVE, Claude APPROVE, Codex REQUEST_CHANGES (both items
resolved). Pinned the dashboard-local scope of the no-builder-stand-in
rule (keep pr in shared GATE_LABELS), the requested_at-aware gate-pending
invariant, the verify-approval='verify review' label contract, and the
detectBlockedSince sync point. Corrected two over-broad reviewer
suggestions: gate-pending check must include requested_at, and
fetchRecentMergedPRs is retained (second consumer).
3 phases: (1) server-derivation — gate-authoritative derivePrReady +
verify-approval label + unify detectBlockedSince [shared infra / VSCode
blast radius]; (2) dashboard-surfacing — PR-rows-only buildItems +
verify styling; (3) remove-dead-projection — delete recentlyMergedIssueIds
end-to-end, retain fetchRecentMergedPRs. VSCode blast radius is an explicit
cross-cutting item with test coverage + an Amr review flag.
3-way: Gemini APPROVE, Claude APPROVE, Codex REQUEST_CHANGES (resolved).
Phase 1 now OWNS the VSCode blast-radius validation (api.ts prReady
doc-comment rewrite + vscode builders.test.ts + VSCode acceptance
criteria/tests; pr regression-guarded). Resolved Codex's 'discussed not
owned' + '+types omitted' points and Claude's test-scope ambiguity.
Added dev-review gateKindClass gap as a flagged optional drive-by
(default out-of-scope). Teed up VSCode UX + drive-by decisions for
plan-approval / Amr.
…al + verify-approval label

- derivePrReady: reduce to the requested_at-aware pr-gate-pending check;
  drop the pr_ready_for_human field dependency and the bugfix && verified
  fallback. The pending pr gate is the universal post-CMAP signal.
- GATE_LABELS: add verify-approval -> 'verify review' (pr stays mapped so
  VSCode is unaffected; dashboard excludes pr locally in a later phase).
- detectBlockedSince: iterate Object.keys(GATE_LABELS) instead of a separate
  hardcoded array (removes the silent drift hazard; verify-approval now
  carries blockedSince).
- api.ts + overview.ts: rewrite prReady doc comments to the gate-authoritative
  contract.
- Tests: rewrite derivePrReady block (universal-gate true; requested_at guard;
  ignores pr_ready_for_human; no bugfix-verified fallback); add verify-approval
  cases to detectBlocked/detectBlockedSince; add VSCode blast-radius suite in
  builders.test.ts (verify-review surfaces as blocked; pr unchanged).

porch build + tests green; vscode tests type-check (Electron run is area/vscode CI).
…tion + verify styling

- buildItems: delete the builder-emit branch and its bookkeeping
  (emittedPrReadyIssueIds, mergedIssueIdSet, recentlyMergedIssueIds param).
  PR-ready builders now surface ONLY as PR rows; the builder loop early-outs
  on if (b.prReady) continue, so a cache-missed pr-gate builder emits nothing
  and the pr gate never becomes a gate row.
- Gate-row loop now naturally covers spec/plan/dev/verify-approval.
- gateKindClass: add 'verify review' -> attention-kind--verify; index.css:
  add the matching rule (review-style accent).
- WorkView: stop passing recentlyMergedIssueIds; NeedsAttentionList prop dropped.
- Tests: invert the two 'missing PR still surfaces a builder' tests (now assert
  no row), replace the merged-suppression test with a 'missing PR => no row'
  case (recentlyMergedIssueIds removed), add a verify-approval gate-row test.

Dashboard tests 14/14; porch build + tests green.
…ses gate timestamp exclusively (Codex CMAP)

Codex REQUEST_CHANGES (Phase 2 iter-1): the affiliated PR path could still
fall back to pr.createdAt, and two tests encoded the now-impossible gateless
BUGFIX shape (prReady=true with no gate/no blockedSince).

- buildItems: waitingSince = prReady ? (readySince ?? pr.createdAt) : pr.createdAt.
  Affiliated PRs use the builder's gate-requested time (blockedSince); the ??
  is an unreachable type guard, not the old gateless fallback. createdAt is now
  reserved for unaffiliated/human PRs.
- tests: reframe the BUGFIX test to the post-#887 gate shape (asserts
  waitingSince === blockedSince); remove the impossible 'no blockedSince'
  fallback test; assert unaffiliated PR uses createdAt. 13/13 pass.

porch build + tests green.
…rgedIssueIds end-to-end

The merged-suppression projection (#901/#902) is dead once the dashboard
builder-emit branch is gone (Phase 2). Remove it:
- OverviewData (api.ts + overview.ts mirror): drop the recentlyMergedIssueIds field.
- overview.ts: delete the merged-issue computation block and its inclusion in
  the returned result.
- overview.test.ts: remove the two recentlyMergedIssueIds tests + the
  null-mergedPRs empty-array assertion.

RETAINED: fetchRecentMergedPRs, the mergedPRs fetch, and the issueToPrUrl map —
still needed for recentlyClosed PR-link enrichment (positive prUrl test at L1853
still passes, proving the fetch is wired). porch build + tests green; dashboard 13/13.
Net -45 LOC across packages/. Documents the universal-pr-gate Needs Attention
contract, the dashboard-local no-builder-stand-in rule, the verify-approval
label/styling (render-verified in headless chromium), and reconciles #919/#902.
Captures the consultation history (Codex was the consistent skeptic; all blocks
legitimate and addressed) and MAINTAIN-candidate lessons.
…R CMAP)

Codex PR-level REQUEST_CHANGES (C1): approved spec/plan artifacts must carry
YAML frontmatter (approved + validated) per the SPIR final-approval steps; they
were left as Status: draft. Add frontmatter (approved: 2026-05-29, validated:
[gemini, codex, claude]) and flip Status -> approved on both.

C2 (dev-review gateKindClass styling) rebutted: explicitly ruled out of scope by
the architect at plan-approval; tracked as a separate follow-up.
@waleedkadous
waleedkadous merged commit 0e300f3 into main May 29, 2026
6 checks passed
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.

Needs Attention: surface PRs via the universal pr gate; delete gateless builder-derived fallbacks

1 participant