Skip to content

fix: preserve persisted cache crash diagnostics#161

Merged
Astro-Han merged 2 commits into
devfrom
codex/fix-i156-persisted-cache
Apr 22, 2026
Merged

fix: preserve persisted cache crash diagnostics#161
Astro-Han merged 2 commits into
devfrom
codex/fix-i156-persisted-cache

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

Preserve the original cause and child-store cache context when workspace persisted cache creation fails. Invalid runtime workspace directory input now fails before persistence setup instead of continuing into Persist.workspace(...).

Why

Closes #156. The packaged app could show only Failed to create persisted cache, which hid the synchronous exception, storage file, key, cache kind, and workspace directory. The fix keeps the failure at the child-store layer and does not change storage namespace behavior.

This intentionally turns empty workspace directories into explicit child-store errors too. Previously ensureChild("") only logged and continued into a fallback workspace cache path, which masked bad upstream input.

Related Issue

Closes #156

How To Verify

bun --cwd packages/app typecheck
(cd packages/app && bun test --preload ./happydom.ts ./src/context/sync-current-child.test.ts ./src/context/global-sync/child-store-error.test.ts ./src/context/global-sync/child-store.test.ts ./src/utils/persist.test.ts)

Screenshots or Recordings

Not applicable. No visible UI layout change.

Checklist

  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I listed the relevant verification steps, including tests when behavior changed
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, or generated/local file changes when relevant
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • New Features

    • Better child-store persistence flow with optional custom persistence support and stricter directory validation.
  • Bug Fixes

    • Improved error wrapping that preserves original causes and prevents partial/invalid cache publishing.
  • Tests

    • Added tests covering error diagnostics, propagation, and persisted-cache failure scenarios.

@Astro-Han Astro-Han added bug Something isn't working P1 High priority app Application behavior and product flows platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions labels Apr 22, 2026
@gemini-code-assist

Copy link
Copy Markdown

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a ChildStoreError utility and helpers to validate directories, create persisted child caches with preserved causes and structured context, and updates the child-store manager to use these utilities instead of inline persisted/runWithOwner logic.

Changes

Cohort / File(s) Summary
Error handling module & tests
packages/app/src/context/global-sync/child-store-error.ts, packages/app/src/context/global-sync/child-store-error.test.ts
New module introducing ChildStoreError, context types, validateChildStoreDirectory, createChildStorePersistedCacheError, and createPersistedChildCache. Tests assert directory validation, serialization markers for unserializable context, cause preservation, message formatting (cache/storage/key), and Solid catchError integration.
Child store manager & tests
packages/app/src/context/global-sync/child-store.ts, packages/app/src/context/global-sync/child-store.test.ts
Manager now accepts optional persist factory and uses createPersistedChildCache for vcs/project/icon caches. Replaces prior persisted() + runWithOwner() pattern and adds explicit directory validation. Tests updated and extended to cover invalid-directory rejection, persisted-init failure wrapping, cause preservation, and prevention of partial cache publication.

Sequence Diagram(s)

sequenceDiagram
  participant Manager as Manager (ensureChild)
  participant Validator as validateChildStoreDirectory
  participant PersistFactory as Persist / persisted / custom persist
  participant Solid as Solid Owner (runWithOwner)
  participant ErrorUtil as createChildStorePersistedCacheError / ChildStoreError

  rect rgba(200,220,255,0.5)
    Manager->>Validator: validate directory
    Validator-->>Manager: directory ok / throws ChildStoreError
  end

  rect rgba(220,255,200,0.5)
    Manager->>PersistFactory: build persist target (storage/key)
    Manager->>Solid: runWithOwner(callback)
    Solid->>PersistFactory: invoke persisted factory
    PersistFactory-->>Solid: returns persisted cache OR throws
    Solid-->>Manager: returns cache OR surfaces error (may be undefined)
  end

  rect rgba(255,220,200,0.5)
    alt persisted step throws or owner surfaces error
      Manager->>ErrorUtil: createChildStorePersistedCacheError(messageKey, context, cause)
      ErrorUtil-->>Manager: throws ChildStoreError (with context + cause)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰✨ I dug a hole through tangled stacks,

Found masked causes and brought them back.
With context clear and traces bright,
Hidden errors hop into light.
A carrot for clues — all fixed tonight! 🍃

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: preserving persisted cache crash diagnostics. It directly relates to the primary objective of surfaces original errors and context information when cache creation fails.
Description check ✅ Passed The PR description is complete and follows the template structure with Summary, Why, Related Issue, How To Verify, Screenshots/Recordings, and a filled-out Checklist covering all required items.
Linked Issues check ✅ Passed The code changes comprehensively address all key objectives from issue #156: validating directory input, preserving original cause and context, adding regression tests, and avoiding masking errors with generic messages.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to child-store error handling, persisted cache creation, and related tests. No unrelated modifications to other domains are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-i156-persisted-cache

Comment @coderabbitai help to get the list of available commands and usage tips.

@Astro-Han Astro-Han force-pushed the codex/fix-i156-persisted-cache branch from 8185142 to 9435849 Compare April 22, 2026 18:39
@Astro-Han Astro-Han marked this pull request as ready for review April 22, 2026 18:39

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick pass. Logic is sound and CI is green; comments below are P2/P3 polish.

Comment thread packages/app/src/context/global-sync/child-store-error.ts Outdated
Comment thread packages/app/src/context/global-sync/child-store-error.ts
Comment thread packages/app/src/context/global-sync/child-store-error.ts
Comment thread packages/app/src/context/global-sync/child-store.ts Outdated
Comment thread packages/app/src/context/global-sync/child-store.ts
Comment thread packages/app/src/context/global-sync/child-store-error.test.ts Outdated
Comment thread packages/app/src/context/global-sync/child-store-error.test.ts
Comment thread packages/app/src/context/global-sync/child-store-error.ts
@Astro-Han Astro-Han force-pushed the codex/fix-i156-persisted-cache branch from 9435849 to 969e304 Compare April 22, 2026 18:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/src/context/global-sync/child-store.ts`:
- Around line 133-168: The current code calls
vcsCache.set/metaCache.set/iconCache.set as each createPersistedChildCache
returns, which can expose partially-initialized state if a later
createPersistedChildCache throws; modify ensureChild() to first call
createPersistedChildCache for vcs, project (meta) and icon and store their
returned tuples in local variables (e.g., vcsTuple, metaTuple, iconTuple)
without mutating vcsCache/metaCache/iconCache or children/disposers, then after
all three succeed call vcsCache.set(directory,...),
metaCache.set(directory,...), iconCache.set(directory,...) and only then
register children[directory] and push to disposers; also ensure that if any
createPersistedChildCache throws you clean up any already-created stores
(dispose or rollback) before rethrowing to avoid leaks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2b2b7626-5fa5-4d10-bedc-a9dea073828b

📥 Commits

Reviewing files that changed from the base of the PR and between 52e46ad and 969e304.

📒 Files selected for processing (4)
  • packages/app/src/context/global-sync/child-store-error.test.ts
  • packages/app/src/context/global-sync/child-store-error.ts
  • packages/app/src/context/global-sync/child-store.test.ts
  • packages/app/src/context/global-sync/child-store.ts

Comment thread packages/app/src/context/global-sync/child-store.ts
@Astro-Han Astro-Han force-pushed the codex/fix-i156-persisted-cache branch from 969e304 to 8f4c148 Compare April 22, 2026 19:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/app/src/context/global-sync/child-store.ts (1)

133-164: ⚠️ Potential issue | 🟠 Major

Roll back the earlier persisted caches when later setup fails.

If project or icon creation throws, the earlier createPersistedChildCache(...) calls have already bound their persistence work to input.owner, but this path has no rollback/dispose step for those partial successes. The cache maps stay empty now, but retries can still accumulate orphaned persisted listeners/writers for the same workspace:* keys. Please create the three persisted caches under a disposable per-directory root and tear that root down on failure before rethrowing.

#!/bin/bash
set -euo pipefail

echo "== child-store setup path =="
fd '^child-store\.ts$' packages/app/src/context/global-sync -x sed -n '130,230p' {}

echo
echo "== persisted factory return contract =="
fd '^persist\.ts$' packages/app/src -x sed -n '1,80p' {}
fd '^persist\.ts$' packages/app/src -x sed -n '485,620p' {}

Expected result: ensureChild() creates vcs, project, and icon sequentially before any directory-scoped disposer is registered, while persisted(...) returns only the 4-tuple and does not give this call site a way to tear down already-created partial successes. As per coding guidelines "Always prefer createStore over multiple createSignal calls in SolidJS".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/context/global-sync/child-store.ts` around lines 133 - 164,
The createPersistedChildCache calls in ensureChild() (creating vcs, meta, icon)
can partially succeed and leave persisted listeners bound to input.owner; wrap
these three creates in a directory-scoped disposable root (e.g. create a
per-directory disposer or CompositeDisposable) so that if any
createPersistedChildCache (vcs, project, icon) throws you call that disposer to
tear down previously-created caches (unbind persistence for Persist.workspace
entries) before rethrowing; update ensureChild() to register the successful
directory-scoped disposer with the parent only after all three caches are
created, and reference the existing symbols createPersistedChildCache,
Persist.workspace, input.owner, and createStore to locate the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/app/src/context/global-sync/child-store.ts`:
- Around line 133-164: The createPersistedChildCache calls in ensureChild()
(creating vcs, meta, icon) can partially succeed and leave persisted listeners
bound to input.owner; wrap these three creates in a directory-scoped disposable
root (e.g. create a per-directory disposer or CompositeDisposable) so that if
any createPersistedChildCache (vcs, project, icon) throws you call that disposer
to tear down previously-created caches (unbind persistence for Persist.workspace
entries) before rethrowing; update ensureChild() to register the successful
directory-scoped disposer with the parent only after all three caches are
created, and reference the existing symbols createPersistedChildCache,
Persist.workspace, input.owner, and createStore to locate the changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5363dbe8-3a24-4dab-8bf2-9b1572c7d68b

📥 Commits

Reviewing files that changed from the base of the PR and between 969e304 and 8f4c148.

📒 Files selected for processing (4)
  • packages/app/src/context/global-sync/child-store-error.test.ts
  • packages/app/src/context/global-sync/child-store-error.ts
  • packages/app/src/context/global-sync/child-store.test.ts
  • packages/app/src/context/global-sync/child-store.ts

@Astro-Han Astro-Han merged commit 359de32 into dev Apr 22, 2026
25 checks passed
@Astro-Han Astro-Han deleted the codex/fix-i156-persisted-cache branch April 22, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows bug Something isn't working P1 High priority platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Packaged app can crash with masked persisted workspace cache error

1 participant