Skip to content

feat: watch 多库化(统一 reconcile 核心)— 适配 Codex 26.609,PR4#19

Closed
Wangnov wants to merge 2 commits into
feat/multi-store-backfill-guardfrom
feat/multi-store-watch
Closed

feat: watch 多库化(统一 reconcile 核心)— 适配 Codex 26.609,PR4#19
Wangnov wants to merge 2 commits into
feat/multi-store-backfill-guardfrom
feat/multi-store-watch

Conversation

@Wangnov

@Wangnov Wangnov commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Stacked on #18(base 指向 feat/multi-store-backfill-guard)。前序合并后自动上移。

背景

PR1(#16 只读发现+多库 status)、PR2(#17 sync/bucket 写路径多库化)、PR3(#18 backfill 守卫)。watch(后台连续监听服务,用 MismatchedRows 增量 scope + AllRows followup,不做备份)在前三个 PR 里一直走旧的单库 reconcile_once。PR4 把它也多库化。共识见 #14

改动

  • 统一多库核心 reconcile_stores_core(.., backup: bool, ..):在 PR2/PR3 的多库写逻辑上加 backup 标志 + MismatchedRows followup(翻完各 ready 库 DB 后若总 changed_rows>0,对 ready 库再跑一次 AllRows rollout 并合并计数)。
  • reconcile_all_stores_with_backup(backup=true,sync/bucket)与新增 reconcile_all_stores(backup=false,watch)都委托给它。
  • backup=false 同时跳过:逐库 .bak 备份 rollout 变更日志 —— watch 不再每轮往 backups/ 写东西(与旧 reconcile_once 一致,旧路径传的 journal 就是 None)。
  • watchDuration::ZERO 作 backfill 等待:某库重建中则本轮跳过、下轮再试,绝不在单轮阻塞;配合 PR3 的整轮跳过规则,backfill 期间 watch 静默等待、完成后自动恢复。
  • 删除单库链:reconcile_once / _with_progress / _unlocked / add_rollout_summary / ReconcileSummary / print_sync_summary;reconcile_rollout_metadata_from_sqlite_with_progress 现仅测试用,标 #[cfg(test)]
  • 净删 ~85 行(统一后更简洁)。

并行 Review(Codex × Claude subagent)

  • Codex 抓到一个 subagent 当成 🟡 的真回归:no-backup 路径仍无条件写 rollout 变更日志,而旧单库 watch 传的是 journal=None → watch 会每轮往 backups/rollouts.*.jsonl
  • 已修复:journal 改为挂在 backup 上(backup=false 不写);新增回归测试 reconcile_all_stores_writes_no_journal_without_backup(断言 watch 路径改了 rollout 但不写 journal)。
  • subagent 深入确认了 followup 与旧单库严格等价(等价测试 changed_rows=1/changed_rollouts=2 实跑过)、幂等无双写、backup=true 零回归;Codex 的 followup failed_stores 防御建议也采纳(加了 debug_assert)。

测试 / 质量

  • cargo test:54 passed(新增 no-journal 回归;MismatchedRows followup 等价测试现走统一 reconcile_all_stores)。
  • cargo clippy --all-targets:0;cargo fmt --check:clean。
  • smoke:watch 对空 CODEX_HOME 启动→无库错误优雅处理→进入轮询→循环不崩;真实库 status 只读回归正常。

后续

--store cli|app|configured|all flag(最后一项)。

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Wangnov Wangnov force-pushed the feat/multi-store-backfill-guard branch from 2aa959e to 7e18e57 Compare June 13, 2026 05:58
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch from 3acf323 to 449d73c Compare June 13, 2026 06:00
@Wangnov Wangnov force-pushed the feat/multi-store-backfill-guard branch from 7e18e57 to 030fd33 Compare June 13, 2026 06:12
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch 2 times, most recently from a9a7e6c to 315fef8 Compare June 13, 2026 06:22
@Wangnov Wangnov force-pushed the feat/multi-store-backfill-guard branch from 030fd33 to 61940f9 Compare June 13, 2026 06:34
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch from 315fef8 to 1f56a37 Compare June 13, 2026 06:35
@Wangnov Wangnov force-pushed the feat/multi-store-backfill-guard branch from 61940f9 to 5d6cce5 Compare June 13, 2026 06:45
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch from 1f56a37 to c81350b Compare June 13, 2026 06:46
@Wangnov Wangnov force-pushed the feat/multi-store-backfill-guard branch from 5d6cce5 to 20e1a7e Compare June 13, 2026 06:59
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch 2 times, most recently from 90c7860 to 758c950 Compare June 13, 2026 07:39
Wangnov added 2 commits June 13, 2026 15:48
PR3 of the multi-store adaptation (builds on #17). Before writing, the
multi-store path now waits (bounded) for each store's Codex startup-backfill to
finish, so threadripper never races Codex's rebuild.

- wait_for_store_backfill polls backfill_state (read-only): no table or a
  `complete` status is ready immediately; otherwise it waits up to backfill_wait
  (default 10s) and then reports the store busy.
- A busy store is reported StoreOutcome::Skipped, and neither its rollout targets
  nor its DB are touched.
- Because rewriting the shared rollout JSONL would race a running backfill's
  reads (the rollout files are its source of truth), a rollout-rewriting scope
  (AllRows) combined with any in-progress backfill skips the whole round;
  --sqlite-only (RolloutScope::None) still writes its ready stores.
- main returns Partial(2) / Failed(1) accordingly; the --sqlite-only App warning
  now fires only when the App store was actually updated.

Reviewed in parallel by Codex and a Claude subagent. Codex caught that the first
cut still rewrote the shared rollout JSONL (racing the backfill) even while
skipping busy stores' DBs; fixed with the whole-round skip above, plus a
regression test asserting that a shared rollout and both DBs stay untouched while
a backfill runs. 53 tests, clippy and fmt clean.
PR4 of the multi-store adaptation (builds on #18). `watch` now maintains every
discovered store, not just one, by sharing the multi-store write path.

- Extract reconcile_stores_core(.., backup, ..) used by both the one-shot
  backed-up path (reconcile_all_stores_with_backup) and a new no-backup
  reconcile_all_stores for the continuous watch service.
- The core supports the incremental MismatchedRows scope with an AllRows rollout
  followup (when rows change), matching the former single-store watch path.
- backup=false skips per-store backups AND the rollout change journal, so watch
  does not litter backups/ every poll (matching the old reconcile_once, which
  passed no journal path).
- watch passes Duration::ZERO as the backfill wait: a store mid-backfill is
  skipped this poll and retried next, never blocking the loop. With a
  rollout-rewriting scope, PR3's whole-round skip means watch quietly waits out a
  backfill and resumes when it completes.
- Remove the now-unused single-store path: reconcile_once, ReconcileSummary,
  print_sync_summary, add_rollout_summary.

Reviewed in parallel by Codex and a Claude subagent. Codex caught that the
no-backup path still wrote a rollout change journal (a regression vs the old
watch); fixed by gating the journal on backup, with a regression test asserting
the watch path writes no backups/rollouts.*.jsonl. 54 tests, clippy and fmt
clean.
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch from 758c950 to 1fc292e Compare June 13, 2026 07:50
@Wangnov Wangnov closed this Jun 13, 2026
@Wangnov Wangnov reopened this Jun 13, 2026
@Wangnov Wangnov force-pushed the feat/multi-store-watch branch 2 times, most recently from 6954175 to 1fc292e Compare June 13, 2026 08:01
@Wangnov

Wangnov commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

✅ 已随这条 stack 通过快进合并落到 main(本 PR 的提交 1fc292e 已在 main,HEAD=ebc2902)。作为已合并部分关闭。

@Wangnov Wangnov closed this Jun 13, 2026
@Wangnov Wangnov deleted the feat/multi-store-watch branch June 13, 2026 08:15
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