Skip to content

Fix blank screen on detail view for projects with no filesystem paths#53

Merged
spaceshipmike merged 2 commits into
mainfrom
fix/detail-view-blank-on-pathless-project
Jun 25, 2026
Merged

Fix blank screen on detail view for projects with no filesystem paths#53
spaceshipmike merged 2 commits into
mainfrom
fix/detail-view-blank-on-pathless-project

Conversation

@spaceshipmike

Copy link
Copy Markdown
Owner

Problem

Clicking certain projects blanked the entire app, not just the detail pane.

Two compounding bugs:

  1. The crash — Core's toFull() (packages/core/src/models.ts:318) omits the paths field entirely when a project has no filesystem paths (non-code projects: trips, partnerships, the tutorial). But the renderer's ProjectFull type declared paths: string[] as always-present, so ProjectDetailView read project.paths.length unguarded → TypeError on every render.
  2. The blast radius — there was no React error boundary anywhere, so that single throw unmounted the whole React tree → blank screen with no recourse.

Reproduced against the real registry DB: exactly 4 path-less projects crashed the detail view (claude-tutorial, country-visit-aug-2026, prague-trip-2026, stray-dog-partnership).

Fix

Change File Why
paths?: string[] (was required) api.ts Match reality; lets TypeScript catch this class of bug
Guard the three project.paths reads ProjectDetailView.tsx The crash fix — consistent with every other renderer file, which already guarded
New ErrorBoundary, wrapped around the view switch ErrorBoundary.tsx, App.tsx Defense in depth — a single bad view shows a recoverable card, never blanks the app again

Verification

  • New Playwright e2e regression test: a path-less project's detail view renders fully (header + all four tabs) and the error boundary does not fire. Passes in ~1.2s.
  • 4354 unit tests pass.
  • App builds clean; better-sqlite3 ABI reconciled back to Node.

Notes (pre-existing, not addressed here)

  • Two latent type errors on main (RegisterProjectDialog.tsx:161, OverviewTab.tsx:55) that the esbuild build silently ignores — this is how the paths type-lie survived. Worth a follow-up to wire tsc --noEmit into CI.
  • Local e2e suite has a teardown hang (the repo's existing detail-view test fails the same way locally); this PR's test force-exits the app to sidestep it.

🤖 Generated with Claude Code

spaceshipmike and others added 2 commits June 25, 2026 14:48
Core's toFull() omits the `paths` field entirely when a project has no
filesystem paths (non-code projects: trips, partnerships, tutorials), but
the renderer's ProjectFull type declared `paths: string[]` as always
present. ProjectDetailView read `project.paths.length` unguarded, throwing
a TypeError on every render. With no React error boundary in the tree, that
throw unmounted the whole app — a blank screen with no recourse.

- api.ts: ProjectFull.paths is now optional, matching reality and the rest
  of the renderer's guards (so TypeScript catches this class of bug).
- ProjectDetailView.tsx: guard the three `project.paths` reads.
- ErrorBoundary.tsx + App.tsx: wrap the view switch so a single view's
  render throw shows a recoverable card instead of blanking the app.
- e2e: regression test — a path-less project's detail view renders fully
  and the error boundary does not fire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iR9LcchEebnoyt5GLRzev
The packages/skills workspace (added in 494f778, the prototype-driven
migration) was committed without updating the root lockfile, and the
release commits bumped workspace versions beta.11 -> beta.21 without
re-running install. `npm ci` therefore fails with "Missing:
@setlist/skills from lock file", breaking the CI `check` job on every PR.
check.yml only runs on pull_request (not push to main), so the breakage
stayed invisible until the first PR after the migration.

Regenerated with `npm install --package-lock-only` — only package-lock.json
changes (skills workspace entry + workspace version sync, no third-party
dependency changes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iR9LcchEebnoyt5GLRzev
@spaceshipmike

Copy link
Copy Markdown
Owner Author

🤖 Codex review — APPROVE

Local Codex review of this PR's changes against origin/main.

No blocking correctness, security, IPC-contract, or better-sqlite3 ABI issues found in the HEAD vs origin/main diff. Static review covered the changed source, generated Electron output, and surrounding path/IPC call sites. I could not run typecheck/tests because this worktree has no node_modules installed.

No issues found.

@spaceshipmike spaceshipmike merged commit 8afe442 into main Jun 25, 2026
2 checks passed
@spaceshipmike spaceshipmike deleted the fix/detail-view-blank-on-pathless-project branch June 25, 2026 19:10
spaceshipmike added a commit that referenced this pull request Jun 25, 2026
First /close. Reconciles the model against the blank-screen fix (#53):
- INVARIANTS: + projection-optionality contract (PROSE); + two CI open
  tensions (renderer types unchecked in CI; CI not run on push to main).
- SURFACES: + "core projection shape ↔ consumer types" cross-cutting edge.
- MODEL_DECISIONS: + D-006 (local Codex review + hosted CI; no self-hosted
  runner because setlist is public).
- lessons.md: + #desktop-app candidate (esbuild doesn't typecheck the
  renderer; add an error boundary so a render throw can't blank the app).
- steward.json: establish lastClose marker.

Follow-ups filed: #55 (renderer tsc in CI), #56 (CI on push to main).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iR9LcchEebnoyt5GLRzev
spaceshipmike added a commit that referenced this pull request Jun 25, 2026
Ships the blank-screen fix (#53): detail views for projects with no filesystem paths now render instead of crashing the renderer. Includes the lockfile sync, agent-model reconciliation, and the local Codex review script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iR9LcchEebnoyt5GLRzev
spaceshipmike added a commit that referenced this pull request Jun 25, 2026
Second /close. Covers the post-#53 work (#54 Codex script, RELEASING.md runbook, the notarized beta.22 release). INVARIANTS: filled the 'Release / propagation' placeholder with a PROSE invariant (CI-only notarized distribution; tag==versions+lockfile; tag/secrets clauses already ENFORCED by release.yml). lessons: +#desktop-app candidate (single-instance-lock-on-shared-userData trap; e2e tests out/ not the packaged artifact). Follow-up #57 (lockfile-sync gate). steward marker → 7b443be.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iR9LcchEebnoyt5GLRzev
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant