Skip to content

feat(personalities): real NTSTATUS/LastError + Darwin errno maps - #90

Merged
undivisible merged 1 commit into
mainfrom
burn-claude-space-errno-maps
Aug 20, 2026
Merged

feat(personalities): real NTSTATUS/LastError + Darwin errno maps#90
undivisible merged 1 commit into
mainfrom
burn-claude-space-errno-maps

Conversation

@undivisible

@undivisible undivisible commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Closes the M4 gap-matrix row "NTSTATUS / errno maps" and the M4 checkbox "LastError / errno consistency end-to-end" in docs/personalities-roadmap.md.

Problem

  • Windows: every failure exit flattened the real VFS return code to ERROR_FILE_NOT_FOUND or ERROR_INVALID_HANDLE. win-ntstatus existed but was never called on a real code — only fed the literal -2 in the demo. So a disk-full or too-many-handles failure was indistinguishable from a missing file.
  • Darwin: darwin-errno had a table and zero callers, and there was no errno slot at all, so a failing call left nothing behind to inspect.

Windows (components/windows.in)

  • Paired win-last-error / win-last-status slots with a single writer (win-set-error, win-set-status, win-set-error-rc), so the two can never disagree.
  • winerror.h + NTSTATUS constant tables; win-ntstatus(rc) maps the VFS/errno-shaped codes the tree actually returns (-2 -5 -6 -9 -12 -13 -16 -17 -21 -22 -28 -38 -39); win-dos-error is an RtlNtStatusToDosError subset and win-status-from-error its inverse for the SetLastError path.
  • Filesystem calls that can only return 0/-1 are refined with an existence probe: mkdir → ERROR_ALREADY_EXISTS vs ERROR_PATH_NOT_FOUND; unlink/rmdir → ERROR_FILE_NOT_FOUND vs ERROR_DIR_NOT_EMPTY; rename → missing source vs occupied destination.
  • New calls 34 RtlGetLastNtStatus, 35 RtlNtStatusToDosError, 36 RtlGetLastWin32Error.

Darwin (components/darwin.in)

  • darwin-dispatch wraps the old body (darwin-dispatch-call) and records every negative result in darwin-errno-last. Successful calls leave errno untouched, per BSD.
  • Space-local __error() shims: 0x2000 get, 0x2001 set. darwin-errno-name renders the number in serial logs.
  • darwin-errno now covers every DARWIN-E* the surface returns (ESRCH, ENOMEM, ENOSYS); unknown codes fall back to EINVAL.

Verification

Both check scripts now grep the exact codes and fail on an explicit FAILED marker, so this is a golden-log gate rather than eyeballing:

  • windows: LastError/NTSTATUS consistency OK — 5/5 scenarios plus 10/10 rc pairs satisfying GetLastError() == RtlNtStatusToDosError(RtlGetLastNtStatus()).
  • darwin: errno consistency OK — 6/6 scenarios.

Ran locally (macOS host, QEMU, INAUGURATION_DIR=../inauguration):

  • scripts/check-personalities.sh → SCI contract + both QEMU demos PASS
  • scripts/check-qemu-boot.sh → PASS

Scope is deliberately tables + wiring only: no PE loader, no event/sync objects, no Mach IPC.

🤖 Generated with Claude Code


Note

Cursor Bugbot is generating a summary for commit 3e6a0be. Configure here.

Windows failures previously flattened every VFS return code to
ERROR_FILE_NOT_FOUND or ERROR_INVALID_HANDLE, and NTSTATUS existed only as an
unused helper. Darwin had an errno table with no caller and no errno slot.

- windows.in: paired win-last-error/win-last-status slots, winerror.h + NTSTATUS
  tables, RtlNtStatusToDosError subset and its inverse, single-writer setters
  used by every failure exit, existence probe to refine 0/-1 fs failures into
  ALREADY_EXISTS / DIR_NOT_EMPTY / PATH_NOT_FOUND, and calls 34-36
  (RtlGetLastNtStatus, RtlNtStatusToDosError, RtlGetLastWin32Error).
- darwin.in: darwin-dispatch wraps darwin-dispatch-call and records negative
  results in darwin-errno-last (success leaves it alone, per BSD); __error()
  shims 0x2000/0x2001; darwin-errno covers ESRCH/ENOMEM/ENOSYS.
- Both demos assert the mapping; check scripts grep the exact codes and fail on
  the FAILED marker.

Verified: check-personalities.sh green (SCI contract + both QEMU demos).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 20, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_45913720-e1dd-452e-a130-8e85309f3a99)

@mergify

mergify Bot commented Aug 20, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e6a0bef15

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread components/windows.in
Comment on lines +302 to +303
if err == WIN-ERROR-FILE-EXISTS {
return WIN-STATUS-OBJECT-NAME-COLLISION

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve ERROR_FILE_EXISTS through the paired mapping

When a caller invokes SetLastError(ERROR_FILE_EXISTS), this branch stores ERROR_FILE_EXISTS (80) but pairs it with STATUS_OBJECT_NAME_COLLISION; RtlNtStatusToDosError maps that status to ERROR_ALREADY_EXISTS (183). The advertised invariant therefore fails for a supported constant, even though the golden test covers only ERROR_DISK_FULL; either the mapping must round-trip 80 or SetLastError must not synthesize a supposedly equivalent NTSTATUS.

Useful? React with 👍 / 👎.

Comment thread components/windows.in
Comment on lines +649 to 650
win-clear-error()
return vfs-lseek(vfd, offset, whence)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record lseek failures before returning

With a valid file handle but an invalid whence or negative resulting offset, vfs-lseek returns -22; this path clears both error slots before returning that failure, so GetLastError() and RtlGetLastNtStatus() incorrectly report success. Capture the result first and route negative values through win-set-error-rc.

Useful? React with 👍 / 👎.

Comment thread components/darwin.in
Comment on lines +175 to +178
if vfs-rc == -38 {
return DARWIN-ENOSYS
}
return DARWIN-EINVAL

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Convert VFS errors to Darwin errno numbers

The new errno slot still exposes Linux/VFS-shaped numbers rather than Darwin values: an unknown syscall maps -38 to errno 38 even though Darwin's ENOSYS is 78, while exhausting the VFS descriptor table makes vfs-open return -16, which falls through here to EINVAL (22) instead of Darwin EMFILE (24). Darwin callers inspecting the newly added errno slot therefore receive incorrect compatibility results for these failures.

Useful? React with 👍 / 👎.

Comment thread components/windows.in
return 0
}
if n == 0 && len > 0 {
win-set-status(WIN-STATUS-END-OF-FILE)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the real STATUS_END_OF_FILE value

When a read reaches EOF, this new path records WIN-STATUS-END-OF-FILE, but that constant is -1073741805 (0xC0000013), which is STATUS_NO_MEDIA_IN_DEVICE; the standard STATUS_END_OF_FILE value is 0xC0000011 (-1073741807). Consequently RtlGetLastNtStatus() returns the wrong standard status after EOF, and RtlNtStatusToDosError also treats the no-media value as ERROR_HANDLE_EOF.

Useful? React with 👍 / 👎.

Comment thread components/windows.in
serial-nl(port)

// Every VFS/errno-shaped code must round-trip status → dos error.
let rcs = alloc(8 * 10)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include every advertised return code in the golden check

The mapping table handles 13 documented VFS codes, but this supposedly exhaustive golden check allocates and tests only ten entries, omitting -6, -21, and -38. The script can therefore print errno/NTSTATUS pairs consistent 10/10 and mark the feature complete even if the no-media, directory, or not-implemented mappings are broken; build the array from all 13 advertised cases and assert the corresponding total.

Useful? React with 👍 / 👎.

Comment thread components/darwin.in
Comment on lines +795 to +798
let rc = darwin-dispatch-call(port, num, a0, a1, a2, a3)
if rc < 0 {
darwin-errno-last = 0 - darwin-errno(rc)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record zero-valued getcwd failures in errno

When getcwd receives a buffer too small for the current path, posix-sys-getcwd returns 0, but this wrapper updates errno only for negative results. The call therefore fails while leaving darwin-errno-last stale instead of reporting ERANGE, so the new errno contract is not end-to-end for this existing Darwin syscall; the dispatch layer needs either syscall-specific failure detection or normalized negative error returns.

Useful? React with 👍 / 👎.

@undivisible
undivisible merged commit 3092855 into main Aug 20, 2026
4 checks passed
@undivisible
undivisible deleted the burn-claude-space-errno-maps branch August 20, 2026 11:31
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