Lab Architect / Ellsworth

Afternoon Brief

Tuesday, October 6, 2026 — Twenty-eighth consecutive night with no nightly-branch build on any app. No commits on any ref in any app repo in the last 36 hours. Codebase health: 0 analyzer issues on all four apps. No morning brief was published today (briefs/ stops at Oct 5). Correction: Closr+'s DashboardPage hasn't been reachable since 0f0b5f5 (Jun 17, "make Closr project-first"). Fourteen dashboard cards are imported only by that page, so they're dead too. That includes the Asset Handover Checklist targeted by yesterday's Recommendation #3, which is withdrawn.

Last Night’s Builds

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

Ran git fetch origin on all four repos. No feature/nightly-20261006 or feature/nightly2-20261006 branch exists, and there are no October nightly branches of either kind. git log --all --since="36 hours ago" is empty on all four. The held assignments (Dominique → Buildr+ Deletes That Wait for the Server; Katey → DailyReportr+ reports_page.dart rework) went unclaimed for a ninth day. Today's Fountainhead morning report (morning-reports/2026-10-06.md) again shows Hermes UP and the nightly review artifacts MISSING. Its log tail still ends Sept 6, and it doesn't check the 00:15 or 01:15 builder jobs. The builder coordination file ~/memory/last-nightly-build.md was last updated Aug 5.

Buildr+ 4 commits unpushed · working copy off main

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

Closr+ 6 commits unpushed · tracked node_modules

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

Inspectr+ 7 commits unpushed

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

DailyReportr+ silent 22 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.

Codebase Health

App Analyzer Issues Unimported files Raw 'Error: $…' text Test files Breakdown Last 3 Commits (local main)
Buildr+ 0 16 60 / 56 files 86 "No issues found!" Nothing new. Still open: unguarded onDismissed deletes, impact counts from unloaded data, 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 (+14 transitive) 35 / 30 files 35 "No issues found!" New today: DashboardPage (1,248 lines) has no importer. 0f0b5f5 (Jun 17) cut the bottom nav to Projects / Map / Settings. The 12-file orphan count missed the 14 widgets imported only by that page: Owner Packet Score, Evidence Matrix (and the Completeness Matrix page it links to), Completion Forecast, Turnover Risk Digest, Asset Handover Checklist, Handoff Risk Score, Owner Callback Queue, Owner Walkthrough Readiness, Retainage Release Radar, Closeout Exposure Snapshot, Exposure Aging, Closeout Aging Digest, Closeout Risk Heatmap, and Subcontractor Chase Plan. PunchListPage is also never constructed. Of the 35 raw-error lines, 7 sit on the reachable Projects → project path (Rec #1). 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 66 "No issues found!" Nothing new. Still open: DrawingReferenceChips hides on error (Oct 4), the gallery ignores the tapped index, and 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 75 "No issues found!" Nothing new. Still open: the admin reports retry loop, the duplicated _buildReportCard, the PDF missed-item check comparing a report with itself (Oct 5), 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. They come from dart analyze lib on fresh git archive main snapshots, after flutter pub get --offline, in /private/tmp/afternoon-brief-20261006/. Test-file counts (test/**/*_test.dart) are a new column today. Closr+ has the fewest tests (35) for the most source files (266). Method note: the "unimported files" metric only counts files with zero importers. A page with no entry point can still keep a whole subtree "imported." Future runs should also count widgets reachable only from orphan pages.

Recurring Themes from Morning Briefs

Sources: the Oct 5, Oct 4, and Oct 3 morning briefs in briefs/. No Oct 6 morning brief was published, only the Fountainhead morning report.

Feature Ideas + UI/Code Health Recommendations

There are 3 recommendations: 2 UI/code health items and 1 feature. All three are in Closr+, because today's finding is specific to it. Dedup checks: git log --all -i --grep for "error state", "owner link", "link status", and "owner viewed" found nothing relevant. The only "error state" hit is 229be66, the Digital Closeout Package feature. No shared error widget exists in Closr+ (onRetry: 0 hits). git log -S "DashboardPage()" shows the last construction was removed in 0f0b5f5. Every target below was checked for an actual entry point, not just an importer. The held items from Sept 28 to Oct 5 still rank ahead of these.

1. Errors a Closeout Manager Can Act On Closr+ — UI/Code Health (shared error widget + tests)

When a load fails on the Projects tab (the app's first screen), users see Text('Error: $error'). For a Cloudflare failure, that reads Error: CloudflareApiException(401, …): …, and there's no way to retry. The same pattern sits on every main step into a project: projects_page.dart:89, project_detail_page.dart:138 (the project itself), :2259 (Punch tab, in red), checklist_page.dart:50, documents_page.dart:185, and under More, subcontractors_tab_view.dart:36 and lien_waiver_tab_view.dart:95. Closr+ has no shared error widget. DailyReportr+ already has the pattern to copy: a private _ErrorState(message, onRetry) with a "Try Again" button (project_map_page.dart:473).

Why now: Closr+ has 35 raw-error lines, the second most of any app, and these 7 are the ones users actually reach. Today's dead-dashboard finding means effort should go to the Projects-first path that ships. Closr+ also has the thinnest test suite (35 files).

Sketch: add lib/widgets/app_error_state.dart with AppErrorState({required String title, String? detail, VoidCallback? onRetry}). Add a friendlyErrorMessage(Object e) helper that maps CloudflareApiException status codes as follows: 401/403 → "Your session expired. Sign in again", 404 → "This project is no longer available", 5xx or socket errors → "Couldn't reach Closr+. Check your connection". Replace the 7 sites, with each onRetry calling ref.invalidate on its own provider. Use SliverFillRemaining on the Projects tab. Add widget tests for the helper's mapping and for Projects-tab error → Try Again → data. Analyzer stays at 0, and the raw-error count drops from 35 to 28.

2. Retire or Re-home the Orphaned Dashboard Closr+ — UI/Code Health (dead-code decision)

0f0b5f5 (Jun 17, by the owner) made Closr+ project-first. It replaced the Dashboard tab with Projects / Map / Settings, but left dashboard_page.dart and 14 cards in lib/. Nightly builders kept shipping into that dead code for seven weeks. Examples are the Turnover Risk Digest polish (Aug 3) and the Completeness Matrix, whose only entry is the dead Evidence Matrix card (Aug 4). Briefs kept recommending fixes there too (yesterday's Rec #3). The cards still compile, analyze clean, and some have tests, so nothing flags them.

Why now: this is the third dead-code correction in five days, after Connected Sources (Oct 2) and the offline queue (Oct 3). Until there's a decision, every builder and brief risks targeting it again.

Sketch (owner decides, builder executes): sort the 14 cards into re-home and retire. Re-homed cards go into a project's Overview (per-project cards like Owner Packet Score) or a Projects-tab "Portfolio" header. Retired cards get deleted in one commit along with dashboard_page.dart, PunchListPage, and any providers left with no watchers. Record the decision in docs/ux/, as Buildr+ did in its Aug 8 audit. Add a CI guard test that fails when a lib/pages/**/*_page.dart class is never constructed, with an allowlist. Analyzer stays at 0. The dead subtree is 9,645 lines (dashboard + 14 cards + Completeness Matrix + PunchListPage), minus whatever gets re-homed.

3. Owner Link Status on the Project Overview Closr+ — Feature

Closr+ already tracks whether the owner review link was sent, viewed, expiring, or expired. OwnerPacketScore.reviewLinkStatusLabel and reviewLinkDetail produce labels like "Owner viewed", "Link expiring", and "Expired today. Refresh the link.", and the model has a 156-line test file. Today that status only appears on the dead dashboard card. On the reachable app, the view count and expiry are visible only after opening the Share dialog. Add one row to the project Overview's existing Handover card (_buildHandoverSummaryCard, project_detail_page.dart:459). It should read "Owner review link · Owner viewed (3 views) · expires in 2 days", and tapping it opens ShareProjectDialog.

Why now: it's the smallest re-home from Rec #2. It brings a tested model back into use, needs no backend, and puts closeout's last-mile signal (did the owner open the package?) on the screen users actually see. Bluebeam's web Session Status (shown per person; reported Oct 5) and Procore's Owner Hub milestone variance (below) both point at owner-facing status.

Sketch: compute OwnerPacketScore.fromProject(project) in _buildHandoverSummaryCard, and add a second _buildOverviewNavRow with a link icon, the status label as the title, and reviewLinkDetail as the detail. Use amber when expiring and red when expired, from AppColors rather than raw colors. Tapping it pushes the share dialog (the same call as :2287). Add a widget test for each of the four states: none, not viewed, viewed, and expired. If Rec #2 retires owner_packet_score_card.dart, keep the model.

UI Inconsistencies

Competitive Intel

Tomorrow’s Build Suggestion

This is the twenty-eighth night without builders. The assignments stay held (ninth day). Queue change: the Closr+ "Copy One Owner-Walk Handoff" item is removed because it targets dead code. Today's Rec #1 replaces it as the Closr+ queue item. Rec #2 needs an owner decision first. 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). Decide on the Closr+ Dashboard and Connected Sources (retire or re-home). For Closr+, stage explicit paths rather than using git add -A.

Dominique → Buildr+

Task: Deletes That Wait for the Server (Sept 28 Rec #1), then impact counts that wait for their data (Oct 5 Rec #1). Rationale: Buildr+ hasn't had a nightly feature since Aug 5 and has the most raw error text (60 lines). Both fixes are reachable and verified.

Katey → DailyReportr+

Task: a single reports_page.dart rework (Admin Reports That Admit Failure → shared ReportSummaryCard → lazy SliverList), then the prior-days-only comparison (Oct 5 Rec #2). Rationale: it's the stalest app (22 days on main). Queued next for whichever builder frees up first: Closr+ Errors a Closeout Manager Can Act On (today's #1), then Inspectr+ Drawing References That Admit Failure (Oct 4), then the Inspectr+ tapped-photo fix. Closr+ Owner Link Status (today's #3) is next after the owner's dashboard decision.