v6.5.0 adds bounded direct bundle-reference reads for applications that need to locate or enumerate retained materialization handles without recursively hydrating every referenced support graph. It also adds bounded reuse for immutable Git metadata and bundle descriptors, and repairs two concurrency edge cases found while proving the new path under stress.
This release is API-additive. It does not change persisted bundle formats and does not require stored-data migration.
Read one exact member descriptor without opening its payload or recursively resolving the member's complete support graph:
const reference = await cas.bundles.getMemberReference({
handle: materializationBundle,
path: 'nodes/user-alice.cbor',
});
if (reference) {
console.log(reference.handle);
console.log(reference.type);
console.log(reference.size);
}Stream canonical member descriptors without collecting the whole bundle:
for await (const reference of cas.bundles.iterateMemberReferences({
handle: materializationBundle,
})) {
await indexReference(reference);
}Each BundleMemberReference contains:
version: 1;- the canonical member
path; - the typed application
handle; - the direct Git object
type; and - the declared byte
size, ornullfor structured tree members.
The existing getMember() and iterateMembers() APIs retain complete recursive
validation semantics and include computed logicalBytes.
The direct path validates:
- the bundle handle codec and root tree type;
- the root descriptor and persisted read limits;
- every descriptor and summary along the selected path, or across the streamed structural traversal;
- every traversed fanout tree edge;
- the selected or enumerated leaf edge; and
- each direct target Git object type.
It does not recursively validate a selected page, asset, or nested bundle's
complete support graph. Callers that require that stronger proof must continue
to use getMember() or iterateMembers().
A reference is also not a retention witness. The containing bundle must remain reachable through a workspace, RootSet, cache acquisition, publication, or other documented lifetime while the reference is consumed.
Repeated exact tree-entry and object-info reads now share successful in-flight
and completed work inside each Git persistence adapter. The default metadata
cache retains at most 2,048 immutable entries and can be lowered with the
metadataCacheEntries constructor option.
Bundle descriptors use a separate cache bounded by both 1,024 entries and 16 MiB. Returned byte arrays and mutable metadata records are copied for callers. Rejected work removes itself so a later read can retry. Values larger than the descriptor byte budget are returned to the current caller but are not retained and do not evict unrelated residents.
These caches contain immutable Git metadata and structural descriptors only. They do not retain application payload bytes, mutable refs, cache indexes, or root-set state.
The RootSet compare-and-swap classifier now recovers exact failed
git update-ref --no-deref races when Git exits fatally without diagnostic
text, provided an independent ref read proves that the managed head advanced.
OID comparisons use canonical lowercase values, avoiding false conflicts from
case-only differences. A checked-in real-Git diagnostic passed 500/500
two-writer replacement races after the repair.
The bounded promise cache now removes rejected work before the returned promise settles, preserving immediate retry semantics. Individually oversized resolved values are discarded before weight-based eviction runs, preserving unrelated residents.
The stable regression contract counts real Git commands rather than asserting portable wall-clock latency:
- a cold direct read must perform metadata work;
- an identical warm direct read must perform zero additional Git metadata commands; and
- direct reference iteration must issue fewer total and object-inspection commands than complete recursive validation.
On the recorded four-node git-warp fixture, the final direct-reference and descriptor-cache path reduced one selected read from 192 Git commands to 69, approximately 64 percent. The same host sample reduced the observed wall time from approximately 3-5 seconds to 1.291 seconds. These timings are diagnostic, not cross-machine promises; command-count integration is the merge gate.
The final release candidate passed 14/14 verifier steps with 6,625 observed tests:
- Node.js: 2,020 unit tests and 192 real-Git integration tests;
- Bun: 2,019 unit tests and 192 real-Git integration tests; and
- Deno: 2,010 unit tests and 192 real-Git integration tests.
The verifier also passed lint, examples, public type compatibility, build stamping, npm package inspection, and the JSR publish dry-run. The checked-in RootSet race diagnostic passed 500/500 two-writer replacement races.
No stored-data migration is required. Existing complete-validation calls keep their behavior. Applications may adopt the new reference APIs selectively where their own retained lifetime already guarantees that recursive support remains available.
See UPGRADING.md for the adoption decision and Application Storage for the full API contract.