feat(sse): broadcast forge mutations on /events #496
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!496
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "boss/493"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Webhook handlers now fire-and-forget a
forge_eventSSE envelope after ingress completes (issue.opened/closed/reopened/assigned/unassigned/labeled/unlabeled/milestoned/demilestoned, pr.opened/closed/merged/reopened/draft_changed/labeled/unlabeled/review_submitted), so the dashboard reflects forge mutations immediately instead of waiting for the polling backstop. Inactive forges still short-circuit before broadcast. Web invalidates pipeline / board / watchdog query keys (granular per-issue when known); poll backstop relaxes 30s → 60s. Adds a one-shot "Live updates connected" toast plus a separate reconnected variant after a real offline window. Closes #493.Test plan
bun x turbo run typecheck— 4/4 packages cleanbun x @biomejs/biome@^2 check .— no errorsbun x turbo run test— 2273 pass / 0 fail (server)apps/server/src/http/forge-event-broadcast.test.ts— 21 tests cover per-forge classifiers, envelope shape, and a synthetic Forgejoissues.openedwebhook → SSE arrival within 100 msbehaviorapps/web/src/routes/planner.index.tsx: The AC requires the polling backstop to drop 30 s → 60 s now thatforge_eventSSE covers the common path.planner.board.tsxwas updated (POLL_INTERVAL_MS = 60_000) butplanner.index.tsx— referenced explicitly in issue #493 §AC as the file with the "current 30 s poll comment" — is not in this diff. ItsrefetchIntervalis still 30 s. The PR body claims "poll backstop relaxes 30s → 60s" but only the board half landed; add the matching change to the pipeline list route'suseQuerycall.Mostly disagree, partially fixed — pushed
12660e9.planner.index.tsxis the foreman chat surface (sessions / specs / composer), not a pipeline list. It has norefetchIntervaland never has — onlystaleTime: 60_000on the repo list. The:140reference in the issue body points at a comment about the per-turn streaming SSE (useSSE'sonEvent), not a polling backstop. The author of the issue almost certainly meantplanner.board.tsx(similar name, actually has the 30 sPOLL_INTERVAL_MS); that file was updated 30s → 60s in the original diff.Going through every web backstop against the AC:
planner.board.tsx— 30s → 60s ✓ (this PR)monitor.index.tsx(/issues/pipeline) — already 60s pre-PRmonitor.issue.$owner.$repo.$issueNumber.tsx— already 60s pre-PRwatchdog-panel.tsx— was still 30s; AC explicitly lists["watchdog"]→ fixed in12660e9(60s + matching docblock +agents.tsxcomment +lib/api.tsdoc).Also dropped a stale "30 s polling backstop" docblock at the top of
planner.board.tsxthat wasn't updated when the constant changed.monitor.index.tsx:407(refetchInterval: 30_000) is the task-history list inside theTaskDrawer— task lifecycle, not forge mutations, explicitly out of scope per the issue.Prior finding was a false positive:
planner.index.tsxhas norefetchIntervalat all. The 30s→60s backstop fix correctly landed inwatchdog-panel.tsx(refetchInterval: 60_000, staleTime: 55_000), andplanner.board.tsxalready carriedPOLL_INTERVAL_MS = 60_000in the original push. CI green.