ReviewOS

home-lang/home

Filesystem parity: preserve recursive mkdir callback results

#893
Closed chris opened this 8 days ago ·
8 days ago

Tracked from #66 and #878.

The unchanged fs-mkdir.test.ts fails two recursive callback cases: the native operation returns the first-created directory, but the public node:fs wrapper forwards only the error and discards that result. Promise mkdir already preserves the native result.

The corrected wrapper passes (null, firstPathCreated) when a directory was created and one error argument otherwise, preserving the undefined callback receiver and the actual native FSREQCALLBACK execution scope.

Acceptance: recursive all-new/partly-existing paths, existing recursive paths, nonrecursive success/errors, callback argument counts/receiver/async resource, promise results, callback exception delivery and unchanged original mkdir/directory tests. Published ordinary-result fix in ef0bec731, with 265 verified evidence artifacts through e9f65141f. Build 56/56, three focused commands, and all five ordinary Node/Home result rows pass. The unchanged 26-file selection has 47 passing registered cases and 19 passing process checks, zero failures, zero TODOs/filtering/retries, and two platform-skipped files (Windows pipes and Linux UCS2) receiving no completion credit. The two original recursive mkdir failures are fixed. Native directory lifetime and async-storage/request-scope controls, Pickier and whitespace checks pass.

Directory callback throw/queue probes also produced different complete traces: Node does not deliver the same repeated-throw/queued-closed-read errors as Home. These unresolved results remain #878 evidence and must not be normalized into pass credit.

Remaining: the mkdir exception diagnostic initially exited without Node output; with a keep-alive timer both runtimes call the callback once with matching arguments/receiver/result, but only Home reports the thrown marker through uncaughtException. The initial full-match assertion failure and complete nonmatching traces are retained in the evidence. This issue remains open; no exception suppression or expectation weakening was used.

8 days ago

Verified mkdir callback checkpoint (2026-10-14): #893 preserves the native first-created path and result-dependent callback arity while retaining the undefined receiver/native request scope. Source ef0bec731, 265 verified evidence artifacts published through e9f65141f. Build 56/56, three focused commands and five exact ordinary Node/Home result rows passed. The 26-file unchanged selection has 47 passing cases and 19 passing process checks, no failures/filtering/retries/TODOs, with two complete-file platform skips (Windows pipes, Linux UCS2) receiving no pass credit. Thrown mkdir callback and directory throw/queued-close traces still differ; #893/#878 remain open. Full suite/platform acceptance and independent builds remain outstanding. Prior VM discovery retains 66 TODOs/two skips and #891 integration remains open.

8 days ago

The remaining exception-delivery mismatch is now classified and should not be ported.

The ordinary recursive mkdir callback-result defect described by this issue was fixed in ef0bec731: Home passes the first created path as the callback's second argument and preserves the expected one-argument form when no path was created.

The last mismatch is a narrow Node implementation bug, not missing Home/Bun behavior. In Node v24.4.1, src/node_file.cc's AfterMkdirp creates a V8 TryCatch while encoding the first-created path and leaves that TryCatch alive across req_wrap->Resolve(path). A user exception from the callback is therefore accidentally caught and discarded only when recursive mkdir returns a created path. When the recursive target already exists, or for nonrecursive mkdir, the callback is resolved before that TryCatch and the same thrown marker reaches uncaughtException normally.

Differential probes confirm:

  • Node v24.4.1, recursive new path: callback called with two arguments; thrown marker swallowed
  • Node v24.4.1, recursive existing path: callback called with one argument; marker reaches uncaughtException
  • Node v24.4.1, nonrecursive path: callback called with one argument; marker reaches uncaughtException
  • Bun 1.4.3: marker reaches uncaughtException for all three paths
  • Home: marker reaches uncaughtException, matching Bun rather than Node's accidental scoped suppression

Adding exception suppression to Home would be a workaround, would copy an upstream lifetime accident, and would regress Bun parity. No expectations were weakened and no suppression was added. The titled callback-result bug is complete, so this issue can close; broader directory callback trace work remains tracked by #878.

Sign in to comment on this issue.