Skip to main content

cortex_context/
audit.rs

1//! Selection audit structures for context packs.
2
3use serde::{Deserialize, Serialize};
4
5use crate::pack::ContextRefId;
6use crate::redaction::{PackMode, RedactionPolicy, Sensitivity};
7
8/// Why a candidate ref was omitted from a context pack.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum ExclusionReason {
12    /// Omitted because it conflicts with selected or current intent.
13    Contradiction,
14    /// Omitted because it is stale for this task.
15    Staleness,
16    /// Omitted because it is outside task scope.
17    ScopeMismatch,
18    /// Omitted to preserve the requested token budget.
19    TokenBudget,
20    /// Omitted by redaction/privacy policy.
21    RedactionPolicy,
22    /// Omitted because current operator intent overrides historical pressure.
23    CurrentIntent,
24    /// Omitted for another explicitly recorded reason.
25    Other,
26}
27
28/// Audit entry for a selected ref.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct IncludedAuditEntry {
31    /// Included ref.
32    pub ref_id: ContextRefId,
33    /// Deterministic rule or policy id that selected it.
34    pub rule_id: String,
35    /// Human-readable reason recorded for audit.
36    pub reason: String,
37    /// Sensitivity tier used during selection.
38    pub sensitivity: Sensitivity,
39}
40
41/// Audit entry for an excluded ref.
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43pub struct ExcludedAuditEntry {
44    /// Excluded ref when policy permits recording the identifier.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub ref_id: Option<ContextRefId>,
47    /// Ref kind retained even when the identifier is redacted.
48    pub ref_kind: String,
49    /// Exclusion reason.
50    pub reason: ExclusionReason,
51    /// Deterministic rule or policy id that excluded it.
52    pub rule_id: String,
53    /// Human-readable rationale.
54    pub rationale: String,
55    /// Sensitivity tier used during selection.
56    pub sensitivity: Sensitivity,
57}
58
59/// Replayable audit data for pack construction.
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub struct SelectionAudit {
62    /// Pack mode used during construction.
63    pub pack_mode: PackMode,
64    /// Redaction policy used during construction.
65    pub redaction_policy: RedactionPolicy,
66    /// Audit entries for included refs.
67    pub included: Vec<IncludedAuditEntry>,
68    /// Audit entries for excluded refs.
69    pub exclusions: Vec<ExcludedAuditEntry>,
70    /// Estimated token count from the local deterministic estimator.
71    pub estimated_tokens: usize,
72}
73
74impl SelectionAudit {
75    /// Construct an empty audit for a pack build.
76    #[must_use]
77    pub fn new(
78        pack_mode: PackMode,
79        redaction_policy: RedactionPolicy,
80        estimated_tokens: usize,
81    ) -> Self {
82        Self {
83            pack_mode,
84            redaction_policy,
85            included: Vec::new(),
86            exclusions: Vec::new(),
87            estimated_tokens,
88        }
89    }
90}