v6.2.0 makes git-cas the storage and cache lifecycle owner for application
packages. Applications can define domain keys, payload schemas, causal
publication rules, and retention intent without constructing Git trees,
persisting naked object IDs, or maintaining a second cache protocol.
A handle is not a durability claim.
cas.assets, cas.pages, and cas.bundles return immutable opaque handles.
The staged result explicitly reports that no root was created. A caller then
chooses how the handle graph should live:
| Policy surface | Intended lifecycle | Git reachability behavior |
|---|---|---|
cas.retention / RootSet |
Caller-managed current set | Anchored while present |
cas.caches |
TTL/capacity/approximate-LRU cache | Anchored until managed eviction |
cas.expiringSets |
Security replay window | Anchored until expiry; no early eviction |
cas.publications |
Application causal history | Anchored by the allowlisted application ref |
| Vault | History-preserving named assets | Anchored by refs/cas/vault history |
Successful retention and publication operations return a RetentionWitness
that identifies the exact ref generation and tree edge that established
reachability.
const staged = await cas.assets.put({
source,
slug: 'warp/materialization',
filename: 'materialization.bin',
});
const retained = await cas.retention.retain({
handle: staged.handle,
root: {
ref: 'refs/cas/rootsets/git-warp/materializations',
name: materializationKey,
},
policy: 'evictable',
});
console.log(retained.witness.root.generation);- Asset writes stream through the existing chunking, deduplication, compression, encryption, manifest, and tree pipeline.
- Pages store bounded immutable blobs and expose targeted streams.
- Bundles build deterministic bounded-fanout trees from named streams or nested handles.
bundles.iterateMembers()streams descriptors, whilegetMember()andopenMember()traverse only the requested descriptor path and payload.cas.publications.commit()validates an entire handle graph, ordered commit parents, an explicit ref allowlist, and expected-head compare-and-swap state before changing a ref.
Handles contain no repository path and support canonical SHA-1 and SHA-256 object IDs. Importing a handle validates that its graph exists and has the expected Git object and codec shape.
cas.caches.open() owns immutable cache indexes under refs/cas/caches/*.
CacheSet handles TTL, entry and logical-byte limits, approximate-LRU sweeps,
coalesced touches, retention witnesses, bounded inspection, doctor, and repair.
A cache miss is read-only.
cas.expiringSets.open() owns digest-only replay markers under
refs/cas/expiring/*. addIfAbsent() is atomic across writers, contains() is
read-only, and sweep() can release only entries whose expiry has passed. The
surface intentionally has no remove, repair, capacity, or recency eviction
operation that could shorten a security acceptance window.
Both services publish parentless current-generation commits. Superseded generations do not remain reachable through their own storage history.
const report = await cas.diagnostics.doctor({
gracePeriodMs: 14 * 24 * 60 * 60 * 1000,
});The report streams Git object, ref, and reflog-reachability inventories; classifies anchored, orphaned, grace-expired volatile, and total unreachable objects; and summarizes CacheSet, RootSet, ExpiringSet, and Vault usage. It fails closed if concurrent writes make derived arithmetic inconsistent.
Diagnostics use plumbing's exact prune dry-run contract for volatile objects.
The doctor does not run git gc or destructive prune and exposes no object or
ref mutation operation. Shared deduplicated bytes, packed-object age, reflog
entry count, alternate-store attribution, and pack metadata overhead remain
explicitly reported limitations rather than guessed values.
This release is API-additive. Existing CAS manifests, RootSets, Vaults, refs,
and low-level createTree() callers remain compatible; no stored-data
migration is required. Repository diagnostics require
@git-stunts/plumbing 3.1.0 or newer.
Applications that currently store tree or blob IDs only in JSON should adopt every still-live object into a RootSet or rebuild it through the matching high-level capability before destructive Git cleanup. An object that Git already pruned cannot be recovered by doctor or repair.
See UPGRADING.md for the adoption sequence, Application Storage for API contracts, and Repository Diagnostics for report fields and limitations.
pnpm run release:verify passed 13/13 steps with 6,124 observed tests:
| Suite | Tests |
|---|---|
| Node unit | 1,871 |
| Bun unit | 1,870 |
| Deno unit | 1,861 |
| Node integration | 174 |
| Bun integration | 174 |
| Deno integration | 174 |
The same run passed ESLint, all three runnable examples, build metadata stamping, npm package-content inspection, and a JSR publish dry-run. GitHub CI, self-review, and Code Lawyer review remain mandatory before tagging.