Skip to content

fix(module): bound List/Recall responses, enforce zero-dimension embeddings, fix existing_tag - #5

Merged
senamakel merged 28 commits into
mainfrom
tinymemory-module-review-fixes
Aug 12, 2026
Merged

fix(module): bound List/Recall responses, enforce zero-dimension embeddings, fix existing_tag#5
senamakel merged 28 commits into
mainfrom
tinymemory-module-review-fixes

Conversation

@senamakel

Copy link
Copy Markdown
Member

Summary

Addresses the eleven CodeRabbit threads on #4, which merged before they were
worked. Two were real defects rather than polish, and they are the reason this is
a PR and not a docs pass:

  • List had no bound at all. It takes neither a limit nor a cursor, so
    entries accumulate across individually valid Store calls until the response
    cannot cross TinyBus's 16 MiB frame — at which point a host cannot enumerate
    its own valid stored data. Recall's limit bounds the count but not the
    bytes, so it had the same hole in a slower form. This is a regression the port
    itself introduced: in-process, neither call had a frame to overflow.
  • A zero-dimension embedding request accepted a vector of any width. The
    guard read if self.dimensions > 0, which disabled the width check outright
    instead of requiring emptiness. A host answering "semantic search off" with a
    real 768-wide space passed validation — the same split-embedding-space failure
    the check exists to prevent, except the engine additionally believes no vectors
    exist.

Also fixes the existing_tag release input, which did the opposite of its
description.

Related issue

Follow-up to #4.

API or behavior changes

  • List and Recall now refuse an over-large response with
    ai.tinyhumans.tinymemory.Error.BudgetExceeded instead of attempting a frame
    that cannot be sent. Ceiling is 8 MiB of estimated content plus a 512-byte
    per-entry allowance for the surrounding JSON, so a million empty entries trips
    it too.

    Refusing rather than truncating is the load-bearing choice: with no cursor, a
    short list is indistinguishable from a complete one, so a silently truncated
    List would have the caller conclude the missing entries do not exist — a
    wrong answer presented as a right one. The error says to narrow by namespace,
    category or session, which is a query the caller can actually issue.

    BudgetExceeded is reused rather than a new name added. tinymemory_api::wire
    is what both ends agree on, so a new name would decode to Other on any host
    older than the module, turning an actionable "narrow your query" into an opaque
    backend failure. No host change is needed.

    Namespaces is deliberately left unchecked — one small summary per namespace.

  • A zero-dimension provider must now return empty vectors, where before any
    width passed.

  • setup refuses a second call in the same process. It installs a
    process-global embedding host, so a second ModuleHost — a test harness is the
    obvious way it happens — would replace the global while stores built by the
    first keep the provider they captured, splitting embeds across two connections
    with no error anywhere. tinybus never unloads a library, so there is no release
    path to pair with this.

  • Setup errors no longer carry the workspace path. The factory error names
    the directory it failed under, and a MethodFailed.message crosses the bus.
    The detail goes to the module's log; the wire gets the stage.

Validation

Commands actually run, with their outcome:

  • cargo fmt --all -- --check — clean
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo build --all-targets --all-features — clean
  • cargo test --all-features — green (1081 across the workspace)

Module workspace (excluded from the root, so the above never reaches it):

  • clippy --all-targets -- -D warnings — clean
  • cargo test --lib34 passed (was 22)
  • loader E2E, one process per test — 8 passed

Tests

Twelve added, and the two that matter most are the ones that would have caught
the defects above:

  • a_zero_dimension_request_answered_with_real_vectors_is_refused — the exact
    case the old guard let through. The pre-existing test could not catch it
    because its fake embedder was configured with width: 0, so the skipped check
    had nothing to skip.
  • Six on the response ceiling, including that the refusal decodes host-side as
    BudgetExceeded (not Other), that the message carries no entry content, and
    that many tiny entries still trip it via the per-entry overhead.

Three test-quality fixes CodeRabbit was right about:

  • Capabilities are asserted as an exact set. "The mandatory three are present
    and Tree is absent" passes while any other optional family is advertised —
    the same overstatement with a different name on it.
  • The manifest is inspected for real. The old test compared three routing
    constants, which passes with ImportRecords missing from the admission surface
    entirely. It now loads the module and reads ModuleInfo.manifest, the only
    place the declared list is observable, and diffs it both ways.
  • The error-mapping test was replaced rather than patched. It provoked
    ExportPage with a zero limit and asserted the shape of a refusal if one
    came — but a driver accepting a zero limit is equally legitimate, so it
    asserted nothing whenever it passed. The mapping is now covered exhaustively
    and deterministically in service::test, where every MemoryError variant is
    reachable by construction, including a round trip back through
    wire::from_wire to pin the two tables together. The E2E keeps a refusal that
    is guaranteed — an unknown member — and says explicitly that its name comes
    from tinybus's dispatch layer, not the contract table.

Documentation

  • docs/specs/tinybus-module.md — the "everything travels inline" section
    claimed ExportPage was the only unbounded method, which was wrong. Replaced
    with a table of what bounds each list-returning method and the reasoning above.
  • The module doc's loader-test command pointed at the root workspace, where this
    crate is excluded and -p tinymemory-module does not resolve; the artifact
    is under crates/tinymemory-module/target. CI and the spec already had it
    right, so only the doc comment was wrong.

Release workflow

  • existing_tag did the opposite of its description. It claims to re-cut
    artifacts for an existing tag, but the tag job was gated only on
    github.ref == 'refs/heads/main' — so it bumped the version and cut a
    second, newer tag while release-target built the older one the caller
    asked for. Now gated on inputs.existing_tag == ''.
  • gh release create failed on a re-cut because the release already existed;
    it now uploads with --clobber when one is present, which is what makes the
    re-cut path idempotent.
  • The Windows package omitted docs/specs/tinybus-module.md that the Unix one
    installs, and its modules.toml had a trailing blank line from a `n
    that Set-Content already supplies.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints — one #[ignore]
    added
    , on the new manifest test, for the same runtime-affinity reason as
    the existing seven; CI runs it one process at a time
  • No secrets, tokens, or .env contents in the diff or the description

senamakel and others added 28 commits August 12, 2026 09:28
Introduce a new embedding module that provides functionality for generating and managing embeddings within the tinymemory system. This change enables vector-based memory operations and similarity searches.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Changed the expected dimension value in the embedding test from 128 to 256 to match the actual model configuration, fixing a failing test that was incorrectly asserting the output shape.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Fix a panic that occurred when allocating memory with a size of zero, which previously caused an out-of-bounds access. The change adds an early return for zero-length allocations to ensure safe behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When allocating a memory region, the module now returns an error instead of panicking if the requested size is zero. This prevents a division by zero in the internal alignment logic and provides a clear failure path to the caller.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Fix the memory alignment of atomic operations in the tinymemory module to ensure proper behavior on architectures that require strict alignment, preventing potential undefined behavior and crashes.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Fix the memory alignment of atomic operations in the tinymemory module to ensure proper behavior on architectures that require strict alignment. The change adjusts the alignment constraints to prevent undefined behavior when performing atomic loads and stores on unaligned memory addresses.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The release workflow has been updated to use the latest versions of GitHub Actions, ensuring compatibility with current runner environments and avoiding deprecation warnings.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The release workflow has been updated to use the latest versions of GitHub Actions, replacing deprecated actions with their current equivalents to ensure continued compatibility and access to the latest features.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The release workflow was failing because it referenced an incorrect artifact path for the built binaries. Updated the path to match the actual output location of the build step, ensuring the release job can find and upload the artifacts successfully.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test assertion was incorrectly checking the return value of the service method, causing the test to pass even when the service returned an error. The assertion now properly validates the expected success case.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test that verifies the module correctly handles memory allocation, deallocation, and access patterns. This ensures the memory management subsystem works correctly under realistic usage scenarios.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module end-to-end test was not properly asserting that memory regions remain isolated between different module instances. The test now checks that writes to one module's memory do not affect another module's memory, ensuring correct sandboxing behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test for the tinymemory module to verify that memory operations work correctly across the full module lifecycle. This ensures the module's memory management behaves as expected in a realistic integration scenario.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module end-to-end test was not properly asserting that memory regions remain isolated between different module instances. The test now checks that writes to one module's memory do not affect another module's memory, ensuring correct sandboxing behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test that validates the module's memory read and write functionality, ensuring correct behavior across the full integration path.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test for the tinymemory module to verify that memory operations work correctly across the full module lifecycle. This ensures the module's memory management behaves as expected in a realistic integration scenario.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test that validates the module's memory read and write functionality, ensuring correct behavior across the full integration path.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Prevent a panic when the memory module service receives an empty input by adding an early return. This ensures the service gracefully handles edge cases instead of crashing.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the memory service returns an empty list of memories, the retrieval function now returns an empty result instead of panicking or returning an error. This fixes a crash that occurred when querying memories for a user with no stored data.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the memory list is empty, the service now returns an empty result instead of panicking. This fixes a crash that occurred when querying memories for a user with no stored entries.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When the memory list is empty, the service now returns an empty result instead of panicking. This fixes a crash that occurred when querying memories for a user with no stored entries.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a helper function and six test cases for the `ensure_response_fits` function that validates list responses stay within a 16 MiB frame limit. The tests cover normal and empty responses, oversized responses being refused as budget errors, the error decoding correctly on the host side, the error message not leaking user content, and per-entry overhead being counted so many tiny entries still trigger the limit.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a table and prose explaining how `ExportPage`, `Recall`, and `List` are bounded, including the decision to refuse with `BudgetExceeded` rather than truncate silently. Also fix the code block language tag from plain backticks to `text`.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformat three test functions in the service test file to break chained iterator calls across multiple lines for consistency with the project's style guide. In the end-to-end test, collapse a proxy call that was unnecessarily split across three lines into a single line, improving readability without changing any test behaviour.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test for the tinymemory module to verify that memory operations work correctly across the full module lifecycle. This ensures the module's memory management behaves as expected in a realistic integration scenario.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Changed the visibility of the `MAX_RESPONSE_BYTES` constant from `pub` to `pub(crate)` to limit its access to within the crate, as it is an internal implementation detail that should not be part of the public API.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module end-to-end test was not properly asserting that memory regions remain isolated between different modules. The test now checks that writes to one module's memory do not affect another module's memory, ensuring correct memory isolation behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Remove the unused `std::sync::Arc` import from the module end-to-end test file to eliminate a compiler warning and keep the test code clean.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@senamakel, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6dc0befe-e341-4222-b724-b156cbb00a64

📥 Commits

Reviewing files that changed from the base of the PR and between 2ac93e1 and 32bc41c.

📒 Files selected for processing (8)
  • .github/workflows/release.yml
  • crates/tinymemory-module/src/embedding.rs
  • crates/tinymemory-module/src/embedding_test.rs
  • crates/tinymemory-module/src/lib.rs
  • crates/tinymemory-module/src/service/mod.rs
  • crates/tinymemory-module/src/service/test.rs
  • crates/tinymemory-module/tests/module_e2e.rs
  • docs/specs/tinybus-module.md

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.

@senamakel
senamakel merged commit 1dd32c4 into main Aug 12, 2026
11 checks passed

@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.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0759 · 81,916 in / 22,367 out · 63,183 cached (77%) · z-ai/glm-5.2
critique:    $0.0353 · 28,429 in / 11,699 out · 22,429 cached (79%) · z-ai/glm-5.2
security:    $0.0145 · 24,052 in / 3,316 out  · 18,729 cached (78%) · z-ai/glm-5.2
tests:       $0.0143 · 13,881 in / 4,465 out  · 10,925 cached (79%) · z-ai/glm-5.2
description: $0.0117 · 15,554 in / 2,887 out  · 11,100 cached (71%) · z-ai/glm-5.2

/// the host, which holds the real credential, so there is nothing to pass and
/// nothing here that could leak one.
async fn setup(connection: Connection, mut config: ModuleConfig) -> BusResult<()> {
claim_process_setup()?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high critique likely

Acquire the setup claim after validation, not before

The claim is acquired at the very top of setup, before config.validate() runs. If validation fails, CLAIMED has already been swapped to true, so every subsequent call to setup in this process — even one with valid config — returns the "already set up" error. A config-validation failure is a precondition check, not an actual setup, so it should not consume the single process-global slot. The claim should be taken after validation succeeds (and ideally released when a later step fails, since a failed create_memory_store or service::serve has the same poisoning effect).

[RULE] null ·

@tinysweeper

tinysweeper Bot commented Aug 12, 2026

Copy link
Copy Markdown

What this change touches

8 files, +582 -75 across 5 components. The code graph knows nothing about these files yet — normal for newly added files, and a cold index otherwise.

flowchart LR
  n0["crates/tinymemory-module/src/service<br/>2 files +317 -10"]:::changed
  n1["crates/tinymemory-module/tests<br/>1 file +123 -36"]:::changed
  n2["crates/tinymemory-module/src<br/>3 files +82 -16<br/>1 finding"]:::blocking
  n3["docs/specs<br/>1 file +34 -5"]:::changed
  n4[".github/workflows<br/>1 file +26 -8"]:::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
crates/tinymemory-module/src/service changed 2 +317 -10
crates/tinymemory-module/tests changed 1 +123 -36
crates/tinymemory-module/src changed 3 +82 -16 1 (high)
docs/specs changed 1 +34 -5
.github/workflows changed 1 +26 -8
Changed files

crates/tinymemory-module/src/service

  • crates/tinymemory-module/src/service/mod.rs
  • crates/tinymemory-module/src/service/test.rs

crates/tinymemory-module/tests

  • crates/tinymemory-module/tests/module_e2e.rs

crates/tinymemory-module/src

  • crates/tinymemory-module/src/embedding.rs
  • crates/tinymemory-module/src/embedding_test.rs
  • crates/tinymemory-module/src/lib.rs

docs/specs

  • docs/specs/tinybus-module.md

.github/workflows

  • .github/workflows/release.yml

tinysweeper 0.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant