@@ -7551,6 +7551,78 @@ def workflow_nodes(self, workflow_id):
75517551 assert app .store .node_calls == 2
75527552
75537553
7554+ def test_cache_invalidates_on_wal_write_so_reload_sees_new_opencode_sessions ():
7555+ # OpenCode runs SQLite in WAL mode, so a new session lands in <db>-wal while the
7556+ # main .db's size/mtime don't move until a checkpoint. cache_inputs() must
7557+ # fingerprint the WAL sidecars, or CachedStore keeps serving the stale rollup and a
7558+ # reload (r) / the report's refresh never shows sessions written since -- the
7559+ # reported "--web refresh doesn't get new sessions" bug.
7560+ with tempfile .TemporaryDirectory () as tmp :
7561+ old_xdg = os .environ .get ("XDG_CONFIG_HOME" )
7562+ os .environ ["XDG_CONFIG_HOME" ] = os .path .join (tmp , "cfg" ) # isolate the cache dir
7563+ db = os .path .join (tmp , "opencode.db" )
7564+ # Writer stays open the whole test with autocheckpoint off, so every commit
7565+ # stays in the -wal file and the main .db is never checkpointed/rewritten.
7566+ w = sqlite3 .connect (db )
7567+ w .execute ("PRAGMA journal_mode=WAL" )
7568+ w .execute ("PRAGMA wal_autocheckpoint=0" )
7569+ w .executescript (
7570+ """
7571+ create table session (
7572+ id text primary key, parent_id text, title text, directory text,
7573+ time_created integer, cost real default 0 not null,
7574+ tokens_input integer default 0 not null, tokens_output integer default 0 not null,
7575+ tokens_reasoning integer default 0 not null, tokens_cache_read integer default 0 not null,
7576+ tokens_cache_write integer default 0 not null
7577+ );
7578+ create table message (id text primary key, session_id text, data text);
7579+ """
7580+ )
7581+ w .execute (
7582+ "insert into session values ('s1',null,'One','/work/repo',1760000000000,1.0,0,0,0,0,0)"
7583+ )
7584+ w .commit ()
7585+ try :
7586+ store = ot .Store (db , type ("A" , (), {"demo" : False })())
7587+ ci = store .cache_inputs ()
7588+ assert db in ci and db + "-wal" in ci and db + "-shm" in ci # sidecars fingerprinted
7589+
7590+ cid = "opencode|" + db
7591+ cargs = type ("A" , (), {"demo" : False , "no_cache" : False })()
7592+
7593+ # Cold: parse s1 and write the cache (workflows + breakdown both fresh).
7594+ c1 = ot .CachedStore (store , cid , cargs )
7595+ assert [x .id for x in c1 .workflows ()] == ["s1" ]
7596+ c1 .model_breakdown ()
7597+ assert c1 .served_from_cache is False
7598+
7599+ # Warm: a fresh wrapper over the unchanged DB serves the cache untouched.
7600+ c2 = ot .CachedStore (store , cid , cargs )
7601+ c2 .workflows ()
7602+ assert c2 .served_from_cache is True
7603+
7604+ # OpenCode adds a new session -> it lands in the WAL, main .db mtime unchanged.
7605+ mtime_before = os .stat (db ).st_mtime_ns
7606+ w .execute (
7607+ "insert into session values ('s2',null,'Two','/work/repo',1760000100000,2.0,0,0,0,0,0)"
7608+ )
7609+ w .commit ()
7610+ assert os .stat (db ).st_mtime_ns == mtime_before # the WAL grew, not the .db
7611+
7612+ # A reload now MISSES the cache (the -wal fingerprint moved) and re-parses,
7613+ # so the new session is visible -- the fix.
7614+ c3 = ot .CachedStore (store , cid , cargs )
7615+ wf3 = c3 .workflows ()
7616+ assert c3 .served_from_cache is False
7617+ assert sorted (x .id for x in wf3 ) == ["s1" , "s2" ]
7618+ finally :
7619+ w .close ()
7620+ if old_xdg is None :
7621+ os .environ .pop ("XDG_CONFIG_HOME" , None )
7622+ else :
7623+ os .environ ["XDG_CONFIG_HOME" ] = old_xdg
7624+
7625+
75547626def test_wsl_mount_root_and_windows_path_mapping ():
75557627 with tempfile .TemporaryDirectory () as tmp :
75567628 # wsl.conf parsing: [automount] root= wins, comments stripped, missing -> /mnt.
0 commit comments