0.5.7: origin-aware retention (compactByOrigin + SymNode opts)#26
Merged
0.5.7: origin-aware retention (compactByOrigin + SymNode opts)#26
Conversation
Adds optional discrimination between self-authored and peer-received
CMBs at compaction time. Apps that benefit from retaining their own
lineage chains longer than peer chatter (e.g. retrospective analysis
of generation-CMB → outcome-CMB chains) configure split thresholds;
existing apps see no behavioral change.
MemoryStore:
- new `compactByOrigin(localFreshnessMs, peerFreshnessMs)` —
self entries (peerId == null) use localFreshness, peer entries
use peerFreshness. Hot-descendant preservation rule unchanged
(chains stay hot regardless of origin).
- `compact(freshnessMs)` shimmed to call compactByOrigin with both
values equal. Back-compat preserved; no behavior change for
callers that don't opt in.
SymNode:
- new constructor opts `localRetentionSeconds` + `peerRetentionSeconds`.
Each defaults to `retentionSeconds` so existing apps unaffected.
- `_runRetentionPurge` (run on start + hourly) uses the origin-
aware path; log line surfaces both values when they differ,
keeps single-value log shape when equal (existing log-grep
tooling unaffected).
Tests:
- shim equivalence: compactByOrigin(N, N) returns a number, same as
legacy compact(N).
- origin discrimination: under split thresholds (local 120s, peer
30s), a 60s-old peer entry compacts to cold while a 60s-old self
entry stays hot. Validates the discrimination is the cause, not
coincidence.
- 18/18 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CMO PR #26 review notes: N13: change `entry.peerId ? peerCutoff : localCutoff` to `entry.peerId != null ? peerCutoff : localCutoff`. Defensive against 0/''/false peerIds that shouldn't exist today but might via test fixtures or future relay edge cases. Matches the docstring's "peerId == null" wording exactly. N15: one-line docstring add to compactByOrigin noting that lineage chains are preserved across origins — a peer entry whose self- descendant is still hot stays hot regardless of peerFreshnessMs. The hot-descendant rule transcends origin discrimination by design (lineage walks must remain intact at retention boundaries); saying so explicitly prevents readers from assuming "peer entries compact at peerCutoff" is absolute. 18/18 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds optional discrimination between self-authored and peer-received CMBs at compaction time. Apps that benefit from retaining their own lineage chains longer than peer chatter (e.g. retrospective analysis of generation-CMB → outcome-CMB chains) configure split thresholds. Existing apps see no behavioral change.
API additions
MemoryStore.compactByOrigin(localFreshnessMs, peerFreshnessMs)— self entries (peerId == null) use localFreshness, peer entries use peerFreshness. Hot-descendant preservation rule unchanged (chains stay hot regardless of origin).SymNodeconstructor optslocalRetentionSeconds+peerRetentionSeconds. Each defaults toretentionSecondswhen omitted.Compatibility
MemoryStore.compact(freshnessMs)is now a back-compat shim that callscompactByOrigin(freshnessMs, freshnessMs). No behavioral change for callers that don't opt into origin-aware retention.SymNodeinstances with onlyretentionSecondsset behave identically to v0.5.6._runRetentionPurgekeeps the single-value shape when local == peer; surfaces both values when they differ.Test plan
node --test tests/memory-store.test.js— 18/18 passcompactByOrigin(N, N)returns a number, same shape as legacycompact(N)localRetentionSeconds: 7776000, peerRetentionSeconds: 2592000, write self + peer entries, observe hourly retention log shows both values🤖 Generated with Claude Code