test: align file-identity guard tests with post-18ac3c4 FTS recovery contract

Main removed the live-path runtime FTS rebuild (18ac3c4fb6) and #99652
narrowed the corruption classifier, after the salvaged PR #89364 branched.
Update its tests to assert the current contract: no fail-open detach on a
replaced file (fts_enabled stays True, no stale marker), fail-open (not
rebuild) for genuine same-file FTS corruption, and FTS-provenance errors
for the guard probe since generic malformed no longer reaches fail-open.
This commit is contained in:
Teknium
2026-08-31 13:17:47 -07:00
parent 71256dfd01
commit 0685bf1992
2 changed files with 34 additions and 13 deletions
@@ -55,7 +55,10 @@ def test_replaced_state_db_diverts_pending_without_fts_rebuild(tmp_path, monkeyp
)
assert store._db._db_replaced is True
assert store._db._fts_runtime_rebuild_attempted is False
# No FTS surgery ran on either layer: state-level fail-open never
# detached, and the gateway one-shot rebuild was not consumed.
assert store._db._fts_enabled is True
assert store._db._fts_stale is False
assert store._fts_rebuild_attempted is False
_assert_diverted(tmp_path, sid, "after-replace")
store.close_all_db_handles()
@@ -91,7 +94,10 @@ def test_copyfile_replaced_state_db_diverts_pending_without_fts_rebuild(
)
assert store._db._db_replaced is True
assert store._db._fts_runtime_rebuild_attempted is False
# No FTS surgery ran on either layer: state-level fail-open never
# detached, and the gateway one-shot rebuild was not consumed.
assert store._db._fts_enabled is True
assert store._db._fts_stale is False
assert store._fts_rebuild_attempted is False
_assert_diverted(tmp_path, sid, "after-cp")
store.close_all_db_handles()
@@ -50,8 +50,9 @@ def test_replace_with_new_inode_fails_loudly_without_fts_repair(tmp_path):
db.append_message("live-sess", role="user", content="after-replace")
assert db._db_replaced is True
assert db._fts_runtime_rebuild_attempted is False
# No FTS surgery ran: fail-open never detached the indexes.
assert db._fts_enabled is True
assert db._fts_stale is False
db.close()
@@ -67,12 +68,18 @@ def test_second_write_after_halt_does_not_attempt_repair(tmp_path):
db.append_message("s", role="user", content="first")
with pytest.raises(StateDbReplacedError):
db.append_message("s", role="user", content="second")
assert db._fts_runtime_rebuild_attempted is False
assert db._fts_enabled is True
assert db._fts_stale is False
db.close()
def test_same_file_fts_corruption_still_rebuilds(tmp_path):
"""Identity guard must not disable genuine in-file FTS recovery."""
def test_same_file_fts_corruption_still_fails_open(tmp_path):
"""Identity guard must not disable genuine in-file FTS recovery.
Since 18ac3c4fb6 the live write path never rebuilds FTS in place; the
recovery contract is the fail-open detach (stale marker + triggers
dropped) followed by a successful canonical retry.
"""
db = _make_db(tmp_path / "state.db", "s1", "hello world")
_require_identity(db)
identity = db._db_file_identity
@@ -85,7 +92,9 @@ def test_same_file_fts_corruption_still_rebuilds(tmp_path):
db.append_message("s1", role="user", content="healed append")
assert db._db_file_identity == identity
assert db._db_replaced is False
assert db._fts_runtime_rebuild_attempted is True
# Fail-open detach ran: canonical write landed, FTS marked stale.
assert db._fts_stale is True
assert db._fts_enabled is False
db.close()
@@ -116,8 +125,10 @@ def test_new_sessiondb_on_replaced_path_records_new_identity(tmp_path):
reopened.close()
def test_malformed_error_on_replaced_file_skips_fts_rebuild(tmp_path):
"""Even if SQLite surfaces malformed, identity mismatch blocks repair."""
def test_fts_scoped_error_on_replaced_file_skips_fts_fail_open(tmp_path):
"""Even FTS-provenance corruption must not authorize surgery on a
replaced file. (A generic malformed error never reaches fail-open at
all since the provenance classifier of #99652 rejects it earlier.)"""
live = tmp_path / "state.db"
other = tmp_path / "other.db"
db = _make_db(live, "s", "a")
@@ -127,10 +138,13 @@ def test_malformed_error_on_replaced_file_skips_fts_rebuild(tmp_path):
os.replace(other, live)
with pytest.raises(StateDbReplacedError):
db._try_runtime_fts_rebuild(
sqlite3.DatabaseError("database disk image is malformed")
db._enter_fts_fail_open(
sqlite3.DatabaseError(
'fts5: corrupt structure record for table "messages_fts"'
)
)
assert db._fts_runtime_rebuild_attempted is False
assert db._fts_enabled is True
assert db._fts_stale is False
db.close()
@@ -156,7 +170,8 @@ def test_copyfile_same_inode_fails_loudly_without_fts_repair(tmp_path):
with pytest.raises(StateDbReplacedError, match="replaced underneath"):
db.append_message("live-sess", role="user", content="after-cp")
assert db._db_replaced is True
assert db._fts_runtime_rebuild_attempted is False
assert db._fts_enabled is True
assert db._fts_stale is False
db.close()