diff --git a/src/idea156_kappabridge_privacy_safe/storage.py b/src/idea156_kappabridge_privacy_safe/storage.py index ddc3fd0..75f73ea 100644 --- a/src/idea156_kappabridge_privacy_safe/storage.py +++ b/src/idea156_kappabridge_privacy_safe/storage.py @@ -155,6 +155,16 @@ class FederationStore: row = session.execute(select(LedgerRow).order_by(LedgerRow.seq.desc())).scalars().first() return 0 if row is None else row.seq + def ledger_root(self) -> str: + """Return the latest ledger entry hash, or a zeroed hash if the ledger is empty. + + This is a convenience accessor used by auditors to quickly obtain the + tamper-evident tip of the governance ledger. + """ + with self.session() as session: + row = session.execute(select(LedgerRow).order_by(LedgerRow.seq.desc())).scalars().first() + return row.entry_hash if row is not None else "0" * 64 + @staticmethod def _row_to_contract_dict(row: ContractRow) -> dict[str, Any]: return { diff --git a/tests/test_ledger_root.py b/tests/test_ledger_root.py new file mode 100644 index 0000000..b6bacc5 --- /dev/null +++ b/tests/test_ledger_root.py @@ -0,0 +1,16 @@ +# simple test to assert ledger_root reflects the latest recorded event +from __future__ import annotations + +from pathlib import Path + +from idea156_kappabridge_privacy_safe import FederationStore + + +def test_ledger_root_updates(tmp_path: Path) -> None: + store = FederationStore(tmp_path / "ledger.db") + # initially empty ledger -> zeroed hash + assert store.ledger_root() == "0" * 64 + + # record an event and ensure ledger_root updates + rec = store.record_event("test_event", {"foo": "bar"}) + assert store.ledger_root() == rec["entry_hash"]