GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Fix manifest read errors treated as absent (#998, #1063, #1123) by mikolalysenko · Pull Request #1776 · SocketDev/socket-patch

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 28, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #998
Fixes #1063
Fixes #1123

Summary

A manifest that exists but can't be read is now refused as manifest_unreadable (exit 1, with the --json envelope) on every command and under every spelling of its path. Before, several commands decided "no manifest" with their own looser probes:

  • apply, apply --check and vendor report noManifest (exit 0) when .socket/manifest.json exists but can't be stat'd #998 (fail-open): apply, apply --check and vendor reported noManifest and exited 0 when stating .socket/manifest.json failed for any reason (.socket checked in as a file, a symlink loop, an unsearchable .socket/), so install hooks and CI read "every patch skipped" as success. repair, remove and rollback said manifest_not_found.
  • scan reads a corrupt manifest as empty, so --prune skips GC and reports success #1063: scan's GC passes (wet and --dry-run preview) read an unloadable manifest as missing and returned a clean summary.
  • A directory at .socket/manifest.json exits 2 with no --json output when --manifest-path spells the path, but exits 1 with manifest_unreadable under the default path #1123: a --manifest-path naming a directory exited 2 with no --json document when the path was spelled out (./.socket/manifest.json, an absolute path, SOCKET_MANIFEST_PATH), but 1 with manifest_unreadable under the default spelling.

Root cause (shared)

Core's read_manifest has one rule: only NotFound means absent. The callers above each decided presence another way: metadata().is_err() (#998), _ => no manifest after read_manifest (#1063), and a directory check keyed on the flag's text (#1123).

Fix

  • socket_patch_core::manifest::operations::manifest_exists keeps read_manifest's rule (a thin wrapper over tokio::fs::try_exists).
  • apply (incl. --check), vendor, repair, remove and rollback use it and refuse a stat error with manifest_unreadable before building a client or taking a lock. A real NotFound keeps every existing no-manifest path (noManifest, hosted/vendored fallbacks).
  • scan GC: an unloadable manifest under the lock now yields a manifest_invalid/manifest_unreadable warning next to the vendored half, and the pre-lock gate no longer treats an unstatable manifest as absent. (Agent-mode scan already failed closed at its top-level load since An unparseable .socket/manifest.json is reported under five different --json error codes depending on the command #931; this closes the GC passes themselves.)
  • GlobalArgs::validate_paths no longer refuses a directory manifest (the issue's option A). read_manifest refuses it the same way for every spelling. The remaining "project directory does not exist" message prints a .-free path (no more ././.socket/…).
  • CLI_CONTRACT.md: the manifest_unreadable row and the exit-2 row describe the new rule.
  • On Windows a path under a plain file reports as not found, so there .socket as a file still reads as "no manifest" for both read_manifest and manifest_exists (consistent). Those test cases are #[cfg(unix)].

Per-issue tests (red on main → green here)

Issue Test On main
#998 manifest_load_error_matrix::socket_dir_as_file_is_manifest_unreadable_on_every_command (ENOTDIR, runs as root) FAILED (apply: noManifest, exit 0)
#998 manifest_load_error_matrix::manifest_symlink_loop_is_manifest_unreadable_on_every_command (ELOOP) FAILED
#998 apply_invariants::apply_with_unreadable_socket_dir_fails_closed un-ignored (chmod 000; self-skips as root) was #[ignore = "RED: …"]
#998 core test_manifest_exists_* new API
#1063 scan::gc::tests::apply_gc_reports_an_unloadable_manifest (invalid JSON + directory, wet + preview) FAILED (warnings: []), verified by reverting only the GC arms
#1123 manifest_load_error_matrix::directory_manifest_verdict_does_not_depend_on_spelling (flag relative, flag absolute, env) FAILED (exit 2, no JSON)

The matrix now covers rollback too. cli_parse_list and cli_path_flags_validated pinned the old exit-2 directory verdict and are updated to the new one.

Local verification

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test --workspace --all-features --no-fail-fast: everything this PR touches passes (core lib, CLI lib 936, apply, repair, rollback, remove, matrix, cli_parse_list, cli_path_flags_validated). Remaining local failures are environmental and also fail on unmodified main in this container: chmod-based write/delete-failure tests that can't fail as root (repair_cleanup_failure_*, repair_*_lock_file_unremovable, three in_process_redirect write-failure tests, four core lib permission tests) and e2e_bun_lockb (Nightly e2e_bun_lockb red: offline takeover test predates #1648 #1770, fix in CI: update bun.lockb offline takeover test (#1770) #1771).
  • No wrapper changes needed: npm/, pypi/, gem/ only dispatch the binary.

/code-review high

Fixed: Windows ENOTDIR→NotFound (tests now Unix-only), stale exit-2 contract row, GC comment accuracy, try_exists reuse, apply --check message parity, repair telemetry, GC message cleanup.
Not fixed, by choice:

  • Share one "probe and emit" helper across the five commands. Each command already has its own error emitter (emit_error_envelope, emit_rollback_error, emit_eject_refusal, error_envelope, apply's refusal), and each call is the existing load-failure mapping, manifest_load_error, plus that emitter. A helper would save a line per site.
  • scan GC's has_ledger probes --cwd instead of the manifest's project, and vendor-ledger presence probes use the same metadata().is_ok() pattern. Both predate this change and are about the vendor ledger, not the manifest. Left as follow-ups so this PR stays one root cause.

https://claude.ai/code/session_011f9aeR3v4Q36DgE4agLMEK


Generated by Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@claude
Start fix for #998, #1063, #1123
c713749
Assisted-by: Claude Code:claude-opus-5-5
This was referenced Oct 28, 2026
apply, apply --check and vendor report noManifest (exit 0) when .socket/manifest.json exists but can't be stat'd #998
Closed
scan reads a corrupt manifest as empty, so --prune skips GC and reports success #1063
Closed
A directory at .socket/manifest.json exits 2 with no --json output when --manifest-path spells the path, but exits 1 with manifest_unreadable under the default path #1123
Closed
Claude (claude) added 2 commits October 28, 2026 08:47
@claude
Test manifest stat errors and path spellings
2123045
Adds regression tests: .socket as a plain file and a self-referencing
manifest symlink must fail every command with manifest_unreadable
(#998), and a directory at the manifest path must get the same verdict
whether the path is the default, spelled with --manifest-path (relative
or absolute) or set through SOCKET_MANIFEST_PATH (#1123). Adds rollback
to the manifest load error matrix and a core manifest_exists probe that
treats only NotFound as absence.

Assisted-by: Claude Code:claude-opus-5-5
@claude
Fail closed when the manifest can't be read
a4395ce
apply, apply --check and vendor treated any error stating
.socket/manifest.json as "no manifest" and exited 0 with noManifest,
so an unsearchable .socket/, .socket checked in as a file or a symlink
loop silently skipped every patch. repair, remove and rollback said
manifest_not_found. All six now ask core's manifest_exists, which
keeps read_manifest's rule (only NotFound is absence), and refuse with
manifest_unreadable before taking a lock (#998).

scan's GC passes read an unloadable manifest as missing too. They now
report the manifest_invalid / manifest_unreadable warning instead of a
clean summary (#1063).

A --manifest-path naming a directory exited 2 with no --json output
when the path was spelled out, but 1 with manifest_unreadable under the
default spelling. Argument validation no longer judges it, so every
spelling gets manifest_unreadable (#1123).

Un-ignores apply_with_unreadable_socket_dir_fails_closed.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 28, 2026
Swarm health manager log #1382
Open
Claude (claude) added 2 commits October 28, 2026 09:18
@claude
Document manifest_unreadable for stat errors
91d884a
The contract's manifest_unreadable row now says a path that cannot be
stated is unreadable, never noManifest or manifest_not_found, and that
the verdict does not depend on how the path is spelled. The ENOTDIR
matrix case accepts vendor --check refusing the vendor ledger under the
same unreadable .socket, which it reads first.

Assisted-by: Claude Code:claude-opus-5-5
@claude
Address review: Windows, contract, check message
1f3e0ba
On Windows a path under a plain file reports as not found, so the
.socket-as-a-file cases are Unix-only tests (read_manifest and
manifest_exists agree there either way). manifest_exists now wraps
tokio::fs::try_exists. The exit-2 contract row no longer lists a
--manifest-path that names a directory. apply --check keeps its
"treating it as drift" message whether the manifest fails to stat or
to load, repair records failure telemetry for the early refusal like
its load failure, and the GC warning skips a throwaway envelope.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 28, 2026 09:36
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

cursor[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Oct 28, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1f3e0ba. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 28, 2026
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Ready for review at 1f3e0ba (burn-down agent).

  • CI: 82/82 check runs on this head green or skipped (32 success, 50 skipped); mergeable into main.
  • Bugbot: reviewed 1f3e0ba, no findings. No open review threads.
  • CHANGELOG.md untouched.
  • Reviewer focus: the directory-manifest verdict moved from GlobalArgs::validate_paths (exit 2) to read_manifest (manifest_unreadable, exit 1), and cli_parse_list / cli_path_flags_validated were updated to match. On Windows, .socket as a plain file still reads as "no manifest".

Generated by Claude Code

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) enabled auto-merge October 28, 2026 10:56
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does. Several commands decided "no manifest" with their own loose probe (metadata().is_err(), _ => after read_manifest, or a directory check on the flag's text), so a manifest that exists but can't be stated or loaded was treated as absent: apply/apply --check/vendor exited 0 with noManifest (#998), scan's GC returned a clean summary (#1063), and a directory --manifest-path exited 2 with no JSON only when spelled out (#1123). A new core manifest_exists (only NotFound is absence) is used everywhere, and stat/load errors now surface as manifest_unreadable/manifest_invalid.

Risk: low. Every change moves a fail-open path to fail-closed; a genuine NotFound keeps all existing no-manifest behavior (hosted/vendored fallbacks, noManifest). The one visible contract change is #1123: a directory --manifest-path now exits 1 with manifest_unreadable (and a JSON envelope) instead of exit 2, documented in CLI_CONTRACT.md.

Look here

  • operations.rs:80: manifest_exists, a wrapper over tokio::fs::try_exists with read_manifest's rule
  • apply.rs:858 and apply.rs:935: the shared refusal, now hit before the API client, lock or telemetry
  • gc.rs:252 and gc.rs:83: GC gate (unwrap_or(true)) and the new load-error warning; nothing is pruned or swept without a readable manifest
  • args.rs:402: the dropped flag-text directory check (A directory at .socket/manifest.json exits 2 with no --json output when --manifest-path spells the path, but exits 1 with manifest_unreadable under the default path #1123)
  • vendor.rs:960: one up-front probe replaces two; --revert still never asks

Verified

  • Read the full diff (13 files, +396/−85). Traced remove, repair, rollback and vendor (incl. the contested-hosted-wiring arm, which only runs without --revert, so the hoisted probe keeps its old meaning). Dangling symlink still reads as absent for both manifest_exists and read_manifest, so they agree. CHANGELOG.md untouched; no debug leftovers.
  • Tests exercise each issue and were red on main per the description (ENOTDIR, ELOOP, chmod-000 un-ignored, GC wet+preview, three path spellings). Windows: .socket-as-file cases are #[cfg(unix)], documented as reading as absent there for both functions.
  • CI on 1f3e0ba: 32 success, 50 path-skipped, 0 failed. Bugbot: no issues. No unresolved threads.

Changes I made: none.

Open questions: none that block merging.

Auto-merge is armed, so approving sends it straight to the merge queue.


Generated by Claude Code

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Wenxin-Jiang
Wenxin Jiang (Wenxin-Jiang) approved these changes Oct 28, 2026
View reviewed changes
@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 28, 2026
Tanmay182003
Tanmay Singla (Tanmay182003) approved these changes Oct 28, 2026
View reviewed changes
Merged via the queue into main with commit 079ba6a Oct 28, 2026
82 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-manifest-presence-probe branch October 28, 2026 14:08
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 28, 2026
CI perf (settings): merge queue builds 5 entries at a time — a 13-PR burst took 100 min to drain on a 21-min CI run (~21 min per PR past the 5th) #1248
Open
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Nov 10, 2026
chore(release): complete 5.1.0 notes for every PR since v5.0.1 #2047
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@cursor cursor[bot] cursor[bot] left review comments
@Wenxin-Jiang Wenxin Jiang (Wenxin-Jiang) Wenxin-Jiang approved these changes
@Tanmay182003 Tanmay Singla (Tanmay182003) Tanmay182003 approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

A directory at .socket/manifest.json exits 2 with no --json output when --manifest-path spells the path, but exits 1 with manifest_unreadable under the default path scan reads a corrupt manifest as empty, so --prune skips GC and reports success apply, apply --check and vendor report noManifest (exit 0) when .socket/manifest.json exists but can't be stat'd

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@mikolalysenko @Wenxin-Jiang @Tanmay182003 @claude
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.