File size: 2,402 Bytes
690acd1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"""Database models for on-chain governance attestations.

``RiskAttestation.rationale_hash`` (see arf-onchain's ``AttestationLib.sol``
and enterprise's ``arf_enterprise.onchain.attestation``) is a ``keccak256``
digest anchored on Monad -- the chain deliberately never stores the rationale
text itself, only its hash, to keep operational detail about a customer's
infrastructure off a public ledger. That means the text has to live
somewhere off-chain, keyed by the same hash, or the anchored hash proves
nothing: nobody could ever produce the preimage to check it against.

This table is that store. It is intentionally separate from
``DecisionAuditLogDB`` (``models_intents.py``) rather than an extension of
it: that table is written for every governance decision, on-chain or not,
and already has its own signature column for a different purpose (Ed25519
intent-signing, not the secp256k1 EIP-712 signature the guard verifies).
Conflating the two would mean a column that is only sometimes meaningful
depending on whether the decision was ever attested on-chain.
"""

import uuid
import datetime

from sqlalchemy import Column, String, DateTime, Text

from .base import Base


class OnchainRationaleDB(Base):
    """The plaintext preimage of an anchored ``rationale_hash``.

    Keyed by the hash itself (unique, indexed) rather than by an
    auto-incrementing id: a lookup always starts from a hash read off-chain
    (from `DecisionAnchored` or `AttestationIssued`), never from a row id
    nothing on-chain knows about.

    No ``tenant_id`` / foreign key to ``tenants``: an on-chain agent is
    identified by its wallet address, not by this service's tenant concept,
    and the two are not yet bridged. `evaluator_address` and `agent_address`
    are recorded instead so a row can still be attributed and audited
    without assuming a tenant relationship that may not exist.
    """

    __tablename__ = "onchain_rationales"

    id = Column(String(64), primary_key=True, default=lambda: str(uuid.uuid4()))
    rationale_hash = Column(
        String(66), nullable=False, unique=True, index=True
    )  # "0x" + 64 hex chars
    rationale = Column(Text, nullable=False)
    agent_address = Column(String(42), nullable=True)
    evaluator_address = Column(String(42), nullable=True)
    created_at = Column(
        DateTime, default=datetime.datetime.utcnow, nullable=False, index=True
    )