Skip to content

fix(sandbox): make publish()'s untracked-dir expansion async - #5506

Open
pedrofrxncx wants to merge 1 commit into
mainfrom
fix/git-publish-expand-untracked-dirs-sync-stat-w1
Open

fix(sandbox): make publish()'s untracked-dir expansion async#5506
pedrofrxncx wants to merge 1 commit into
mainfrom
fix/git-publish-expand-untracked-dirs-sync-stat-w1

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Continues the daemon's sync-fs → async-fs hardening pass (#5471 discard, #5481 decofile-block validation, #5497 hooks-dir mkdtemp) for the same reason: any blocking *Sync fs call on the daemon's single-threaded Bun event loop stalls the /health probe Studio polls, which can get a live sandbox marked dead.

Bug: publish()'s expandUntrackedDirs() helper called fs.statSync from inside the already-async publish() handler. git status --porcelain collapses an untracked directory into one ?? dir/ entry, so this runs on every publish that touches a fresh untracked directory — e.g. the very common case of a brand-new .deco/blocks/ dir before its first commit — blocking the event loop for the syscall's duration.

Fix: swap fs.statSync (node:fs) for fs.promises.stat, awaited at the one call site inside publish(). Behavior-preserving: same directory-vs-file detection, same fallback to false on a stat error (e.g. a raced deletion), same single call site. Net diff: +9/-3.

Verify: cd packages/sandbox && bunx tsc --noEmit (clean) and bun test packages/sandbox/daemon/routes/git.test.ts (51 pass) — several existing publish() tests (e.g. "publish() commits a valid decofile block") write directly into a fresh untracked .deco/blocks/ dir, exercising this exact code path.

Locally ran: bun run fmt, targeted tsc --noEmit in packages/sandbox, the single test file above, and bunx oxlint packages/sandbox/daemon/routes/git.ts (0 warnings/errors). Full CI validates the rest.


Summary by cubic

Make publish()’s untracked-dir expansion async to avoid blocking the daemon’s event loop and stalling the /health probe. Replaces fs.statSync with fs.promises.stat to prevent stalls when publishing into fresh untracked dirs (e.g. .deco/blocks/).

  • Bug Fixes
    • Converted expandUntrackedDirs to async and awaited it in publish().
    • Preserved behavior (dir vs file check, fallback on stat errors).
    • Removes event-loop stalls on publishes touching untracked directories.

Written for commit db9ca1d. Summary will update on new commits.

Review in cubic

expandUntrackedDirs() called fs.statSync from inside the already-async
publish() handler, blocking the daemon's single-threaded event loop for
the syscall's duration on every publish that touches an untracked
directory (e.g. a fresh .deco/blocks/ dir before its first commit) —
stalling the /health probe Studio polls to detect a live sandbox.

Swap fs.statSync for fs.promises.stat, awaited at the one call site.
Behavior-preserving: same directory-vs-file detection, same fallback to
false on a stat error.
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