Repository navigation
fix(list): skip unresolvable entries when dating changes - #1866
Conversation
To sort changes by recency, list stats every file inside each change, and any entry it could not stat failed the whole command. A dangling symlink, such as the .#file lock Emacs keeps beside every file with unsaved edits, or a symlink loop made list exit 1 and list --json report no changes at all. Skip an entry that no longer resolves (ENOENT or ELOOP) when computing a change's last-modified time. Valid symlinks are dated as before, and any other error still fails the listing.
|
Warning Review limit reachedNext included review available in 53 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review. 📝 WalkthroughWalkthrough
ChangesList resilience
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix · Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to The listing resilience change is covered for dangling links, loops, valid symlinks, nested entries, and CLI JSON output. No merge-blocking risk was identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Hardening pushed for merge:
Verified: reproduced |
alfred-openspec
left a comment
There was a problem hiding this comment.
The recency walk now skips only entries that disappeared or cannot resolve, while retaining valid symlink dating and surfacing other filesystem errors. Focused list and CLI tests pass.
Closes #1865.
Why
openspec listsorts changes by recency. To do that,getLastModified(
src/core/list.ts:44-71) walks every entry of each change, dotfiles included,and calls
fs.staton each non-directory (:54) with no error handling.fs.statfollows symlinks, so any entry that no longer resolves throws, and thewhole command fails. Such entries include:
unsaved changes:
.#tasks.md, pointing atuser@host.PID:TIMESTAMP.ELOOP)readdirandstat, such as an editor's temp fileWith
openspec/changes/add-thing/.#tasks.mddangling:list --jsonis how agents discover changes, and it reports none at all whilethe file is open with unsaved edits.
view,statusandvalidatewalk thesame tree without failing; only
listbroke.Verified on a build of
main@9d4e597and on the published@fission-ai/openspec@1.13.0.What Changes
ENOENTorELOOP,that one entry is skipped when computing the change's last-modified time. A
new
isUnresolvableEntryErrorhelper sits next to the existingisMissingPathError.Unchanged:
Direntreports them assymlinks, not directories.
EACCES, still fails the listing, as before.Testing
test/core/list.test.tsgains 5 tests under "entries that cannot be stat-ed". Iwrote them first. On
main, 4 failed:ENOENTtwice,ELOOPonce, and CLI exitalongside it and its task counts intact
newest file
openspec list --jsonthrough the built CLI exits 0 and liststhe change
The symlink tests use
it.skipIf(process.platform === 'win32'), the repo'sexisting convention, because creating symlinks on Windows needs elevated
rights. The fix itself is platform-independent. The existing
ListCommandtests pass unchanged.
CI parity: I ran the CI steps in a clean Linux container under Node 20.19.0 (the
CI version), after
pnpm install --frozen-lockfile.pnpm run build,pnpm exec tsc --noEmitandpnpm lintpass. The container was shared withother test runs (load average 12–18 on 6 CPUs). That load made the repo's
CLI-spawning tests time out under the default 10-second
testTimeout, so I ranthe full suite with
--testTimeout=120000 --hookTimeout=120000. It ran 4568tests: 4567 passed and 1 failed.
The one failure was environmental: an
npm source installationtest whosenpmsubprocess hit its 30-secondspawnSynctimeout (ETIMEDOUT). I reranthat file on its own, under the suite lock with
--maxWorkers=2. It passes onthis branch, and it passes the same way on a pristine
main@9d4e597.CI's
validate-changesetsjob runs on Node 24, and@changesets/cli3 needs Node 22 or newer because it callsmodule.enableCompileCache. So I ranpnpm exec changeset statusunderNode 22; it lists the patch bump for
@fission-ai/openspec.Changeset
.changeset/list-skips-unresolvable-entries.md(patch).Summary by CodeRabbit
openspec listfailing when a change contains dangling or looping symlinks, or files removed during scanning.