Skip to content

feat(drivers): tinyflows-drivers — StateStore and Checkpointer over tinystoragedrivers ports - #108

Merged
senamakel merged 20 commits into
mainfrom
storage-drivers
Oct 9, 2026
Merged

senamakel merged 20 commits into
mainfrom
storage-drivers

Conversation

@senamakel

@senamakel senamakel commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Summary

This is the first tinyflows step of the storage-drivers migration. A new unpublished crate, tinyflows-drivers, adds two backends for the engine over a tinystoragedrivers document port. The published tinyflows engine is unchanged (no diff in crates/tinyflows). A host can then keep flow-run state and graph checkpoints in whichever backend it opened (SQLite on a desktop, MongoDB in the cloud, memory in tests), scoped per tenant.

  • DriverStateStore, a StateStore. Each key is one document {key, value} in flows_state. Keys the driver cannot use as ids are refused as capability errors rather than hashed, so two keys never share a slot.

  • DriverCheckpointer<State>, a graph Checkpointer. It is ported from TinyAgents' merged DriverCheckpointer (feat(storage): tinystoragedrivers adapters for the harness store and graph checkpointer tinyagents#333), including everything its two review rounds hardened:

    • one document per checkpoint with a compare-and-swap per-thread seq, so listing is insertion order and the latest write wins for a reused id, as in the SQLite and file backends;
    • get_scoped pushed down to one indexed (thread, namespace, seq) query;
    • pending writes merged with merge_writes under compare-and-swap;
    • length-prefixed key components and an injective namespace encoding;
    • over-long ids hashed with SHA-256;
    • a bulk state_history that reads the namespace's checkpoints and pending writes in two queries and walks the lineage in memory, instead of two round trips per ancestor.

    The lease methods are not ported, because tinyflows' trait has none.

  • Default collections (flows_state, flows_graph_*) stay clear of TinyAgents' graph_* collections, so both can share one scoped backend.

  • Dependency: tinystoragedrivers-core is a git dependency at tag v0.4.0, not a vendored copy. A host that already vendors the storage crates (OpenHuman, through tinyagents) points that URL at its one copy with [patch."https://github.com/tinyhumansai/tinystoragedrivers"], the same way it unifies tinytools. Then there is exactly one DocumentStore trait in the graph.

  • Why a separate crate: the published tinyflows package cannot carry a git dependency, even an optional one, so cargo publish would fail. tinyflows-drivers is publish = false, needs Rust 1.88 (the storage crates' MSRV), and leaves the engine's dependencies and its 1.85 MSRV untouched. cargo package -p tinyflows still succeeds.

Next steps: put tinyflows-sqlite's flows.db/jobs.db on the SQLite driver's native mode, and shim tinyflows-adaptive's Storage onto the storage config and scopes.

Tests

  • DriverCheckpointer passes the same behavioural checks as the SQLite checkpointer, ported from tinyflows-sqlite's checkpoint_tests.rs:

    • latest-write reads and insertion-order listing;
    • thread isolation;
    • namespace-scoped reads;
    • append-once data writes vs upserting control-plane writes;
    • thread deletion;
    • pruning.

    Added on top:

    • tenant-scope and collection-prefix isolation;
    • namespace scoping when checkpoint ids repeat;
    • no write merging across lookalike namespaces;
    • unambiguous and hashed keys;
    • corrupt records reported as checkpoint errors.
  • Bulk state_history: newest-first lineage, off-lineage siblings and other namespaces excluded, the write ledger preferred, limit, a cycle guard, and agreement with the trait default's hop-by-hop walk.

  • delete_thread drops pending writes; delete_checkpoints removes only the named ids and their writes, leaving other threads alone (plus its empty-ids early return).

  • DriverStateStore: round trips, a stored null, scope and collection isolation, and unstorable keys.

cargo test -p tinyflows-drivers                                   # 18 passed
cargo package --locked -p tinyflows --no-verify                   # the engine still packages
cargo test --all-features && cargo test                           # all passed
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all --check

senamakel and others added 8 commits October 9, 2026 08:09
Add the checkpoint drivers module to the graph checkpoint package.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add the checkpoint drivers module to the graph checkpoint package.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a capability layer that exposes checkpoint drivers through the
caps module, letting graphs persist and restore state via pluggable
backends. The checkpoint module now routes through these drivers instead
of hardcoding driver behaviour.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The driver state store now reports every storage failure as a capability
error instead of splitting invalid input into a validation error, since a
key the driver cannot store as an id is a capability limit rather than
caller input. The storage-drivers feature also enables sha2, which the
driver crate needs for its id handling.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests exercising the checkpoint drivers to verify state is saved and
restored correctly across round-trips.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reordered imports and reformatted long expressions in the storage
driver checkpointer and its tests. The pending-write test now builds
its fixture through the PendingWrite constructor instead of a
hand-rolled JSON fallback, which keeps the test aligned with the
type's actual API.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The driver test referenced the resume write index through the crate's public
path, which fails to resolve when the test is compiled inside the crate. It now
uses the crate-relative path so the test builds in both contexts.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add CHANGELOG and README entries for the new `storage-drivers` cargo feature, covering `caps::DriverStateStore` and `graph::checkpoint::DriverCheckpointer` over a tinystoragedrivers document port. The feature is off by default and requires Rust 1.88.

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

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T06:03:24.868601Z 9fd522e New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

  • Run on-demand review

This review includes 11 billable files and costs up to $2.75.

Or wait 16 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ef38888c-e76d-4168-b8ba-5729b5a80d9c
📥 Commits

Reviewing files that changed from the base of the PR and between 3f3e341 and 9fd522e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • CHANGELOG.md
  • README.md
  • crates/tinyflows-drivers/Cargo.toml
  • crates/tinyflows-drivers/README.md
  • crates/tinyflows-drivers/src/checkpoint.rs
  • crates/tinyflows-drivers/src/checkpoint_history_tests.rs
  • crates/tinyflows-drivers/src/checkpoint_keys.rs
  • crates/tinyflows-drivers/src/checkpoint_tests.rs
  • crates/tinyflows-drivers/src/lib.rs
  • crates/tinyflows-drivers/src/state_store.rs
  • crates/tinyflows-drivers/src/state_store_tests.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ad2e70b4-5b51-459f-86c0-b37c2e37a286
📥 Commits

Reviewing files that changed from the base of the PR and between a48f7c5 and 3f3e341.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • CHANGELOG.md
  • README.md
  • crates/tinyflows/Cargo.toml
  • crates/tinyflows/src/caps/drivers.rs
  • crates/tinyflows/src/caps/drivers_tests.rs
  • crates/tinyflows/src/caps/mod.rs
  • crates/tinyflows/src/graph/checkpoint/drivers.rs
  • crates/tinyflows/src/graph/checkpoint/drivers_tests.rs
  • crates/tinyflows/src/graph/checkpoint/mod.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds optional document-backed implementations for state storage and graph checkpointing. The feature is disabled by default and requires Rust 1.88. It includes tests and documentation for the storage behavior.

Changes

Document-backed storage

Layer / File(s) Summary
Feature wiring and state storage
crates/tinyflows/Cargo.toml, crates/tinyflows/src/caps/*, README.md, CHANGELOG.md
The optional storage-drivers feature enables DriverStateStore. It reads and writes values in a tenant-scoped document collection. Tests cover stored values, isolation, and error handling. Documentation describes the feature and its requirements.
Checkpoint storage and lookup
crates/tinyflows/src/graph/checkpoint/drivers.rs, crates/tinyflows/src/graph/checkpoint/drivers_tests.rs, crates/tinyflows/src/graph/checkpoint/mod.rs
DriverCheckpointer stores checkpoints in prefixed collections. It reserves per-thread sequence numbers with compare-and-swap and supports checkpoint lookup, listing, and namespace-scoped reads. Tests cover ordering, isolation, and key encoding.
Checkpoint deletion and pending writes
crates/tinyflows/src/graph/checkpoint/drivers.rs, crates/tinyflows/src/graph/checkpoint/drivers_tests.rs
The checkpointer deletes thread and selected-checkpoint data and merges pending writes with compare-and-swap retries. Tests cover deletion, pruning, write merging, and corrupt records.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Host
  participant DriverCheckpointer
  participant DocumentStore
  Host->>DriverCheckpointer: Provide tenant-scoped DocumentStore handle
  DriverCheckpointer->>DocumentStore: Read per-thread sequence counter
  DocumentStore-->>DriverCheckpointer: Return counter document
  DriverCheckpointer->>DocumentStore: Compare-and-swap sequence reservation
  DocumentStore-->>DriverCheckpointer: Return reservation result
  DriverCheckpointer->>DocumentStore: Store checkpoint record under thread and sequence key
Loading

Merge Risk

Merge Risk: ⚪ Minimal · up to 3f3e3

No actionable issue was established for the optional storage drivers. The change is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 3f3e3

The integration is opt-in and uses host-provided storage handles. However, checkpoint deletion and pending-write cleanup are separate operations, so interruption or concurrent thread reuse can leave inconsistent recovery data. Tenant isolation also depends on the storage provider and correct host configuration.

Retained concerns

  • Medium · reliability · inferred: The new checkpointer deletes checkpoint documents before separately deleting their pending-write ledgers. Cancellation or failure between operations can leave durable orphan writes; concurrent recreation of a thread can also place new writes within the delayed cleanup filter. Explicit-ID write reads do not check checkpoint existence. This creates a checkpoint-data lifecycle and recovery-consistency concern within the supplied storage scope, not an established cross-tenant vulnerability. SQLite cleanup is transactional, while a related partial-cleanup weakness already exists in the unchanged file backend. Resume first requires a checkpoint and may recover completion information from inline writes, so loss of the separate ledger does not invariably repeat side effects.

Security review details

Security Blast Radius

  • inferred — Effective exposure is the state and checkpoint data accessible through the injected document handle and chosen collections. Thread-wide cleanup reaches every namespace within that thread. A tenant-scoped provider should contain this to one tenant, but provider scope enforcement and production construction were not independently verified. The reported high-fanout ranges are test helpers, not demonstrated production authority expansion.

Security Findings and Attack Paths

  • inferred — The supported failure path is interrupted or interleaved deletion leaving an orphan ledger or removing a newly created ledger. Exploitation would require access to affected workflow lifecycle operations or concurrent execution within the same storage scope; no unauthenticated entrypoint, cross-tenant access, or privilege gain was established. Resume rejects a missing checkpoint before consulting its ledger, limiting direct execution from orphan writes.

Trust Boundaries and Controls

  • observed — The documented trust boundary places backend credentials and tenant selection with the host. The adapters preserve the supplied handle and add namespace filtering and compound-key separation for checkpoints. State keys pass unchanged to the provider, so rejection of unsupported IDs is delegated rather than implemented locally. Tests contain assertions for separate tenant scopes and collections, but those assertions do not establish every provider's behavior.

Resilience and Maintainability Implications

  • observed — Recovery prefers the separately persisted completion ledger but falls back to inline pending writes when that ledger is empty. The unchanged SQLite backend deletes checkpoints and ledgers in one transaction; the unchanged file backend performs separate file operations and already has partial-cleanup exposure. These differences prevent treating all existing backends as equally atomic or the new concern as a universal regression.

Hardening Proposals

  • proposed — Define a deletion protocol that remains recoverable after interruption and cannot clean up a later thread generation. Possible designs include a provider transaction or durable generation fencing with idempotent cleanup. Validate the chosen protocol against cancellation, second-operation failure, and concurrent recreation.
  • proposed — Document and validate the host/provider integration requirements: immutable tenant-scoped handles, opaque document IDs, atomic conditional writes, and trusted collection selection. Treat these as explicit prerequisites rather than implying that constructor use alone establishes isolation.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 55.32% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 47 functions across 6 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the addition of DriverStateStore and DriverCheckpointer over the tinystoragedrivers ports. It accurately describes the main change.
Full details: Docstring Coverage

Explanation

Docstring coverage is 55.32% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 47 functions across 6 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checks the keys at night,
Then stores a state just right.
Checkpoints line up by thread and name,
While pending writes retain their frame.
I nibble clover, hop, and say:
“The document store is set today!”

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

@tinysweeper

tinysweeper Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 5 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Ready for maintainer review
Priority: medium
Reviewed head: 9fd522e1a25a
Updated: 1791525625 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 4 Active findings 3
Tests 3 Noted findings 0
Documentation 3 Resolved findings 33
Configuration 1 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

  • medium · critique · Keep the new crate compatible with the repository MSRV — The repository rules require Rust 1.85, but this entry explicitly introduces a workspace crate requiring Rust 1.88. That makes the new crate incompatible with the declared MSRV for (CHANGELOG\.md:22)
  • medium · tests · Drive a flow through the driver checkpointer and state store end to end — Every test here pokes the adapter's trait methods directly against an in-memory document store. Nothing exercises the adapter plugged into `engine::run_with_checkpointer` / `resume (crates/tinyflows\-drivers/src/checkpoint\_tests\.rs)
  • medium · description · Drive a flow through the driver checkpointer and state store end to end — Both adapters are only exercised against the in-memory backend at the unit level. Nothing in the diff runs an actual engine flow (`run_with_checkpointer` / `resume_with_checkpointe (\(pull request description\))

Resolved this pass

  • Exercise pending-write cleanup when deleting a thread
  • Keep the storage-driver feature compatible with the MSRV
  • Keep the storage feature compatible with the declared MSRV
  • Cover delete\_checkpoints, including the empty-ids early return
  • Split the module before it exceeds the source-file limit
  • Split the test file below 500 lines
  • Use non-ordered IDs to test insertion ordering
  • Split the checkpoint tests below the 500-line limit
  • Keep the drivers crate compatible with the workspace MSRV
  • Return no writes for an unknown checkpoint
  • Start the test file with the required wildcard import
  • Exercise pending-write cleanup when deleting a thread
  • Keep the storage-driver feature compatible with the MSRV
  • Keep the storage feature compatible with the declared MSRV
  • Cover delete\_checkpoints, including the empty-ids early return
  • Split the module before it exceeds the source-file limit
  • Split the test file below 500 lines
  • Use non-ordered IDs to test insertion ordering
  • Split the checkpoint tests below the 500-line limit
  • Keep the drivers crate compatible with the workspace MSRV
  • Return no writes for an unknown checkpoint
  • Start the test file with the required wildcard import
  • Exercise pending-write cleanup when deleting a thread
  • Keep the storage-driver feature compatible with the MSRV
  • Keep the storage feature compatible with the declared MSRV
  • Cover delete_checkpoints, including the empty-ids early return
  • Split the module before it exceeds the source-file limit
  • Split the test file below 500 lines
  • Use non-ordered IDs to test insertion ordering
  • Split the checkpoint tests below the 500-line limit
  • Keep the drivers crate compatible with the workspace MSRV
  • Return no writes for an unknown checkpoint
  • Start the test file with the required wildcard import

Before merge

None.

Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This changelog entry accurately describes the new driver crate, but it documents an MSRV that conflicts with the repository’s declared Rust 1.85 requirement. The change is not safe to merge until the crate is made compatible or the repository policy is intentionally updated. (21 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: CHANGELOG\.md — Keep the new crate compatible with the repository MSRV

security

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No changed file has any attack surface. 1 file was not security-reviewed: CHANGELOG.md (prose or tabular data).

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This revision is the drivers crate with its tests already split into sibling _tests.rs files under the line limit, ordered-id tests, write-cleanup and delete_checkpoints coverage, so nearly all earlier findings are resolved. The one still-standing concern is that no test drives a real flow through DriverCheckpointer/DriverStateStore end to end; the change otherwise looks sound and mergeable. (1 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinyflows\-drivers/src/checkpoint\_tests\.rs — Drive a flow through the driver checkpointer and state store end to end

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The new tinyflows-drivers crate matches its description: DriverStateStore and DriverCheckpointer over a tinystoragedrivers document port, with the tests, keys, CAS sequence and history walk the body claims. Most earlier findings (delete_checkpoints coverage, delete_thread write cleanup, test-file splitting, non-ordered id tests, unknown-checkpoint writes, MSRV handling via a separate 1.88 crate) are addressed in this revision. Two items remain: no integration test drives the two backends through a real flow, and the new files carry no GPL-3.0-or-later licensing as the repo rule requires. (1 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: \(pull request description\) — Drive a flow through the driver checkpointer and state store end to end

e2e

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The revision adds the tinyflows-drivers crate with a StateStore and Checkpointer over tinystoragedrivers, now split into small modules with thorough sibling test files; the earlier unit-level findings (write cleanup on delete, delete_checkpoints coverage, insertion-order ids, file splitting, MSRV handling via a separate crate) are addressed. What remains uncovered is end to end: no test or CI job drives a running flow through these adapters — the engine's integration harness never touches DriverStateStore or DriverCheckpointer, and there is no e2e workflow in the tree — so the persisted layout, scoping and resume path are exercised only at the unit level. That coverage gap stands from the last review. (1 already reported on an earlier push) (4 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.001253
  • Tokens: 102041 input · 5603 output · 2918 cached · 0 embedding
Head State Pass summary
3f3e34170871 ready for maintainer review 5 active finding(s), 0 resolved finding(s) (at 1791523177)
b4c89eb672c2 ready for maintainer review 13 active finding(s), 46 resolved finding(s) (at 1791524136)
7ce87400875f ready for maintainer review 10 active finding(s), 137 resolved finding(s) (at 1791525427)
9fd522e1a25a ready for maintainer review 3 active finding(s), 33 resolved finding(s) (at 1791525625)

tinysweeper 0.1.0

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f3e341708

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinyflows/Cargo.toml Outdated
Comment thread crates/tinyflows-drivers/src/checkpoint.rs

@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.0210 · 441,459 in / 25,204 out · 42,105 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0100 · 182,815 in / 12,358 out · 22,079 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0104 · 186,299 in / 9,288 out  · 19,770 cached (11%) · gpt-5.6-luna
tests:       $0.0001 · 17,049 in  / 659 out    · 64 cached (0%)      · glm-5.3-flash
description: $0.0001 · 17,154 in  / 371 out    · 64 cached (0%)      · glm-5.3-flash
e2e:         $0.0002 · 20,562 in  / 335 out    · 64 cached (0%)      · glm-5.3-flash

Comment thread crates/tinyflows-drivers/src/checkpoint_tests.rs
Comment thread README.md Outdated
Comment thread crates/tinyflows/Cargo.toml Outdated
Comment thread crates/tinyflows-drivers/src/checkpoint.rs
@tinysweeper tinysweeper Bot added the priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. label Oct 9, 2026
senamakel and others added 7 commits October 9, 2026 08:25
Introduce checkpoint and state store driver traits so graphs can persist
and restore execution state through pluggable backends. The capabilities
are wired into the driver registry and covered by tests.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The optional storage-drivers feature and its DriverStateStore re-export are
gone, along with the tinystoragedrivers-core dependency they pulled in. The
storage ports remain defined by the StateStore trait, so hosts can still
supply their own backend without the extra crate.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a checkpoint driver and a state store abstraction so workflow
execution state can be persisted and restored. The new modules ship with
tests covering the checkpoint round-trip behaviour.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The driver now overrides state_history to fetch a namespace's checkpoints
and pending writes with one indexed query each, then walks the lineage in
memory, replacing the trait default's two round trips per ancestor on
remote backends. A by_namespace index and a stored ns_key field back the
new query, and the write ledger is preferred over inline writes to match
resolved_writes.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Move the merge_writes import out of the grouped tinyflows::graph use
statement into its own line, matching the crate's import ordering.

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

Add tests for deleting a thread and its pending writes, deleting named
checkpoints without touching siblings or other threads, and walking a
lineage newest-first in a single read including cycle handling. The
history test also checks the batched result matches the trait default's
hop-by-hop walk.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the cloned single-element slice with std::slice::from_ref in the state history test, avoiding an unnecessary clone of the ledger write.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel senamakel changed the title feat(storage): DriverStateStore and DriverCheckpointer over tinystoragedrivers ports feat(drivers): tinyflows-drivers — StateStore and Checkpointer over tinystoragedrivers ports Oct 9, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b4c89eb672

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinyflows-drivers/src/checkpoint.rs
Comment thread crates/tinyflows-drivers/src/checkpoint_tests.rs Outdated
Comment thread crates/tinyflows-drivers/src/state_store.rs

@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.0278 · 588,844 in / 40,630 out · 56,551 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0155 · 312,767 in / 22,242 out · 33,402 cached (11%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0115 · 182,977 in / 14,288 out · 18,029 cached (10%) · gpt-5.6-luna
tests:       $0.0002 · 22,058 in  / 573 out    · 1,856 cached (8%)   · glm-5.3-flash
description: $0.0002 · 22,343 in  / 913 out    · 1,408 cached (6%)   · glm-5.3-flash
e2e:         $0.0002 · 25,518 in  / 913 out    · 1,728 cached (7%)   · glm-5.3-flash

Comment thread crates/tinyflows-drivers/src/checkpoint.rs
Comment thread crates/tinyflows-drivers/src/checkpoint_tests.rs Outdated
Comment thread crates/tinyflows-drivers/src/checkpoint_tests.rs Outdated
Comment thread crates/tinyflows-drivers/src/checkpoint.rs
Comment thread crates/tinyflows-drivers/src/checkpoint.rs
Comment thread crates/tinyflows-drivers/src/checkpoint_tests.rs Outdated
Comment thread crates/tinyflows-drivers/Cargo.toml
Comment thread crates/tinyflows-drivers/src/checkpoint.rs
senamakel and others added 3 commits October 9, 2026 08:40
Adds a history view over stored checkpoints and a helper for enumerating
checkpoint keys, so callers can inspect past states and discover existing
checkpoints without knowing their identifiers in advance.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests covering checkpoint save and restore behaviour in the state
store, verifying that persisted state round-trips correctly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a state store test asserting that a document without a value field
surfaces as a capability error rather than missing state, and tidy the
checkpoint test module ordering and formatting.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add the StorageError import to the checkpoint test module so the tests can
reference the storage error type.

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ce8740087

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +380 to +383
let live = self
.docs
.count(&self.checkpoints, &Filter::eq("thread", thread))
.await

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid one remote query per retained thread counter

On a remote document store such as MongoDB, list_threads performs a serialized count request for every counter document. Because delete_thread deliberately retains these counters, the cost grows with every thread ID ever created rather than the number of live threads; a tenant with 10,000 deleted threads therefore incurs more than 10,000 round trips just to list an empty set. Derive the live thread IDs from a bulk checkpoint query or maintain their liveness without this per-counter query.

Useful? React with 👍 / 👎.

@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.0242 · 491,109 in / 40,447 out · 60,942 cached (12%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0151 · 270,626 in / 22,122 out · 36,451 cached (13%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0083 · 125,000 in / 12,940 out · 19,819 cached (16%) · gpt-5.6-luna
tests:       $0.0002 · 22,698 in  / 989 out    · 1,536 cached (7%)   · glm-5.3-flash
description: $0.0002 · 22,960 in  / 701 out    · 1,408 cached (6%)   · glm-5.3-flash
e2e:         $0.0002 · 26,157 in  / 932 out    · 1,728 cached (7%)   · glm-5.3-flash

.await
.unwrap();

store.delete_thread("doomed").await.unwrap();

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 medium critique confident

Exercise pending-write cleanup when deleting a thread

This test inserts checkpoints but no pending writes before deleting the thread, so it would still pass if delete_thread removed checkpoints while leaving that thread's writes orphaned. Add writes for the doomed thread and assert they are gone, while also confirming another thread's writes remain.


Additional security observation

priority medium confident

Exercise pending-write cleanup when deleting a thread

[RULE] missing-cleanup-test

This deletion test creates checkpoints but never creates pending writes for the deleted thread. It therefore cannot catch an implementation that removes checkpoint records while leaving orphaned writes behind. Add writes for doomed, delete the thread, and assert that get_writes no longer returns them while another thread's writes remain.

[RULE] missing-delete-cleanup-coverage ·

/// deleted; it must take that thread's writes with it and leave every other
/// thread alone.
#[tokio::test]
async fn deleting_a_thread_removes_its_checkpoints_and_leaves_others() {

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 medium critique confident

Cover delete_checkpoints, including the empty-ids early return

The new suite exercises delete_thread but never calls delete_checkpoints. That leaves both deletion of selected checkpoint IDs and the documented empty-ID path untested, so regressions in either behavior can pass this suite. Add cases that delete selected checkpoints and verify unrelated namespaces/threads remain, including a call with an empty ID list.


Additional security observation

priority medium confident

Cover delete_checkpoints, including the empty-ids early return

[RULE] missing-delete-test

The new tests exercise delete_thread but do not exercise the separate delete_checkpoints operation, including its empty-ID early-return path. A regression in that API could therefore pass this suite; add focused coverage for deleting selected checkpoints and for an empty ID list.

[RULE] missing-delete-checkpoints-coverage ·

.map(|m| m.checkpoint_id)
.collect();
assert_eq!(left, vec!["b".to_string()]);
assert!(

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 medium critique confident

Cover delete_checkpoints, including the empty-ids early return

The empty-IDs case is now covered, but the deletion assertion checks only checkpoint a. The test deletes both a and c, so an implementation that removes c from the checkpoint list while leaving its pending writes behind would still pass. Assert that both named checkpoints have no writes after deletion.

[RULE] incomplete-test-coverage ·

)))
}

async fn get_writes(&self, config: &CheckpointConfig) -> Result<Vec<PendingWrite>> {

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 medium critique confident

Return no writes for an unknown checkpoint

resolve_write_target returns an explicitly supplied checkpoint id without checking that the checkpoint exists, and this method then reads the write ledger directly. A caller can first call put_writes for an arbitrary id (or read after the checkpoint has been removed) and get_writes will return those writes, violating the Checkpointer::get_writes contract that unknown checkpoints return an empty vector. Verify the scoped checkpoint exists before loading its ledger.

[RULE] unknown-checkpoint-writes ·

.iter()
.map(|tuple| tuple.checkpoint.checkpoint_id.as_str())
.collect();
assert_eq!(ids, vec!["c", "b", "a"]);

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 medium critique confident

Use non-ordered IDs to test insertion ordering

The lineage IDs are inserted and expected in alphabetical order (a, b, c), so this does not distinguish walking the parent lineage from an implementation that sorts IDs in descending order. Use deliberately non-ordered IDs (for example, a root z, child a, and grandchild m) so the assertion fails for ID-based ordering.

[RULE] insufficient-test-discrimination ·

Comment on lines +3 to +4
use super::tests::{checkpoint, store};
use super::*;

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 medium security confident

Start the test file with the required wildcard import

The repository rule requires test files to start with use super::*;, but the helper import precedes it. Swap these imports so the file follows the required test-file layout.

Suggested change
use super::tests::{checkpoint, store};
use super::*;
use super::*;
use super::tests::{checkpoint, store};

[RULE] test-file-convention ·

async fn deleting_checkpoints_removes_only_the_named_ones_and_their_writes() {
let saver = store();
assert_eq!(saver.delete_checkpoints("t", &[]).await.unwrap(), 0);
for (thread, id) in [("t", "a"), ("t", "b"), ("t", "c"), ("other", "a")] {

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 medium security confident

Use non-ordered IDs to test insertion ordering

The deletion fixture inserts checkpoint IDs in lexical order and only asserts that the surviving ID is b. This cannot expose an implementation that accidentally derives ordering from the identifier or insertion sequence. Use deliberately non-ordered IDs and assert the documented ordering explicitly.

[RULE] insufficient-ordering-coverage ·

mod checkpoint_keys;
mod state_store;

pub use checkpoint::{DEFAULT_PREFIX, DriverCheckpointer};

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 medium e2e uncertain

Drive a flow through the driver checkpointer and state store end to end

DriverStateStore and DriverCheckpointer are host-facing adapters whose whole point is to be plugged into engine::run_with_checkpointer / resume_with_checkpointer and Capabilities::state. No end-to-end test reaches that: the harness is entirely in crates/tinyflows and never constructs a DriverCheckpointer or DriverStateStore (the candidate hits are lexical matches on words like source, thread, namespace), and there is no e2e workflow in the tree at all. Every guarantee the new code makes — CAS seq reservation, namespace-scoped resume, write-ledger precedence in state_history — is currently verified only against the adapter's own trait methods, not against a flow that runs, checkpoints, and resumes through it. A test would have to run a small graph with the driver checkpointer and state store wired in, complete a superstep, then resume on a fresh handle from the same backing store and observe the flow continue from the persisted checkpoint/state.

[RULE] e2e-uncovered ·

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

@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.0013 · 102,041 in / 5,603 out · 2,918 cached (3%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0004 · 6,740 in   / 1,285 out · 2,598 cached (39%) · gpt-5.6-luna, glm-5.3-flash
tests:       $0.0002 · 22,741 in  / 1,259 out · 64 cached (0%)     · glm-5.3-flash
description: $0.0002 · 23,003 in  / 926 out   · 64 cached (0%)     · glm-5.3-flash
e2e:         $0.0002 · 26,200 in  / 800 out   · 64 cached (0%)     · glm-5.3-flash

Comment thread CHANGELOG.md
`state_history` in two queries, length-prefixes every key component and
hashes over-long ids with SHA-256. A separate crate rather than an engine
feature because the published `tinyflows` package cannot carry a git
dependency; the engine is unchanged and keeps its MSRV, this crate needs

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 medium critique confident

Keep the new crate compatible with the repository MSRV

The repository rules require Rust 1.85, but this entry explicitly introduces a workspace crate requiring Rust 1.88. That makes the new crate incompatible with the declared MSRV for users and CI environments pinned to 1.85. Either lower the crate's requirement to Rust 1.85 or update the repository's MSRV policy and all affected compatibility guarantees together.

[RULE] msrv-compatibility ·

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9fd522e1a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +134 to +136
Some(found) => (
found.doc.get("next").and_then(Value::as_u64).unwrap_or(0),
found.unchanged(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject malformed counters instead of resetting the sequence

When an existing thread-counter document has a missing, negative, or non-integer next, this silently treats it as zero and successfully overwrites the counter before inserting the checkpoint. For a thread with existing checkpoints, subsequent puts then collide with old low sequence IDs or create a checkpoint ordered behind the actual latest record, so a successful write may be invisible to resume. Return a checkpoint error for a malformed existing counter rather than mutating it as though the thread were new.

Useful? React with 👍 / 👎.

@senamakel
senamakel merged commit 74d6c38 into main Oct 9, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant