Skip to content

refactor(core): collapse speculative flow-store scaffolding - #47

Merged
lao merged 2 commits into
mainfrom
simplify-flow-store
Jul 30, 2026
Merged

refactor(core): collapse speculative flow-store scaffolding#47
lao merged 2 commits into
mainfrom
simplify-flow-store

Conversation

@lao

@lao lao commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Removes the durable/multi-instance-Store scaffolding from the conversation flow engine — abstraction built for a future that isn't here and that no caller touches. Behavior is unchanged; only the in-memory single-instance path remains.

Cuts (from the repo-wide over-engineering audit)

  • ConversationStore + expirer interfaces — one implementation each, never injected (the ctor hardcoded memConversationStore, no setter). Folded the map directly into conversationManager.
  • ConversationState.Version — write-only field; only ever self-incremented in Set, read nowhere in prod or tests. Existed for a future compare-and-swap path.
  • 256-way striped locks + inlined FNV-1a hasher → a single mutex. sweep now holds it across the scan, so the expiredKeys snapshot + per-key re-check collapses into one pass.
  • sweepRecovered — with no custom store, sweep has no panic path, so the recover guard guarded nothing.

Verification

  • make all green (fmt + vet + lint + test-race, incl. _examples).
  • Flow start/advance/timeout/cancel, sweeper lifecycle, and the concurrent-sweep-vs-advance / no-lost-updates tests all pass under -race. Pure-abstraction tests (Version bump, striped-lock bounds, expirer snapshot, store-panic recovery) removed with the code they covered.

Net: ~190 fewer lines, no dependency change.

Summary by CodeRabbit

  • Bug Fixes
    • Improved conversation state reliability by managing active conversations with safer in-memory synchronization.
    • Expired conversations are now cleaned up consistently, including during background maintenance.
    • Improved handling of conversation completion, cancellation, TTL refreshes, and concurrent updates.
    • Reduced the risk of stalled conversation processing after unexpected errors.

The conversation flow engine carried a durable/multi-instance Store seam
that nothing built against. Cut it down to what the single-instance,
in-memory v1 actually uses:

- Remove the ConversationStore and expirer interfaces (one impl each,
  never injected) — fold memConversationStore's map straight into
  conversationManager.
- Drop ConversationState.Version — write-only, only ever self-incremented,
  read nowhere; it existed for a future compare-and-swap path.
- Replace the 256-way striped locks + inlined FNV-1a hasher with a single
  mutex. Sweep now holds it across the scan, so the expiredKeys snapshot +
  per-key re-check goes away.
- Remove sweepRecovered — with no custom store, sweep has no panic path.

Behavior is unchanged; the flow/advance/sweeper tests still pass under
-race. Net ~190 fewer lines, no dependency change.
@botbooter-test

botbooter-test Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. 4e46df2e

  • Fetch changed files
  • Build repository context
  • Generate review
  • Post findings

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cd60d132-af58-47d4-9d9f-47d904a02af8

📥 Commits

Reviewing files that changed from the base of the PR and between 4e46df2 and f4bf5c6.

📒 Files selected for processing (1)
  • internal/core/flow_test.go
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch simplify-flow-store

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.

@botbooter-test botbooter-test Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: approve · Grade: 9/10

To reach a higher grade: Refresh the stale 'shard'/'striped shards' wording in flow.go's Validate doc to reflect the single-mutex model.

📝 Summary of changes

Clean refactor that removes speculative Store/expirer/Version/striped-lock scaffolding from the conversation engine, collapsing it to a single mutex + map. The concurrency reasoning is sound: sweep now holds the manager mutex across the whole scan (safe to delete during range in Go), which also eliminates the old snapshot-then-recheck dance; withLock still releases on panic via defer; transitionLocked continues to run user validators/callbacks under the lock with the same reaping asymmetry. startSweeper's panic-recovery removal is justified — sweep now contains only map/time operations with no user code, so there is no panic path to guard. Tests are updated consistently and the -race coverage is preserved.

One out-of-diff follow-up worth noting (not a blocking finding since the file isn't touched here): flow.go's Validate doc still warns that a slow validator "blocks the shard for its whole duration, stalling ... every other one whose key hashes to the same one of the striped shards." With the new single global mutex that warning is both stale (no shards) and understated — a slow validator now stalls every conversation, not just same-shard ones. Refreshing that comment would keep the docs honest with the new locking model.

✅ No issues found.


Reviewed by prbooter. Comment /recheck to re-run, /security-review for a security audit, /auto-fix to have me attempt the fixes, or /clean to remove my comments.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@internal/core/flow_test.go`:
- Around line 105-111: Direct conversationManager get/set calls in flow tests
bypass the required locking contract. Add getConvState and setConvState helpers
that invoke get/set inside withLock, then replace every unguarded
bot.conversations.get/set call throughout this test file with the corresponding
helper while preserving existing assertions and state updates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c43b3c41-4efd-4ddd-a708-01e1ff8a7557

📥 Commits

Reviewing files that changed from the base of the PR and between 830d7c5 and 4e46df2.

📒 Files selected for processing (4)
  • internal/core/conversation.go
  • internal/core/conversation_test.go
  • internal/core/core.go
  • internal/core/flow_test.go

Comment thread internal/core/flow_test.go Outdated
get/set/del are documented as requiring the manager mutex; flow_test was
calling them unguarded. Add getConvState/setConvState that wrap the access
in withLock so every site honors the contract.
@lao
lao merged commit 50d8f58 into main Jul 30, 2026
2 checks passed
@lao
lao deleted the simplify-flow-store branch July 30, 2026 11:28
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.

1 participant