Skip to content

fix(fixtures): fail loud on non-ENOENT readdir errors in the conformance runner#80

Merged
SingleSourceStudios merged 1 commit into
mainfrom
fix/fixtures-runner-loud-failure
May 26, 2026
Merged

fix(fixtures): fail loud on non-ENOENT readdir errors in the conformance runner#80
SingleSourceStudios merged 1 commit into
mainfrom
fix/fixtures-runner-loud-failure

Conversation

@SingleSourceStudios
Copy link
Copy Markdown
Collaborator

@SingleSourceStudios SingleSourceStudios commented May 26, 2026

Summary

spec/fixtures/run-fixtures.mjs wrapped readdirSync in a bare catch {} that treated every error as "directory not found", silently skipped the whole category (valid/, invalid/, or edge-cases/), and still exited 0. A filesystem hiccup, permission glitch, or transient I/O error on any fixture directory would report partial success as full success.

Fix

Narrow the catch in runCategory:

  • err.code === "ENOENT": keep the quiet skip and return (a genuinely absent directory).
  • any other code (EACCES, ENOTDIR, EIO, EMFILE, ...): write ✗ Failed to read <category>/: <err.message> to stderr and process.exit(2).

Exit 2 is distinct from the existing exit 1 (test failures) and exit 0 (all pass), so CI can tell "the runner could not run" apart from "tests failed".

Verification

The non-ENOENT path was exercised against the real runner code by temporarily pointing a category at a file (a non-directory) inside spec/fixtures/:

✗ Failed to read run-fixtures.mjs/: ENOTDIR: not a directory, scandir '.../spec/fixtures/run-fixtures.mjs'
exit=2

It stopped before the results summary, as intended. The ENOENT path still skips quietly and continues. The temporary probe file was removed; only the one-file change is committed.

Why no committed exit-2 test

The runner is a self-executing script: it hardcodes runCategory("valid"|"invalid"|"edge-cases") and calls process.exit at the top level. Asserting an exit code in-process is not possible (the call exits the process), and a faithful automated test would require refactoring the runner into an importable module and adding a subprocess harness in a separate test file. That exceeds the single-file scope of this fix and the issue's intent, so the non-ENOENT path was verified manually instead (shown above).

Gates (all pass, node v22.22.2)

  • npm run build:core and full npm run build: success
  • npm test (root): 473 passed, 0 failed
  • npm run typecheck: clean
  • npm run lint: changed file clean (repo baseline of 5 errors / 22 warnings is in untouched files)
  • node spec/fixtures/run-fixtures.mjs: exit 0, all three categories reported (valid/, invalid/, edge-cases/), 29 passed / 0 failed

Closes #68


Summary by cubic

Stops the fixtures conformance runner from silently skipping categories on non-ENOENT errors. On read failures, it now prints a clear error and exits with code 2 so CI can distinguish runner errors from test failures.

  • Bug Fixes
    • ENOENT still skips the category with a warning.
    • Other errors (e.g., EACCES, ENOTDIR, EIO) print “Failed to read /: ” to stderr and exit 2.

Written for commit 8270b64. Summary will update on new commits. Review in cubic

…nce runner

The bare catch around readdirSync treated every error as "directory not
found", silently skipped the whole category, and continued to exit 0. A
filesystem hiccup, permission error, or transient I/O fault on valid/,
invalid/, or edge-cases/ would report partial success as full success.

Narrow the catch: on err.code === "ENOENT" keep the quiet skip and return; on
any other code (EACCES, ENOTDIR, EIO, EMFILE, ...) write a loud message to
stderr and process.exit(2). The exit code is distinct from the existing exit 1
for test failures and exit 0 for all-pass, so CI can tell "runner could not
run" apart from "tests failed".

No automated exit-2 test is committed: the runner is a self-executing script
with hardcoded categories that calls process.exit at the top level, so
asserting the exit code would require refactoring it into an importable module
plus a subprocess harness in a separate file, beyond this single-file fix. The
non-ENOENT path was verified manually against the real runner code (pointing a
category at a file yields "Failed to read .../: ENOTDIR ..." and exit 2), and
the normal run still exits 0 across all three categories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Warning

Review limit reached

@SingleSourceStudios, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 42 minutes and 13 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12795557-9517-45e4-8499-b4154e9fef77

📥 Commits

Reviewing files that changed from the base of the PR and between 42425fe and 8270b64.

📒 Files selected for processing (1)
  • spec/fixtures/run-fixtures.mjs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/fixtures-runner-loud-failure

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

Re-trigger cubic

@SingleSourceStudios SingleSourceStudios merged commit c995997 into main May 26, 2026
4 checks passed
@SingleSourceStudios SingleSourceStudios deleted the fix/fixtures-runner-loud-failure branch May 26, 2026 22:38
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.

bug(fixtures): run-fixtures.mjs bare catch swallows all readdirSync errors as 'directory not found'

1 participant