← back to Unclaimed Property Platform
Cycle 7: state suppression / reinstatement path (near-real-time takedown)
3ca22d7316b65f8c4b2c55b5b9742b17b13c513c · 2026-08-01 20:13:56 -0700 · Steve Abrams
- SqliteRepository.suppress_property/reinstate_property: flip search_document_state.is_suppressed
so a record leaves/returns to anonymous search IMMEDIATELY (masked_search already filters it),
while property + owner + version history are fully retained. Every action writes an immutable
audit_event; audit_trail() reads it back. Unknown record -> False (no silent success).
- Closes the brief's near-real-time suppression requirement (privacy/fraud takedown) — the gap
where nothing could pull a record from public search. State-authenticated in production.
- tests/test_cycle8_suppression.py: suppress->gone, data retained, audit written, reinstate->back.
Tests: 8/8 suites green. All local/synthetic/$0.
TK-10097
Files touched
M services/common/sqlite_repo.pyA tests/test_cycle8_suppression.py
Diff
commit 3ca22d7316b65f8c4b2c55b5b9742b17b13c513c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Aug 1 20:13:56 2026 -0700
Cycle 7: state suppression / reinstatement path (near-real-time takedown)
- SqliteRepository.suppress_property/reinstate_property: flip search_document_state.is_suppressed
so a record leaves/returns to anonymous search IMMEDIATELY (masked_search already filters it),
while property + owner + version history are fully retained. Every action writes an immutable
audit_event; audit_trail() reads it back. Unknown record -> False (no silent success).
- Closes the brief's near-real-time suppression requirement (privacy/fraud takedown) — the gap
where nothing could pull a record from public search. State-authenticated in production.
- tests/test_cycle8_suppression.py: suppress->gone, data retained, audit written, reinstate->back.
Tests: 8/8 suites green. All local/synthetic/$0.
TK-10097
---
services/common/sqlite_repo.py | 54 ++++++++++++++++++++++++++
tests/test_cycle8_suppression.py | 84 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+)
diff --git a/services/common/sqlite_repo.py b/services/common/sqlite_repo.py
index f2f854f..36adba3 100644
--- a/services/common/sqlite_repo.py
+++ b/services/common/sqlite_repo.py
@@ -238,3 +238,57 @@ class SqliteRepository:
"amount_band": r["amount_band"],
}))
return out
+
+ # --- state suppression / reinstatement (state-integration API surface) ---------------
+ # A state instructs "remove from public search" (privacy / fraud takedown). We flip the
+ # search-publication flag — the record leaves anonymous search IMMEDIATELY (masked_search
+ # filters is_suppressed=0) while ALL underlying data + version history is retained for
+ # audit. Every action writes an immutable audit_event. In production this is authenticated
+ # to a state actor; here it's a repository method the state-integration layer would call.
+ def _property_id(self, jurisdiction: str, source_property_id: str) -> str | None:
+ row = self.conn.execute(
+ "SELECT property_id FROM property WHERE jurisdiction_id=? AND source_property_id=?",
+ (jurisdiction, source_property_id),
+ ).fetchone()
+ return row["property_id"] if row else None
+
+ def _set_suppression(self, jurisdiction: str, source_property_id: str,
+ suppressed: bool, actor: str, reason: str = "") -> bool:
+ pid = self._property_id(jurisdiction, source_property_id)
+ if pid is None:
+ return False
+ before = self.conn.execute(
+ "SELECT is_suppressed FROM search_document_state WHERE property_id=?", (pid,)
+ ).fetchone()
+ before_val = None if before is None else before["is_suppressed"]
+ self.conn.execute(
+ "UPDATE search_document_state SET is_suppressed=? WHERE property_id=?",
+ (1 if suppressed else 0, pid),
+ )
+ self.conn.execute(
+ """INSERT INTO audit_event
+ (audit_event_id, actor, action, resource, before_hash, after_hash, created_at)
+ VALUES (?,?,?,?,?,?,?)""",
+ (str(uuid.uuid4()), actor, "suppress" if suppressed else "reinstate",
+ pid, str(before_val), "1" if suppressed else "0", _now()),
+ )
+ self.conn.commit()
+ return True
+
+ def suppress_property(self, jurisdiction: str, source_property_id: str,
+ actor: str, reason: str = "") -> bool:
+ """Remove a record from public search (retains all data + history). Returns False
+ if the record isn't found."""
+ return self._set_suppression(jurisdiction, source_property_id, True, actor, reason)
+
+ def reinstate_property(self, jurisdiction: str, source_property_id: str,
+ actor: str, reason: str = "") -> bool:
+ """Return a previously-suppressed record to public search."""
+ return self._set_suppression(jurisdiction, source_property_id, False, actor, reason)
+
+ def audit_trail(self, resource_property_id: str) -> list[dict]:
+ rows = self.conn.execute(
+ "SELECT actor, action, created_at FROM audit_event WHERE resource=? ORDER BY created_at",
+ (resource_property_id,),
+ ).fetchall()
+ return [dict(r) for r in rows]
diff --git a/tests/test_cycle8_suppression.py b/tests/test_cycle8_suppression.py
new file mode 100644
index 0000000..f0d6481
--- /dev/null
+++ b/tests/test_cycle8_suppression.py
@@ -0,0 +1,84 @@
+"""Cycle 7 test — state suppression / reinstatement of a record from public search.
+
+Run: python -m tests.test_cycle8_suppression
+
+Proves the brief's near-real-time suppression requirement:
+ 1. a state can remove a record from public search immediately (is_suppressed flip);
+ 2. the underlying data + version history are RETAINED (nothing deleted);
+ 3. every suppress/reinstate writes an immutable audit_event;
+ 4. reinstate returns it to search;
+ 5. suppressing an unknown record returns False (no silent no-op success).
+"""
+from __future__ import annotations
+
+import sys
+import tempfile
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
+
+from services.common.sqlite_repo import FileObjectStore, SqliteRepository
+from services.ingestion.ingest import FeedDefinition, ingest_authorized_feed
+
+SAMPLE = Path(__file__).resolve().parents[1] / "data" / "sample" / "sample_state_feed.csv"
+
+
+def ok(msg: str) -> None:
+ print(f" ✓ {msg}")
+
+
+def _refs(repo, q):
+ return {h["public_reference"] for h in repo.masked_search(q)}
+
+
+def main() -> int:
+ tmp = Path(tempfile.mkdtemp(prefix="upp-cycle8-"))
+ store = FileObjectStore(tmp / "obj")
+ (tmp / "obj").mkdir(parents=True, exist_ok=True)
+ store.write_bytes("incoming/s.csv", SAMPLE.read_bytes())
+ repo = SqliteRepository(str(tmp / "p.db"))
+ ingest_authorized_feed(FeedDefinition("SAMPLE", "incoming/s.csv"), store, repo)
+
+ pid = repo._property_id("SAMPLE", "SP-0001")
+ assert pid, "SP-0001 should exist"
+
+ print("1) record is publicly searchable before suppression")
+ assert pid in _refs(repo, "Catherine"), "SP-0001 should be searchable"
+ ok("SP-0001 (Catherine O'Neil) appears in masked search")
+
+ print("2) suppress -> gone from search immediately")
+ assert repo.suppress_property("SAMPLE", "SP-0001", actor="state:CA", reason="privacy")
+ assert pid not in _refs(repo, "Catherine"), "suppressed record must not appear in search"
+ ok("after suppress, SP-0001 no longer in search results")
+
+ print("3) data + version history RETAINED (nothing deleted)")
+ assert repo._property_id("SAMPLE", "SP-0001") == pid, "property row must remain"
+ owner = repo.conn.execute(
+ "SELECT owner_name_raw FROM owner WHERE property_id=?", (pid,)).fetchone()
+ assert owner and owner["owner_name_raw"], "owner row must remain"
+ vers = repo.conn.execute(
+ "SELECT COUNT(*) FROM property_version WHERE property_id=?", (pid,)).fetchone()[0]
+ assert vers >= 1, "version history must remain"
+ ok(f"property + owner + {vers} version(s) all retained")
+
+ print("4) audit trail records the action")
+ trail = repo.audit_trail(pid)
+ assert any(e["action"] == "suppress" and e["actor"] == "state:CA" for e in trail), trail
+ ok(f"audit_event 'suppress' by state:CA recorded ({len(trail)} event(s))")
+
+ print("5) reinstate -> back in search + audit event")
+ assert repo.reinstate_property("SAMPLE", "SP-0001", actor="state:CA")
+ assert pid in _refs(repo, "Catherine"), "reinstated record should be searchable again"
+ assert any(e["action"] == "reinstate" for e in repo.audit_trail(pid))
+ ok("reinstate restores search visibility + writes audit event")
+
+ print("6) suppressing an unknown record returns False")
+ assert repo.suppress_property("SAMPLE", "NO-SUCH-ID", actor="state:CA") is False
+ ok("unknown record -> False (no silent success)")
+
+ print("\nALL CYCLE-7 SUPPRESSION ASSERTIONS PASSED ✅")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
← 02a3ead docs: ledger Cycle-6 record (recall fix); TK-10097
·
back to Unclaimed Property Platform
·
docs: ledger Cycle-7 record (suppression path); TK-10097 afbc9ad →