Skip to content

Make Kitsune2MemoryOpStore generic over its op type #277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

maackle
Copy link
Contributor

@maackle maackle commented Jul 27, 2025

I'm going to try integrating kitsune2 into a project as a standalone, with no Holochain. So far so good, but here is a change I found helpful.

Kitsune2MemoryOpStore is useful for testing other kitsune hosts, but it is written to be used with MemoryOp which is clearly for testing purposes -- its OpId implementation is intentionally not robust, making it unsuitable for real-world situations. Aside from that, host implementers will have written their own custom op types, and having to convert to MemoryOp isn't great. A better pattern is that any reusable OpStore implementation should be abstract over its op data.

I defined a trait that has the key elements necessary for working with your mem op store implementation: created_at timestamp, op id calculation, and serialization. This lets users more quickly get up and running with Kitsune2MemoryOpStore, which as far as I know is the only working OpStore implementation in the world aside from Holochain's. Without this, your first attempts at hooking up your own custom op type likely result in confusing deserialization errors, and in my case, discovering that I got the same OpId for every op due to the first 32 bytes being the same.

If you don't want to use this that's fine, but I will be using this in my branch.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error messages for configuration and URL parsing failures, now displaying the actual problematic values for easier troubleshooting.
  • Refactor

    • Generalized the in-memory operation store to support any operation type via a new trait, increasing flexibility and extensibility.
    • Replaced the previous fixed operation type in tests and internal logic with a new test-specific operation type for better clarity and maintainability.
    • Updated test code and supporting modules to use the new generic operation store and operation type throughout the codebase.
  • Style

    • Streamlined and consolidated import statements for improved readability in test files.
  • Documentation

    • Updated function and method signatures in documentation to reflect new generic and test operation types.

@maackle
Copy link
Contributor Author

maackle commented Jul 27, 2025

Oh yeah, I based this on a commit behind main due to #275, if you want I can clean this up once that's resolved.

@maackle
Copy link
Contributor Author

maackle commented Jul 28, 2025

I will also sneak a totally unrelated question in here: is there a way to register a handler that gets called whenever new ops have been received via publish/gossip/fetch? Or must one simply poll the op store?

@ThetaSinner
Copy link
Member

ThetaSinner commented Jul 28, 2025

We've gone back and forth a bit about whether to re-use the in-memory op store. It is useful for writing tests within Kitsune2 and it is valid as a reference implementation but not persisting ops is not usable outside tests, there is also no op location logic used in tests with the memory op store. We've found that the problems run deeper when you try to re-use it and it's worth the initial effort to create one.

Even for Wind Tunnel testing, we needed different functionality and ended up defining a new op store https://github.com/holochain/wind-tunnel/blob/main/bindings/kitsune_client/src/op_store.rs.

host implementers will have written their own custom op types

That is entirely intentional, Kitsune2 needs to know very little about the data it is handling. Everything is done with bytes::Bytes and Kitsune2 just needs to be told about identifiers and locations for ops.

is there a way to register a handler that gets called whenever new ops have been received via publish/gossip/fetch? Or must one simply poll the op store

Yes and no. No, in the sense that the memory op store doesn't do this. Yes, in the sense that Kitsune2 notifies the host about newly arrived op data using the OpStore::process_incoming_ops and it's up to the host implementation to decide whether to accept new data. Part of that process can involve notifying some other part of the system. Any received op data that is considered acceptable has to be sent back to the DHT model to become part of the DHT model that Kitsune2 will use in gossip. In the Holochain implementation that requires "store as pending validation" and "on integrated, add to the DHT model".


Kitsune2 could obviously use more documentation about which trait implementations from the core module are intended to be re-used, and which ones the host is supposed to implement. The op store is one the host is expected to implement. What I'd really like is some sample application that uses a real database to show how everything fits together. Is there something else about the memory op store that is useful, beyond getting started quicker? Is it that you'd like the storage logic separated from the op store logic somehow so that you can run unit tests in-memory and then only use a database for integration tests?

@maackle
Copy link
Contributor Author

maackle commented Jul 28, 2025

Is there something else about the memory op store that is useful, beyond getting started quicker?

No, but the value of getting started quicker can't be overstated. I'm trying to get a demo of an app ready in two weeks, and it doesn't have to be robust, it just has to have a p2p experience. Getting something working with a mem op store ASAP lets me have all of this without investing in building my own op store:

  • see if kitsune is actually going to be a good fit for this app
  • see if kitsune is going to perform well enough for my demo
  • start figuring out the p2p patterns I need to use for my app
  • have confidence that any problems are at least probably not due to the op store
  • have a demo sooner

not persisting ops is not usable outside tests, there is also no op location logic used in tests with the memory op store

My plan was to set up an always-online node that just syncs with other people. Good enough for a demo, and even lets me test initial sync over and over. Also I don't have any need for location, all Spaces will be full-sync for a long time, and I'm not doing anything like holochain's authorities pattern.

Kitsune2 could obviously use more documentation about which trait implementations from the core module are intended to be re-used, and which ones the host is supposed to implement. The op store is one the host is expected to implement.

It seems to me that in the ideal world, the host shouldn't be expected to implement an op store, but rather initially to select one from a list of quality first- and third-party op store implementations. Maybe implementing their own if needed. Most framework users are accustomed to picking a pre-made "backend" or "driver", which this basically is.

Regardless of whether something is designed to be reused or not, people who are trying to get stuff done are certainly going to attempt to reuse and repurpose them anyway (especially when there are no other guides), so why not go the extra mile and make them reusable? :)


I'm definitely not going to invest in building my own op store at this time, especially since I have one that already works for me. Depending how this goes I may invest further in making a persistent op store, if one doesn't already exist by then (or I may have to choose another framework for other reasons before that point). If you're not already thinking this way, I would encourage you to think of every op store as reusable, as I think that will be important for actual adoption of Kitsune.

Last question, would you recommend I use the windtunnel op store you linked to instead of the one I'm currently using?

@ThetaSinner
Copy link
Member

It seems to me that in the ideal world, the host shouldn't be expected to implement an op store

I would like to have more example and/or ready-to-use code for Kitsune2 but we haven't had time to do that. Between the memory op store and the Holochain implementation on sqlite, the elements of implementing the trait are visible at least and that's the best we've been able to do so far.

Even if we did implement a persistent op store for re-use, we then have to make decisions about the op type that is in use and how to process that. We'd end up defining another trait that can hide the common operations that need to be done to convert between bytes <-> op data <-> op id. Then there's the question of what database we use. My first preference would be to have a clean and simple implementation of a Rust app built on top of K2 that implements the traits we expect a host application to implement, rather than using the core implementations like our showcase app currently does. That would be a good starting point to having demonstrated how K2 works outside of Holochain.

so why not go the extra mile and make them reusable?

I really don't want people to use the memory op store in a binary. I was thinking this PR was about using it in tests but with the op type being defined as something other than the memory op. Kitsune expects that op data is persistent and it's only in-memory for unit tests and so that Kitsune isn't opinionated about how you store your data.

My plan was to set up an always-online node that just syncs with other people

If that computer has to restart because of a loss of power, or even just for software updates or perhaps a kernel issue - all the network data is gone. That might be acceptable for a demo but it certainly wouldn't be expected behavior by people in general.

if one doesn't already exist by then

I have already written one that uses the Fjall key-value database, which is why I'm defending the position that having a persistent store is practical outside of Holochain. I did run into the same serialization errors along the way that you're describing, it's not a trivial task, but it can certainly be done. That code isn't open source yet and I haven't finished figuring out how/when I'm going to do that - unfortunately it's unlikely that will be in the next two weeks though.

If you're happy that you are getting what you need from the memory op store then I don't object to you using it for your demo of course - but that's a different story to making the functionality available to people who don't understand the system as well as you do.

would you recommend I use the windtunnel op store you linked to instead of the one I'm currently using?

That op store has code in that depends on Wind Tunnel so it won't work outside of that environment. I think the useful part of that one is the post step to receiving data where it records metrics. That is the point where in a custom op store you could do the step you were asking about which is notify the host about ops being received.

@maackle
Copy link
Contributor Author

maackle commented Jul 30, 2025

I have already written one that uses the Fjall key-value database, which is why I'm defending the position that having a persistent store is practical outside of Holochain

Of course my ideal is to have a persistent op store, and I imagine it would be the ideal for just about anyone else. I'm only using the mem one because it's available and it works now.

I really don't want people to use the memory op store in a binary. I was thinking this PR was about using it in tests but with the op type being defined as something other than the memory op.

Yes, most normal use cases would want a persistent store, including mine. Still, I wouldn't go so far as to say there are no valid reasons for using a mem op store in production. Off the top of my head: imagine IoT devices that don't have persistent storage of their own and/or are extremely limited in memory, and want to do some ephemeral syncing of small amounts of data and don't need to install a database for that. p2p syncing of data is a very general pattern and I can't imagine anticipating all real world use cases up front.

Or even in the course of development of a custom op store, it's quite useful to have a simple-as-possible working reference implementation, both as guidance and also as something testable, so you can A/B test to find if the problem is in your own implementation. The more complex the reference implementation, the less useful it is.

I would like to have more example and/or ready-to-use code for Kitsune2 but we haven't had time to do that.

When you do please let me know! Until then I'll keep using the only op store that exists.

No further reply needed unless it's about wanting to use this, otherwise feel free to close.

Copy link

coderabbitai bot commented Aug 7, 2025

Walkthrough

This change refactors the in-memory operation store to use a generic, trait-based abstraction for operations, replacing the hardcoded MemoryOp type with a new MemoryOp trait and a TestMemoryOp implementation. All test and example usages are updated to use TestMemoryOp. Related imports, function signatures, and factory usages are adjusted throughout the codebase for consistency.

Changes

Cohort / File(s) Change Summary
Generic MemoryOp Store Refactor
crates/core/src/factories/mem_op_store.rs
Introduced MemoryOp trait; made op store generic over MemOp; renamed MemoryOp struct to TestMemoryOp; updated all store internals and records to use generics; added trait implementations and conversions.
Test Code: MemoryOp → TestMemoryOp
crates/core/src/factories/core_fetch/test.rs, crates/core/src/factories/core_fetch/test/incoming_request_queue.rs, crates/core/src/factories/core_fetch/test/incoming_response_queue.rs, crates/core/src/factories/core_fetch/test/outgoing_request_queue.rs, crates/core/src/factories/core_publish/test.rs, crates/core/src/factories/mem_op_store/test.rs, crates/core/tests/fetch.rs, crates/dht/src/dht/tests.rs, crates/dht/src/dht/tests/harness.rs, crates/dht/src/hash.rs, crates/dht/src/test.rs, crates/dht/src/time.rs, crates/gossip/src/gossip.rs, crates/gossip/src/harness.rs, crates/gossip/src/harness/op_store.rs, crates/gossip/src/respond/accept.rs, crates/gossip/src/respond/disc_sector_details_diff.rs, crates/gossip/src/respond/disc_sector_details_diff_response.rs, crates/gossip/src/respond/initiate.rs, crates/gossip/src/respond/ring_sector_details_diff.rs, crates/gossip/src/respond/ring_sector_details_diff_response.rs, crates/gossip/src/respond/tests.rs, crates/gossip/tests/historical_load.rs, crates/gossip/tests/initial_sync.rs, crates/kitsune2/tests/integration.rs
Updated all test code to use TestMemoryOp instead of MemoryOp; changed imports, factory usages, and function signatures as needed; no logic changes.
Factory/Builder Usage Update
crates/core/src/lib.rs, crates/dht/src/test.rs, crates/kitsune2/src/lib.rs
Updated instantiations of op store factories to explicitly use TestMemoryOp as the generic parameter; adjusted imports.
Showcase App and File Store
crates/kitsune2_showcase/src/app.rs, crates/kitsune2_showcase/src/app/file_op_store.rs
Switched all usages of MemoryOp to TestMemoryOp; updated factory and record generics; adjusted deserialization and op construction accordingly.
Error Message Improvements
crates/core/src/factories/core_bootstrap.rs, crates/transport_tx5/src/lib.rs
Enhanced error messages to include the problematic URL or string value in error context; no logic or control flow changes.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Code
    participant Factory as MemOpStoreFactory<TestMemoryOp>
    participant Store as Kitsune2MemoryOpStore<TestMemoryOp>
    participant Op as TestMemoryOp

    Test->>Factory: create()
    Factory->>Store: instantiate generic store
    Test->>Store: process_incoming_ops(Vec<Bytes>)
    Store->>Op: TestMemoryOp::from_bytes
    Op-->>Store: TestMemoryOp instance
    Store-->>Test: operation processed
    Test->>Store: retrieve_ops(...)
    Store->>Op: TestMemoryOp::to_bytes
    Store-->>Test: Vec<Bytes> (serialized ops)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Suggested reviewers

  • ThetaSinner
  • jost-s

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
crates/gossip/src/respond/accept.rs (1)

357-360: Avoid Timestamp::now() to keep tests deterministic

Using wall-clock time can introduce rare, timing-dependent failures (e.g., if two ops end up with identical timestamps on fast machines or when tests run close to a second boundary).

-            let op = TestMemoryOp::new(Timestamp::now(), vec![i; op_size]);
+            let op = TestMemoryOp::new(Timestamp::from_micros(1_000 + i as i64), vec![i; op_size]);
crates/core/src/factories/mem_op_store.rs (2)

109-132: Remove duplicate method implementations

These methods duplicate the trait implementation without adding value. Since TestMemoryOp already implements MemoryOp trait with public methods, these wrapper methods are redundant.

Apply this diff to remove the duplication:

-impl TestMemoryOp {
-    /// Deserialize a [TestMemoryOp] from bytes.
-    pub fn from_bytes(bytes: Bytes) -> Self {
-        MemoryOp::from_bytes(bytes).unwrap()
-    }
-
-    /// Serialize a [TestMemoryOp] to bytes.
-    pub fn to_bytes(&self) -> Bytes {
-        MemoryOp::to_bytes(self).unwrap()
-    }
-
-    /// Compute the op id for this op.
-    ///
-    /// Note that this produces predictable op ids for testing purposes.
-    /// It is simply the first 32 bytes of the op data.
-    pub fn compute_op_id(&self) -> OpId {
-        MemoryOp::compute_op_id(self)
-    }
-
-    /// Get the creation timestamp of the op.
-    pub fn created_at(&self) -> Timestamp {
-        self.created_at
-    }
-}
-
 impl TestMemoryOp {

If these methods are needed for backward compatibility, consider documenting that rationale.


289-291: Update error message to reflect generic implementation

The error message references the old type name which no longer exists.

-                K2Error::other("Failed to deserialize op data, are you using `Kitsune2MemoryOp`s?")
+                K2Error::other(format!("Failed to deserialize op data: {}", e))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5510376 and 2a3d1e2.

📒 Files selected for processing (32)
  • crates/core/src/factories/core_bootstrap.rs (1 hunks)
  • crates/core/src/factories/core_fetch/test.rs (2 hunks)
  • crates/core/src/factories/core_fetch/test/incoming_request_queue.rs (3 hunks)
  • crates/core/src/factories/core_fetch/test/incoming_response_queue.rs (4 hunks)
  • crates/core/src/factories/core_fetch/test/outgoing_request_queue.rs (1 hunks)
  • crates/core/src/factories/core_publish/test.rs (4 hunks)
  • crates/core/src/factories/mem_op_store.rs (10 hunks)
  • crates/core/src/factories/mem_op_store/test.rs (4 hunks)
  • crates/core/src/lib.rs (2 hunks)
  • crates/core/tests/fetch.rs (2 hunks)
  • crates/dht/src/dht/tests.rs (15 hunks)
  • crates/dht/src/dht/tests/harness.rs (3 hunks)
  • crates/dht/src/hash.rs (2 hunks)
  • crates/dht/src/test.rs (2 hunks)
  • crates/dht/src/time.rs (13 hunks)
  • crates/gossip/src/gossip.rs (8 hunks)
  • crates/gossip/src/harness.rs (3 hunks)
  • crates/gossip/src/harness/op_store.rs (3 hunks)
  • crates/gossip/src/respond/accept.rs (2 hunks)
  • crates/gossip/src/respond/disc_sector_details_diff.rs (2 hunks)
  • crates/gossip/src/respond/disc_sector_details_diff_response.rs (2 hunks)
  • crates/gossip/src/respond/initiate.rs (2 hunks)
  • crates/gossip/src/respond/ring_sector_details_diff.rs (2 hunks)
  • crates/gossip/src/respond/ring_sector_details_diff_response.rs (2 hunks)
  • crates/gossip/src/respond/tests.rs (5 hunks)
  • crates/gossip/tests/historical_load.rs (2 hunks)
  • crates/gossip/tests/initial_sync.rs (3 hunks)
  • crates/kitsune2/src/lib.rs (2 hunks)
  • crates/kitsune2/tests/integration.rs (2 hunks)
  • crates/kitsune2_showcase/src/app.rs (4 hunks)
  • crates/kitsune2_showcase/src/app/file_op_store.rs (3 hunks)
  • crates/transport_tx5/src/lib.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: cdunster
PR: holochain/kitsune2#290
File: crates/core/src/factories/mem_peer_store/test.rs:317-346
Timestamp: 2025-08-06T07:54:53.186Z
Learning: The `Inner::remove` method in `mem_peer_store` returns `Option<Arc<AgentInfoSigned>>`, while the `PeerStore::remove` trait method returns `BoxFut<'_, K2Result<()>>`. The `Inner::remove` method is called directly on `Inner` instances in tests.
📚 Learning: the `inner::remove` method in `mem_peer_store` returns `option>`, while the `pe...
Learnt from: cdunster
PR: holochain/kitsune2#290
File: crates/core/src/factories/mem_peer_store/test.rs:317-346
Timestamp: 2025-08-06T07:54:53.186Z
Learning: The `Inner::remove` method in `mem_peer_store` returns `Option<Arc<AgentInfoSigned>>`, while the `PeerStore::remove` trait method returns `BoxFut<'_, K2Result<()>>`. The `Inner::remove` method is called directly on `Inner` instances in tests.

Applied to files:

  • crates/dht/src/dht/tests.rs
  • crates/gossip/src/respond/ring_sector_details_diff_response.rs
  • crates/gossip/src/respond/disc_sector_details_diff_response.rs
  • crates/gossip/src/respond/disc_sector_details_diff.rs
  • crates/gossip/src/respond/accept.rs
  • crates/gossip/src/respond/initiate.rs
  • crates/core/src/factories/core_fetch/test/incoming_request_queue.rs
  • crates/dht/src/hash.rs
  • crates/kitsune2/src/lib.rs
  • crates/gossip/src/respond/ring_sector_details_diff.rs
  • crates/gossip/src/respond/tests.rs
  • crates/gossip/src/gossip.rs
  • crates/core/src/factories/core_publish/test.rs
  • crates/dht/src/time.rs
  • crates/kitsune2_showcase/src/app.rs
  • crates/gossip/tests/initial_sync.rs
  • crates/core/src/lib.rs
  • crates/core/src/factories/core_fetch/test/incoming_response_queue.rs
  • crates/dht/src/dht/tests/harness.rs
  • crates/core/tests/fetch.rs
  • crates/gossip/src/harness.rs
  • crates/dht/src/test.rs
  • crates/gossip/src/harness/op_store.rs
  • crates/core/src/factories/mem_op_store/test.rs
  • crates/kitsune2_showcase/src/app/file_op_store.rs
  • crates/core/src/factories/mem_op_store.rs
📚 Learning: in the kitsune2 codebase, for test-only functionality that won't be exposed as public api, direct ac...
Learnt from: cdunster
PR: holochain/kitsune2#290
File: crates/core/src/factories/mem_blocks/test.rs:46-46
Timestamp: 2025-08-05T13:46:15.678Z
Learning: In the Kitsune2 codebase, for test-only functionality that won't be exposed as public API, direct access to internal implementation details (like accessing internal mutex with .0.lock()) is acceptable when the implementation is unlikely to change, rather than adding public methods solely for testing purposes.

Applied to files:

  • crates/dht/src/dht/tests.rs
  • crates/gossip/src/respond/ring_sector_details_diff_response.rs
  • crates/gossip/src/respond/disc_sector_details_diff_response.rs
  • crates/gossip/src/respond/accept.rs
  • crates/gossip/src/respond/initiate.rs
  • crates/dht/src/hash.rs
  • crates/kitsune2/src/lib.rs
  • crates/gossip/src/respond/tests.rs
  • crates/gossip/src/gossip.rs
  • crates/kitsune2/tests/integration.rs
  • crates/core/src/factories/core_fetch/test.rs
  • crates/dht/src/time.rs
  • crates/kitsune2_showcase/src/app.rs
  • crates/gossip/tests/initial_sync.rs
  • crates/core/src/factories/core_fetch/test/incoming_response_queue.rs
  • crates/dht/src/dht/tests/harness.rs
  • crates/core/tests/fetch.rs
  • crates/gossip/src/harness.rs
  • crates/dht/src/test.rs
  • crates/core/src/factories/mem_op_store/test.rs
  • crates/kitsune2_showcase/src/app/file_op_store.rs
  • crates/core/src/factories/mem_op_store.rs
🧬 Code Graph Analysis (4)
crates/core/src/factories/core_fetch/test/outgoing_request_queue.rs (1)
crates/core/src/factories/core_fetch/test.rs (1)
  • make_op (16-18)
crates/kitsune2/tests/integration.rs (2)
crates/api/src/timestamp.rs (1)
  • from_micros (36-38)
crates/test_utils/src/lib.rs (1)
  • random_bytes (32-37)
crates/dht/src/dht/tests/harness.rs (1)
crates/core/src/factories/mem_op_store.rs (4)
  • from (145-148)
  • from (152-156)
  • from (192-197)
  • from (201-203)
crates/core/tests/fetch.rs (5)
crates/core/src/lib.rs (2)
  • default_test_builder (154-171)
  • new (71-82)
crates/kitsune2/tests/integration.rs (1)
  • create_op_list (25-36)
crates/gossip/src/harness.rs (1)
  • ops (143-150)
crates/core/src/factories/mem_op_store.rs (3)
  • new (136-141)
  • new (181-188)
  • new (237-242)
crates/test_utils/src/lib.rs (1)
  • random_bytes (32-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: static
🔇 Additional comments (59)
crates/core/src/factories/core_bootstrap.rs (1)

83-98: Enhanced error messaging with dynamic URL context.

This improvement includes the actual server_url value in error messages, making debugging URL parsing and validation failures much more informative.

crates/transport_tx5/src/lib.rs (1)

36-39: Improved error context for SigUrl parsing failures.

Including the actual input string in the error message provides better diagnostics for debugging URL parsing issues.

crates/gossip/src/respond/initiate.rs (2)

187-187: Updated import to use TestMemoryOp for test operations.

This change aligns with the broader refactor where MemoryOp was generalized to a trait with TestMemoryOp as the concrete test implementation.


612-612: Consistent usage of TestMemoryOp in test code.

The operation creation now uses TestMemoryOp::new which is consistent with the new type system where test operations use the dedicated test implementation.

crates/gossip/src/respond/ring_sector_details_diff_response.rs (2)

195-195: Updated import to use TestMemoryOp for test operations.

Consistent with the refactor where MemoryOp became a trait and TestMemoryOp serves as the concrete test implementation.


271-271: Consistent usage of TestMemoryOp in test code.

The operation instantiation now uses TestMemoryOp::new which aligns with the new generic operation store design.

crates/dht/src/hash.rs (2)

456-456: Updated import to use TestMemoryOp for test operations.

This change is consistent with the systematic refactor where MemoryOp was generalized to a trait with TestMemoryOp as the concrete test implementation.


651-651: Consistent usage of TestMemoryOp in test code.

The operation creation now uses TestMemoryOp::new which maintains consistency with the new generic operation store architecture.

crates/gossip/src/respond/disc_sector_details_diff.rs (2)

200-201: Import rename aligns tests with new generic op abstraction

Switching to TestMemoryOp keeps the test compiling after the store-generic refactor. Nothing else to flag here.


247-249: Good use of deterministic timestamp in test op creation

Using Timestamp::from_micros(100 + i) produces stable, reproducible test data – much better than relying on Timestamp::now().

crates/gossip/src/respond/accept.rs (1)

325-326: Import rename acknowledged

kitsune2_core::factories::TestMemoryOp is the correct concrete type after the refactor.

crates/gossip/src/respond/disc_sector_details_diff_response.rs (2)

188-189: Import update looks correct

No issues detected with bringing TestMemoryOp into the test module.


258-260: Deterministic timestamp – good

Keeping the timestamp calculation deterministic maintains test repeatability.

crates/gossip/src/respond/ring_sector_details_diff.rs (2)

237-238: Import update to TestMemoryOp is appropriate

Change is consistent with the new generic op store.


301-305: 👍 deterministic, boundary-relative timestamps

Basing the timestamp on disc_boundary rather than now() keeps tests reproducible and meaningful.

crates/core/src/factories/core_fetch/test/outgoing_request_queue.rs (1)

4-7: LGTM - Clean import reorganization

The consolidation of factory-related imports improves code organization by grouping related modules together.

crates/dht/src/test.rs (2)

6-8: LGTM - Updated import for generic refactor

The addition of TestMemoryOp to the imports aligns with the generic memory op store abstraction.


32-32: LGTM - Explicit generic type parameter specification

The explicit specification of TestMemoryOp as the generic parameter is required for the new generic factory design and is appropriate for test code.

crates/gossip/tests/historical_load.rs (2)

6-6: LGTM - Updated import for test operation type

The addition of TestMemoryOp import supports the transition to the generic memory op store abstraction.


59-59: LGTM - Consistent use of TestMemoryOp

The change from MemoryOp::new to TestMemoryOp::new aligns with the generic refactor while maintaining identical test behavior.

crates/gossip/src/gossip.rs (2)

448-448: LGTM - Updated test imports

The addition of TestMemoryOp import supports the generic memory op store refactor while maintaining access to both types as needed.


527-728: LGTM - Systematic TestMemoryOp adoption

The consistent replacement of MemoryOp::new with TestMemoryOp::new across all test functions maintains identical test behavior while adapting to the new generic operation abstraction.

crates/dht/src/dht/tests.rs (2)

6-6: LGTM - Updated DHT test imports

The addition of TestMemoryOp import enables the transition to the generic memory op store while maintaining compatibility.


24-515: LGTM - Comprehensive TestMemoryOp integration

The systematic replacement of MemoryOp::new with TestMemoryOp::new across all DHT test functions is well-executed and maintains identical test semantics while supporting the generic operation abstraction. The changes are consistent and comprehensive across the entire test suite.

crates/gossip/src/respond/tests.rs (2)

19-19: LGTM! Import updated correctly.

The import has been correctly updated to use TestMemoryOp as part of the generic operation store refactor.


56-56: LGTM! Operation construction updated consistently.

All instances of MemoryOp::new have been correctly replaced with TestMemoryOp::new. The test logic remains unchanged, which is appropriate for this refactor.

Also applies to: 162-162, 280-280, 401-401

crates/core/src/factories/core_publish/test.rs (2)

4-4: LGTM! Import updated correctly.

The import has been correctly updated to include TestMemoryOp as part of the generic operation store refactor.


37-37: LGTM! Operation construction updated consistently.

All instances of MemoryOp::new have been correctly replaced with TestMemoryOp::new. The test functionality remains unchanged, which is appropriate for this refactor.

Also applies to: 39-39, 90-90, 92-92, 321-321

crates/dht/src/time.rs (2)

721-721: LGTM! Import updated correctly.

The import has been correctly updated to use TestMemoryOp in the test module as part of the generic operation store refactor.


900-910: LGTM! Test operation construction updated consistently.

All test functions have been correctly updated to use TestMemoryOp::new instead of MemoryOp::new. The test logic and functionality remain unchanged, which is appropriate for this refactor.

Also applies to: 985-987, 1035-1047, 1098-1104, 1153-1163, 1182-1187, 1219-1221, 1247-1253, 1310-1325, 1396-1401, 1471-1477, 1580-1591

crates/core/src/factories/core_fetch/test.rs (2)

7-7: LGTM! Import updated correctly.

The import has been correctly updated to use TestMemoryOp as part of the generic operation store refactor.


16-17: LGTM! Test utility function updated consistently.

The make_op function has been correctly updated to return TestMemoryOp and use TestMemoryOp::new. This maintains the same functionality while supporting the generic operation store refactor.

crates/gossip/tests/initial_sync.rs (2)

6-6: LGTM! Import updated correctly.

The import has been correctly updated to include both MemoryOp and TestMemoryOp as part of the generic operation store refactor.


33-34: LGTM! Test operation construction updated consistently.

All instances of MemoryOp::new in the integration tests have been correctly replaced with TestMemoryOp::new. The sync test functionality and timing remain unchanged, which is appropriate for this refactor.

Also applies to: 96-97

crates/core/src/lib.rs (2)

165-165: LGTM! Proper generic type specification.

The explicit type parameter <TestMemoryOp> correctly specifies the concrete operation type for the generic memory operation store factory, aligning with the refactoring to make Kitsune2MemoryOpStore generic over its op type.


178-178: LGTM! Import correctly added.

The import of TestMemoryOp from the factories module supports the usage on line 165 and maintains consistency with the generic abstraction changes.

crates/kitsune2/tests/integration.rs (2)

10-10: LGTM! Import correctly updated.

The import now includes both the MemoryOp trait and the concrete TestMemoryOp implementation, which is appropriate for test code that needs to create specific test operations.


29-31: LGTM! Operation creation updated correctly.

The change from MemoryOp::new to TestMemoryOp::new correctly uses the concrete test implementation while maintaining the same functionality for creating test operations.

crates/core/src/factories/core_fetch/test/incoming_response_queue.rs (3)

6-6: LGTM! Import updated correctly.

The import now includes TestMemoryOp alongside the trait import, supporting the usage in the test functions below.


96-99: LGTM! Test operation creation updated.

The changes from MemoryOp::new to TestMemoryOp::new correctly use the concrete test implementation while maintaining the same test logic and functionality.


159-159: LGTM! Consistent operation creation updates.

Both instances correctly change from MemoryOp::new to TestMemoryOp::new, maintaining consistency with the refactoring across all test functions in the file.

Also applies to: 234-234

crates/core/src/factories/core_fetch/test/incoming_request_queue.rs (3)

5-5: LGTM! Import updated for generic factory usage.

The import now includes MemOpStoreFactory and TestMemoryOp, which are needed for the explicit generic instantiation and type annotations used in the test code.


31-31: LGTM! Generic factory instantiation.

The explicit type parameter <TestMemoryOp> correctly specifies the concrete operation type for the generic memory operation store factory, ensuring type safety in the test setup.


223-223: LGTM! Explicit type annotation for clarity.

The explicit type annotation Vec<TestMemoryOp> makes the expected operation type clear and ensures type safety when processing fetch responses in the test code.

crates/dht/src/dht/tests/harness.rs (3)

8-8: LGTM! Import updated correctly.

The import change from MemoryOp to TestMemoryOp aligns with the refactoring to use the concrete test implementation in the DHT test harness.


52-52: LGTM! Method parameter type updated.

The parameter type change from MemoryOp to TestMemoryOp correctly uses the concrete test implementation while maintaining the same functionality for injecting operations into the DHT test harness.


419-419: LGTM! Type conversion updated consistently.

The change from MemoryOp::from(op) to TestMemoryOp::from(op) correctly uses the concrete test implementation's conversion method while maintaining the same functionality for transferring operations between DHT instances.

crates/gossip/src/harness.rs (1)

11-11: LGTM! Consistent refactor from MemoryOp to TestMemoryOp.

The import, function signature, and conversion logic are all properly updated to use the new TestMemoryOp type. This aligns with the PR's goal of making the memory op store generic.

Also applies to: 120-120, 146-146

crates/gossip/src/harness/op_store.rs (1)

66-66: LGTM! Proper usage of TestMemoryOp in conversions.

The conversions correctly use TestMemoryOp for deserializing operation data and reconstructing MetaOp instances, consistent with the refactoring goals.

Also applies to: 172-175

crates/kitsune2_showcase/src/app.rs (1)

7-10: LGTM! Consistent usage of TestMemoryOp throughout the application.

The changes properly update the showcase app to use TestMemoryOp for operation creation, conversion, and deserialization. The import correctly includes both MemoryOp (likely the trait) and TestMemoryOp (the concrete implementation).

Also applies to: 278-278, 352-352, 394-394

crates/core/tests/fetch.rs (1)

2-3: LGTM! Proper test updates for the generic refactor.

The test correctly updates to use TestMemoryOp while maintaining the same test logic. The function signature and operation creation are consistent with the new type system.

Also applies to: 21-21, 25-25

crates/core/src/factories/mem_op_store/test.rs (1)

1-2: Excellent demonstration of the generic memory op store refactor.

The test file properly showcases the new generic Kitsune2MemoryOpStore<TestMemoryOp> usage while maintaining all existing test logic. The updates are comprehensive and consistent:

  • Helper functions updated to use TestMemoryOp
  • Store instances properly parameterized with TestMemoryOp
  • Deserialization correctly targets TestMemoryOp

This demonstrates the successful transition from hardcoded types to the generic trait-based system.

Also applies to: 7-7, 12-12, 18-18, 20-20, 31-32, 39-39, 60-60, 90-90

crates/kitsune2_showcase/src/app/file_op_store.rs (3)

7-9: LGTM!

The imports correctly reference the new generic types and TestMemoryOp implementation.


19-19: LGTM!

The generic parameter is properly specified as TestMemoryOp and initialization follows the new pattern correctly.

Also applies to: 26-26


77-78: LGTM!

The conversion correctly uses the generic MemoryOpRecord::<TestMemoryOp>::new() constructor and the trait method to_bytes().

crates/core/src/factories/mem_op_store.rs (4)

25-35: LGTM!

The generic implementation with PhantomData is the correct pattern for zero-cost type parameterization.


79-107: LGTM!

The TestMemoryOp correctly implements the MemoryOp trait with appropriate error handling using Infallible for test scenarios.


206-224: Well-designed trait abstraction

The MemoryOp trait provides a clean abstraction with appropriate bounds and flexibility through the associated Error type. This enables the generic implementation while maintaining type safety.


271-524: LGTM!

The OpStore implementation correctly uses trait methods throughout, properly handling serialization/deserialization and maintaining the generic abstraction.

@@ -3,6 +3,7 @@ use kitsune2_api::{
BoxFut, Builder, Config, DhtArc, DynOpStore, K2Error, K2Result, MetaOp,
OpId, OpStore, OpStoreFactory, SpaceId, Timestamp,
};
use kitsune2_core::factories::MemoryOp;
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify import consistency with the refactoring.

The import shows MemoryOp while the actual usage in lines 66 and 172 uses TestMemoryOp. Please confirm whether this import should be TestMemoryOp for consistency with the rest of the codebase.


🏁 Script executed:

#!/bin/bash
# Check what MemoryOp refers to in the factories module
rg "pub.*MemoryOp" crates/core/src/factories/
rg "pub.*TestMemoryOp" crates/core/src/factories/

Length of output: 895


We need more context from op_store.rs to confirm whether the import of MemoryOp (trait) is intentional or a typo for TestMemoryOp (struct). Let’s inspect the file to see how MemoryOp is used versus where TestMemoryOp is constructed.


🏁 Script executed:

#!/bin/bash
set -e

# Show imports and usages in op_store.rs
echo "=== Imports and first 50 lines ==="
sed -n '1,50p' crates/gossip/src/harness/op_store.rs

echo -e "\n=== Usages of MemoryOp ==="
rg -n "MemoryOp" crates/gossip/src/harness/op_store.rs || true

echo -e "\n=== Usages of TestMemoryOp ==="
rg -n "TestMemoryOp" crates/gossip/src/harness/op_store.rs || true

Length of output: 3287


Remove the unused MemoryOp import in op_store.rs

The use kitsune2_core::factories::MemoryOp; on line 6 isn’t referenced by any trait bounds or code in this module—only TestMemoryOp is actually used (via its full path). To keep imports accurate:

  • Delete line 6:
    - use kitsune2_core::factories::MemoryOp;
  • (Optional) If you prefer, you can import TestMemoryOp for readability:
    use kitsune2_core::factories::TestMemoryOp;
    and then update the two fully‐qualified uses at lines 66 and 172 to just TestMemoryOp.
🤖 Prompt for AI Agents
In crates/gossip/src/harness/op_store.rs at line 6, remove the unused import
statement for MemoryOp since it is not referenced anywhere in the module.
Optionally, add an import for TestMemoryOp to improve readability and update its
fully-qualified usages at lines 66 and 172 to just TestMemoryOp.

Comment on lines +17 to 18
factories::{self, MemOpStoreFactory, TestMemoryOp},
Ed25519Verifier,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Exporting test-only op type from public API is risky

TestMemoryOp lives in the factories test helpers; wiring it into the public default_builder() makes that test struct effectively part of the production API. Down-stream crates pulling Kitsune2 will now depend on a type that is explicitly “for tests”.

-use kitsune2_core::{
-    factories::{self, MemOpStoreFactory, TestMemoryOp},
+use kitsune2_core::{
+    factories::{self, MemOpStoreFactory},

And later:

-        op_store: MemOpStoreFactory::<TestMemoryOp>::create(),
+        // Use the generic mem-op store with the default in-crate op type.
+        // Consider exposing a `ProdMemoryOp` or require callers to specify their own.
+        op_store: MemOpStoreFactory::create(),

Alternatively, make default_builder() generic over the op type so production code can choose a suitable concrete type without importing test utilities.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
factories::{self, MemOpStoreFactory, TestMemoryOp},
Ed25519Verifier,
// crates/kitsune2/src/lib.rs
use kitsune2_core::{
factories::{self, MemOpStoreFactory},
Ed25519Verifier,
};
pub fn default_builder() -> Builder {
Builder::new()
// Use the generic mem-op store with the default in-crate op type.
// Consider exposing a `ProdMemoryOp` or require callers to specify their own.
.op_store(MemOpStoreFactory::create())
.verifier(Ed25519Verifier::new())
}
🤖 Prompt for AI Agents
In crates/kitsune2/src/lib.rs around lines 17 to 18, the issue is that the
test-only type TestMemoryOp is being exported and used in the public API via
default_builder(), which exposes test utilities to production code. To fix this,
remove TestMemoryOp from the public exports and refactor default_builder() to be
generic over the operation type, allowing production code to specify its own
concrete type without depending on test-only types.

Comment on lines +50 to 51
op_store: MemOpStoreFactory::<TestMemoryOp>::create(),
peer_meta_store: factories::MemPeerMetaStoreFactory::create(),
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Follow-up: require callers to supply an op type or provide a prod-ready default

Continuing from the above, consider:

  1. Adding pub struct DefaultOp inside kitsune2_core meant for real usage.
  2. Or make default_builder() generic:
pub fn default_builder<O: MemoryOp + 'static>() -> Builder {}

This prevents accidental leakage of test-only code into production binaries.

🤖 Prompt for AI Agents
In crates/kitsune2/src/lib.rs around lines 50 to 51, the current code uses a
test-only operation type directly, which risks leaking test code into
production. To fix this, either define a public DefaultOp struct in
kitsune2_core for production use or make the default_builder function generic
over an operation type parameter constrained by the MemoryOp trait. This ensures
callers explicitly specify the operation type or use a proper production
default, preventing accidental inclusion of test-only types.

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