Skip to content

refactor(doctor): extract flow finalization#52067

Merged
vincentkoc merged 2 commits intomainfrom
vincentkoc-code/doctor-refactor-phase11
Mar 22, 2026
Merged

refactor(doctor): extract flow finalization#52067
vincentkoc merged 2 commits intomainfrom
vincentkoc-code/doctor-refactor-phase11

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • extract the final doctor config confirm/write policy into a doctor-layer finalizer
  • thin doctor-config-flow further by removing the pendingChanges and shouldWriteConfig tail
  • add targeted coverage for preview accept/decline and repair-mode auto-write behavior

Testing

  • pnpm exec vitest run src/commands/doctor/finalize-config-flow.test.ts src/commands/doctor-config-flow.test.ts
  • pnpm build
  • pnpm check

Thanks @vincentkoc

@openclaw-barnacle openclaw-barnacle bot added the commands Command implementations label Mar 22, 2026
@vincentkoc vincentkoc self-assigned this Mar 22, 2026
@openclaw-barnacle openclaw-barnacle bot added size: S maintainer Maintainer-authored PR labels Mar 22, 2026
@vincentkoc vincentkoc marked this pull request as ready for review March 22, 2026 04:17
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 22, 2026

Greptile Summary

This PR extracts the final "confirm/write" step of the doctor config flow into a dedicated finalizeDoctorConfigFlow helper, reducing the surface area of loadAndMaybeMigrateDoctorConfig and making the three decision branches (preview-accept, preview-decline, repair-auto) independently testable.

  • Correctness: The refactoring faithfully preserves the original logic. Returning params.cfg (not params.candidate) in repair mode is intentional — by the time finalizeDoctorConfigFlow is called, runDoctorRepairSequence has already updated cfg in place.
  • Test coverage: The two preview-path tests (confirm and decline) are thorough and use distinct cfg/candidate objects. The repair-mode test covers the right scenario but passes identical values for cfg and candidate, so it cannot detect a regression where the wrong object is returned (see inline comment).
  • No behavioral change: The shouldWriteConfig local removed from the caller was the only other change; all callsites receive equivalent behavior through finalized.shouldWriteConfig.

Confidence Score: 5/5

  • This PR is safe to merge — it is a pure refactoring with no behavioral changes and adds targeted test coverage.
  • The extracted logic is a verbatim translation of the original inline code with no semantic differences. The only note is a minor test-coverage gap in the repair-mode test (identical cfg/candidate values), which is a non-blocking follow-up and does not affect correctness.
  • No files require special attention; the minor test improvement is tracked in the inline comment on finalize-config-flow.test.ts.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/commands/doctor/finalize-config-flow.test.ts
Line: 46-61

Comment:
**Repair-mode test doesn't distinguish `cfg` from `candidate`**

In this test `cfg` and `candidate` are set to identical values, so the assertion passes regardless of whether the implementation returns `params.cfg` or `params.candidate`. In repair mode the intent is to return the already-repaired `cfg` (updated upstream by `runDoctorRepairSequence`), but a future refactor that accidentally returned `params.candidate` here would go undetected.

Consider using distinct objects so the test pins the exact returned value:

```suggestion
  it("writes automatically in repair mode when changes exist", async () => {
    const result = await finalizeDoctorConfigFlow({
      cfg: { channels: { signal: { enabled: true } } },
      candidate: { channels: { signal: { enabled: false } } }, // deliberately different
      pendingChanges: true,
      shouldRepair: true,
      fixHints: [],
      confirm: async () => true,
      note: vi.fn(),
    });

    expect(result).toEqual({
      cfg: { channels: { signal: { enabled: true } } }, // cfg, not candidate
      shouldWriteConfig: true,
    });
  });
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "refactor(doctor): ex..."

Comment on lines +46 to +61
it("writes automatically in repair mode when changes exist", async () => {
const result = await finalizeDoctorConfigFlow({
cfg: { channels: { signal: { enabled: true } } },
candidate: { channels: { signal: { enabled: true } } },
pendingChanges: true,
shouldRepair: true,
fixHints: [],
confirm: async () => true,
note: vi.fn(),
});

expect(result).toEqual({
cfg: { channels: { signal: { enabled: true } } },
shouldWriteConfig: true,
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Repair-mode test doesn't distinguish cfg from candidate

In this test cfg and candidate are set to identical values, so the assertion passes regardless of whether the implementation returns params.cfg or params.candidate. In repair mode the intent is to return the already-repaired cfg (updated upstream by runDoctorRepairSequence), but a future refactor that accidentally returned params.candidate here would go undetected.

Consider using distinct objects so the test pins the exact returned value:

Suggested change
it("writes automatically in repair mode when changes exist", async () => {
const result = await finalizeDoctorConfigFlow({
cfg: { channels: { signal: { enabled: true } } },
candidate: { channels: { signal: { enabled: true } } },
pendingChanges: true,
shouldRepair: true,
fixHints: [],
confirm: async () => true,
note: vi.fn(),
});
expect(result).toEqual({
cfg: { channels: { signal: { enabled: true } } },
shouldWriteConfig: true,
});
});
it("writes automatically in repair mode when changes exist", async () => {
const result = await finalizeDoctorConfigFlow({
cfg: { channels: { signal: { enabled: true } } },
candidate: { channels: { signal: { enabled: false } } }, // deliberately different
pendingChanges: true,
shouldRepair: true,
fixHints: [],
confirm: async () => true,
note: vi.fn(),
});
expect(result).toEqual({
cfg: { channels: { signal: { enabled: true } } }, // cfg, not candidate
shouldWriteConfig: true,
});
});
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/doctor/finalize-config-flow.test.ts
Line: 46-61

Comment:
**Repair-mode test doesn't distinguish `cfg` from `candidate`**

In this test `cfg` and `candidate` are set to identical values, so the assertion passes regardless of whether the implementation returns `params.cfg` or `params.candidate`. In repair mode the intent is to return the already-repaired `cfg` (updated upstream by `runDoctorRepairSequence`), but a future refactor that accidentally returned `params.candidate` here would go undetected.

Consider using distinct objects so the test pins the exact returned value:

```suggestion
  it("writes automatically in repair mode when changes exist", async () => {
    const result = await finalizeDoctorConfigFlow({
      cfg: { channels: { signal: { enabled: true } } },
      candidate: { channels: { signal: { enabled: false } } }, // deliberately different
      pendingChanges: true,
      shouldRepair: true,
      fixHints: [],
      confirm: async () => true,
      note: vi.fn(),
    });

    expect(result).toEqual({
      cfg: { channels: { signal: { enabled: true } } }, // cfg, not candidate
      shouldWriteConfig: true,
    });
  });
```

How can I resolve this? If you propose a fix, please make it concise.

@vincentkoc vincentkoc merged commit ec59974 into main Mar 22, 2026
38 checks passed
@vincentkoc vincentkoc deleted the vincentkoc-code/doctor-refactor-phase11 branch March 22, 2026 04:27
aquaright1 pushed a commit to aquaright1/openclaw that referenced this pull request Mar 22, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
JohnJAS pushed a commit to JohnJAS/openclaw that referenced this pull request Mar 22, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
pholpaphankorn pushed a commit to pholpaphankorn/openclaw that referenced this pull request Mar 22, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
MaheshBhushan pushed a commit to MaheshBhushan/openclaw that referenced this pull request Mar 22, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
martingarramon added a commit to martingarramon/openclaw that referenced this pull request Mar 23, 2026
The doctor config-flow refactor series (PRs openclaw#51753openclaw#52067) extracted
shared modules into src/commands/doctor/shared/ with companion test
files. default-account-warnings.ts was the only substantive module
(157 lines, two public functions) without direct test coverage.

Adds 16 tests covering both exported functions:
- collectMissingDefaultAccountBindingWarnings: wildcard bindings,
  partial coverage, no bindings, multi-channel isolation
- collectMissingExplicitDefaultAccountWarnings: single vs multi
  account, matching/mismatched defaultAccount, missing defaultAccount

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
furaul pushed a commit to furaul/openclaw that referenced this pull request Mar 24, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 25, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg

(cherry picked from commit ec59974)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 25, 2026
* refactor(doctor): extract flow finalization

* test(doctor): pin repair finalization to cfg

(cherry picked from commit ec59974)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant