Skip to main content

chio_kernel/
receipt_query.rs

1use crate::receipt_store::StoredToolReceipt;
2
3/// Maximum number of receipts returnable in a single query page.
4pub const MAX_QUERY_LIMIT: usize = 200;
5
6/// Query parameters for filtering and paginating tool receipts.
7#[derive(Debug, Default, Clone)]
8pub struct ReceiptQuery {
9    /// Filter by capability ID (exact match).
10    pub capability_id: Option<String>,
11    /// Filter by tool server name (exact match).
12    pub tool_server: Option<String>,
13    /// Filter by tool name (exact match).
14    pub tool_name: Option<String>,
15    /// Filter by decision outcome (maps to decision_kind column:
16    /// "allow", "deny", "cancelled", "incomplete").
17    pub outcome: Option<String>,
18    /// Include only receipts with timestamp >= since (Unix seconds, inclusive).
19    pub since: Option<u64>,
20    /// Include only receipts with timestamp <= until (Unix seconds, inclusive).
21    pub until: Option<u64>,
22    /// Include only receipts with financial cost_charged >= min_cost (minor units).
23    /// Receipts without financial metadata are excluded when this filter is set.
24    pub min_cost: Option<u64>,
25    /// Include only receipts with financial cost_charged <= max_cost (minor units).
26    /// Receipts without financial metadata are excluded when this filter is set.
27    pub max_cost: Option<u64>,
28    /// Cursor for forward pagination: return only receipts with seq > cursor (exclusive).
29    pub cursor: Option<u64>,
30    /// Maximum number of receipts to return per page (capped at MAX_QUERY_LIMIT).
31    pub limit: usize,
32    /// Filter by agent subject public key (hex-encoded Ed25519). Resolved through
33    /// capability_lineage JOIN -- does not replay issuance logs.
34    pub agent_subject: Option<String>,
35    /// Phase 1.5 multi-tenant receipt isolation: restrict results to a
36    /// tenant. When `Some(id)`, the store returns receipts whose
37    /// `tenant_id = id` OR whose `tenant_id IS NULL` (the pre-
38    /// multi-tenant "public" set) so legacy receipts remain visible
39    /// during the transition. When `None`, no filter is applied --
40    /// intended for admin / compat query paths only.
41    ///
42    /// For strict isolation that excludes the NULL fallback set, the
43    /// caller must also flip the store's strict-tenant-isolation mode
44    /// via `SqliteReceiptStore::with_strict_tenant_isolation(true)`.
45    ///
46    /// MUST be derived from the caller's authentication context at the
47    /// HTTP edge, not from a query parameter. See
48    /// `docs/protocols/STRUCTURAL-SECURITY-FIXES.md` section 6.
49    pub tenant_filter: Option<String>,
50}
51
52/// Result of a receipt query, including pagination state.
53#[derive(Debug)]
54pub struct ReceiptQueryResult {
55    /// Receipts matching the query filters, ordered by seq ASC.
56    pub receipts: Vec<StoredToolReceipt>,
57    /// Total number of receipts matching the filters (independent of limit/cursor).
58    pub total_count: u64,
59    /// Cursor for the next page: Some(last_seq) when more results exist, None on last page.
60    pub next_cursor: Option<u64>,
61}