Skip to content

Commit a7cfbfa

Browse files
authored
Merge pull request #470 from DecapodLabs/agent/codex/bugs_01kk3wktkzarkbqb-self-heal-validation
Self-heal validate and add structured reports
2 parents 5899726 + 3c6867c commit a7cfbfa

8 files changed

Lines changed: 557 additions & 129 deletions

File tree

.decapod/OVERRIDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,10 @@
134134
### plugins/DECIDE.md
135135

136136
### plugins/AUTOUPDATE.md
137+
138+
### plugins/CONTAINER.md
139+
## Runtime Guard Override (auto-generated)
140+
DECAPOD_CONTAINER_RUNTIME_DISABLED=true
141+
reason: No docker/podman runtime found during validation self-heal.
142+
remediation: Install Docker or Podman, then remove this override if you want strict container gating restored.
143+
warning: disabling isolated containers increases risk of concurrent agents stepping on each other.

.decapod/governance/plan.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"schema_version": "1.0.0",
3+
"title": "Self-heal validation and structured reporting",
4+
"intent": "Make decapod validation converge toward green via safe self-heal actions, structured reporting, and environment-aware gating in the claimed workspace.",
5+
"state": "APPROVED",
6+
"todo_ids": [
7+
"bugs_01kk3wktkzarkbqb"
8+
],
9+
"proof_hooks": [
10+
"decapod validate",
11+
"cargo test --test validate_termination validate_json_reports_self_heal_and_structured_summary -- --nocapture"
12+
],
13+
"unknowns": [],
14+
"human_questions": [],
15+
"constraints": {
16+
"forbidden_paths": [],
17+
"file_touch_budget": null
18+
},
19+
"updated_at": "1772879509Z"
20+
}

src/core/docs_cli.rs

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,45 @@ pub struct DocsRunResult {
7575
pub ingested_core_constitution: bool,
7676
}
7777

78+
#[derive(Debug, Clone, PartialEq, Eq)]
79+
pub enum OverrideChecksumStatus {
80+
MissingOverride,
81+
Cached,
82+
Updated,
83+
Unchanged,
84+
}
85+
86+
pub fn sync_override_checksum(
87+
repo_root: &Path,
88+
force: bool,
89+
) -> Result<OverrideChecksumStatus, error::DecapodError> {
90+
let override_path = repo_root.join(".decapod").join("OVERRIDE.md");
91+
92+
if !override_path.exists() {
93+
return Ok(OverrideChecksumStatus::MissingOverride);
94+
}
95+
96+
let current_checksum = calculate_sha256(&override_path)?;
97+
if force {
98+
cache_checksum(repo_root, &current_checksum)?;
99+
return Ok(OverrideChecksumStatus::Cached);
100+
}
101+
102+
match get_cached_checksum(repo_root) {
103+
Some(cached_checksum) if cached_checksum == current_checksum => {
104+
Ok(OverrideChecksumStatus::Unchanged)
105+
}
106+
Some(_) => {
107+
cache_checksum(repo_root, &current_checksum)?;
108+
Ok(OverrideChecksumStatus::Updated)
109+
}
110+
None => {
111+
cache_checksum(repo_root, &current_checksum)?;
112+
Ok(OverrideChecksumStatus::Cached)
113+
}
114+
}
115+
}
116+
78117
pub fn run_docs_cli(cli: DocsCli) -> Result<DocsRunResult, error::DecapodError> {
79118
match cli.command {
80119
DocsCommand::List => {
@@ -216,42 +255,19 @@ pub fn run_docs_cli(cli: DocsCli) -> Result<DocsRunResult, error::DecapodError>
216255
let current_dir = std::env::current_dir().map_err(error::DecapodError::IoError)?;
217256
let repo_root = find_repo_root(&current_dir)?;
218257
let override_path = repo_root.join(".decapod").join("OVERRIDE.md");
219-
220-
if !override_path.exists() {
221-
println!("ℹ No OVERRIDE.md found at {}", override_path.display());
222-
println!(" Run `decapod init` to create one.");
223-
return Ok(DocsRunResult::default());
224-
}
225-
226-
// Calculate current checksum
227-
let current_checksum = calculate_sha256(&override_path)?;
228-
229-
if force {
230-
println!("🔄 Force re-caching OVERRIDE.md checksum...");
231-
cache_checksum(&repo_root, &current_checksum)?;
232-
println!("✓ Checksum cached: {}", current_checksum);
233-
return Ok(DocsRunResult::default());
234-
}
235-
236-
// Check if changed
237-
let cached = get_cached_checksum(&repo_root);
238-
match cached {
239-
Some(cached_checksum) if cached_checksum == current_checksum => {
240-
println!("✓ OVERRIDE.md unchanged");
241-
println!(" Cached checksum: {}", cached_checksum);
258+
match sync_override_checksum(&repo_root, force)? {
259+
OverrideChecksumStatus::MissingOverride => {
260+
println!("ℹ No OVERRIDE.md found at {}", override_path.display());
261+
println!(" Run `decapod init` to create one.");
242262
}
243-
Some(cached_checksum) => {
244-
println!("📝 OVERRIDE.md has changed");
245-
println!(" Old checksum: {}", cached_checksum);
246-
println!(" New checksum: {}", current_checksum);
247-
cache_checksum(&repo_root, &current_checksum)?;
248-
println!("✓ Checksum updated");
263+
OverrideChecksumStatus::Cached => {
264+
println!("✓ OVERRIDE.md checksum cached");
249265
}
250-
None => {
251-
println!("📝 First time caching OVERRIDE.md checksum");
252-
println!(" Checksum: {}", current_checksum);
253-
cache_checksum(&repo_root, &current_checksum)?;
254-
println!("✓ Checksum cached");
266+
OverrideChecksumStatus::Updated => {
267+
println!("📝 OVERRIDE.md checksum refreshed");
268+
}
269+
OverrideChecksumStatus::Unchanged => {
270+
println!("✓ OVERRIDE.md unchanged");
255271
}
256272
}
257273

0 commit comments

Comments
 (0)