quilt3: recover from corrupt cached manifests, explain unverifiable ones - #5218
Open
QuiltSimon wants to merge 5 commits into
Open
quilt3: recover from corrupt cached manifests, explain unverifiable ones#5218QuiltSimon wants to merge 5 commits into
QuiltSimon wants to merge 5 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5218 +/- ##
==========================================
+ Coverage 54.55% 54.64% +0.09%
==========================================
Files 871 871
Lines 36448 36527 +79
Branches 6438 6438
==========================================
+ Hits 19883 19959 +76
- Misses 14807 14810 +3
Partials 1758 1758
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…able ones Two follow-ups to the unconditional manifest verification in #5184. A cached manifest that will not parse was never evicted: _from_path ran outside the try, so the eviction below was unreachable. Nothing re-downloads a file that exists, so one truncated cache entry — exactly what the shared .tmp race that PR also fixes could leave behind — failed every future browse of that revision with a raw JSON error and no way back but deleting the cache by hand. Evict, re-download once, re-parse. An entry missing hash or size makes verification impossible, and _get_top_hash_parts raised before the mismatch branch could produce its actionable message — naming a physical key and nothing about manifests or hashes. Since the check cannot be skipped, that message is the user's only lead; name the package, the revision, and the failing step. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
QuiltSimon
force-pushed
the
fix/release-hardening-quilt3
branch
from
August 26, 2026 14:09
c52e7dc to
360aedc
Compare
- The unverifiable-manifest error is a QuiltException (PackageException is not one), so the CLI's handler prints it instead of dumping a traceback — the exact path this branch set out to make friendlier. - A cached manifest that parses but cannot be hashed is evicted (no retry: the same bytes re-download identically), so a server-side fix is picked up on the next call. Pinned by a test that would fail loudly on a retry. - MemoryError is never treated as cache corruption. - Cache eviction tolerates a Windows sharing violation instead of masking the original error. - One staging closure and an explicit from_cache flag replace the duplicated tmp-download sequence and the path-equality cache-hit test. - Tests derive cache paths via _filesystem_safe_encode; narrative trimmed. Deliberately unchanged: the mismatch branch keeps #5184's evict-and-raise semantics (its own test pins them); generalizing it to retry is flagged for that PR's author instead. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Two follow-ups to the unconditional manifest verification (#5184), from tonight's hardening review of master vs 26.7.4.
Fixes
_from_pathran outside thetry, so a cached manifest that failed to parse was never evicted — and nothing re-downloads a file that exists, so one truncated cache entry (exactly what the shared-.tmprace fixed in Verify browsed package manifest hashes #5184 could leave behind) failed every futurebrowse()of that revision with a raw JSON error. Recovery was manually deleting~/.cache/quilt. Now: evict, re-download once, re-parse; a fresh copy that is also bad raises as-is and is never promoted into the cache.hash/size(typically a non-quilt3 producer) made_get_top_hash_partsraise before the mismatch branch could speak — naming a bare physical key, nothing about manifests, hashes, or what to do. Since the check cannot be skipped, that message is the user's only lead. NowPackageExceptionnames the package, the revision, and the failing step, and suggests re-pushing with quilt3.Verification
tests/integration/test_packages.py: 230 passed, 1 xfailed.Deliberately not fixed here
The review also found that the accepted-parent set from #5180 is monotonic: an object that pushed rev2 and rev3 still accepts rev1, so a stale notebook can silently undo a
Package.rollbackthat the old_origincheck would have refused. A per-destination compare-and-swap would fix it without breaking the #2722 mirror flow the set exists for — but that changes semantics #5180 chose deliberately, so it's flagged for its author rather than redesigned here.🤖 Generated with Claude Code
Greptile Summary
The PR makes remote package browsing recover from an unparsable cached manifest and adds contextual guidance when manifest verification cannot compute a top hash.
Confidence Score: 4/5
The implementation appears safe to merge, with only the non-blocking changelog links needing correction.
Cache recovery remains limited to cache hits, retries only once through a unique temporary file, and preserves unconditional top-hash verification; the sole accepted issue is incorrect pull-request attribution in the changelog.
Files Needing Attention: docs/CHANGELOG.md
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Resolve remote manifest] --> B{Cached manifest exists?} B -->|No| C[Download to unique temporary path] B -->|Yes| D[Parse cached manifest] D -->|Parse fails| E[Evict cache entry] E --> C D -->|Parse succeeds| F[Compute and verify top hash] C --> G[Parse downloaded manifest] G --> F F -->|Missing hash or size| H[Raise contextual PackageException] F -->|Hash mismatch| I[Reject manifest] F -->|Verified| J[Promote temporary manifest to cache] J --> K[Return package]Reviews (1): Last reviewed commit: "fix(quilt3): recover from a corrupt cach..." | Re-trigger Greptile
Context used:
Update 2026-08-26: retargeted to master, /code-review complete
/code-reviewon this branch returned 10 findings — 7 fixed inb29bc43db, 3 dismissed:Fixed: the unverifiable-manifest error was a
PackageException, which is not aQuiltException, so the CLI dumped a traceback instead of a one-line error (nowQuiltException, via a private_ManifestUnverifiablesubclass); a cached manifest that parses but can't be hashed was never evicted (now evicted, no retry — pinned by a test whose stubber fails loudly if a retry download happens);MemoryErroris excluded from the corruption handler; eviction tolerates Windows sharing violations; the duplicated tmp-staging sequence became one closure; the path-equality cache-hit test became an explicitfrom_cacheflag; tests reuse_filesystem_safe_encode.Dismissed in writing:
test_remote_browse_rejects_manifest_top_hash_mismatchstubs no retry download). Generalizing it is @drernie's call, flagged here rather than changed._get_top_hash_partsinstead of_browse— the source lacks the package/revision context the message needs, and it serves push/build paths where the browse framing would be wrong. The wrap interpolates the underlying message, so unusual causes (e.g. unsupported hash type) still surface their own text.Also noted for @drernie: the pre-existing mismatch error from #5184 raises
PackageException, which the CLI'sexcept QuiltExceptionhandler atmain.py:523doesn't catch — soquilt3 installof a tampered manifest prints a traceback. Same shape as finding 1 here, but in landed code; not changed in this PR.Full run after everything:
test_packages.py232 passed, 1 xfailed;poe fmt --checkand ruff clean.