feat: raid doctor runs verify entries with self-heal (closes #42)#87
Conversation
Every verify: entry on the active profile and per-repo raid.yaml files now runs as part of `raid doctor` and produces a finding: - first-try pass → ok - failure → onFail → pass → warn (remediated by onFail) - failure that can't be healed → error RunVerify now returns (VerifyOutcome, error) so doctor can distinguish a clean pass from a successful self-heal — the latter is a warning so the user knows something silently fixed itself. The remediated state maps to the doctor warn severity; failures don't short-circuit subsequent entries, so one run reports the full picture. The cmd/doctor JSON shape is unchanged — verify findings flow through the existing Finding type. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #87 +/- ##
==========================================
- Coverage 92.33% 92.17% -0.17%
==========================================
Files 37 37
Lines 3380 3423 +43
==========================================
+ Hits 3121 3155 +34
- Misses 168 175 +7
- Partials 91 93 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR wires verify: execution into raid doctor, extending health checks to run profile/repo precondition entries and report tri-state outcomes.
Changes:
- Adds
VerifyOutcomeand updatesRunVerifyto return OK/remediated/failed outcomes. - Adds doctor-side verify finding generation and tests for outcome mapping.
- Updates templates and docs to describe doctor verify behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
src/resources/repo-template |
Updates repo template verify guidance for doctor execution. |
src/resources/profile-template |
Updates profile template verify guidance for doctor execution. |
src/raid/raid.go |
Re-exports VerifyOutcome and updated RunVerify signature. |
src/internal/lib/verify.go |
Adds tri-state verify outcomes. |
src/internal/lib/verify_test.go |
Updates verify tests to assert outcomes. |
src/internal/lib/doctor.go |
Runs verify entries and converts outcomes into doctor findings. |
src/internal/lib/doctor_test.go |
Adds doctor verify tests. |
site/docs/whats-new.mdx |
Adds release note for doctor verify execution. |
site/docs/usage/doctor.mdx |
Documents doctor verify findings and behavior. |
site/docs/references/schema.mdx |
Updates schema reference text for verify doctor integration. |
Comments suppressed due to low confidence (4)
src/internal/lib/doctor.go:217
- Verify tasks are executed without applying the same default working-directory handling used by install tasks (
withDefaultDir(..., home)for profile tasks andwithDefaultDir(..., repoPath)for repo tasks). Any Shell verify entry that omitspathwill run from the doctor process's current directory, which can make relative checks/remediation pass or fail against the wrong location.
outcome, err := RunVerify(v)
src/internal/lib/doctor.go:217
raid doctornow executes arbitrary verify tasks andonFailremediation here, so this path can mutate the workspace or raid vars, but it is not run underWithMutationLocklike other task-executing/mutating commands (for example install/env/user commands). Concurrent doctor/install/env invocations can now race on the same files or~/.raid/vars; acquire the mutation lock around verify execution or the doctor command.
outcome, err := RunVerify(v)
src/internal/lib/doctor.go:217
- Running verify tasks here lets their stdout/stderr go through the global command output writers (defaulting to
os.Stdout/os.Stderr). Because the doctor CLI callsraid.Doctor()before encoding--json, any verify command that prints to stdout will prepend arbitrary text to the JSON response and make it unparsable; doctor should capture or redirect task output while collecting findings.
outcome, err := RunVerify(v)
src/internal/lib/doctor.go:217
- Verify entries can contain any task type, including
PromptandConfirm, andRunVerifyexecutes them unfiltered. That makesraid doctorblock waiting for stdin when a verify block contains an interactive task, which breaks doctor’s one-shot/non-interactive contract; reject or skip interactive task types for verify execution in doctor.
outcome, err := RunVerify(v)
| Message: "valid", | ||
| }) | ||
|
|
||
| findings = append(findings, checkVerify(fmt.Sprintf("repo/%s verify", repo.Name), repo.Verify)...) |
| repo := Repo{ | ||
| Name: "r", | ||
| Path: dir, | ||
| URL: "http://example.com/r.git", | ||
| Verify: []Verify{{Name: "hello", Tasks: []Task{{Type: Shell, Cmd: "exit 0"}}}}, | ||
| } |
| // VerifyOutcome distinguishes a first-try pass from a successful | ||
| // self-heal. Doctor maps these to OK / warn severities; a fourth state | ||
| // (failed) is conveyed by RunVerify's error return. |
| :::warning Verify tasks execute real commands | ||
| Doctor invokes the actual `tasks:` and `onFail:` shell commands you've defined. Keep verify checks small, fast, and side-effect-light (a `node --version` probe, a `test -f`, a `Wait` against a local port). Heavy bootstrap work belongs in `install:`. |
| ## 0.14.0 — upcoming | ||
|
|
||
| **Declarative `verify:` blocks.** Profiles and per-repo `raid.yaml`s now accept a top-level `verify:` list. Each entry runs `tasks:` to assert a precondition (a tool is installed, a port is reachable, a credentials file exists), and an optional `onFail:` remediation gets exactly one chance to fix things — if it succeeds, raid re-runs `tasks:` once and the verify is reported as remediated; otherwise it surfaces as a structured `VERIFY_FAILED` error. Verify entries share execution context with `install:` tasks (active env + raid vars + task options). `raid doctor` integration to surface verify entries as health-report findings follows in [#42](https://github.com/8bitAlex/raid/issues/42). See [Schema → Verify](/docs/references/schema#verify). Closes [#38](https://github.com/8bitAlex/raid/issues/38). | ||
| **`raid doctor` runs `verify:` entries with self-heal.** Every `verify:` entry on the active profile and per-repo `raid.yaml` files now runs as part of `raid doctor` and produces its own finding: `ok` for a first-try pass, `warn` when the optional `onFail:` block recovered a failing precondition (the verify holds *now*, but didn't before — worth knowing), and `error` when the precondition can't be made to hold. Failures don't short-circuit subsequent entries, so a single `raid doctor` run reports the full picture. Doctor invokes the actual `tasks:` shell commands — keep verify checks small and fast, since they'll run every time you (or CI, or an agent) checks raid's health. See [Doctor → Verify entries](/docs/usage/doctor#verify-entries). Closes [#42](https://github.com/8bitAlex/raid/issues/42). |
| Declarative precondition checks. Each entry runs `tasks:` to assert that a dependency or environmental requirement is in place. An optional `onFail:` remediation gets exactly one chance to fix things — if remediation succeeds, raid re-runs `tasks:` once; if that pass succeeds the verify is reported as remediated, otherwise it fails. | ||
|
|
||
| Verify entries are accepted on both profiles and per-repo `raid.yaml` files. They share execution context with `install:` — the active environment, raid vars, and task options all apply. The schema accepts verify entries today; a future release will surface them through `raid doctor` (and, longer-term, a dedicated `raid verify` command). | ||
| Verify entries are accepted on both profiles and per-repo `raid.yaml` files. They share execution context with `install:` — the active environment, raid vars, and task options all apply. `raid doctor` runs every verify entry and surfaces each as a finding: a first-try pass is an `ok` finding, a successful self-heal is a `warn` (the precondition holds now, but didn't before — worth knowing), and a failure is an `error` carrying the underlying task error. |
- doctor: load per-repo raid.yaml verify entries before running them. Previously the doctor path never invoked buildRepo/ExtractRepo on the repo, so verify blocks defined only in raid.yaml were silently skipped (BuildSingleRepoProfile keeps only name/path/branch; ExtractProfile only sees what's in the wrapping profile). - verify: fix VerifyOutcome doc comment — describe the real tri-state enum rather than implying failed is a separate "fourth state". - docs: clarify that verify tasks/onFail can be any task type (HTTP, Git, Template, Prompt/Confirm, SetVar, …), not just shell. Updates doctor.mdx warning, whats-new.mdx release note, and the embedded verifyArray schema description (which still said verify entries were inert / doctor integration was future work). - tests: replace the pre-populated repo.Verify test with one that exercises the load-from-raid.yaml path, and add a merge case that covers both profile-level and raid.yaml verify entries. Co-Authored-By: Copilot <copilot@github.com>
|
Auto-review by meeseeks Updates pushed: 1 commit
Copilot comments addressed: 6 of 6
Skipped: 0 Codecov patch: 90.74% (project 92.17%) — within 8pt (gap 1.43pt, well under the 8pt tolerance), acceptable. |
Summary
Closes #42. Builds on the verify-block schema work in #86.
raid doctornow executes everyverify:entry on the active profile and per-reporaid.yamlfiles and surfaces each as its own finding:oktasks:exited cleanly on the first attemptwarntasks:failed,onFail:ran and recovered, retry oftasks:passed. Worth knowing — the precondition holds now, but didn't on the first tryerroronFail:, oronFail:itself failed, or the retry oftasks:still failed. The underlying error message is includedA failure on one entry doesn't short-circuit subsequent entries — one
raid doctorrun reports the full picture.RunVerify(v) (VerifyOutcome, error)now returns a tri-state outcome so doctor can distinguish a clean pass from a successful self-heal.VerifyOutcomeand its constants are re-exported throughsrc/raid.checkVerify(label, entries)lives indoctor.goand is called by bothcheckProfile()(for profile-levelverify:) andcheckRepo()(for repo-levelverify:).Findingtype, severity-encoded as\"ok\"/\"warn\"/\"error\".Profile and repo templates now describe the tri-state semantics; schema reference + doctor usage docs explain how doctor reports verify entries and warn that doctor invokes the real
tasks:shell commands.Test plan
go test ./... -race— all packages greenRunVerifyoutcome assertions insrc/internal/lib/verify_test.go(passes, fails-without-onFail, remediation-succeeds, remediation-fails, second-pass-fails, empty-tasks no-op)checkVerifytests insrc/internal/lib/doctor_test.go: passing → ok, remediated → warn, failed → error, zero entries skipped, failures don't short-circuit, empty list is no-opTestCheckProfile_runsProfileLevelVerify(mixed pass/fail at the profile level),TestCheckRepo_runsRepoLevelVerify(repo-level verify)verify.go+checkVerifyat 100% line coverage (per-package run); project coverage 92.9%cd site && npm run build— no broken links🤖 Generated with Claude Code