Skip to main content

zagens_core/
scratchpad.rs

1//! Scratchpad runtime configuration — shared between core and TUI.
2
3use serde::Deserialize;
4
5/// Resolved scratchpad settings for engine + tools.
6#[derive(Debug, Clone)]
7pub struct ScratchpadConfig {
8    pub enabled: bool,
9    pub max_notes_per_run: usize,
10    pub remind_after_readonly_tools: usize,
11    pub remind_enabled: bool,
12    pub inject_summary_max_chars: usize,
13    pub inject_on_report_keywords: Vec<String>,
14    pub retention_days: u32,
15    /// Phase C1: soft warn when `accounted_ratio` is below this (default 0.85).
16    pub coverage_soft_ratio: f64,
17    /// Phase C1: hard block P2 summary when below this (default 0.60).
18    pub coverage_hard_ratio: f64,
19    pub coverage_hard_block_enabled: bool,
20    /// When true, `deferred` counts toward accounted only with `kind=meta` reason (§6.12.4).
21    pub coverage_count_deferred_as_accounted: bool,
22    /// Phase C1: `set_area(deferred)` requires `kind=meta` with non-empty claim.
23    pub require_deferred_meta: bool,
24    /// L0 lists deferred areas when `reviewed_ratio` is below this (default 0.70).
25    pub coverage_reviewed_warn_ratio: f64,
26    /// Hard block `write_file` to audit deliverables when `reviewed_ratio` is below this (default 0.40).
27    pub coverage_reviewed_hard_ratio: f64,
28    pub coverage_reviewed_hard_block_enabled: bool,
29    /// Phase C2: prepend scratchpad verified `note_id` table to Auditor spawn.
30    pub auditor_from_scratchpad: bool,
31    /// Phase C2: include all MEDIUM in track A when count ≥ this (default 3).
32    pub auditor_include_medium_min: usize,
33}
34
35impl Default for ScratchpadConfig {
36    fn default() -> Self {
37        Self {
38            enabled: true,
39            max_notes_per_run: 2000,
40            remind_after_readonly_tools: 8,
41            remind_enabled: true,
42            inject_summary_max_chars: 6000,
43            inject_on_report_keywords: vec![
44                "审查报告".into(),
45                "final report".into(),
46                "synthesize".into(),
47                "write the report".into(),
48                "写报告".into(),
49                "全库".into(),
50                "全仓".into(),
51                "代码级审核".into(),
52                "代码级审查".into(),
53                "repo-wide".into(),
54                "code-level audit".into(),
55                "deliverables".into(),
56                "audit report".into(),
57                "输出md".into(),
58                "md格式".into(),
59                "md 报告".into(),
60                "code_review".into(),
61            ],
62            retention_days: 30,
63            coverage_soft_ratio: 0.85,
64            coverage_hard_ratio: 0.60,
65            coverage_hard_block_enabled: true,
66            coverage_count_deferred_as_accounted: true,
67            require_deferred_meta: true,
68            coverage_reviewed_warn_ratio: 0.70,
69            coverage_reviewed_hard_ratio: 0.40,
70            coverage_reviewed_hard_block_enabled: true,
71            auditor_from_scratchpad: true,
72            auditor_include_medium_min: 3,
73        }
74    }
75}
76
77/// Deserializable scratchpad table for TOML.
78#[derive(Debug, Clone, Deserialize, Default)]
79pub struct ScratchpadConfigToml {
80    #[serde(default)]
81    pub enabled: Option<bool>,
82    #[serde(default)]
83    pub max_notes_per_run: Option<usize>,
84    #[serde(default)]
85    pub remind_after_readonly_tools: Option<usize>,
86    #[serde(default)]
87    pub remind_enabled: Option<bool>,
88    #[serde(default)]
89    pub inject_summary_max_chars: Option<usize>,
90    #[serde(default)]
91    pub inject_on_report_keywords: Option<Vec<String>>,
92    #[serde(default)]
93    pub retention_days: Option<u32>,
94    #[serde(default)]
95    pub coverage_soft_ratio: Option<f64>,
96    #[serde(default)]
97    pub coverage_hard_ratio: Option<f64>,
98    #[serde(default)]
99    pub coverage_hard_block_enabled: Option<bool>,
100    #[serde(default)]
101    pub coverage_count_deferred_as_accounted: Option<bool>,
102    #[serde(default)]
103    pub require_deferred_meta: Option<bool>,
104    #[serde(default)]
105    pub coverage_reviewed_warn_ratio: Option<f64>,
106    #[serde(default)]
107    pub coverage_reviewed_hard_ratio: Option<f64>,
108    #[serde(default)]
109    pub coverage_reviewed_hard_block_enabled: Option<bool>,
110    #[serde(default)]
111    pub auditor_from_scratchpad: Option<bool>,
112    #[serde(default)]
113    pub auditor_include_medium_min: Option<usize>,
114}
115
116impl ScratchpadConfigToml {
117    #[must_use]
118    pub fn into_runtime(self) -> ScratchpadConfig {
119        let defaults = ScratchpadConfig::default();
120        ScratchpadConfig {
121            enabled: self.enabled.unwrap_or(defaults.enabled),
122            max_notes_per_run: self.max_notes_per_run.unwrap_or(defaults.max_notes_per_run),
123            remind_after_readonly_tools: self
124                .remind_after_readonly_tools
125                .unwrap_or(defaults.remind_after_readonly_tools),
126            remind_enabled: self.remind_enabled.unwrap_or(defaults.remind_enabled),
127            inject_summary_max_chars: self
128                .inject_summary_max_chars
129                .unwrap_or(defaults.inject_summary_max_chars),
130            inject_on_report_keywords: self
131                .inject_on_report_keywords
132                .unwrap_or(defaults.inject_on_report_keywords),
133            retention_days: self.retention_days.unwrap_or(defaults.retention_days),
134            coverage_soft_ratio: self
135                .coverage_soft_ratio
136                .unwrap_or(defaults.coverage_soft_ratio),
137            coverage_hard_ratio: self
138                .coverage_hard_ratio
139                .unwrap_or(defaults.coverage_hard_ratio),
140            coverage_hard_block_enabled: self
141                .coverage_hard_block_enabled
142                .unwrap_or(defaults.coverage_hard_block_enabled),
143            coverage_count_deferred_as_accounted: self
144                .coverage_count_deferred_as_accounted
145                .unwrap_or(defaults.coverage_count_deferred_as_accounted),
146            require_deferred_meta: self
147                .require_deferred_meta
148                .unwrap_or(defaults.require_deferred_meta),
149            coverage_reviewed_warn_ratio: self
150                .coverage_reviewed_warn_ratio
151                .unwrap_or(defaults.coverage_reviewed_warn_ratio),
152            coverage_reviewed_hard_ratio: self
153                .coverage_reviewed_hard_ratio
154                .unwrap_or(defaults.coverage_reviewed_hard_ratio),
155            coverage_reviewed_hard_block_enabled: self
156                .coverage_reviewed_hard_block_enabled
157                .unwrap_or(defaults.coverage_reviewed_hard_block_enabled),
158            auditor_from_scratchpad: self
159                .auditor_from_scratchpad
160                .unwrap_or(defaults.auditor_from_scratchpad),
161            auditor_include_medium_min: self
162                .auditor_include_medium_min
163                .unwrap_or(defaults.auditor_include_medium_min),
164        }
165    }
166}