Skip to content

imagecache: record image digest in bundle overlay specs; atomic WriteSpec - #656

Merged
Dmitry Berkovich (dberkov) merged 3 commits into
agent-substrate:mainfrom
igooch:imagecache-spec-digest
Aug 1, 2026
Merged

imagecache: record image digest in bundle overlay specs; atomic WriteSpec#656
Dmitry Berkovich (dberkov) merged 3 commits into
agent-substrate:mainfrom
igooch:imagecache-spec-digest

Conversation

@igooch

@igooch igooch commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Second foundation slice of #463 Phase 2 (GC), independent of #650 and inert on its
own: nothing reads the new field and nothing deletes anything.

  • OverlaySpec.ImageDigest (optional, omitempty): the manifest digest the
    bundle's image ref resolved to, populated in prepareOCIDirectory. The GC
    root-set scan will use it to root the whole image record while the bundle
    exists. Compatible in both directions: ateom consumers never read the field
    (old binaries drop the unknown JSON key), and specs written by older atelets
    keep parsing with the field empty — so there is no deploy-ordering constraint.
  • Atomic WriteSpec (temp file + rename in the bundle dir): the root-set scan
    will read specs concurrently with bundle preparation, and a torn spec would
    under-report the layers an actor is using — an error in the dangerous
    direction (toward deleting in-use layers). With the rename, a reader sees the
    complete old spec or the complete new one, never a fragment.

Landing early matters: every bundle written from now on carries the digest,
shrinking the digestless-spec population the GC's compatibility fallback has to
cover.

Testing: round-trip + old-spec compat and no-temp-files-left unit tests;
go test -race green on both affected packages.

…Spec

Second foundation slice for agent-substrate#463 Phase 2 (GC), inert on its own:

- OverlaySpec gains an optional imageDigest field, populated from the
  resolved manifest digest in prepareOCIDirectory. The GC root-set
  scan will use it to root the whole image record while the bundle
  exists; ateom consumers ignore it, and specs written by older
  atelets keep parsing (field is omitempty and never required).
- WriteSpec becomes atomic (temp file + rename): the root-set scan
  will read specs concurrently with bundle preparation, and a torn
  spec would under-report an actor's layers — failing toward
  deletion.

Landing early shrinks the population of digestless specs the GC's
compatibility rule has to cover.

Extracted from the phase2-gc-record-first prototype branch. This
slice: go test -race green standalone; gofmt/vet clean; no behavior
change for any current consumer (ateoms ignore unknown spec fields).
Comment thread internal/imagecache/spec_test.go Outdated
Comment thread internal/imagecache/spec.go
Dmitry Berkovich (dberkov) pushed a commit that referenced this pull request Aug 1, 2026
…ep (#658)

Third foundation slice of #463 Phase 2 (GC), independent of #650 and
#656. The
primitives are uncalled until the eviction engine PR; the only live
behavior is
the startup sweep, which only ever sees `.rm-*` dirs the engine will
create.

- **`retireLayer`**: evicts a layer with one atomic rename to a `.rm-*`
name
inside the layer singleflight; the slow `RemoveAll` is the caller's job,
outside all locks. Existence/mtime pre-flight runs *outside* the flight
(a
retire must never block behind an in-progress download) and both checks
are
re-run inside it before the rename. Returns gone/vetoed/retired so the
engine
  can distinguish "nothing there" from "must keep".
- **Reuse interlock**: `ensureLayer` now refreshes the layer dir mtime
inside
the same flight, so a retirement and a reuse cannot interleave — either
the
retire wins (the pull re-unpacks) or the touch wins (the retire vetoes).
- **Startup sweep**: `.rm-*` dirs (a crash between rename and removal)
are
reclaimed alongside the existing `.tmp-*` dirs, via `RemoveAllWritable`
since
  layer trees legitimately contain read-only content.
- **`isLayerDirName`** validates names read from disk or records.

Divergence from the prototype: `retireLayer` reports no freed size —
size
crediting belongs to the engine's call sites and arrives with it.

**Testing**: unit tests for the status contract, startup-sweep recovery
and
non-interference, and a retire-vs-pull race test; `go test -race` green.
@dberkov
Dmitry Berkovich (dberkov) merged commit cbdeb7d into agent-substrate:main Aug 1, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants