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/).
- Don't manufacture certainty: five briefs running. It covered sync receipts (Sept 27),
_markSynced(Sept 29), queue honesty (Oct 3), "Rev. 0" and hidden drawing refs (Oct 4). Today: Buildr+ shows zero impact from unloaded data, DailyReportr+ compares a report against itself, and Closr+ copies a different scope than it shows. Every one is still unbuilt. The fixes keep getting smaller and more mechanical, which makes them good builder work. - Loading/error collapsed into "empty": this is the specific code pattern behind most of the theme.
valueOrNull ?? []orSizedBox.shrink()on error appears in Buildr+ impact (today), Closr+ handover copy (today), Inspectr+ drawing refs (Oct 4), and the DailyReportr+ admin Reports page (Sept 28). This is why Recommendation #1 asks for a pattern fix plus a test, not just one screen. - Drawings and plan context: three briefs running (revision impact today; snapshot revision and sheet reference Oct 4;
DrawingReferencerevision Sept 29). Morning intel keeps citing Procore and Fieldwire drawing viewers. - Automation stall: 27 nights. The morning sources still check only the retired review producer and not the builder launch jobs.
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
- Raw exception text in error states:
Text('Error: $e')-style strings appear on 60 lines in Buildr+ (56 files), 35 in Closr+ (30 files), and 5 in Inspectr+. DailyReportr+ has 0 and uses friendly copy instead ("Could not load…", 34 uses). No app has a shared error-state widget; Buildr+ and Inspectr+ each define a private_ErrorState. A sharedAppErrorState(message, onRetry)per app, adopted file by file with each fix, would make this consistent. Recommendation #1 starts it in Buildr+. - Closr+ copy-action labels and scope: the same app has "Copy Handoff" (dashboard card,
TextButton.icon, cross-project, 8 items, SnackBar "Asset handover checklist copied") and "Copy Handoff Brief" (owner handover tab,FilledButton.icon, single project, SnackBar "Owner handoff brief copied"). The button styles differ, the labels nearly collide, and neither states its scope. Recommendation #3 fixes the dashboard side. - Empty vs. loading vs. failed still look the same: Buildr+ impact counts (today), Closr+ handover copy (today), Inspectr+ drawing refs (Oct 4), and DailyReportr+ admin Reports (Sept 28).
- Carried over, unchanged (no commits): the Buildr+ custom
Icons.arrow_back_iosback button on 9 reachable pages. The Inspectr+DrawingReferenceChipspassesisDark28 times. The Inspectr+ gallery ignores the tapped index. The DailyReportr+ "Today" pill looks tappable but isn't. RawColors.green: DailyReportr+ 40, Inspectr+ 29, Buildr+ 0, Closr+ 0.
Competitive Intel
- Bluebeam on web: Session Status. Attendees in a Studio Session can be marked Reviewing, Waiting, or Finished in the Attendees panel and Sessions list, and Sessions can be sorted by status. Status syncs between Web and Revu, and custom Revu statuses also show. It's relevant to owner/consultant review loops in Closr+ (owner review links) and Buildr+ (submittal review). Status is shown per person, not inferred. new to these briefs; release date unverified [source]
- Procore Workflows: Step Override (web + mobile, Oct General Enhancements published Sept 29). Authorized users can advance a stalled approval only with a required reason and an attributed history entry. already reported Oct 2, Oct 3 [source]
- Procore Daily Log email redesign (Web/iOS/Android). Consistent notifications for rejected logs, completed logs, and weather delays. DailyReportr+ has no comparable state notification. already reported Sept 25 [source]
- Not used: the Procore Inspections ETA/selective-download item and Connected Items pinning came back again; they were already reported more than 10 times in September. The Autodesk results ("Open for Manager", "Download All Attachments", As Built Export) are older posts with no 2026 date. Fieldwire's newest product-update post is from earlier in 2026; its status page shows incidents Oct 1 and Oct 4–5, but no feature shipped. No PlanGrid ship found. It's a quiet week for in-scope features.
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.