carlos / platform Public

release: putImmutable — immutable now means immutable-while-present

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell e19fdf19a8a8eea9756eecdd3365f956be4fcc1d parent ace4de0
1 file changed, +6 −0
  • internal/release/release.go +6 −0
diff --git a/internal/release/release.go b/internal/release/release.go
index e76ec9743..82f305a35 100644
--- a/internal/release/release.go
+++ b/internal/release/release.go
@@ -588,6 +588,12 @@ func Ship(ctx context.Context, s Store, acct string, m Manifest, files map[strin
// putImmutable claims a content-addressed key create-only; a lost race is
// fine iff the existing bytes are identical (idempotent re-ship), and an
// error otherwise (an immutable path must never change meaning).
+//
+// Since issue #136, "immutable" means immutable-WHILE-PRESENT: a release
+// object's bytes never change under its key, but retention (prune.go) and
+// whole-app purge (trash.go) may delete it. Create-only writes still refuse
+// to overwrite, and a re-ship of a pruned version is a NEW release that
+// happens to reuse the name.
func putImmutable(ctx context.Context, s Store, key string, body []byte) error {
_, err := s.Put(ctx, key, body, "")
if !errors.Is(err, ErrCASConflict) {