From a full route audit of drb-frontend (all app/ routes except the fenced /, /features, /pricing, /faq, /settings/billing, and the map internals). P1/P2 items in this list are NOT yet fixed unless noted; the honest-error-state items for /incidents and /watch shipped in the fix/frontend-map-and-error-states PR.
P1 — broken / crash-risk
Zero-node org lands on a blank map.app/page.tsx:147 renders <LiveView/> for any user && orgId; LiveView.tsx:37 only has a "configured but quiet" empty state. The UI_REDESIGN.md Activation screen (chunk 10) was never built — no components/Activation.tsx. A new customer sees an empty map with no "mint a token" path.
components/CallSpineEntry.tsxInlinePlayer — conditional hook.if (!hasAudio) return null (~line 33) sits between useState/useRef calls and a later useEffect → React error #310 if ever mounted with hasAudio={false}. Masked only because the parent mounts it exclusively when hasAudio is true (dead guard). Fix: delete the dead hasAudio prop+guard, or hoist the return above all hooks.
/incidents raw Firestore index error — FIXED in fix/frontend-map-and-error-states (friendlyIncidentsError). Root cause still server-26 #13/#51.
P2 — misleading state / wrong data
/watch alerts events tab swallowed query failures → false "No alerts triggered yet." — FIXED in the same PR. Also: RulesTab (~line 36) calls load() from the render body — move to useEffect.
app/nodes/[id]/page.tsx:123 "Recent Calls" usually wrongly empty.useCalls(20) fetches 20 most-recent org-wide then filters c.node_id === id client-side. Busy multi-node org → "No calls recorded from this node" for nodes that have plenty. Needs a server-side node_id filter.
app/nodes/page.tsx:44 pending-node card double-fires.<NodeCard> is a <Link>; the pending branch wraps it in a <div onClick={setConfigNode}>. Click → navigates AND tries to open the config modal; navigation wins, modal never shows. Fix: pending card not a Link, or stopPropagation.
app/trips/page.tsx upcoming/past mismatch. List buckets on end_date >= today (line 176); TripCard badge uses start_date >= today (line 25). In-progress trip shows under "Upcoming" with a "Past" badge. Align both on end_date.
DEFERRED drift — settings/organization. DEFERRED says the org-name Save button is disabled/no backend, but c2api.getOrg/updateOrg are wired and the button is live (page.tsx:80). Confirm PATCH /org exists on c2-core; update DEFERRED or the button 403s raw.
app/calls/page.tsx (Archive) ahead of its doc. Built against GET /calls/search; UI_REDESIGN.md lists the route as BLOCKED on backend. If /calls/search isn't deployed → "Couldn't load calls: C2 API error 404". Verify the endpoint. (Possibly the user's reported /archive CORS symptom.)
P3 — visual / polish
Two-tier visual seam. Token-migrated: Live, Incidents, Incident detail, Archive, Network hub. NOT migrated (hardcoded bg-gray-*, depend on the globals.css!important block): /nodes, /systems, /alerts body, /admin, /profile, /settings/*, /trips, /onboarding, /login, /signup, /waitlist. Known (DEFERRED globals.css row) but jars visibly. This is the remaining migration backlog.
app/network/page.tsx is a 3-card hub, not UI_REDESIGN.md §5.6 (no Enrollment tab, still at /settings/nodes; "Bot Tokens" shows —). Scope decision.
components/StatusBadge.tsx:6 offline state + adminToggle off-state → pale-gray-on-near-white in light mode. Borderline contrast; off-toggle reads as "no control".
app/trips/page.tsx:100 CreateModal has no p-4 / no inner scroll → clips on short viewports. Same for NodeConfigModal, DiscordJoinModal. Add p-4 overlay + max-h-[90vh] overflow-y-auto panel (incidents CreateModal already does).
lib/types.ts — IncidentRecord.units/vehicles non-optional but Firestore omits them on older docs; incidents/[id]/page.tsx:216 already ?.-guards, contradicting the type. Make them optional.
/settings/members + /settings/nodes 403 for a pure org-owner (both call /admin/users, require_admin_token; B7 gate lets them reach the page). Known (SAAS_PLAN B7); error surface is at least honest.
Generated by a frontend-audit agent.
From a full route audit of `drb-frontend` (all `app/` routes except the fenced `/`, `/features`, `/pricing`, `/faq`, `/settings/billing`, and the map internals). P1/P2 items in this list are NOT yet fixed unless noted; the honest-error-state items for `/incidents` and `/watch` shipped in the `fix/frontend-map-and-error-states` PR.
## P1 — broken / crash-risk
1. **Zero-node org lands on a blank map.** `app/page.tsx:147` renders `<LiveView/>` for any `user && orgId`; `LiveView.tsx:37` only has a "configured but quiet" empty state. The `UI_REDESIGN.md` Activation screen (chunk 10) was never built — no `components/Activation.tsx`. A new customer sees an empty map with no "mint a token" path.
2. **`components/CallSpineEntry.tsx` `InlinePlayer` — conditional hook.** `if (!hasAudio) return null` (~line 33) sits between `useState`/`useRef` calls and a later `useEffect` → React error #310 if ever mounted with `hasAudio={false}`. Masked only because the parent mounts it exclusively when `hasAudio` is true (dead guard). Fix: delete the dead `hasAudio` prop+guard, or hoist the return above all hooks.
3. **`/incidents` raw Firestore index error** — FIXED in `fix/frontend-map-and-error-states` (friendlyIncidentsError). Root cause still server-26 #13/#51.
## P2 — misleading state / wrong data
4. **`/watch` alerts events tab swallowed query failures** → false "No alerts triggered yet." — FIXED in the same PR. Also: `RulesTab` (~line 36) calls `load()` from the render body — move to `useEffect`.
5. **`app/nodes/[id]/page.tsx:123` "Recent Calls" usually wrongly empty.** `useCalls(20)` fetches 20 most-recent org-wide then filters `c.node_id === id` client-side. Busy multi-node org → "No calls recorded from this node" for nodes that have plenty. Needs a server-side `node_id` filter.
6. **`app/nodes/page.tsx:44` pending-node card double-fires.** `<NodeCard>` is a `<Link>`; the pending branch wraps it in a `<div onClick={setConfigNode}>`. Click → navigates AND tries to open the config modal; navigation wins, modal never shows. Fix: pending card not a Link, or stopPropagation.
7. **`app/trips/page.tsx` upcoming/past mismatch.** List buckets on `end_date >= today` (line 176); `TripCard` badge uses `start_date >= today` (line 25). In-progress trip shows under "Upcoming" with a "Past" badge. Align both on `end_date`.
8. **DEFERRED drift — `settings/organization`.** DEFERRED says the org-name Save button is disabled/no backend, but `c2api.getOrg`/`updateOrg` are wired and the button is live (`page.tsx:80`). Confirm `PATCH /org` exists on c2-core; update DEFERRED or the button 403s raw.
9. **`app/calls/page.tsx` (Archive) ahead of its doc.** Built against `GET /calls/search`; `UI_REDESIGN.md` lists the route as BLOCKED on backend. If `/calls/search` isn't deployed → "Couldn't load calls: C2 API error 404". Verify the endpoint. (Possibly the user's reported `/archive` CORS symptom.)
## P3 — visual / polish
10. **Two-tier visual seam.** Token-migrated: Live, Incidents, Incident detail, Archive, Network hub. NOT migrated (hardcoded `bg-gray-*`, depend on the `globals.css` `!important` block): `/nodes`, `/systems`, `/alerts` body, `/admin`, `/profile`, `/settings/*`, `/trips`, `/onboarding`, `/login`, `/signup`, `/waitlist`. Known (DEFERRED globals.css row) but jars visibly. This is the remaining migration backlog.
11. `app/network/page.tsx` is a 3-card hub, not `UI_REDESIGN.md` §5.6 (no Enrollment tab, still at `/settings/nodes`; "Bot Tokens" shows `—`). Scope decision.
12. `components/StatusBadge.tsx:6` offline state + `admin` `Toggle` off-state → pale-gray-on-near-white in light mode. Borderline contrast; off-toggle reads as "no control".
13. `app/trips/page.tsx:100` CreateModal has no `p-4` / no inner scroll → clips on short viewports. Same for `NodeConfigModal`, `DiscordJoinModal`. Add `p-4` overlay + `max-h-[90vh] overflow-y-auto` panel (incidents CreateModal already does).
14. `lib/types.ts` — `IncidentRecord.units`/`vehicles` non-optional but Firestore omits them on older docs; `incidents/[id]/page.tsx:216` already `?.`-guards, contradicting the type. Make them optional.
15. `/settings/members` + `/settings/nodes` 403 for a pure org-owner (both call `/admin/users`, `require_admin_token`; B7 gate lets them reach the page). Known (SAAS_PLAN B7); error surface is at least honest.
Generated by a frontend-audit agent.
Live re-walk 2026-09-07 ~18:38 ET. Items 1/2/3 in this list confirmed still broken in prod — all three are backend/infra deploys, no frontend PR closed them:
Map (P1 #1 area): every map (/, /incidents/[id]) renders full-screen API KEY REQUIRED Carto watermarks. MAP_TILE_URL override merged in code but NEXT_PUBLIC_MAP_TILE_URL was never set in the CI build env, so prod still uses the dead Carto URL. Filed separately.
/watch Triggered Alerts: dead — alert_events composite index (acknowledged, org_id, triggered_at desc) never deployed. Same index throws useUnacknowledgedAlerts: FirebaseError: The query requires an index in layout.js console on every page. Blocks the whole tab + the site-wide alert bell. -> #51.
/calls (Archive):TypeError: Failed to fetch — CORS preflight failure, root-caused in #110.
New, lower severity (added to Version 5C/UI_AUDIT_0907b.md):
Stray unstyled clock (18:37:23) bottom-left of the Leaflet map on / and /incidents/[id] — no label, no styling. Leftover debug element.
Incident mini-card overlay collides with the leaflet zoom controls + severity legend (top-left of the map).
Possible transcript-block leak: incident 4d49e09c call transcript shows 1. ... 2. 10-4. 3. 5, I'm out. 4. 10-4. — looks like _build_transcript_block's {i}. segment numbering bleeding into the user-visible corrected transcript. Unconfirmed (could be Whisper). Worth checking the #102 0-based change.
Item 2 (CallSpineEntry conditional hook) and item 14 (IncidentRecord.units optional) from this list were fixed in the punch-list PRs this session.
Live re-walk 2026-09-07 ~18:38 ET. Items 1/2/3 in this list **confirmed still broken in prod** — all three are backend/infra deploys, no frontend PR closed them:
- **Map (P1 #1 area):** every map (`/`, `/incidents/[id]`) renders full-screen `API KEY REQUIRED` Carto watermarks. `MAP_TILE_URL` override merged in code but `NEXT_PUBLIC_MAP_TILE_URL` was never set in the CI build env, so prod still uses the dead Carto URL. Filed separately.
- **/watch Triggered Alerts:** dead — `alert_events` composite index (`acknowledged`, `org_id`, `triggered_at` desc) never deployed. Same index throws `useUnacknowledgedAlerts: FirebaseError: The query requires an index` in `layout.js` console on **every page**. Blocks the whole tab + the site-wide alert bell. -> #51.
- **/calls (Archive):** `TypeError: Failed to fetch` — CORS preflight failure, root-caused in #110.
New, lower severity (added to `Version 5C/UI_AUDIT_0907b.md`):
- **Stray unstyled clock** (`18:37:23`) bottom-left of the Leaflet map on `/` and `/incidents/[id]` — no label, no styling. Leftover debug element.
- **Incident mini-card overlay collides** with the leaflet zoom controls + severity legend (top-left of the map).
- **Possible transcript-block leak:** incident `4d49e09c` call transcript shows `1. ... 2. 10-4. 3. 5, I'm out. 4. 10-4.` — looks like `_build_transcript_block`'s `{i}.` segment numbering bleeding into the user-visible corrected transcript. Unconfirmed (could be Whisper). Worth checking the `#102` 0-based change.
Item 2 (`CallSpineEntry` conditional hook) and item 14 (`IncidentRecord.units` optional) from this list were fixed in the punch-list PRs this session.
P2 punch-list pass on branch fix/109-punchlist-p2 (local commit only, not pushed).
Item 4 — FIXED.RulesTab in app/alerts/page.tsx (not /watch) called load() from the render body. Moved to useEffect(() => { load(); }, []); load() already self-guards on its loaded state flag, so [] deps are honest. Added useEffect to the react import.
Item 6 — ALREADY FIXED (verified).components/NodeCard.tsx already has a linkToDetail?: boolean prop (defaults true) that drops the <Link> wrapper when false, and app/nodes/page.tsx:45 already passes linkToDetail={false} on the pending branch. The wrapping <div onClick={() => setConfigNode(n)}> now opens the config modal without navigating. No change needed.
Item 8 — ENDPOINT EXISTS; button is correctly wired.drb-c2-core/app/routers/org.py:48@router.patch("") on prefix /org → update_org(OrgUpdateBody, Depends(require_org_owner_token)). Frontend c2api.updateOrg (lib/c2api.ts:306) does PATCH /org with {name}. app/settings/organization/page.tsx Save button is live and guarded (!canEdit / empty / unchanged disable it). No frontend change made. The stale entry is DEFERRED.md:35 ("no backend to save to — save button is disabled"), which lives at the Version 5C root, outside the Server repo and this worktree — cannot commit it here. Flagging for someone with repo-root access to correct that row.
Item 5 — deferred with TODO (limit raised).useCalls in lib/useCalls.ts is a direct Firestore query (where org_id ==, optional started_at range, orderBy started_at desc, limit). Adding where('node_id','==', id) alongside the existing org_id equality + started_at orderBy would require a brand-new composite index, so took the safe path: app/nodes/[id]/page.tsx:123 now calls useCalls(200) (was 20) and keeps the client-side c.node_id === id filter, with a // TODO(server-26#109 item5) comment. Proper fix is a server-side node_id filter.
Item 7 — ALREADY FIXED (verify only).app/trips/page.tsx: TripCard badge (line 27) uses trip.end_date >= today; list buckets (lines 178-179) use end_date. Consistent. No change.
Items 1-3, 9-15 out of scope for this pass. Files changed: drb-frontend/app/alerts/page.tsx, drb-frontend/app/nodes/[id]/page.tsx.
P2 punch-list pass on branch `fix/109-punchlist-p2` (local commit only, not pushed).
**Item 4 — FIXED.** `RulesTab` in `app/alerts/page.tsx` (not `/watch`) called `load()` from the render body. Moved to `useEffect(() => { load(); }, [])`; `load()` already self-guards on its `loaded` state flag, so `[]` deps are honest. Added `useEffect` to the react import.
**Item 6 — ALREADY FIXED (verified).** `components/NodeCard.tsx` already has a `linkToDetail?: boolean` prop (defaults true) that drops the `<Link>` wrapper when false, and `app/nodes/page.tsx:45` already passes `linkToDetail={false}` on the pending branch. The wrapping `<div onClick={() => setConfigNode(n)}>` now opens the config modal without navigating. No change needed.
**Item 8 — ENDPOINT EXISTS; button is correctly wired.** `drb-c2-core/app/routers/org.py:48` `@router.patch("")` on prefix `/org` → `update_org(OrgUpdateBody, Depends(require_org_owner_token))`. Frontend `c2api.updateOrg` (`lib/c2api.ts:306`) does `PATCH /org` with `{name}`. `app/settings/organization/page.tsx` Save button is live and guarded (`!canEdit` / empty / unchanged disable it). No frontend change made. The stale entry is `DEFERRED.md:35` ("no backend to save to — save button is disabled"), which lives at the Version 5C root, outside the Server repo and this worktree — cannot commit it here. Flagging for someone with repo-root access to correct that row.
**Item 5 — deferred with TODO (limit raised).** `useCalls` in `lib/useCalls.ts` is a direct Firestore query (`where org_id ==`, optional `started_at` range, `orderBy started_at desc`, `limit`). Adding `where('node_id','==', id)` alongside the existing `org_id` equality + `started_at` orderBy would require a brand-new composite index, so took the safe path: `app/nodes/[id]/page.tsx:123` now calls `useCalls(200)` (was 20) and keeps the client-side `c.node_id === id` filter, with a `// TODO(server-26#109 item5)` comment. Proper fix is a server-side node_id filter.
**Item 7 — ALREADY FIXED (verify only).** `app/trips/page.tsx`: `TripCard` badge (line 27) uses `trip.end_date >= today`; list buckets (lines 178-179) use `end_date`. Consistent. No change.
Items 1-3, 9-15 out of scope for this pass. Files changed: `drb-frontend/app/alerts/page.tsx`, `drb-frontend/app/nodes/[id]/page.tsx`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
From a full route audit of
drb-frontend(allapp/routes except the fenced/,/features,/pricing,/faq,/settings/billing, and the map internals). P1/P2 items in this list are NOT yet fixed unless noted; the honest-error-state items for/incidentsand/watchshipped in thefix/frontend-map-and-error-statesPR.P1 — broken / crash-risk
app/page.tsx:147renders<LiveView/>for anyuser && orgId;LiveView.tsx:37only has a "configured but quiet" empty state. TheUI_REDESIGN.mdActivation screen (chunk 10) was never built — nocomponents/Activation.tsx. A new customer sees an empty map with no "mint a token" path.components/CallSpineEntry.tsxInlinePlayer— conditional hook.if (!hasAudio) return null(~line 33) sits betweenuseState/useRefcalls and a lateruseEffect→ React error #310 if ever mounted withhasAudio={false}. Masked only because the parent mounts it exclusively whenhasAudiois true (dead guard). Fix: delete the deadhasAudioprop+guard, or hoist the return above all hooks./incidentsraw Firestore index error — FIXED infix/frontend-map-and-error-states(friendlyIncidentsError). Root cause still server-26 #13/#51.P2 — misleading state / wrong data
/watchalerts events tab swallowed query failures → false "No alerts triggered yet." — FIXED in the same PR. Also:RulesTab(~line 36) callsload()from the render body — move touseEffect.app/nodes/[id]/page.tsx:123"Recent Calls" usually wrongly empty.useCalls(20)fetches 20 most-recent org-wide then filtersc.node_id === idclient-side. Busy multi-node org → "No calls recorded from this node" for nodes that have plenty. Needs a server-sidenode_idfilter.app/nodes/page.tsx:44pending-node card double-fires.<NodeCard>is a<Link>; the pending branch wraps it in a<div onClick={setConfigNode}>. Click → navigates AND tries to open the config modal; navigation wins, modal never shows. Fix: pending card not a Link, or stopPropagation.app/trips/page.tsxupcoming/past mismatch. List buckets onend_date >= today(line 176);TripCardbadge usesstart_date >= today(line 25). In-progress trip shows under "Upcoming" with a "Past" badge. Align both onend_date.settings/organization. DEFERRED says the org-name Save button is disabled/no backend, butc2api.getOrg/updateOrgare wired and the button is live (page.tsx:80). ConfirmPATCH /orgexists on c2-core; update DEFERRED or the button 403s raw.app/calls/page.tsx(Archive) ahead of its doc. Built againstGET /calls/search;UI_REDESIGN.mdlists the route as BLOCKED on backend. If/calls/searchisn't deployed → "Couldn't load calls: C2 API error 404". Verify the endpoint. (Possibly the user's reported/archiveCORS symptom.)P3 — visual / polish
bg-gray-*, depend on theglobals.css!importantblock):/nodes,/systems,/alertsbody,/admin,/profile,/settings/*,/trips,/onboarding,/login,/signup,/waitlist. Known (DEFERRED globals.css row) but jars visibly. This is the remaining migration backlog.app/network/page.tsxis a 3-card hub, notUI_REDESIGN.md§5.6 (no Enrollment tab, still at/settings/nodes; "Bot Tokens" shows—). Scope decision.components/StatusBadge.tsx:6offline state +adminToggleoff-state → pale-gray-on-near-white in light mode. Borderline contrast; off-toggle reads as "no control".app/trips/page.tsx:100CreateModal has nop-4/ no inner scroll → clips on short viewports. Same forNodeConfigModal,DiscordJoinModal. Addp-4overlay +max-h-[90vh] overflow-y-autopanel (incidents CreateModal already does).lib/types.ts—IncidentRecord.units/vehiclesnon-optional but Firestore omits them on older docs;incidents/[id]/page.tsx:216already?.-guards, contradicting the type. Make them optional./settings/members+/settings/nodes403 for a pure org-owner (both call/admin/users,require_admin_token; B7 gate lets them reach the page). Known (SAAS_PLAN B7); error surface is at least honest.Generated by a frontend-audit agent.
Live re-walk 2026-09-07 ~18:38 ET. Items 1/2/3 in this list confirmed still broken in prod — all three are backend/infra deploys, no frontend PR closed them:
/,/incidents/[id]) renders full-screenAPI KEY REQUIREDCarto watermarks.MAP_TILE_URLoverride merged in code butNEXT_PUBLIC_MAP_TILE_URLwas never set in the CI build env, so prod still uses the dead Carto URL. Filed separately.alert_eventscomposite index (acknowledged,org_id,triggered_atdesc) never deployed. Same index throwsuseUnacknowledgedAlerts: FirebaseError: The query requires an indexinlayout.jsconsole on every page. Blocks the whole tab + the site-wide alert bell. -> #51.TypeError: Failed to fetch— CORS preflight failure, root-caused in #110.New, lower severity (added to
Version 5C/UI_AUDIT_0907b.md):18:37:23) bottom-left of the Leaflet map on/and/incidents/[id]— no label, no styling. Leftover debug element.4d49e09ccall transcript shows1. ... 2. 10-4. 3. 5, I'm out. 4. 10-4.— looks like_build_transcript_block's{i}.segment numbering bleeding into the user-visible corrected transcript. Unconfirmed (could be Whisper). Worth checking the#1020-based change.Item 2 (
CallSpineEntryconditional hook) and item 14 (IncidentRecord.unitsoptional) from this list were fixed in the punch-list PRs this session.P2 punch-list pass on branch
fix/109-punchlist-p2(local commit only, not pushed).Item 4 — FIXED.
RulesTabinapp/alerts/page.tsx(not/watch) calledload()from the render body. Moved touseEffect(() => { load(); }, []);load()already self-guards on itsloadedstate flag, so[]deps are honest. AddeduseEffectto the react import.Item 6 — ALREADY FIXED (verified).
components/NodeCard.tsxalready has alinkToDetail?: booleanprop (defaults true) that drops the<Link>wrapper when false, andapp/nodes/page.tsx:45already passeslinkToDetail={false}on the pending branch. The wrapping<div onClick={() => setConfigNode(n)}>now opens the config modal without navigating. No change needed.Item 8 — ENDPOINT EXISTS; button is correctly wired.
drb-c2-core/app/routers/org.py:48@router.patch("")on prefix/org→update_org(OrgUpdateBody, Depends(require_org_owner_token)). Frontendc2api.updateOrg(lib/c2api.ts:306) doesPATCH /orgwith{name}.app/settings/organization/page.tsxSave button is live and guarded (!canEdit/ empty / unchanged disable it). No frontend change made. The stale entry isDEFERRED.md:35("no backend to save to — save button is disabled"), which lives at the Version 5C root, outside the Server repo and this worktree — cannot commit it here. Flagging for someone with repo-root access to correct that row.Item 5 — deferred with TODO (limit raised).
useCallsinlib/useCalls.tsis a direct Firestore query (where org_id ==, optionalstarted_atrange,orderBy started_at desc,limit). Addingwhere('node_id','==', id)alongside the existingorg_idequality +started_atorderBy would require a brand-new composite index, so took the safe path:app/nodes/[id]/page.tsx:123now callsuseCalls(200)(was 20) and keeps the client-sidec.node_id === idfilter, with a// TODO(server-26#109 item5)comment. Proper fix is a server-side node_id filter.Item 7 — ALREADY FIXED (verify only).
app/trips/page.tsx:TripCardbadge (line 27) usestrip.end_date >= today; list buckets (lines 178-179) useend_date. Consistent. No change.Items 1-3, 9-15 out of scope for this pass. Files changed:
drb-frontend/app/alerts/page.tsx,drb-frontend/app/nodes/[id]/page.tsx.