Skip to content

feat(memory): carve the inert diff types out from behind git-diff - #141

Merged
senamakel merged 2 commits into
mainfrom
memory-git-carve-out
Aug 10, 2026
Merged

feat(memory): carve the inert diff types out from behind git-diff#141
senamakel merged 2 commits into
mainfrom
memory-git-carve-out

Conversation

@senamakel

@senamakel senamakel commented Aug 10, 2026

Copy link
Copy Markdown
Member

Why

git-diff gated the whole memory::diff module, so a host that did not want libgit2 in its dependency graph could not so much as name a CrossSourceDiff.

That is more than the feature needs to gate. Of the eleven files under src/memory/diff/, exactly two touch git2:

9  src/memory/diff/ledger.rs
4  src/memory/diff/ledger_helpers.rs
0  everything else

types.rs and source.rs are serde/std-only.

What

pub mod diff is now always compiled.

Ungated types, source, and their re-exports
Gated on git-diff ledger + ledger_helpers (touch git2), checkpoint / diff / snapshot (impls written against Ledger), and DiffEngine itself

DiffEngine is gated even though its own declaration is dependency-free: its inherent methods live in the gated modules, so an ungated engine would be a handle with nothing to call.

The distinction is describe vs compute. Without the feature a host can pass a diff around, match on a ChangeKind, and implement SnapshotItemSource; it simply cannot produce one.

Who needs this

A memory-git gate in OpenHuman, whose always-on subconscious memory profile renders CrossSourceDiff and ChangeKind into agent prompts. Stubbing those types host-side instead would mean two definitions of one serde shape, free to drift apart — which is why OpenHuman's own gate guidance says to put a domain's inert types in a dependency-free submodule and gate only behaviour. That gate sheds git2 + libgit2-sys + libz-sys, two of the five remaining native C builds in its kernel profile.

Tests

Two #[cfg(not(feature = "git-diff"))] tests pin the carve-out. The disabled build is the only thing that can catch this regressing — re-gating these types compiles fine with the feature on and only breaks downstream.

They construct and serde-round-trip the types rather than just naming them, so a gated-away derive fails too. The pre-existing types/source unit tests now also run in the disabled build.

Verification

cargo check --no-default-features --features obsidian,persona,sync              # clean
cargo check --no-default-features --features obsidian,persona,sync,git-diff,wiki-git   # clean
cargo test  --no-default-features --features ...,git-diff,wiki-git --lib memory::diff::   # 43 passed
cargo test  --no-default-features --features obsidian,persona,sync --lib memory::diff::  # 14 passed
cargo fmt --all -- --check

Summary by CodeRabbit

  • Refactor
    • Improved modularity of memory and diff functionality.
    • Core diff data types remain available when Git-based comparison support is disabled.
    • Git-dependent comparison capabilities are isolated behind an optional feature.
    • Improved compatibility for configurations that do not include Git support.
    • Expanded validation confirms diff data remains serializable and usable across supported configurations.
    • Updated documentation clarifies feature availability and configuration behavior.

`git-diff` gated the whole `memory::diff` module, so a host that did not want
libgit2 in its dependency graph could not so much as *name* a `CrossSourceDiff`.
That is more than the feature needs to gate: `types.rs` and `source.rs` are
`serde`/`std`-only and reach no `git2` symbol — only `ledger.rs` and
`ledger_helpers.rs` do.

`pub mod diff` is now always compiled. Ungated: `types`, `source`, and their
re-exports. Gated on `git-diff`: `ledger` + `ledger_helpers` (the two that touch
git2), `checkpoint` / `diff` / `snapshot` (whose impls are written against
`Ledger`), and `DiffEngine` itself — its inherent methods live in those modules,
so an ungated engine would be a handle with nothing to call.

The distinction is describe-vs-compute: without the feature a host can pass a
diff around, match on a `ChangeKind`, and implement `SnapshotItemSource`; it
simply cannot produce one.

This unblocks a `memory-git` gate in OpenHuman, whose always-on subconscious
profile renders `CrossSourceDiff`/`ChangeKind` into prompts. Stubbing those
types host-side instead would mean two definitions of one serde shape drifting
apart silently — which is why OpenHuman's own gate guidance says to put a
domain's inert types in a dependency-free submodule and gate only behaviour.

Two `#[cfg(not(feature = "git-diff"))]` tests pin the carve-out, because the
disabled build is the only thing that can catch it regressing: re-gating these
types compiles fine with the feature on and only breaks downstream. They
construct and serde-round-trip the types rather than just naming them, so a
gated-away derive fails too. The pre-existing `types`/`source` unit tests now
run in the disabled build as well.

Verified both ways: `--features obsidian,persona,sync` (43 → the git-backed
tests compile out, 14 inert ones run) and with `git-diff,wiki-git` added (43
diff tests pass, unchanged).

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 39fcf7d9-5117-4701-8257-144f574cd5ad

📥 Commits

Reviewing files that changed from the base of the PR and between 59e4e00 and be7b395.

📒 Files selected for processing (2)
  • src/memory/diff/carve_out_tests.rs
  • src/memory/diff/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/memory/diff/mod.rs

📝 Walkthrough

Walkthrough

The memory diff module keeps types and sources available without git-diff. Git-backed computation, DiffEngine, and related tests require git-diff. Module documentation describes the updated feature boundary.

Changes

Memory diff feature boundary

Layer / File(s) Summary
Diff gating and compatibility tests
src/memory/diff/mod.rs, src/memory/diff/carve_out_tests.rs
Git-dependent imports, modules, and DiffEngine use git-diff gates. Tests cover Git-enabled engine behavior and feature-disabled type serialization and source implementation.
Memory feature-gating documentation
src/memory/mod.rs
Documentation describes the partially compiled diff module and the fully gated providers and persona modules.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a rabbit with a tidy diff,
Git sleeps when features drift.
Types still hop from branch to branch,
Sources stay light, tests dance.
DiffEngine wakes when git-diff sings.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes making inert diff types available without the git-diff feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/memory/diff/mod.rs`:
- Around line 140-171: Move the cfg-gated carve_out_tests module from
src/memory/diff/mod.rs into the matching sibling diff_tests.rs file, preserving
both test functions and their imports. Leave only the conditional module
declaration in mod.rs, pointing to the sibling test module, and keep the tests
gated for builds without the git-diff feature.
- Around line 156-159: Update the CrossSourceDiff serialization test to
deserialize the generated json back into a CrossSourceDiff, requiring its
Deserialize implementation, then assert a restored field such as the checkpoint
value matches the original. Keep the existing serialization assertion and
ChangeKind coverage.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a219b860-1676-458e-9ce4-a2623c6e3c73

📥 Commits

Reviewing files that changed from the base of the PR and between ce98837 and 59e4e00.

📒 Files selected for processing (2)
  • src/memory/diff/mod.rs
  • src/memory/mod.rs

Comment thread src/memory/diff/mod.rs Outdated
Comment thread src/memory/diff/mod.rs Outdated

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking. Approving.

             $0.0015 · 18,668 in / 4,980 out · 15,150 cached (81%) · z-ai/glm-5.2
critique:    $0.0005 · 5,033 in  / 1,813 out · 4,318 cached (86%)  · z-ai/glm-5.2
security:    $0.0002 · 4,991 in  / 411 out   · 3,998 cached (80%)  · z-ai/glm-5.2
tests:       $0.0002 · 3,576 in  / 544 out   · 3,021 cached (84%)  · z-ai/glm-5.2
description: $0.0005 · 4,223 in  / 1,914 out · 3,145 cached (74%)  · z-ai/glm-5.2

@tinysweeper

tinysweeper Bot commented Aug 10, 2026

Copy link
Copy Markdown

What this change touches

3 files, +96 -10 across 2 components. The code graph knows nothing about these files yet — normal for newly added files, and a cold index otherwise.

flowchart LR
  n0["src/memory/diff<br/>2 files +81 -1"]:::changed
  n1["src/memory<br/>1 file +15 -9"]:::changed
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading

Green: changed. Grey: untouched, reached through an import or a call. Orange: has findings. Red: has a finding that blocks the merge.

Component Files Lines Findings
src/memory/diff changed 2 +81 -1
src/memory changed 1 +15 -9
Changed files

src/memory/diff

  • src/memory/diff/carve_out_tests.rs
  • src/memory/diff/mod.rs

src/memory

  • src/memory/mod.rs

tinysweeper 0.1.0

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Aug 10, 2026
…ip them

Review follow-ups on #141:

- The tests were an inline `mod` in `mod.rs`; every other test module in this
  directory is a `#[path = "*_tests.rs"]` sibling. Now they match.
- The serde test only serialised. These types exist to cross a boundary, so a
  `Deserialize` derive that got gated away would not have failed it — it now
  round-trips and asserts the restored fields.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel senamakel self-assigned this Aug 10, 2026
@senamakel
senamakel merged commit d8c0d76 into main Aug 10, 2026
13 checks passed
@senamakel
senamakel deleted the memory-git-carve-out branch August 10, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant