Repository navigation
repair and scan --prune delete the beforeHash blobs of active patches, so a later offline rollback fails and tells the user to run repair #893
Description
Activity
- addedbugSomething isn't workingSomething isn't workingarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)Filed by a scheduled architecture audit routine (see the architecture review discussion)
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Triaged as priority:p3 (cross-cutting CLI: blob retention in repair and scan --prune). Not a duplicate: #559 / #600 fixed the same class of bug for
removeonly. No open PR covers it yet.
Generated by Claude Code
- added a commit that references this issue
on Oct 6, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Re-checked on
823810a. The finding still holds;scan/gc.rsmoved (+82/−31 sinceb96a785), so here are fresh permalinks.- The two retention policies are unchanged:
ArtifactReferences::for_applykeeps only afterHash blobs, whileafter_removalalso keeps the beforeHash blobs of every remaining patch. repair(repair.rs#L630) andscan --prune(scan/gc.rs#L158) still sweep withfor_apply.remove(remove.rs#L940) androllback(rollback.rs#L1605) still useafter_removal.- Offline rollback still names
repairas the remedy for missing blobs (rollback.rs#L2485-L2494). cleanup_unused_blobs/cleanup_unused_archivesstill have no production caller; only a test comment names them.
Generated by Claude Code
- The two retention policies are unchanged:
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.and removed
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). Routine repair/prune must not discard the restore blobs of active agent patches and break their documented offline undo path.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming for v5 blocker burn-down (shared root cause: repair and scan --prune use ArtifactReferences::for_apply, which keeps only afterHash blobs of active patches). Branch: agent/v5-gc-keep-before-blobs. Claim-ID: 2026-10-09T16:41:47Z-245b4f
- added 2 commits that reference this issue
on Oct 9, 2026
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: register comment.
Kind: bug. Source: new finding (C50). Same bug class as #559, which #600 fixed for
removeonly.Problem
There are two artifact-retention policies in
cleanup_blobs.rs#L30-L64,`` and they disagree about the same blobs:ArtifactReferences::after_removalkeeps the beforeHash blobs of every patch still in the manifest. Its doc says "a crawler miss must not destroy the only local restore data".rollback(rollback.rs#L1598) andremove(remove.rs#L940) use it. The contract says this "preserves offline rollback of other active patches".ArtifactReferences::for_applykeeps only the afterHash blobs.repair(repair.rs#L630) andscan --prune(scan/gc.rs#L159) use it. It deletes the originals of patches that are still active.getstores those originals:write_all_patch_blobswritesbefore_blob_contentto.socket/blobs/<beforeHash>. The firstrepair(aliasgc) then deletes them again.The offline rollback error also points to the wrong fix. It says
Run "socket-patch repair" to download missing blobs(rollback.rs#L2462-L2483).`` Butrepairdownloads only `get_missing_blobs`, which checks afterHash blobs only (`blob_fetcher.rs#L78-L90`). So running `repair` can never restore the blob that its own GC deleted.The old rationale is left behind as dead public API:
cleanup_unused_blobs("beforeHash blobs are considered unused because they are downloaded on-demand during rollback"),cleanup_unused_archivesandformat_cleanup_result(cleanup_blobs.rs#L175-L232).`` They have no caller in any crate except their own unit tests.Proof (debug build on
9c43dfc, run twice, identical results). Setup: an npm project with one active patch,node_modules/t/index.jsin its patched state, and both blobs present in.socket/blobs, the same layoutgetleaves.rollback --offline --jsonexits 0,status: success, and the file is restored.repair --offline --jsonexits 0, and.socket/blobskeeps only the afterHash blob. Thenrollback --offline --jsonexits 1,status: partial_failure:Cannot roll back: package/index.js - Before blob not found: 9b81… and --offline prevents fetching. Run "socket-patch repair" to download missing blobs.The file stays patched.scan --prunereaches the samefor_applycall. That path is verified by reading only, becausescanrefuses--offline.Symptoms
None filed. #559 was the same data loss reached through
remove.Impact: an air-gapped or offline rollback of a patch that is still active fails after any
repair/gcorscan --prune/--sync. The remedy it prints is wrong. Online, rollback falls back to downloading the blob, which works only while the patch service still serves it.Proposed change
ArtifactReferencesone retention policy for an unchanged manifest: keep the afterHash and beforeHash blobs, and the diff archive, of every manifest patch. In practice,for_applybecomesafter_removal(m, m, [])or a namedArtifactReferences::active(m).repairandscan --prunecall it, andfor_applyis deleted.cleanup_unused_blobs,cleanup_unused_archives,format_cleanup_resultand their tests.ArtifactReferences::sweepalready covers them.--offlineto download the original blobs".repaircan't fetch them.Size and scope
cleanup_blobs.rs,repair.rs,scan/gc.rs,rollback.rs(messages), and the contract'srepair/scan --prunetext. About 30 production lines changed and about 90 dead lines deleted. Out of scope: teachingrepairto download beforeHash blobs.Acceptance criteria
repair --offlineon a project with an active patch and both blobs,rollback --offlineexits 0 and restores the file.scan --mode agent --pruneagainst a mock API: the active patch's beforeHash blob survives.repairstill removes beforeHash blobs that only manifest-absent patches reference.cleanup_unused_*/format_cleanup_resultare gone, andcargo test -p socket-patch-core manifest::cleanup_blobsand therepair,remove,rollbackand scan-GC suites stay green.repair.CLI_CONTRACT.mddescribes one retention policy forrepairandscan --prune.Dependencies
None. This touches the same files as #791 (
--download-modeinrepair) only in separate blocks.Backlog review — 2026-10-08
Priority: P3 → P2. Deleting original blobs of active patches breaks offline rollback. Keep the data-retention fix; it is more consequential than P3 cleanup.