feat(autoheal): deploy_drift_probe plan-object (slice A, closes #65) #77

Merged
pdurlej merged 1 commit from gemini/autoheal-slice-A into main 2026-06-08 19:54:24 +02:00
Collaborator

Authored by gemini (Gemini 3.1 Pro via Antigravity), Swarmheart worker under claude's arbitration. claude read the plan-generator + risk taxonomy line-by-line, verified the verdict-semantics invariant, ran tests independently.

What

Auto-heal roadmap slice A / closes substance of #65. The evaluator now emits an actionable plan object for a read-only repair (e.g. deploy_drift_probe) so the operator/Iskra sees what a proposed repair would touch. Deterministic, read-only, no network, no mutation.

Plan shape (emitted only for eligible read-only repairs)

"plan": {
  "changed_files": [...],
  "expected_target_paths": [...],
  "risk_class": "low|medium|high",
  "recommended_executor": "iskra-openclaw deterministic executor",
  "required_postchecks": [...]
}

risk_class is derived deterministically from changed-file prefixes: deploy/ infra/ secrets/ systemd/ services/ .forgejo/ compose/ → high; scripts/ plugins/ skills/ → medium; else low.

claude's review (invariants held)

  • Plan gate is exactly right: emitted only when policy is not None AND not policy.mutation AND verdict ∉ {blocked, needs_human} AND proposed_repair is a dict. So a plan appears only on eligible_repair_dry_run for a read-only class; it is null for every mutation class and every blocked verdict.
  • Verdict semantics untouched — the plan is computed after the verdict; a mutation class still never reaches eligible and never gets a plan. recommended_executor names Iskra, never Patchwarden (D20 intact).
  • Schema: plan is ["object","null"], NOT in top-level required → optional/nullable → cross-branch safe with slice D's contract test.
  • 🔸 Minor (non-blocking): risk_class is effectively driven by repo-relative changed_files (absolute target_paths won't independently raise it, due to lstrip("/") + prefix match). This is reasonable — it mirrors pr_check's repo-prefix classification — and the typical signal (a changed systemd/… or deploy/… file) is caught. Plus a little trailing whitespace. Fine to fold into a later pass.

Arbiter verification (claude)

  • PYTHONPATH=src python3 -m unittest discover tests208/208 OK (200 baseline + 8 PlanObjectTests).
  • Tests cover: plan emitted for drift probe; risk low/medium/high derivation; plan null for mutation + blocked; example validates against schema.
  • D20 boundary test passes; grep for requests|httpx|tenacity|backoff → zero; stdlib-only preserved.
  • Schema + example updated consistently.

Files

src/patchwarden/runtime_repair.py (+41), spec/schemas/runtime-repair-verdict.schema.json (+31), spec/schemas/examples/...eligible-dry-run.json (+13), tests/test_runtime_repair.py (+87).

Merge order note

Independent of slice D (#76) — different files. Either order merges cleanly; D's contract test is tolerant of A's optional plan.

Closes substance of #65; roadmap slice A (docs/operations/autoheal-roadmap.md). Refs #68, #70.

> **Authored by gemini** (Gemini 3.1 Pro via Antigravity), Swarmheart worker under claude's arbitration. claude read the plan-generator + risk taxonomy line-by-line, verified the verdict-semantics invariant, ran tests independently. ## What Auto-heal roadmap **slice A** / closes substance of #65. The evaluator now emits an actionable **`plan` object** for a read-only repair (e.g. `deploy_drift_probe`) so the operator/Iskra sees what a proposed repair would touch. Deterministic, read-only, no network, no mutation. ## Plan shape (emitted only for eligible read-only repairs) ```json "plan": { "changed_files": [...], "expected_target_paths": [...], "risk_class": "low|medium|high", "recommended_executor": "iskra-openclaw deterministic executor", "required_postchecks": [...] } ``` `risk_class` is derived deterministically from changed-file prefixes: `deploy/ infra/ secrets/ systemd/ services/ .forgejo/ compose/` → high; `scripts/ plugins/ skills/` → medium; else low. ## claude's review (invariants held) - ✅ **Plan gate is exactly right:** emitted only when `policy is not None AND not policy.mutation AND verdict ∉ {blocked, needs_human} AND proposed_repair is a dict`. So a plan appears **only** on `eligible_repair_dry_run` for a read-only class; it is `null` for every mutation class and every blocked verdict. - ✅ **Verdict semantics untouched** — the plan is computed *after* the verdict; a mutation class still never reaches eligible and never gets a plan. `recommended_executor` names Iskra, never Patchwarden (D20 intact). - ✅ **Schema:** `plan` is `["object","null"]`, NOT in top-level `required` → optional/nullable → cross-branch safe with slice D's contract test. - 🔸 **Minor (non-blocking):** `risk_class` is effectively driven by repo-relative `changed_files` (absolute `target_paths` won't independently raise it, due to `lstrip("/")` + prefix match). This is reasonable — it mirrors `pr_check`'s repo-prefix classification — and the typical signal (a changed `systemd/…` or `deploy/…` file) is caught. Plus a little trailing whitespace. Fine to fold into a later pass. ## Arbiter verification (claude) - `PYTHONPATH=src python3 -m unittest discover tests` → **208/208 OK** (200 baseline + 8 `PlanObjectTests`). - Tests cover: plan emitted for drift probe; risk low/medium/high derivation; plan `null` for mutation + blocked; example validates against schema. - D20 boundary test passes; `grep` for `requests|httpx|tenacity|backoff` → zero; stdlib-only preserved. - Schema + example updated consistently. ## Files `src/patchwarden/runtime_repair.py` (+41), `spec/schemas/runtime-repair-verdict.schema.json` (+31), `spec/schemas/examples/...eligible-dry-run.json` (+13), `tests/test_runtime_repair.py` (+87). ## Merge order note Independent of slice D (#76) — different files. Either order merges cleanly; D's contract test is tolerant of A's optional `plan`. Closes substance of #65; roadmap slice A (`docs/operations/autoheal-roadmap.md`). Refs #68, #70.
This commit introduces a `plan` object to the runtime-repair evaluator verdict for read-only repairs with a proposed_repair bundle. The `plan` contains:
- `changed_files`: List of changed files.
- `expected_target_paths`: List of expected target paths.
- `risk_class`: Deterministically derived risk (low/medium/high) based on file prefixes (high for deploy/, infra/, secrets/, systemd/, services/, .forgejo/, compose/; medium for scripts/, plugins/, skills/; low otherwise).
- `recommended_executor`: Fixed string "iskra-openclaw deterministic executor".
- `required_postchecks`: List of required postchecks.

Final test count: 208

Co-Authored-By: Gemini 3.1 Pro (Antigravity) <noreply@antigravity.google>
pdurlej deleted branch gemini/autoheal-slice-A 2026-06-08 19:54:24 +02:00
Sign in to join this conversation.
No reviewers
No labels
agent/claude-code
agent/codex
agent/gemini
agent/hermes
agent/iskra
agent/ollama
agent/patchwarden
area:business-model
area:competitive
area:discovery
area:forgejo
area:metrics
area:product-strategy
area:v0-core
cagan-grade-approved
client:platform
dependency/blocked
dependency/blocks-others
dependency/cross-repo
dependency/needs-confirmation
domain:agents
domain:ci
domain:docs
domain:forgejo
domain:infra
domain:memory
domain:runtime
domain:signal
domain:ux
flow/architecture
flow/blocked
flow/deployed
flow/done
flow/implementation
flow/intake
flow/maintained
flow/observed
flow/ready
flow/refining
flow/retired
flow/review
judge/codex-candidate
judge/hermes-candidate
judge/low-confidence
judge/needs-refinement
judge/operator-needed
judge/p0
judge/p1
judge/p2
judge/p3
judge/park
judge/patchwarden-candidate
judge/stale-priority
kind/adr
kind/bug
kind/chore
kind/feature
kind/infra
kind/ops
kind/refactor
kind/research
kind:artifact
kind:decision
kind:dogfood
kind:epic
kind:implementation
kind:research
merge/auto
merge/manual
merge/manual-dependency-conflict
merge/manual-failing-tests
merge/manual-merge-conflict
merge/manual-missing-review
merge/manual-operator-preference
merge/manual-red-zone
merge/manual-security-sensitive
merge/manual-unclear-scope
merge/manual-unknown
mode:operator-only
mode:patchwarden-iskra-approved
mode:safe-auto
observed/erroring
observed/needs-followup
observed/pending
observed/retire-candidate
observed/unused
observed/used
priority:p0
priority:p1
priority:p2
priority:p3
ready-for-agent
review:claude-reviewed
review:codex-reviewed
review:dziadek-reviewed
review:needs-human
safety:external-write
safety:no-prod-mutation
safety:prod-impact
safety:secret-touch
size/large
size/medium
size/small
size/tiny
size/unknown
source/adr
source/agent-generated
source/manual
source/operator-chat
source/voice-note
status:blocked
status:blocked-on-discovery
status:cagan-grade-review-pending
status:codex-ready
status:merged:pending-evidence
status:needs-evidence
status:needs-operator-decision
status:operator-needed
status:parked
tier:0-anchor
tier:0-platform-substrate
tier:1-core
tier:1-iskra-value-layer
tier:2-supporting
tier:2-tools-products-modules
type:bug
type:chore
type:docs
type:feat
type:policy
type:research
wave:1-foundation
wave:2-positioning
wave:3-validation
wave:4-economics
wave:5-operating
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pdurlej/patchwarden!77
No description provided.