Skip to content

fix(state): make fork migration parent links deterministic#2476

Closed
cyq1017 wants to merge 1 commit into
Hmbown:mainfrom
cyq1017:codex/fix-2082-fork-migration
Closed

fix(state): make fork migration parent links deterministic#2476
cyq1017 wants to merge 1 commit into
Hmbown:mainfrom
cyq1017:codex/fix-2082-fork-migration

Conversation

@cyq1017

@cyq1017 cyq1017 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Problem

#2082's main fork support is already in place, but the follow-up review noted two remaining blockers: legacy migration can miss parent links when messages share the same second-level created_at, and test_fork still has a stray dbg!(&thread).

Change

  • Reconstruct migrated parent_entry_id using (created_at, id) ordering, so same-second legacy messages keep deterministic parent links.
  • Add a regression test for same-second legacy messages.
  • Remove the stray debug print from test_fork.

Fixes #2082.

Verification

  • cargo fmt --all -- --check
  • cargo test -p codewhale-state --test parity_state --locked -- --nocapture
  • cargo check -p codewhale-state --locked
  • git diff --check HEAD~1..HEAD

Greptile Summary

This PR fixes a determinism bug in the legacy schema migration: when multiple messages share the same created_at timestamp, the previous ORDER BY m2.id DESC without a matching WHERE filter could assign any preceding message as the parent rather than the immediately preceding one. The fix adds a compound (created_at, id) ordering to both the filter predicate and the ORDER BY, ensuring the parent link is always the closest lower-id message in the same second.

  • crates/state/src/lib.rs: Updates the one-time migration UPDATE for parent_entry_id to use a composite (created_at ASC, id ASC) tiebreaker, fixing non-deterministic parent assignment for same-second messages.
  • crates/state/tests/parity_state.rs: Adds init_schema_migration_same_second_messages to regression-test the four-message same-second scenario, and removes the stray dbg!(&thread) from test_fork.

Confidence Score: 4/5

Safe to merge; the migration SQL fix is logically correct and the new regression test validates the happy path.

The composite (created_at, id) predicate and ORDER BY correctly handle same-second messages, and the recursive list_messages CTE will walk the resulting parent chain in the right order. The only gap is that the new test skips the idempotency re-open check that the existing migration test performs, so a double-ALTER regression on an already-migrated database would not be caught by this test alone.

crates/state/tests/parity_state.rs — the new test would benefit from an idempotency re-open check mirroring the one in init_schema_migration.

Important Files Changed

Filename Overview
crates/state/src/lib.rs One-time migration SQL updated with correct composite (created_at, id) filter and ORDER BY for deterministic parent link assignment; logic is sound.
crates/state/tests/parity_state.rs New regression test covers same-second message ordering; idempotency re-open check present in original test is omitted here, and thread current_leaf_id is not asserted.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[StateStore::open - user_version = 0] --> B[Run migration SQL]
    B --> C[ALTER TABLE messages\nADD COLUMN parent_entry_id]
    C --> D{For each message M\nin thread}
    D --> E["Find predecessor:\nm2.created_at < M.created_at\nOR\n(m2.created_at = M.created_at AND m2.id < M.id)"]
    E --> F["ORDER BY m2.created_at DESC, m2.id DESC\nLIMIT 1"]
    F --> G[SET parent_entry_id = m2.id or NULL if no predecessor]
    G --> D
    D --> H[CREATE INDEX idx_messages_parent_entry_id]
    H --> I[UPDATE threads SET current_leaf_id = highest message id per thread]
    I --> J[PRAGMA user_version = 1]
    J --> K[Migration complete]
Loading

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (1): Last reviewed commit: "fix(state): stabilize fork migration par..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Comment on lines +224 to +227
assert_eq!(messages[0].parent_entry_id, None);
assert_eq!(messages[1].parent_entry_id, Some(messages[0].id));
assert_eq!(messages[2].parent_entry_id, Some(messages[1].id));
assert_eq!(messages[3].parent_entry_id, Some(messages[2].id));

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.

P2 Missing idempotency re-open check

The original init_schema_migration test ends with a second StateStore::open call to verify the migration is safe to run on an already-migrated database. The new same-second test omits this step, so a regression where re-opening a migrated store causes a double-ALTER TABLE or index conflict would not be caught here. Adding StateStore::open(Some(path.clone())).expect("open state store - idempotent"); after the assertions would close this gap.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Codex Fix in Claude Code Fix in Cursor

@cyq1017 cyq1017 marked this pull request as ready for review June 1, 2026 04:33
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@Hmbown

Hmbown commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Harvested into codex/v0.8.50-triage for the release branch. Thank you for the tight fix.

I cherry-picked the state migration patch and added one local follow-up test commit covering same-second migration idempotency on reopen, matching the review concern. I’m leaving this PR open until the triage branch itself is reviewed/merged so GitHub doesn’t lose the contributor thread.

@Hmbown

Hmbown commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Thanks @cyq1017 — the fork parent-link migration fix is patch-equivalent to work already present on origin/main and the public v0.9.0 integration branch (codex/v0.9.0-stewardship) through b76a11b99 plus follow-up 18550339a.

The integration map records this as harvested/present, with your contribution credited. Closing this PR as superseded by the already-landed patch-equivalent implementation.

I am not closing issue #2082 here; that should only close after confirming the remaining message_type wording is obsolete too.

@Hmbown Hmbown closed this Jun 5, 2026
Hmbown added a commit that referenced this pull request Jun 5, 2026
Update the execution map after closing harvested or superseded PRs #2476, #2498, #2502, #2513, #2530, #2576, #2581, #2636, #2639, #2640, #2708, and #2730, and refresh the live PR count.
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