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}