Skip to content

Tombstone replay edge removals#588

Open
TZZheng wants to merge 1 commit into
Lingtai-AI:mainfrom
TZZheng:codex/issue-564-replay-edge-tombstones-20260708
Open

Tombstone replay edge removals#588
TZZheng wants to merge 1 commit into
Lingtai-AI:mainfrom
TZZheng:codex/issue-564-replay-edge-tombstones-20260708

Conversation

@TZZheng

@TZZheng TZZheng commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Fixes #564.

Summary

  • emit explicit replay delta tombstones for removed avatar/contact/mail edges
  • apply those edge removals in the portal frontend replay reconstruction path, including removal-only deltas
  • version replay chunk caches as v:2
  • preserve readable legacy v:0 replay chunks when JSONL history cannot fully reconstruct that hour, while rewriting to v:2 when JSONL coverage is complete

Why

Replay deltas already tombstone removed nodes with State: "__REMOVED__", and the frontend deletes those nodes during reconstruction. Edge deltas did not have an equivalent removal path: backend deltas only added/changed avatar/contact/mail edges, and the frontend only upserted edge arrays.

That meant a removed edge could persist in reconstructed replay frames until the next keyframe, up to the keyframe interval, and could temporarily dangle toward nodes that had already been tombstoned.

Behavior

  • FrameDelta now has avatar_edges_removed, contact_edges_removed, and mail_removed tuple lists.
  • computeDelta emits deterministic removed-edge tuples by comparing previous edge keys against current edge keys.
  • reconstructFrames deletes removed edges using the same composite keys as the existing upsert paths, then applies add/change deltas.
  • Removal-only deltas are applied correctly.
  • Existing node tombstone behavior is unchanged.
  • ReplayChunk now carries cache format version v:2.

Legacy cache handling

The cache migration is intentionally compatibility-preserving:

  • valid v:2 chunks are served directly;
  • readable legacy chunks with missing/stale version are distinguished from corrupt/unreadable cache files;
  • if JSONL fully covers the cached hour, the chunk is re-encoded and rewritten as v:2;
  • if JSONL is empty or only partially covers that historical hour, the readable legacy chunk is served as a compatibility fallback rather than blanking historical replay;
  • corrupt/unreadable cache files are not served as compatibility fallback.

This preserves old replay history after topology JSONL compaction/truncation, while ensuring newly generated chunks use the removal-capable wire format.

Non-goals

  • no change to node tombstone representation
  • no change to keyframe interval or recording cadence
  • no frontend test-runner infrastructure added
  • no topology producer changes outside replay encoding/reconstruction

Validation

Parent and reviewer validation included:

  • git diff --check canonical/main...HEAD
  • cd portal && go test ./internal/api/... -count=1
  • cd portal/web && npm ci && npm run build
  • cd portal && go build ./...
  • cd portal && go vet ./...
  • cd portal && go test ./... -count=1

Focused tests cover:

  • removed avatar edges
  • removed contact/mail edges, including removal-only deltas
  • node removal together with dependent edge removals
  • delta encode/reconstruction contract for edge add/remove
  • stale v:0 cache rewrite when JSONL coverage is complete
  • stale v:0 compatibility serving when JSONL has no frames
  • stale v:0 compatibility serving when JSONL coverage is partial
  • corrupt cache rejection

npm ci reported existing audit advisories during local validation; dependency remediation is outside this issue.

Review

This went through the requested multi-review workflow:

  • Codex review: APPROVE, no blockers/nits.
  • Claude Code review: APPROVE-WITH-NITS, no blockers, public-PR-ready.
  • GLM review: APPROVE, no blockers/nits.

The only review feedback was optional robustness cleanup for future consideration; no reviewer requested a blocking code change.

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.

Replay delta encoding never emits edge tombstones, so removed edges persist for up to a full keyframe interval

1 participant