Lab Architect / Ellsworth

Afternoon Brief

Monday, October 5, 2026 — Twenty-seventh consecutive night with no nightly-branch build on any app. There is no feature/nightly-20261005 or feature/nightly2-20261005 branch, and git log --all --since="36 hours ago" is empty on all four app repos. Codebase health: 0 analyzer issues on all four apps. For the second day running, all three morning ideas survived verification (reachable, never shipped). Two of them share a pattern this brief has flagged for weeks: an AsyncValue that's loading or failed gets turned into an empty list, so the screen reports "zero" or "nothing to copy" instead of "not loaded yet".

Last Night’s Builds

No nightly-branch build on any app, twenty-seventh night running missed

Ran git fetch origin --prune on all four repos. No new nightly branches exist; the newest on any remote are still feature/nightly-20260908 (Buildr+) and feature/nightly2-20260909 (Buildr+). The held assignments (Dominique → Buildr+ Deletes That Wait for the Server; Katey → DailyReportr+ reports_page.dart rework) went unclaimed for an eighth day. Today's morning brief again reports Hermes UP but the nightly producer/review artifacts MISSING, and again doesn't check the 00:15 and 01:15 builder jobs. ~/memory/last-nightly-build.md (the builder coordination file) was last updated Aug 5.

Buildr+ 4 commits unpushed · working copy off main

Local main head a7a5a03 (Sept 21) is 4 ahead / 0 behind origin/main (33c825f, Sept 18). The working copy is still on fix/project-card-contract-value-spacing. Unchanged.

Closr+ 6 commits unpushed · tracked node_modules

Local main head 0925b0b (Sept 21) is 6 ahead / 0 behind origin/main (7a3ca21). git status still lists 1,648 changed paths, nearly all deleted-but-tracked node_modules/ files. Unchanged.

Inspectr+ 7 commits unpushed

Local main head 8145093 (Sept 21) is 7 ahead / 0 behind origin/main (4140149, Sept 8). Unchanged.

DailyReportr+ silent 21 days · working copy off main

main = origin/main = 0433f44 (Sept 14, 3.8.1 TestFlight prep). The working copy is still on the Aug 11 fix/owner-report-media-web branch with modified tracked files. The morning brief's "checked-out" heads (Buildr+ b983e74, DailyReportr+ af49e33) are those off-main working copies, not main.

Codebase Health

App Analyzer Issues Unimported files Raw 'Error: $…' text Breakdown Last 3 Commits (local main)
Buildr+ 0 16 60 / 56 files "No issues found!" New today: drawing_revision_impact_page.dart:63-65 computes the impact summary from rfisAsync.valueOrNull ?? [] (same for submittals and transmittals). While those load, or if they fail, the summary card and every revision card show 0 impacted. _showLinkSheet (:435-437) does the same, and the page's own error branch shows raw 'Error: $e' (:61). Reachable: Doc Control → Document Workstreams (document_workstreams.dart:173; relocated, not retired, in 85364d3). Still open: 10 unguarded onDismissed deletes, the "Unlinked Rev. 0" label, the producer-less offline queue, and the 6 owner-retired pages. a7a5a03 merge harden-ios-release-gate • a2873c3 merge project-card spacing fix • fac04bd source protected secrets file (unpushed)
Closr+ 0 12 35 / 30 files "No issues found!" New today: AssetHandoverChecklistCard renders .take(4) rows (asset_handover_checklist_card.dart:68) but Copy Handoff copies .take(8) across projects (:152). It also builds the copy from projectsAsync.valueOrNull ?? [] (:28-31), so tapping it while projects are still loading copies "No asset handover checklist items in Closr+ right now." Reachable from the dashboard (dashboard_page.dart:196, behind the paywall overlay). Still open: the isExpiringSoon boundary gap, the silent portfolio catch (_), tracked node_modules/, and the Connected Sources retire/restore decision. 0925b0b merge harden-ios-release-gate • d4c8952 gate TestFlight IPA on client IDs • ca33394 bump TestFlight 2.32.75 (unpushed)
Inspectr+ 0 18 5 / 5 files "No issues found!" Nothing new today. Still open: DrawingReferenceChips hides on error (Oct 4 Rec #1), the tapped-photo gallery index, 29 raw Colors.green. 8145093 merge Google sign-in client-ID fix • 5e0849b merge harden-ios-release-gate • 744cc12 add iOS artifact gate (unpushed)
DailyReportr+ 0 11 0 "No issues found!" New today: _exportPDF in daily_report_pdf_preview.dart:858-859 carries the comment "excluding today's draft" but runs recentReports.take(5) on getReportsByProject with no ID or date filter. It's been that way since 820fb17 (Missed-Item Prompt, v2.28.0). The service doesn't sort on the client (report_service.dart:55), so "most recent" depends on the server's order. Reachable from the report wizard. Still open: the admin reports retry loop, the duplicated _buildReportCard, and 40 raw Colors.green. 0433f44 prepare 3.8.1 TestFlight • 2495d04 merge keyboard-recovery fix • 7253e65 stop keyboard recovery stranding text field (pushed)

Analyzer counts: Buildr+ 0 · Closr+ 0 · Inspectr+ 0 · DailyReportr+ 0, from dart analyze lib on fresh git archive main snapshots (after flutter pub get --offline) in /private/tmp/afternoon-brief-20261005/. These match the morning brief. Unimported-file counts are carried from Oct 2; no main has changed since. New metric: raw exception text, counted as lines matching Text('Error: $ in lib/. Analyzer "0" doesn't catch user-facing $e strings. DailyReportr+ is the model to copy (0).

Recurring Themes from Morning Briefs

Sources: the Oct 5, Oct 4, and Oct 3 morning briefs (briefs/).

Feature Ideas + UI/Code Health Recommendations

There are 3 recommendations: 2 UI/code health items and 1 feature, all taken from today's morning brief after verification on main. For dedup, I checked git log main -S on rfisAsync.valueOrNull, excluding today, and Copy this project. The only hits are the commits that introduced the code (254438f/85364d3 Buildr+, 820fb17 DailyReportr+); no fix exists. Reachability was confirmed through importers and call sites for each widget. The held items from Sept 28 to Oct 4 still rank ahead of these.

1. Don’t Turn Unloaded Impact Data Into Zero Buildr+ — UI/Code Health (async states + error copy + tests)

The Drawing Revision Impact page waits only on drawingRevisionsProvider. RFIs, submittals, and transmittals are read with valueOrNull ?? [], so on a slow connection or a failed fetch, every revision shows "0 impacted" and the summary card reads like an all-clear. The owner-approved Aug 8 feature audit already said "absence of links must not be an all-clear". This is the same failure at the loading layer. The page's own error state is raw 'Error: $e'.

Why now: it's in today's morning brief, and the code confirms it. It's the fifth day of the "honest states" theme, and Buildr+ has the most raw 'Error: $e' text of any app (60 lines). Procore's Drawings viewer treats revision provenance as a fact (morning intel).

Sketch: in build, combine the three linked providers. If any isLoading, render the revision list but replace impact counts with a small "Checking linked RFIs/submittals…" line and a LinearProgressIndicator. If any hasError, show a compact banner, "Couldn't load linked <RFIs/submittals/transmittals>. Impact counts unavailable.", with Retry that calls ref.invalidate on only the failed providers. Don't call buildDrawingRevisionImpactSummary until all three have data. Apply the same guard in _showLinkSheet. Replace :61 'Error: $e' with the friendly-copy pattern. Add widget tests for loading, error (retry shown, no "0"), and genuinely empty (shows "Nothing linked", not "No impact"). Analyzer stays at 0, and raw-error count drops by 1.

2. Compare Against Prior Days Only DailyReportr+ — UI/Code Health (logic fix + first tests)

Before PDF export, the Missed-Item Prompt compares the current report against "up to 5 most recent reports (excluding today's draft)". The code doesn't exclude anything. If today's report was already saved, it's one of the five, so it's compared with itself. That dilutes the baseline and hides real gaps. The order also depends on whatever the server returns.

Why now: it's in today's morning brief, and the code confirms it. The comment and the code have disagreed since 820fb17. It's a ~10-line fix, and ReportCompletenessChecker has no tests on its input selection.

Sketch: move the selection into a pure helper, selectComparisonReports(all, {currentReportId, currentDate, limit: 5}). It drops the active report ID and any report on the same local reporting day, sorts by date descending, and takes 5. Keep the try/catch so a failed Cloudflare read still lets export continue. Unit tests: today's saved report excluded, same-day duplicate excluded, unordered input sorted, fewer than 5 prior days, empty list skips the prompt. Analyzer stays at 0.

3. Copy One Owner-Walk Handoff Closr+ — Feature

The Asset Handover Checklist shows up to four project rows, but its only action, Copy Handoff, silently copies up to eight projects. A closeout manager who wants to send one owner their walk prep can't do it without manually deleting other projects' notes, and could leak them. A per-row copy action is the useful field feature here, and fixing the header action's scope comes with it.

Why now: it's in today's morning brief, and the code confirms the 4-shown/8-copied mismatch plus the loading case (copies "no items" while projects load). It's small and user-visible, and it's the only feature-type idea this week that needs no backend.

Sketch: add a trailing copy IconButton (with a Semantics/tooltip "Copy handoff for <project>") to _HandoverProjectRow. It reuses _copyChecklist with a one-item list and the SnackBar "Handoff for <project> copied". Relabel the header action "Copy all (N)" with N = the copied count, and disable it while projectsAsync.isLoading. Tests: single-row output, all-projects output and count, disabled while loading, empty state. No backend or plan viewer.

UI Inconsistencies

Competitive Intel

Tomorrow’s Build Suggestion

This is the twenty-seventh night without builders. The assignments stay held (eighth day). Queue change: today's Recommendations #1 and #2 are added as second-slot items in the same apps as the held tasks, so a builder that picks up its assignment can ship both in one branch. Owner actions before either build: check the 00:15 and 01:15 builder launch jobs, push the unpushed main commits (Buildr+ 4, Closr+ 6, Inspectr+ 7), and make the Connected Sources decision. For Closr+, stage explicit paths rather than using git add -A.

Dominique → Buildr+

Task: Deletes That Wait for the Server (Sept 28 Recommendation #1). If time remains, do today's Recommendation #1 (impact counts that wait for their data). Rationale: Buildr+ hasn't had a nightly feature since Aug 5 and has the most raw error text (60 lines). Both fixes stop the app from showing outcomes that haven't happened.

Katey → DailyReportr+

Task: a single reports_page.dart rework: Admin Reports That Admit Failure, then the shared ReportSummaryCard, then a lazy SliverList. If time remains, do today's Recommendation #2 (prior-days-only comparison, with its first unit tests). Rationale: it's the stalest app (21 days on main), and #2 is a pure-function fix with tests. Queued next for whichever builder frees up first: Inspectr+ Drawing References That Admit Failure (Oct 4), then Closr+ Copy One Owner-Walk Handoff (today's #3), then the Inspectr+ tapped-photo fix.