Skip to content

Doctor: add health-check contract and --lint validation#80055

Merged
giodl73-repo merged 8 commits into
openclaw:mainfrom
giodl73-repo:doctor-detection-validation
May 17, 2026
Merged

Doctor: add health-check contract and --lint validation#80055
giodl73-repo merged 8 commits into
openclaw:mainfrom
giodl73-repo:doctor-detection-validation

Conversation

@giodl73-repo

@giodl73-repo giodl73-repo commented May 10, 2026

Copy link
Copy Markdown
Contributor

Branch: doctor-detection-validation
Base: upstream/main
Head: a0eaef75cc

Summary

Today doctor health work is mostly procedural: a contribution runs, reports
status, and may repair inside the same run(ctx) flow. This PR introduces the
next doctor health-check contract, following the existing config-change pattern
of separating detection from application.

detect(ctx, scope?) -> HealthFinding[]
repair?(ctx, findings) -> HealthRepairResult

detect() powers the new read-only openclaw doctor --lint mode and also
powers post-fix validation after a modern repair() runs. --fix remains the
operator repair path; --lint is the structured detection/reporting path.

repair() now also carries the reporting shape needed for dry-run/diff follow-up: repair contexts can receive dryRun/diff, and repair results can report concrete diffs plus non-file effects. Detection stays read-only; repair owns mutation planning and preview reporting.

Motivation

Doctor already owns workspace health, but most checks today are shaped around a
single procedural run(ctx) path. That works for guided repair, but it blurs
three separate operator needs:

  • diagnose what is wrong without mutating the workspace
  • repair selected issues through the existing doctor --fix path
  • validate that the repair actually cleared the finding

The result is that users and automation often have to treat doctor --fix as
both diagnosis and repair. That is awkward for CI, risky for preflight checks,
and hard to reason about when a repair partially succeeds or needs manual
follow-up.

This PR keeps doctor as the owner of health checks and upgrades the contract
toward a detect/apply/validate flow. doctor --lint becomes the structured
reporting mode, while detect() gives doctor --fix the same logic for
post-repair validation.

Related issue signal:

  • #79166: asks for a
    doctor dry-run/diff mode because doctor --fix applies changes without a
    structured preview.
  • #77802: doctor --fix
    reports repairs, then fails validation and the same stale findings return on
    the next run.
  • #78217: doctor --fix
    partially runs against a live gateway and exits abruptly, leaving the user
    unsure what was applied.
  • #62261: update preflight
    already treats lint as a gate, but operators need clearer machine-readable
    diagnostics when a gate fails.

This PR does not claim to close those issues. It adds the shared doctor
detection, repair, and validation contract that current and follow-up checks can
use.

Maintainer Input Requested

  1. Should lint live inside doctor, or be a separate openclaw lint command?

    This PR treats linting as doctor's read-only health detection mode rather
    than a separate extension or command. The intent is to avoid creating a
    second health surface that would need its own check registry, docs, severity
    rules, and repair story.

    I also prepared an alternate draft that exposes the same diagnostic contract
    as top-level openclaw lint while keeping doctor focused on guided repair:
    Lint: add standalone diagnostic command #80800

  2. Is detect() / repair() the right health-check contract?

    Today many doctor contributions combine detection, reporting, and repair
    inside run(ctx). This PR keeps that legacy path, but follows the existing
    config change model by separating the needed change from the code that
    applies it. The doctor driver can then report, apply, and validate the result
    through:

    detect(ctx, scope?) -> HealthFinding[]
    repair?(ctx, findings) -> HealthRepairResult

    detect() powers doctor --lint and post-repair validation. repair() lets
    a modern check report whether it repaired, skipped, or failed the requested
    findings and why.

  3. Is this the right migration path for existing doctor rules?

    The PR migrates a small set of core checks first and leaves existing doctor
    checks on the legacy path. If accepted, remaining hard-coded doctor rules can
    migrate incrementally: move diagnostics into detect(ctx) first, add
    repair(ctx, findings) only when repair behavior is understood and covered,
    and keep legacy run(ctx) for checks that still need prompts, service
    changes, backups, or platform-specific flows.

  4. Is src/flows the right home, or should health move toward a capability
    home?

    This PR keeps the new doctor health code near the existing doctor flow
    machinery to minimize movement during the contract change. If maintainers
    expect health checks to become part of the broader capability ownership
    model, the same contract could move under a clearer health or capability
    home as the remaining rules migrate.

What Changed

  • Added structured health primitives: HealthFinding, HealthCheck,
    HealthCheckContext, HealthCheckScope, and HealthRepairResult.
  • Added a small doctor health-check registration point for modern detect() /
    repair() checks, alongside the existing legacy doctor contribution flow.
  • Exported the narrow health contract through openclaw/plugin-sdk/health for
    bundled health-check consumers. Test-only registry reset helpers remain
    internal.
  • Added doctor --lint with --json, --severity-min, --skip, and --only.
  • Kept doctor --lint plugin-free at CLI startup. This preserves structured
    config/error reporting even when plugin loading would otherwise fail.
  • Modernized five core checks:
    • core/doctor/gateway-config
    • core/doctor/command-owner
    • core/doctor/workspace-status
    • core/doctor/skills-readiness
    • core/doctor/final-config-validation
  • Added structured repair() support for modern checks in doctor --fix.
  • Added explicit repair outcomes (repaired, skipped, failed) so a check
    can tell the driver it did not perform the requested repair and why.
  • Added repair preview metadata: dryRun/diff repair context flags, structured
    diffs for config/file edits, and effects for service, process, package,
    state, or other side effects.
  • Added scoped post-repair validation: after repair(), doctor runs
    detect(ctx, scope) again and reports remaining findings as repair warnings.
  • Updated doctor docs and gateway doctor docs.

Behavior

Example lint output:

doctor --lint: ran 5 check(s), 1 finding(s)
  [warning] core/doctor/gateway-config gateway.mode - gateway.mode is unset; gateway start will be blocked.
    fix: Run `openclaw configure` and set Gateway mode (local/remote), or `openclaw config set gateway.mode local`.

Exit codes:

  • 0: no findings at or above the selected threshold
  • 1: one or more findings met the selected threshold
  • 2: command/runtime failure before findings could be emitted

Repair validation behavior:

  • repair(ctx, findings) receives findings from its own check.
  • repair() reports repaired, skipped, or failed with an optional reason.
  • after a repaired result, doctor re-runs scoped detect(ctx, scope) for
    validation.
  • remaining findings are surfaced as repair warnings; the follow-up detection
    pass is the proof.

Review Notes

This is an internal contract, not a public repair API. Existing doctor repairs
still cover prompts, backups, service changes, plugin installs, and
platform-specific flows through the legacy contribution pipeline.

This PR prepares the modern repair contract for future doctor --fix --dry-run / diff output, but does not expose a whole-doctor dry-run flag yet. Legacy repairs still need to migrate or explicitly classify their side effects before that CLI can be honest across the full doctor surface.

Structured repairs run inside the existing doctor contribution sequence before
legacy repair steps, so rules can migrate gradually. Checks that are not ready
for detect() / repair() keep using run(ctx).

Real behavior proof

Behavior addressed: openclaw doctor --lint exposes read-only doctor health detection backed by the new detect() / repair() contract, and the repair contract now carries dry-run/diff reporting metadata without moving mutation planning into detect().

Real environment tested: WSL Ubuntu-24.04 source checkout on branch doctor-detection-validation, PR head a0eaef75cc.

Exact steps or command run after this patch:

node scripts/run-node.mjs doctor --lint --only core/doctor/gateway-config --json
node scripts/run-vitest.mjs src/flows/doctor-repair-flow.test.ts src/flows/doctor-core-checks.test.ts src/flows/doctor-lint-flow.test.ts src/commands/doctor-lint.test.ts
pnpm plugin-sdk:api:check
node scripts/format-docs.mjs --check docs/cli/doctor.md docs/gateway/doctor.md
git diff --check

Evidence after fix: Real CLI output from the WSL checkout:

$ node scripts/run-node.mjs doctor --lint --only core/doctor/gateway-config --json
{"ok":false,"checksRun":1,"checksSkipped":4,"findings":[{"checkId":"core/doctor/gateway-config","severity":"warning","message":"gateway.mode is unset; gateway start will be blocked.","path":"gateway.mode","fixHint":"Run `openclaw configure` and set Gateway mode (local/remote), or `openclaw config set gateway.mode local`."}]}

The focused repair-flow test also now proves runDoctorHealthRepairs(..., { dryRun: true, diff: true }) passes dryRun / diff into repair(), collects returned diffs and effects, does not apply returned config, and skips post-repair validation during preview mode.

Observed result after fix: The lint command ran a real registered core detect() check and emitted structured JSON findings. The repair contract now reports preview metadata through repair() results, while detect() remains read-only diagnosis.

What was not tested: No external channel or gateway service was started. This proof covers the doctor lint/health-check contract, core detection/reporting path, and structured repair dry-run plumbing.

Testing

Passed focused doctor lint/repair/core-check tests, CLI registration coverage,
plugin SDK API checks, docs checks, and targeted oxlint on the changed doctor
flow files.

Follow-Up

If this model is accepted, migrate remaining hard-coded doctor rules
incrementally: move diagnostics into detect(ctx) first, then add
repair(ctx, findings) only when the repair behavior is understood and covered.

The stacked policy drafts show bundled-extension consumers of this model. The
channels draft is the smaller first example: policy contributes doctor findings
through a narrow bundled health registration path, uses doctor --lint for
workspace validation, and participates in doctor --fix with scoped
post-repair validation.

Related stacked drafts:

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime cli CLI command changes commands Command implementations size: XL maintainer Maintainer-authored PR labels May 10, 2026
@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by maintainer comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors can comment @clawsweeper re-review or @clawsweeper re-run on their own open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
This PR adds a doctor health-check contract, openclaw doctor --lint, structured repair metadata, a plugin-sdk/health export, docs, and focused tests.

Reproducibility: yes. for the review finding: source inspection at PR head shows doctor --lint registers the final config validation check, and that check performs a default observing config read. I did not run the command because this review is read-only.

Real behavior proof
Sufficient (terminal): The PR body and linked proof summary include terminal-style before/after evidence from clean worktrees showing the new doctor lint path running real registered detect checks and emitting structured findings.

Next step before merge
There is one narrow mechanical blocker that an automated repair branch can address, while final merge still needs maintainer API/product approval.

Security
Cleared: No concrete security or supply-chain regression found; the package export needs API review, but the diff does not add dependency sources, workflow permissions, lifecycle hooks, secret handling, or downloaded executables.

Review findings

  • [P2] Keep final validation read-only under lint — src/flows/doctor-core-checks.ts:177
Review details

Best possible solution:

Land the doctor-owned lint and repair contract only after every lint check is non-mutating and the new health SDK boundary is explicitly approved.

Do we have a high-confidence way to reproduce the issue?

Yes for the review finding: source inspection at PR head shows doctor --lint registers the final config validation check, and that check performs a default observing config read. I did not run the command because this review is read-only.

Is this the best way to solve the issue?

No for the current patch: the contract direction is plausible, but lint detection must reuse non-observing config state or pass { observe: false } before the read-only mode is safe.

Full review comments:

  • [P2] Keep final validation read-only under lint — src/flows/doctor-core-checks.ts:177
    doctor --lint runs the registered core checks, including final config validation, but this check calls readConfigFileSnapshot() without { observe: false }. The PR's config IO observes by default and its new regression test shows a default snapshot read creates config-health.json, so lint can still write local state despite the docs promising no config/state writes. Use the already loaded lint snapshot or a non-observing read for this detection path.
    Confidence: 0.92

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • node scripts/run-vitest.mjs src/commands/doctor-lint.test.ts src/flows/doctor-core-checks.test.ts src/config/io.best-effort.test.ts
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
  • git diff --check

What I checked:

  • Protected active PR: The provided GitHub context shows this PR is open, contributor-authored, recently updated, and labeled maintainer, so this cleanup workflow should not close it automatically. (8eccc6566807)
  • Current main does not already contain the feature: Current main has no runDoctorLintCli, HealthFinding, plugin-sdk/health, or doctor --lint implementation surface. (fb53c2d61092)
  • Lint runs core checks: At PR head, runDoctorLintCli() calls registerCoreHealthChecks() before executing lint checks. (src/commands/doctor-lint.ts:38, 8eccc6566807)
  • Final validation still observes config during lint: The final config validation health check calls readConfigFileSnapshot() without { observe: false }, so normal lint runs can still update config observation state. (src/flows/doctor-core-checks.ts:177, 8eccc6566807)
  • Config snapshot reads observe by default: The PR adds observe?: boolean, defaults it to true, and only skips observeConfigSnapshot() when callers pass { observe: false }. (src/config/io.ts:957, 8eccc6566807)
  • Regression test documents the write side effect: The added config test proves { observe: false } avoids config-health.json, while a default snapshot read creates that state file. (src/config/io.best-effort.test.ts:17, 8eccc6566807)

Likely related people:

  • giodl73-repo: The current main history includes recent doctor health-flow work by Gio Della-Libera, and this PR also comes from the same contributor account. (role: recent area contributor; confidence: medium; commits: fb53c2d61092; files: src/flows/doctor-health-contributions.ts, src/commands/doctor-session-snapshots.ts)
  • Peter Steinberger: Current-main blame and history for the config IO, doctor health contribution, package export, and plugin SDK entrypoint surfaces point to commit 543518b. (role: adjacent owner; confidence: medium; commits: 543518bd43d7; files: src/config/io.ts, src/flows/doctor-health-contributions.ts, src/plugin-sdk/entrypoints.ts)

Remaining risk / open question:

  • The public-versus-bundled boundary for plugin-sdk/health still needs maintainer API approval.
  • The stacked policy PRs depend on this health contract, so landing order and contract shape matter beyond this PR alone.

Codex review notes: model gpt-5.5, reasoning high; reviewed against fb53c2d61092.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from 7a83aea to cc848f4 Compare May 10, 2026 02:44
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label May 10, 2026
@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch 3 times, most recently from 2372d24 to 584507a Compare May 10, 2026 03:07
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from 584507a to e8b26f1 Compare May 10, 2026 03:36
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from e8b26f1 to 5038cc8 Compare May 10, 2026 06:10
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from 5038cc8 to f5f503c Compare May 10, 2026 06:57
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from f5f503c to 244d15f Compare May 10, 2026 14:14
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo force-pushed the doctor-detection-validation branch from 244d15f to 1f2d5b3 Compare May 10, 2026 14:30
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

Maintainer update on the lint direction:

I am closing the alternate standalone lint-command draft (#80800) and keeping this PR as the active path. The current plan is to avoid creating a second health surface: doctor --lint becomes the reporting/validation mode for the same doctor health-check contract that powers doctor --fix.

To keep the follow-up reviewable, I split the larger conversion work into small area-specific branches. The first on-deck branch converts only read-only checks and adds the checked conversion plan: giodl73-repo#1. That branch is stacked on this PR for now and can be opened upstream once this base is accepted.

…lidation

# Conflicts:
#	docs/.generated/plugin-sdk-api-baseline.sha256
#	src/config/io.ts
@clawsweeper clawsweeper Bot added the impact:session-state Session, memory, transcript, context, or agent state can drift or corrupt. label May 17, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 17, 2026
@giodl73-repo giodl73-repo merged commit 9a5f2f6 into openclaw:main May 17, 2026
113 checks passed
giodl73-repo added a commit to giodl73-repo/openclaw that referenced this pull request May 17, 2026
Update the read-only doctor health conversion branch after openclaw#80055 landed on main, keep the conversion inventory aligned with the new session snapshot contribution, and remove the brittle doctor-lint exact core-check count assertion.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
galiniliev pushed a commit to galiniliev/openclaw that referenced this pull request May 20, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
galiniliev pushed a commit to galiniliev/openclaw that referenced this pull request May 25, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
* feat(doctor): add --lint mode + structured HealthFinding shape

Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.

Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
   types. Findings carry severity per-finding; checks return
   readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
   distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
   duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
   Catches throws into synthetic error findings (anchored at check id;
   message scrubbed of control chars, capped at 256 bytes). Sorts
   findings by severity desc, check id, path. Exports
   exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
   logic from existing legacy run*Health functions:
     core/doctor/gateway-config            (warning)
     core/doctor/command-owner             (info)
     core/doctor/workspace-status          (info)
     core/doctor/final-config-validation   (error)
   Each was audited safe per the proposal's adapter constraints
   (no writes, no repair calls, no prompts, no probes incl. local-bind).
   Legacy run*Health contributions in doctor-health-contributions.ts
   are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
   snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
   filters by --severity-min, emits human or JSON output, returns exit
   code from unfiltered set so --severity-min hides info findings
   without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
   --severity-min, --skip, --only flags to existing doctor command.
   --lint branches to runDoctorLintCli; without --lint, doctor runs
   unchanged.

LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.

* fix: avoid string spread in doctor errors

* chore: refresh plugin SDK API baseline

* docs: clarify doctor lint usage

* feat(doctor): prepare repairs for dry-run reporting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes commands Command implementations dependencies-changed PR changes dependency-related files docs Improvements or additions to documentation extensions: qa-lab gateway Gateway runtime impact:session-state Session, memory, transcript, context, or agent state can drift or corrupt. maintainer Maintainer-authored PR P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants