mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-02 08:16:57 +00:00
95d4f7cmade the predecessor check fail open so a five-second blip against a live predecessor could not drop its blobs out of the referenced set. That was right, but the boolean it flipped does two jobs: manifestBelongsToHold decides both "keep these blobs referenced" and "this manifest is ours", and for an unreachable hold those want different answers. The consequence showed up on hold01 the moment it started running this code. Five stale dev manifests pointing at did:web:localhost%3A8080 and did:web:172.28.0.3:8080 were adopted into knownManifests, and since hold01 had never stored them, every one of their ten layers was reported as a missing layer record. Worse than the noise: reconcileMissingRecords acts on exactly that list, so a Reconcile would have written io.atcr.hold.layer records asserting hold01 stores blobs for a localhost hold. These DIDs are loopback and RFC1918, so they can never resolve from a server. This is not a transient outage that clears itself on the next run. manifestBelongsToHold and isPredecessorHold now return (value, definitive), matching the idiom checkPredecessor already uses. An indefinite answer still carries the manifest so its blobs stay referenced, but marks it ProtectOnly, and analyzeRecords protects its digests without adding it to knownManifests — the same shape the in-grace takedown branch above it already uses. Left alone deliberately: the legacy holdEndpoint path still treats a resolve failure as a definitive "not ours". That predates95d4f7cand fails closed rather than open, so it is a different bug with a different blast radius. The regression test was verified to fail without the fix, reporting the adoption rather than a build error. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KWoKzpgtBJ33sCyGxJGR7x