Skip to content

Fix vendor --check artifact failure message (#1467) - #1468

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-vendor-check-artifact-reason
Oct 13, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-vendor-check-artifact-reason

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

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

Fixes #1467

Summary

When a committed vendored artifact is missing or changed, vendor --check
now says what is wrong, names the file, and gives the step that fixes it.
Before, it printed the Rust Debug form of an internal state, with no path
and no remedy:

pkg:npm/minimist@1.2.2: artifact verification failed: Corrupt { reason: "vendor_workspace_artifact_missing" }

Now (Bun bun.lockb workspace, member copy deleted):

pkg:npm/minimist@1.2.2: Bun workspace copy packages/a/.socket/vendor/npm/<uuid>/minimist-1.2.2.tgz is missing (vendor_workspace_artifact_missing); the committed artifact .socket/vendor/npm/<uuid>/minimist-1.2.2.tgz it mirrors is intact; run `socket-patch repair` to restore it, then commit it

The same text goes into the --json event's reason. The stable tag
stays in parentheses so logs remain searchable.

Root cause

run_check in crates/socket-patch-cli/src/commands/vendor.rs turned every
non-healthy ArtifactHealth into format!("artifact verification failed: {health:?}").
That string is shared by every vendored ecosystem, so the root-artifact
rows in the issue (Missing, Corrupt { reason: "vendor_sha256_mismatch" })
were affected as well as the Bun member-copy rows.

Fix

  • New vendor::describe_artifact_failure in core. It turns each health
    state into a cause, the committed path, and the remedy that matches what
    repair does for that state:
    • missing or corrupt: socket-patch repair, then commit. When repair
      would refuse because the ledger has no archive SHA-256 (file artifact)
      or no file inventory (directory artifact), the message gives repair's
      own refusal and remedy instead (shared redownload::ledger_blocks_restore).
      For a JVM entry, "missing" also covers a missing tree marker.
    • Bun member copy: names the member path (bun_workspace::failing_mirror).
      It calls the root artifact intact only when the ledger records its
      sha256.
    • pending re-vendor (vendor_uuid_mismatch): socket-patch vendor.
    • unverifiable: says repair won't rebuild it. When the Bun workspace
      copies can't be listed, the message carries the real cause; other cases
      point at the ledger, the manifest, or a re-vendor.
    • unknown npm flavor: upgrade socket-patch.
  • ArtifactHealth::is_workspace_copy_issue() replaces repair's private
    copy of the same check, so vendor --check and repair agree on what
    counts as a member-copy failure.
  • No wrapper changes are needed: npm/, pypi/, and gem/ only
    dispatch to the binary and never parse this text.

Tests (red → green)

Issue row Test
#1467 member mirror deleted / changed (Bun bun.lockb workspace) vendor::verify::tests::binary_workspace_health_attests_every_installable_tarball (asserts the exact text, including the member path)
#1467 root artifact deleted / changed (Missing / vendor_sha256_mismatch) CLI in_process_vendor::vendor_check_names_damaged_artifact_and_repair_remedy
every other health state, plus the no-sha256 fallback vendor::verify::tests::describe_artifact_failure_names_path_and_remedy

Without the fix (the CLI change reverted), the CLI test fails:

left: String("artifact verification failed: Corrupt { reason: \"vendor_sha256_mismatch\" }")
right: "committed artifact .socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz does not match the sha256 in the vendor ledger (vendor_sha256_mismatch); run `socket-patch repair` to restore it, then commit it"

With the fix, it passes. Commands run locally:

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test -p socket-patch-core --all-features --lib -- vendor::: everything passes except two chmod-based write-failure tests (pypi_poetry::wire_write_failure_*, pypi_requirements::wire_failure_rolls_back_*). Those tests can't make a write fail when run as root, which is how this sandbox runs. They are unrelated to this change, and CI runs as a non-root user.
  • cargo test --workspace --all-features: this sandbox's disk allowance cannot hold every test binary (it fails with ENOSPC while linking), so I ran the suites this change touches instead. in_process_vendor: 133/133 pass. repair: 126 pass; the 2 failures are chmod-based tests (*_unremovable, repair_cleanup_failure_*). covgap_commands_vendor: 54 pass; the 3 failures are chmod-based *_state_write_failure_* tests. A root user ignores those permissions, which is why they fail here. CI runs the full workspace.

Bugbot

Two findings on c8c77bf. Both were real, both are fixed in c8cec59, and
both threads are answered and resolved: repair advice where repair would
refuse, and the wrong cause given for vendor_workspace_artifact_invalid.

Code review (/code-review high)

Fixed: the "intact" claim without a recorded sha256, the one-size remedy
for unverifiable entries, the StaleUuid wording, the JVM marker case, the
duplicated workspace-copy check, and the test doc.

Not fixed:

  • failing_mirror re-reads the mirrors to find the path, which costs I/O
    and allows a re-check race. It runs only after a check has already
    failed, and vendor --check is a read-only audit. Carrying the path in
    ArtifactHealth::Corrupt would change a public enum that about ten
    match sites use.
  • repair keeps its own StaleUuid and UnknownFlavor wording. Changing repair's
    output is out of scope here.

Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
When a committed vendored artifact was missing or changed, vendor
--check printed the Rust Debug form of an internal state, such as
`Corrupt { reason: "vendor_workspace_artifact_missing" }`, with no
path and no next step. CI logs gave users nothing to act on.

The reason now says what is wrong, names the committed file (for a
Bun bun.lockb workspace, the member copy that is off, and that the
root artifact is intact), and gives the fix that matches what repair
does: `socket-patch repair` then commit, `socket-patch vendor` for a
pending re-vendor, fix state.json for an entry that can't be
verified, or upgrade for an unknown npm flavor. The stable tag stays
in parentheses so logs remain searchable.

Fixes #1467

Assisted-by: Claude Code:claude-opus-5-5
Follow-up from review of the new vendor --check wording:

- Only call the root artifact intact for a Bun member-copy failure
  when the ledger records its sha256; without one it was never
  checked.
- An entry that can't be verified no longer always blames state.json:
  an unreadable bun.lockb says so, and other cases point at the
  ledger, the manifest or a re-vendor, and say repair won't rebuild.
- A pending re-vendor says the ledger and manifest disagree.
- A JVM entry also counts as missing when only its tree marker is
  gone, so the message names both.
- vendor --check and repair now share one check for a Bun member
  copy failure.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread crates/socket-patch-core/src/vendor/verify.rs Outdated
Comment thread crates/socket-patch-core/src/vendor/verify.rs
vendor --check told users to run `socket-patch repair` for any
missing or damaged artifact. When the ledger records no archive
SHA-256 (file artifacts) or no file inventory (directory artifacts),
repair has nothing to verify a download against and refuses, so that
advice left the check red. The message now gives repair's own
refusal and its remedy instead.

When a Bun workspace's copies can't be listed, the message used to
guess at an unreadable bun.lockb. It now carries the real cause
(unreadable lock, unsafe path, symlinked member copy, ...).

restore() and vendor --check share one check for when repair
refuses.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor 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.

✅ 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 c8cec59. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review by the burn-down agent.

  • Head: c8cec59e (mergeable against main, no conflicts; CHANGELOG.md untouched)
  • CI: 35/35 green + 19 path-skipped; no main-wide failures
  • Bugbot: reviewed c8cec59, no new issues; both earlier threads resolved
  • Reviewer focus: how a failed ArtifactHealth is rendered in vendor --check (vendor/verify.rs) — cause, path and remedy instead of Debug output — and the new in_process_vendor.rs assertions.
  • Slack announcement not sent: the Slack send tool isn't available to this run.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does: vendor --check used to report a damaged vendored artifact as Rust Debug text (artifact verification failed: Corrupt { reason: "..." }) with no path or fix. It now names the artifact (or the Bun workspace member copy), says what is wrong, and gives the remedy repair actually supports, keeping the stable tag in parentheses. Repair's empty-ledger refusal and its "is this a member-copy issue" check are shared, so check and repair don't disagree.

Risk: low. Only the text of failure messages changes; pass/fail decisions and exit codes don't. The one refactor on a live path (redownload::restore's guard moved into ledger_blocks_restore) keeps the same checks in the same order.

Look here:

Verified:

  • Read the full diff. Checked each remedy against what repair does. Repair rebuilds Bun member copies only when the canonical sha256 is recorded (bun_workspace::repair refuses otherwise), and the message follows that.
  • Ran locally: describe_artifact_failure_names_path_and_remedy, binary_workspace_health_attests_every_installable_tarball, and CLI vendor_check_names_damaged_artifact_and_repair_remedy, all passing. The tests assert exact strings, so they fail on the old Debug text.
  • CI 35/35 green on c8cec59e (19 skipped), with ci-ok and clippy green. Bugbot clean. No open review threads. CHANGELOG.md untouched.
  • Nit, not blocking: failing_mirror re-hashes the mirrors to find the bad one, but this runs only when the check has already failed.

Changes I made: none.

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


Generated by Claude Code

Merged via the queue into main with commit 960dc92 Oct 13, 2026
54 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-vendor-check-artifact-reason branch October 13, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

3 participants