feat(status): add GitHub status tracking badge - #123
Merged
wgordon17 merged 17 commits intoAug 8, 2026
Conversation
Fetches GitHub's status summary API, filters to five tracked components (Actions, API Requests, Git Operations, Issues, Pull Requests), blends severity, and exposes it via a SolidJS signal. Validates the third-party response shape with Zod and includes a live-network smoke test (excluded from the default suite) guarding against silent component-name drift.
Adds the exact origin (no wildcard, no regional subdomains) so the new GitHub status polling fetch is not blocked by CSP.
Calls fetchGitHubStatus() fire-and-forget from doFetch(), alongside the existing fetchRateLimitDetails() call, so it inherits the poll coordinator's interval, manual-refresh trigger, and hidden-tab skip behavior for free.
Renders a severity-colored dot in the header with a click-to-open Kobalte Popover showing active-incident detail. Adds an optional forceClosed prop to the shared Tooltip component so the badge's hover tooltip can be suppressed while its Popover is open.
Places the badge between the user avatar and the Settings icon in the header's icon row.
Updates the documented convention to present-indicative mood
("adds feature"), matching what this environment's commit-msg
hook actually enforces — the prior imperative-mood example
contradicted every commit accepted in practice.
Extracts a shared recordFetchFailure() helper so both the schema-validation-failure branch and the catch block go through the same CONSECUTIVE_FAILURE_THRESHOLD gate added in 087ae11 — the schema-drift path previously called dismissNotificationBySource unconditionally, reintroducing the CR-002 bug via a different trigger. Adds a test confirming the counter is shared across both failure types.
Adds coverage for three previously-untested branches: an unrecognized component status string falling back to "none" severity, an empty incident_updates array yielding an empty latestUpdateBody, and resetGitHubStatusState() clearing the current status back to null.
Dismissing the Popover via Escape or an outside click bypasses the Tooltip trigger's own onClick/onPointerLeave/onBlur handlers entirely (Kobalte's DismissableLayer calls context.close directly), so isHovered/isFocused could be left stale as true. If the pointer was still resting on the trigger, the tooltip would flash back open on its own once forceClosed flipped back to false. Adds a createEffect(on(...)) that resets both signals on that specific true-to-false transition, using SolidJS's built-in previous-value parameter rather than a hand-rolled tracking variable, matching this codebase's existing on() idiom. Adds a direct regression test in Tooltip.test.tsx toggling forceClosed via a signal.
Replaces two status()!.incidents non-null assertions with an incidentList createMemo narrowing to GitHubStatusIncident[] | null, plus a single Show callback-narrowing block, matching this codebase's established idiom (StatusDot.tsx, Header.tsx, ItemRow.tsx). The shared fallback helper is named statusSummaryRow rather than neutralStatus, since a tracked component can be critical with zero recorded incidents yet. Also extends the checking-state test to open the popover and assert its fallback content, and adds a regression test dismissing the popover via Escape while simulating a held hover to confirm the tooltip does not reopen.
detectNewItems() in lib/notifications.ts mutates module-level Sets on every call — calling it "pure" in the comment above notifyTransitions() was wrong. Reworded to describe the change-detector/dispatcher split without the incorrect purity claim.
vitest.smoke.config.ts duplicated plugins/environment/globals/setupFiles verbatim from vitest.config.ts. Rewrites it to extend the base config via mergeConfig, setting test.include as a direct post-merge assignment since mergeConfig concatenates array values instead of replacing them. Also replaces the smoke test's per-name expect(liveNames.has(tracked)).toBe(true) loop with a single missing-names array assertion, so a failure reports exactly which tracked component name drifted instead of a bare true/false.
The github-status smoke test existed but was never wired into CI, so Statuspage component-name drift would only surface if someone remembered to run pnpm test:status-smoke manually. Adds a scheduled GitHub Actions workflow (weekly cron + workflow_dispatch) mirroring ci.yml's existing setup steps.
pnpm test:status-smoke existed since the original implementation but was never listed in the Running checks section, and now has a real CI consumer (the new weekly workflow).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary