Service for AuditChain persistence and querying. All public methods are async and require an ``AsyncSession`` as the first positional argument so the caller controls transaction boundaries. Usage:: svc = AuditChainService() chain_id = await svc.initialize(db, miss
| 92 | |
| 93 | |
| 94 | class AuditChainService: |
| 95 | """ |
| 96 | Service for AuditChain persistence and querying. |
| 97 | |
| 98 | All public methods are async and require an ``AsyncSession`` as the |
| 99 | first positional argument so the caller controls transaction boundaries. |
| 100 | |
| 101 | Usage:: |
| 102 | |
| 103 | svc = AuditChainService() |
| 104 | chain_id = await svc.initialize(db, mission_id="msn_...", agent_id="aid_...") |
| 105 | await svc.append(db, chain_id=chain_id, layer=AuditLayer.EXECUTION, event="EXECUTION_tool_call", ...) |
| 106 | chain = await svc.get_by_mission(db, "msn_...") |
| 107 | valid = await svc.verify_integrity(db, chain_id) |
| 108 | """ |
| 109 | |
| 110 | async def initialize( |
| 111 | self, |
| 112 | db: AsyncSession, |
| 113 | mission_id: str, |
| 114 | agent_id: str, |
| 115 | ) -> str: |
| 116 | """ |
| 117 | Create a new AuditChain and write the genesis IDENTITY entry. |
| 118 | |
| 119 | Args: |
| 120 | db: AsyncSession. |
| 121 | mission_id: Mission this chain belongs to. |
| 122 | agent_id: Agent that owns this chain. |
| 123 | |
| 124 | Returns: |
| 125 | The chain_id of the newly created chain. |
| 126 | """ |
| 127 | # Create chain header |
| 128 | chain_id = "ac_" + _new_id() |
| 129 | initialized_at = _now_utc() |
| 130 | |
| 131 | chain_model = AuditChainModel( |
| 132 | chain_id=chain_id, |
| 133 | mission_id=mission_id, |
| 134 | agent_id=agent_id, |
| 135 | initialized_at=initialized_at, |
| 136 | ) |
| 137 | db.add(chain_model) |
| 138 | |
| 139 | # Compute genesis entry |
| 140 | genesis_entry = AuditEntry( |
| 141 | chain_id=chain_id, |
| 142 | sequence=0, |
| 143 | layer=AuditLayer.IDENTITY, |
| 144 | event="IDENTITY_chain_initialized", |
| 145 | agent_id=agent_id, |
| 146 | mission_id=mission_id, |
| 147 | prev_hash=_GENESIS_HASH, |
| 148 | data={"initialized_at": initialized_at.isoformat()}, |
| 149 | entry_hash="", # placeholder |
| 150 | ) |
| 151 | genesis_hash = _compute_entry_hash(genesis_entry) |
no outgoing calls
no test coverage detected