33 * World snapshot sync hook (cross-process bridge to the MCP memory server)
44 *
55 * @ai -context: 珊瑚/发现数据存于渲染进程 IndexedDB,MCP 记忆服务器读主进程
6- * sqlite——本 hook 是两者间的单向桥:订阅 retention store 变化,防抖 2s 后
7- * 把摘要快照 upsert 到 world_snapshots 表(单行 id='latest')。
6+ * sqlite——本 hook 是两者间的单向桥:数据变化防抖 2s 后把摘要快照 upsert
7+ * 到 world_snapshots 表(单行 id='latest')。阶段 C 新增事件驱动:订阅
8+ * useWorldEvents 签名时刻(掌握/创世/入籍,含 knowledge_settled 语义)
9+ * 立即同步——AI 在签名时刻后马上读到新世界,不等防抖窗口。
810 * 失败静默(快照是增强项,不影响主流程)。
911 *
1012 * @ai -context: One-way bridge from renderer retention stores to the
11- * world_snapshots sqlite row consumed by the MCP memory server.
13+ * world_snapshots sqlite row. Debounced 2s on data change; immediate on
14+ * signature moments (mastery/genesis/settling) via the world event bus.
1215 */
13- import { useEffect , useRef } from 'react' ;
16+ import { useCallback , useEffect , useRef } from 'react' ;
1417import { useEcosystemStore } from '../store/useEcosystemStore' ;
1518import { useDiscoveryStore } from '../store/useDiscoveryStore' ;
19+ import { useWorldEvents } from '../store/useWorldEvents' ;
1620
1721const SNAPSHOT_ID = 'latest' ;
1822const DEBOUNCE_MS = 2000 ;
@@ -21,42 +25,54 @@ export function useWorldSnapshotSync(): void {
2125 const corals = useEcosystemStore ( ( s ) => s . corals ) ;
2226 const totalDepth = useEcosystemStore ( ( s ) => s . totalDepth ) ;
2327 const discoveriesCount = useDiscoveryStore ( ( s ) => s . totalCount ) ;
28+ // 签名时刻序列号(宪法第三条:掌握/创世/入籍)——事件驱动同步信号
29+ const signatureSeq = useWorldEvents ( ( s ) => s . signatureSeq ) ;
2430 const timer = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
2531
26- useEffect ( ( ) => {
32+ /** 写快照(幂等 upsert,失败静默)——防抖与事件驱动共用 / Shared upsert */
33+ const write = useCallback ( async ( ) => {
2734 if ( ! window . electronAPI ?. db ) return ;
35+ const healthy = corals . filter ( ( c ) => c . health === 'healthy' ) . length ;
36+ const payload = JSON . stringify ( {
37+ corals : {
38+ total : corals . length ,
39+ healthy,
40+ bleached : corals . length - healthy ,
41+ totalDepth,
42+ } ,
43+ discoveries : { count : discoveriesCount } ,
44+ capturedAt : new Date ( ) . toISOString ( ) ,
45+ } ) ;
46+ const row = { id : SNAPSHOT_ID , payload, updated_at : new Date ( ) . toISOString ( ) } ;
47+ try {
48+ // 先查后写实现 upsert(db 桥查询方法白名单为 getAll/getById/count)
49+ const existing = await window . electronAPI . db . query ( 'worldSnapshots' , 'getById' , [ SNAPSHOT_ID ] ) ;
50+ if ( existing ) {
51+ await window . electronAPI . db . update ( 'worldSnapshots' , SNAPSHOT_ID , {
52+ payload, updated_at : row . updated_at ,
53+ } ) ;
54+ } else {
55+ await window . electronAPI . db . insert ( 'worldSnapshots' , row ) ;
56+ }
57+ } catch { /* 快照失败静默降级 */ }
58+ } , [ corals , totalDepth , discoveriesCount ] ) ;
2859
29- const write = async ( ) => {
30- const healthy = corals . filter ( ( c ) => c . health === 'healthy' ) . length ;
31- const payload = JSON . stringify ( {
32- corals : {
33- total : corals . length ,
34- healthy,
35- bleached : corals . length - healthy ,
36- totalDepth,
37- } ,
38- discoveries : { count : discoveriesCount } ,
39- capturedAt : new Date ( ) . toISOString ( ) ,
40- } ) ;
41- const row = { id : SNAPSHOT_ID , payload, updated_at : new Date ( ) . toISOString ( ) } ;
42- try {
43- // 先查后写实现 upsert(db 桥查询方法白名单为 getAll/getById/count)
44- const existing = await window . electronAPI . db . query ( 'worldSnapshots' , 'getById' , [ SNAPSHOT_ID ] ) ;
45- if ( existing ) {
46- await window . electronAPI . db . update ( 'worldSnapshots' , SNAPSHOT_ID , {
47- payload, updated_at : row . updated_at ,
48- } ) ;
49- } else {
50- await window . electronAPI . db . insert ( 'worldSnapshots' , row ) ;
51- }
52- } catch { /* 快照失败静默降级 */ }
53- } ;
54-
60+ // 数据变化:防抖 2s 后写(批量小变化合并为一次)
61+ useEffect ( ( ) => {
5562 if ( timer . current ) clearTimeout ( timer . current ) ;
5663 timer . current = setTimeout ( ( ) => { void write ( ) ; } , DEBOUNCE_MS ) ;
57- } , [ corals , totalDepth , discoveriesCount ] ) ;
64+ } , [ write ] ) ;
5865
66+ // 事件驱动:签名时刻立即同步(取消挂起防抖,避免重复写)
67+ useEffect ( ( ) => {
68+ if ( signatureSeq === 0 ) return ;
69+ if ( timer . current ) clearTimeout ( timer . current ) ;
70+ void write ( ) ;
71+ } , [ signatureSeq , write ] ) ;
72+
73+ // 卸载清理
5974 useEffect ( ( ) => ( ) => {
6075 if ( timer . current ) clearTimeout ( timer . current ) ;
6176 } , [ ] ) ;
6277}
78+
0 commit comments