Skip to content

Per-push batch-frame compression + transport file split#7

Merged
rekal-dev merged 3 commits into
mainfrom
claude/capabilities-scope-8uqk1g
Jul 5, 2026
Merged

Per-push batch-frame compression + transport file split#7
rekal-dev merged 3 commits into
mainfrom
claude/capabilities-scope-8uqk1g

Conversation

@rekal-dev

Copy link
Copy Markdown
Owner

Two changes on top of the earlier refactors. CI green (incl. the E2E push→clone→import roundtrip through DuckDB and the team-sync import path).

Per-push batch-frame compression (the substance)

The wire format compressed each frame as its own zstd stream, so a frame could never back-reference the paths, emails, ULIDs, or phrasing repeated in its sibling frames, and paid framing overhead per frame — the dominant cost on small frames.

New batch frame (0x06): one checkpoint's session frames plus its checkpoint frame are concatenated uncompressed (each member = type + varint length + payload) and compressed together as a single stream. Members carry the exact bytes a standalone frame would, so they decode with the existing per-type parsers after one decompress. On a redundant multi-session push this is multiple-x smaller (6.8× in the codec test's synthetic case; realistically ~2–4×).

Backwards compatibility — the same contract the v2 frames use, tested in all four directions:

  • new reads new: batch round-trip + the E2E push/clone/import test.
  • new reads old: existing standalone-frame tests still pass; import/sync keep the 0x010x05 handlers, and bodies may interleave old frames with new batches.
  • old reads new: a pre-batch binary skips a 0x06 frame by its envelope length and still reads the frames around it.
  • corrupt/truncated batches error, never panic.

Export batches per checkpoint (falling back to standalone frames if a single checkpoint would overflow the envelope's u24 length). Import and sync-to-index decode batches by dispatching each member through the same handlers as standalone frames. No data migration; existing branches stay readable. Documented in docs/git-transportation.md.

transport.go file split

The transport package's single ~820-line file split by concern into export.go / import.go / sync.go. No logic change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TBMA7dNfAQn86m59P64dsS


Generated by Claude Code

claude added 3 commits July 5, 2026 08:25
The transport package was one ~820-line file. Split it along the three
jobs it already did, no logic change:

- export.go: encode checkpoints to the wire format and commit them to
  the orphan branch (ExportNewFrames/ExportAllFrames/CommitWireFormat/
  EnsureOrphanBranch).
- import.go: decode a branch back into data.db (ImportBranch).
- sync.go: fetch teammate branches and import them into the index
  (FetchRemoteRekalRefs/ListRemoteRekalBranches/ImportBranchToIndex).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBMA7dNfAQn86m59P64dsS
The wire format compressed each frame as its own zstd stream, so a
frame could never back-reference the paths, emails, ULIDs, or phrasing
repeated in its sibling frames, and paid zstd framing overhead once per
frame. On small frames that is the dominant cost — the preset dictionary
was largely compensating for the isolation.

Add a batch frame (type 0x06): one checkpoint's session frames plus its
checkpoint frame are concatenated uncompressed (each member prefixed
with type + varint length) and compressed together as a single stream.
Members carry the exact bytes a standalone frame would, so they decode
with the existing per-type parsers after one decompress. On a redundant
multi-session push this is multiple-x smaller (6.8x in the codec test's
synthetic case; realistically ~2-4x).

Backwards compatibility is the same contract the v2 frames use, and is
tested in all four directions:
- new reads new: batch round-trip + the E2E push/clone/import test.
- new reads old: existing standalone-frame tests still pass; import and
  sync keep handling 0x01-0x05 frames, and bodies may mix old frames
  with new batches (TestBatch_MixedBody).
- old reads new: a pre-batch binary skips a 0x06 frame by its envelope
  length and still reads the frames around it (TestBatch_OldReaderSkips).
- corrupt/truncated batches error, never panic (truncation sweep +
  oversized-member-length guard).

Export batches per checkpoint, falling back to standalone frames if a
single checkpoint would overflow the envelope's u24 length. Import and
sync-to-index decode batches by dispatching each member through the same
handlers as standalone frames. Format documented in
docs/git-transportation.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBMA7dNfAQn86m59P64dsS
TestPush_E2E_ExportAndPush asserted the pushed body's raw frame layout,
which the batch frame deliberately changed: a single-checkpoint push is
now one batch frame (session + checkpoint grouped) plus a meta frame —
2 frames, not 3; two pushes give 4, not 6.

Update the counts and, instead of decoding standalone session/checkpoint
frames, decode the batch and assert on its members — which also
exercises DecodeBatch end-to-end. The append-only prefix check is
unchanged and confirms batching preserves that property.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBMA7dNfAQn86m59P64dsS
@rekal-dev rekal-dev merged commit b98f16c into main Jul 5, 2026
4 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