Skip to content

feat(cli): add doctor diagnostics and help snapshots#43

Open
devcool20 wants to merge 9 commits into
inthhq:mainfrom
devcool20:fix/13-cli-doctor-help
Open

feat(cli): add doctor diagnostics and help snapshots#43
devcool20 wants to merge 9 commits into
inthhq:mainfrom
devcool20:fix/13-cli-doctor-help

Conversation

@devcool20

@devcool20 devcool20 commented May 18, 2026

Copy link
Copy Markdown

Linked Issue

Closes #13.

Implemented:

  • dsar doctor config/runtime/auth/persistence reachability checks
  • command-specific and command-group help
  • help snapshots and regression coverage
  • sanitized doctor diagnostics output
  • readable default doctor text output with --output json retained for automation

Completed in follow-up commits on this PR (maintainer update):

  • operator/service-scoped GET /status/diagnostics backend endpoint exposing schema migration freshness and per-adapter health
  • dsar doctor now fails on stale migrations or down adapters, warns on degraded adapters, and keeps graceful warn/skip behavior against older backends
  • changeset added (dsar: minor)

Description

Adds an initial dsar doctor command for CLI/runtime diagnostics and expands CLI help coverage.

This includes:

  • API URL validation
  • runtime /status reachability check
  • authenticated protected-request probe when a token is configured
  • warning/skipped diagnostics for migration freshness and adapter health when the backend does not expose those surfaces yet
  • command-specific help output via dsar <command> --help
  • grouped help output via dsar requests --help
  • golden help snapshots for every registered CLI command
  • exit-code documentation

With the diagnostics endpoint added in the follow-up commits, this PR now fully closes #13.

##Screenshots for validation

Screenshot 2026-05-18 222129 Screenshot 2026-05-18 222057 Screenshot 2026-05-18 222013

Validation

bun --cwd packages/cli vitest run
bun run --cwd packages/cli typecheck
bun x ultracite check packages/cli/src/config.ts packages/cli/src/runtime.ts packages/cli/src/types.ts packages/cli/src/commands/doctor.ts packages/cli/src/commands/system.ts packages/cli/test/doctor.test.ts packages/cli/test/help.test.ts packages/cli/test/e2e/parity-guard.e2e.test.ts packages/cli/README.md docs/reference/developer/cli.mdx
bun run check:docs-lint
bun run check:tsdoc
git diff --check

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@devcool20, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c3c27d87-2750-44c6-a39e-c2686fbdce7e

📥 Commits

Reviewing files that changed from the base of the PR and between a917ea2 and 53d4dca.

📒 Files selected for processing (4)
  • packages/backend/src/routes/status.ts
  • packages/backend/test/routes/status.test.ts
  • packages/cli/src/commands/doctor.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
📝 Walkthrough

Walkthrough

Adds dsar doctor, protected status diagnostics, token-aware CLI help, optional API URL parsing, structured output envelopes, and updated tests/docs for the new diagnostics flow.

Changes

CLI doctor diagnostics command and help system

Layer / File(s) Summary
Infrastructure: types, config, and persistence status
packages/cli/src/types.ts, packages/cli/src/config.ts, packages/internals/persistence/src/index.ts, packages/internals/persistence/src/services/persistence.ts, packages/internals/persistence/src/services/persistence/migrations.ts
Adds allowMissingApiUrl, isSuccessfulResult, and formatTextResult to CommandDefinition; exports parseCliArguments; makes API URL parsing optionally allow missing values; and adds persistence migration status types, helpers, service wiring, and re-exports.
Status diagnostics endpoint
packages/backend/src/http-api/groups/status.ts, packages/backend/src/routes/status.ts
Adds protected /status/diagnostics OpenAPI and route handlers that authorize operator/service actors, read migration status, probe adapter health/diagnostics, and return structured diagnostics payloads.
Doctor command implementation
packages/cli/src/commands/doctor.ts
Implements the doctor command checks for config, runtime reachability, authenticated reads, migration freshness, and adapter health, with summary aggregation, JSON/text formatting, and success classification.
Runtime help and envelope handling
packages/cli/src/runtime.ts, packages/cli/src/commands/system.ts, packages/cli/src/commands/audit-tail.ts
Reworks envelope formatting, token-aware help rendering, command resolution, result validation, system command wiring, and flag help metadata.
Tests and documentation
packages/cli/test/e2e/doctor.e2e.test.ts, packages/cli/test/help.test.ts, packages/cli/test/parity.test.ts, packages/cli/test/e2e/parity-guard.e2e.test.ts, packages/backend/test/routes/status.test.ts, packages/backend/test/e2e/tenant-isolation.test.ts, docs/reference/developer/cli.mdx, packages/cli/README.md, .changeset/cli-doctor-diagnostics.md
Adds doctor/help/parity/status-route coverage and updates CLI docs, README, and changeset notes for diagnostics, help behavior, and exit codes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • inthhq/dsar#48: Touches protected-route authorization and forbidden handling that affect GET /status/diagnostics.
  • inthhq/dsar#29: Also adds GET /status/diagnostics to backend route coverage.
  • inthhq/dsar#34: Works in the persistence migration-status area used by dsar doctor.

Poem

I’m a bunny with a clipboard light,
I hop through help and checks all night.
Migrations hum, adapters glow,
And tidy exit codes now know.
🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The webhook-secret-encryption refactor is unrelated to the CLI doctor/help objectives and looks like an extra non-functional change. Split the unrelated webhook-secret-encryption formatting changes into a separate PR unless they are required for this feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: a CLI doctor diagnostics feature with help snapshots.
Description check ✅ Passed The description matches the changeset and covers the new doctor command, help snapshots, diagnostics, and exit-code docs.
Linked Issues check ✅ Passed The PR covers command help snapshots, doctor diagnostics, migration and adapter checks, auth probing, and documented exit codes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/commands/doctor.ts`:
- Around line 152-160: The diagnostics probe in doctor.ts currently returns the
full `result` from `ctx.api.invoke` (the `/requests` GET) as `details`, which
may leak sensitive payloads; change the probe to call `ctx.api.invoke` as it
does now but replace `details: result` in the returned object with a sanitized
summary (e.g., HTTP status, total/count of items, truncated or masked request
IDs, and any non-sensitive timestamps) and ensure any user/request fields are
omitted or redacted before returning; update the code around the invocation and
the return statement that references `result` so only this minimal metadata is
exposed.

In `@packages/cli/src/runtime.ts`:
- Around line 156-166: The help flag (-h/--help) is being interpreted as a
positional token because renderHelp calls parseCliArguments(argv) directly; to
fix, strip known help flags from argv before calling parseCliArguments in
renderHelp so that -h/--help are not included in commandTokens, then continue to
call resolveCommand and renderCommandHelp/renderCommandGroupHelp as before
(update renderHelp to filter argv for "-h" and "--help" prior to
parseCliArguments).

In `@packages/cli/test/help.test.ts`:
- Around line 6-14: The test helper renderHelp currently returns only the first
captured stdout entry (stdout[0]) which misses multi-line/multi-write help
output; update renderHelp to join all captured output entries (e.g., using
stdout.join("\n") or similar) and return that combined string (falling back to
"" when empty) so snapshots receive the full help output; modify the code around
the stdout array and the return in the renderHelp function accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ecd9e62a-6885-4c90-80ff-a2a3ee56cf0c

📥 Commits

Reviewing files that changed from the base of the PR and between e0c300b and 2d6da4a.

⛔ Files ignored due to path filters (1)
  • packages/cli/test/__snapshots__/help.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • docs/reference/developer/cli.mdx
  • packages/cli/README.md
  • packages/cli/src/commands/doctor.ts
  • packages/cli/src/commands/system.ts
  • packages/cli/src/config.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/types.ts
  • packages/cli/test/doctor.test.ts
  • packages/cli/test/e2e/parity-guard.e2e.test.ts
  • packages/cli/test/help.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/cli/test/help.test.ts
  • packages/cli/test/e2e/parity-guard.e2e.test.ts
  • packages/cli/src/commands/system.ts
  • packages/cli/src/types.ts
  • packages/cli/test/doctor.test.ts
  • packages/cli/src/config.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/commands/doctor.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types instead of relying on Oxlint + Oxfmt to catch naming issues
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/cli/test/help.test.ts
  • packages/cli/test/e2e/parity-guard.e2e.test.ts
  • packages/cli/src/commands/system.ts
  • packages/cli/src/types.ts
  • packages/cli/test/doctor.test.ts
  • packages/cli/src/config.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/commands/doctor.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,jsx,ts,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/cli/test/help.test.ts
  • packages/cli/test/e2e/parity-guard.e2e.test.ts
  • packages/cli/test/doctor.test.ts
🔇 Additional comments (8)
packages/cli/test/doctor.test.ts (1)

1-110: LGTM!

packages/cli/test/help.test.ts (1)

16-33: LGTM!

packages/cli/test/e2e/parity-guard.e2e.test.ts (1)

7-7: LGTM!

docs/reference/developer/cli.mdx (1)

19-23: LGTM!

Also applies to: 53-69, 100-100, 104-108

packages/cli/README.md (1)

20-20: LGTM!

Also applies to: 44-47, 56-60

packages/cli/src/types.ts (1)

107-108: LGTM!

packages/cli/src/config.ts (1)

13-131: LGTM!

packages/cli/src/commands/system.ts (1)

7-10: LGTM!

Comment thread packages/cli/src/commands/doctor.ts Outdated
Comment thread packages/cli/src/runtime.ts
Comment thread packages/cli/test/help.test.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TL;DR — Adds a dsar doctor preflight that probes API-URL config, /status, and an authenticated read; expands --help to per-command and group output backed by golden snapshots; documents exit codes.

Key changes

  • Doctor diagnostics commanddsar doctor chains config → /status → authenticated probe → migration/adapter checks and exits non-zero when any check fails.
  • Per-command and group helpdsar <command> --help and dsar requests --help route via parseCliArguments + resolveCommand, falling back to a prefix-match group listing.
  • Help snapshots — golden snapshots for every registered command, the global help, and the requests group.
  • Diagnostic exit envelope — runtime adds an { ok: false, data, meta } envelope for commands that report failure via result rather than throw, gated by a new optional CommandDefinition.isSuccessfulResult predicate.
  • Config plumbingparseCliInput accepts allowMissingApiUrl so doctor can report a missing URL as a check instead of throwing; parseFlags is renamed and exported as parseCliArguments.
  • Docs — CLI MDX and CLI README gain Diagnostics and Exit Codes sections.

Summary | 11 files | 1 commit | base: mainfix/13-cli-doctor-help


Doctor diagnostics

Before: No first-party CLI command to verify CLI/runtime wiring.
After: dsar doctor runs config → /status → authenticated GET /requests?limit=1 → migration/adapter checks, with downstream checks short-circuiting to skip when an upstream check did not pass.

The probe is conservative: a missing token surfaces as warn, not fail; backend surfaces that don't yet exist (migration freshness, adapter health) surface as warn/skip instead of pretending to validate. Failure of any check returns exit 1 via the new isSuccessfulResult predicate. Tests exercise the missing-URL, happy-path, and bad-token branches against the in-process runtime.

packages/cli/src/commands/doctor.ts · packages/cli/src/runtime.ts · packages/cli/src/types.ts · packages/cli/test/doctor.test.ts


Help routing and snapshots

Before: --help only rendered the global command listing.
After: dsar <command> --help resolves to a per-command panel; dsar requests --help lists every command whose usage starts with requests; unmatched prefixes print "No commands matched."

Golden snapshots cover the global help, every registered command, and the requests group, giving a single-file diff when descriptions or usage tokens change.

packages/cli/src/runtime.ts · packages/cli/test/help.test.ts · packages/cli/test/__snapshots__/help.test.ts.snap


Config and runtime plumbing

Before: parseCliInput always threw on missing API URL during arg parsing.
After: Callers can pass allowMissingApiUrl: true (the runtime sets this only when the top-level token is doctor) so the diagnostic surface can report a missing URL as a failed check instead of an exception.

isDoctorRequest is evaluated after the optional interactive wizard returns, so wizard-selected doctor runs also benefit from the bypass.

packages/cli/src/config.ts · packages/cli/src/runtime.ts · packages/cli/src/commands/system.ts

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread packages/cli/src/runtime.ts Outdated
Comment thread packages/cli/src/runtime.ts Outdated
Comment thread packages/cli/test/doctor.test.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No new issues. Reviewed the following changes:

  • Sanitized the authenticated probe details to { probe: "GET /requests?limit=1" } so the response payload is no longer echoed in diagnostic output.
  • Stripped --help/-h from argv via withoutHelpFlags before parseCliArguments so help flags no longer leak into commandTokens.
  • Replaced the hardcoded isDoctorRequest runtime check with a declarative CommandDefinition.allowMissingApiUrl field, resolved from the matched command before parseCliInput.
  • Introduced CommandDefinition.formatTextResult and a formatDoctorReport formatter so text-mode doctor output renders a readable per-check summary instead of pretty-printed JSON.
  • Renamed test/doctor.test.ts to test/e2e/doctor.e2e.test.ts and switched the test harness to join the full stdout buffer rather than indexing [0].
  • Added -h parity snapshots covering global, command, and group help, plus a text-mode doctor rendering test.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@devcool20

Copy link
Copy Markdown
Author

Updated after review:

  • Sanitized the authenticated /requests doctor probe so protected response payloads are no longer emitted in diagnostics.
  • Fixed targeted -h/--help handling by stripping help flags before help target resolution.
  • Updated help tests to capture full stdout.
  • Added command-owned doctor text formatting while preserving --output json.
  • Replaced the runtime’s hardcoded doctor special case with command metadata.
  • Moved doctor coverage under test/e2e.

Validation passed locally:

  • bun --cwd packages/cli vitest run
  • bun run --cwd packages/cli typecheck
  • bun x ultracite check ...
  • bun run check:docs-lint
  • bun run check:tsdoc
  • git diff --check

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/reference/developer/cli.mdx`:
- Line 60: Replace the vague phrase "persistence-backed read path through the
authenticated probe" with a clearer description of what is being verified;
update the sentence in docs/reference/developer/cli.mdx to something like
"backend database read operations via the authenticated request" or "that the
runtime can query persisted data when authenticated" (choose the one that
matches intent) so readers immediately understand it verifies authenticated
reads against persisted storage.

In `@packages/cli/test/e2e/doctor.e2e.test.ts`:
- Around line 22-28: The parseDoctorEnvelope function currently uses a raw type
assertion JSON.parse(output) as DoctorEnvelope which bypasses runtime
validation; replace that with parsing to unknown then validate with a runtime
type guard (e.g., implement isDoctorEnvelope(obj): obj is DoctorEnvelope) to
check required fields/types and throw a clear Error when validation fails so
tests fail with a helpful message; update parseDoctorEnvelope to call
JSON.parse(output) to get unknown, run isDoctorEnvelope on the result, return
the narrowed DoctorEnvelope when valid, otherwise throw an Error describing the
malformed response.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc877b93-2a1e-4e6c-bcfa-2d114b86d216

📥 Commits

Reviewing files that changed from the base of the PR and between 2d6da4a and 3fcf26a.

📒 Files selected for processing (7)
  • docs/reference/developer/cli.mdx
  • packages/cli/README.md
  • packages/cli/src/commands/doctor.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/types.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/help.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/help.test.ts
  • packages/cli/src/types.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/commands/doctor.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types instead of relying on Oxlint + Oxfmt to catch naming issues
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/help.test.ts
  • packages/cli/src/types.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/commands/doctor.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,jsx,ts,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/help.test.ts
🔇 Additional comments (20)
packages/cli/test/e2e/doctor.e2e.test.ts (1)

1-21: LGTM!

Also applies to: 30-146

packages/cli/test/help.test.ts (1)

1-51: LGTM!

docs/reference/developer/cli.mdx (3)

19-23: LGTM!


107-110: LGTM!


103-103: ⚡ Quick win

No changes needed. The documented diagnostic failure envelope format { ok: false, data, meta: { command } } is correct and matches the implementation in packages/cli/src/runtime.ts (lines 45-52). The unusual pairing of ok: false with data instead of error is intentional—it allows the doctor command to return partial diagnostic results even when checks fail.

packages/cli/README.md (4)

20-20: LGTM!


44-44: LGTM!


46-47: LGTM!


57-60: LGTM!

packages/cli/src/types.ts (1)

97-112: LGTM!

packages/cli/src/commands/doctor.ts (6)

1-36: LGTM!


38-73: LGTM!


75-101: LGTM!


103-175: LGTM!


177-220: LGTM!


222-257: LGTM!

packages/cli/src/runtime.ts (4)

15-81: LGTM!


83-174: LGTM!


232-291: LGTM!


292-302: LGTM!

Comment thread docs/reference/developer/cli.mdx Outdated
Comment thread packages/cli/test/e2e/doctor.e2e.test.ts
@devcool20 devcool20 force-pushed the fix/13-cli-doctor-help branch from 3fcf26a to 22d3914 Compare May 19, 2026 04:04

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No new issues. Reviewed the following changes:

  • Reworded the diagnostics bullet in docs/reference/developer/cli.mdx from "persistence-backed read path through the authenticated probe" to "runtime database read operations through the authenticated request probe".
  • Replaced the raw JSON.parse(output) as DoctorEnvelope assertion in parseDoctorEnvelope with isDoctorEnvelope/isDoctorCheck runtime type guards that throw a descriptive error on malformed output.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@KayleeWilliams

Copy link
Copy Markdown
Collaborator

Maintainer review + update: the original scope was solid (doctor command, help snapshots, exit codes, honest warn/skip for missing backend surfaces), and the diff is clean from a supply-chain standpoint (no new deps, no workflow changes). Since we only merge full fixes, I pushed follow-up commits completing issue #13:

  • GET /status/diagnostics (operator/service principals only): schema migration freshness via a new read-only readMigrationStatus/migrationStatus surface in @dsar/persistence, plus per-adapter healthCheck()/diagnostics() enumeration from the adapter registry (sanitized output).
  • doctor wiring: persistence.migrations now passes/fails on actual freshness (listing missing migrations on failure); adapters.health passes when all healthy, warns on degraded, fails on down; both degrade gracefully (warn/skip) against older backends without the endpoint.
  • OpenAPI group + snapshot, backend route tests (authz + shape + stale-migration case), doctor e2e updates, docs/README updates, and a dsar minor changeset.

Verified: full backend (100), cli (159), and persistence (23) suites pass; ultracite, tsdoc, error-docs, docs-lint, alpha-warning all clean. Note for merge sequencing: this touches the same CLI parity/help files as #44, so whichever lands second needs a trivial rebase.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ℹ️ No critical issues — one minor, defer-able suggestion inline.

Reviewed changes — the backend diagnostics endpoint added since the prior pullfrog review (22d3914) and the wiring that turns dsar doctor's migration/adapter checks from always-warn/skip into real pass/warn/fail results.

  • Add operator-scoped GET /status/diagnostics — new OpenAPI group entry and RouteDefinition in packages/backend/src/routes/status.ts, gated by requirePrincipalKinds(["operator","service"]), returning migration freshness, per-adapter health, and persistence.reachable. Per-adapter healthCheck()/diagnostics() failures are caught and reported as down/error-details rather than failing the whole request.
  • Expose migration freshness from persistencereadMigrationStatus(sql) and currentPersistenceMigrationStatus() in packages/internals/persistence, plus an optional migrationStatus?() on PersistenceService and new PersistenceMigrationStatus/PersistenceMigrationInfo types.
  • Wire dsar doctor to the endpointfetchDiagnostics + runtime type guards (isDiagnosticsData, unwrapDiagnostics); checkMigrations now fails on stale migrations and checkAdapters fails/warns on down/degraded adapters, with graceful warn/skip degradation when the endpoint 404s on older backends.
  • Tests + docs — backend status.test.ts (403 subject / 200 operator), tenant-isolation probe, OpenAPI snapshot, a CLI stale-migration fail test, parity compositeCommandRoutes exclusion, and updated CLI docs/README/changeset.

ℹ️ A permission error on /status/diagnostics degrades differently than a missing endpoint

The auth probe (GET /requests?limit=1) has no principal-kind gate, so any authenticated actor — including a subject principal — passes it, then hits 403 on the operator-scoped diagnostics endpoint. Only a 404 is treated as "endpoint unavailable" (warn/skip); every other status, 403 included, becomes a hard fail on both the migrations and adapters checks. The net effect is that a non-operator token makes dsar doctor fail as if the backend were broken, rather than signalling a permissions gap.

Technical details
# 403 on diagnostics is a hard fail, not a graceful degrade

## Affected sites
- `packages/cli/src/commands/doctor.ts:117-118``isUnavailableDiagnosticsError` matches only `/\(404\)/`.
- `packages/cli/src/commands/doctor.ts:281-286` and `:318-323` — non-404 errors become `fail` for migrations/adapters.
- `packages/backend/src/routes/requests/core.ts:145-148``GET /requests` (the auth probe) is tenant-scoped only, no `requirePrincipalKinds`, so subject tokens pass the probe.
- `packages/backend/src/routes/status.ts:61-65``/status/diagnostics` requires `operator`/`service`, so those same tokens get 403.

## Required outcome
- A token that authenticates but lacks operator/service scope should not make `doctor` look like the backend is broken. A `403` should be distinguishable from a genuine backend/persistence failure.

## Suggested approach (optional)
- Treat `403` like the unavailable case (skip/warn with a "requires operator or service access" message) rather than a hard fail, e.g. broaden the predicate to also match `(403)` or key off the parsed status.

## Open questions for the human
- Is `dsar doctor` intended to be operator-only? If so, a hard fail on `403` may be acceptable and this is purely a messaging nicety.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread packages/cli/src/commands/doctor.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — the single commit since the prior pullfrog review (092aa96), which makes dsar doctor degrade gracefully when the configured token lacks operator/service access to /status/diagnostics, directly resolving the round-4 informational finding.

  • Treat 401/403 diagnostics errors as warn — new isForbiddenDiagnosticsError (regex /\((?:401|403)\)/) is checked ahead of the general non-404 fail branch in both unavailableMigrationCheck (newly extracted) and unavailableAdapterCheck, returning a warn with a message that points the user to rerun with an operator or service token. Because a warn does not increment summary.failed, the doctor exit code stays 0.
  • Add e2e coveragewarns instead of failing when diagnostics are forbidden for the token stubs /status/diagnostics to 403 (other routes hit the real in-process runtime) and asserts exit 0 with both persistence.migrations and adapters.health reported as warn.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@KayleeWilliams

Copy link
Copy Markdown
Collaborator

DX follow-up pushed in 378240b: --help now renders a Command flags section via an optional CommandDefinition.flagHelp field (audit tail declares --request/--interval; doctor needs none since it only uses global flags). Previously, flag-driven commands only showed global flags in help, making required flags like --request undiscoverable without the docs. Help snapshots updated.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — the single commit since the prior pullfrog review (ceb2d66), which surfaces command-specific flags in dsar <command> --help.

  • Add optional CommandDefinition.flagHelp — a readonly string[] of preformatted flag lines, rendered by the new renderCommandFlagLines helper in runtime.ts as a "Command flags:" block above the global flags. The helper returns an empty array when the field is absent, so commands without command-specific flags render unchanged.
  • Populate flagHelp on auditTailCommand — documents --request (required) and --interval (default 2000). These match the flags the command actually reads; the test-only --max-polls bound is intentionally left undocumented.
  • Snapshot coverage — the audit tail --help golden snapshot gains the new block, and it.each(allCommands) exercises the rendering for every command with -h/--help parity asserted by equality.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/backend/src/http-api/groups/status.ts`:
- Around line 53-55: The persistence status schema in the diagnostics response
is hardcoded to reachable true, so update the status model in the group/status
definitions to allow a boolean value instead of a literal. Then fix the status
handler in routes/status to catch failures from the migration status call and
return a reachable false response with error details rather than failing the
entire endpoint.

In `@packages/backend/src/routes/status.ts`:
- Around line 66-69: The diagnostics handler currently lets
`services.repos.persistence.migrationStatus?.()` fail the whole `status` route,
so update the migration path in `status.ts` to catch errors the same way the
adapter health checks do and return a persistence status object with `reachable:
false` plus error details on failure. Also update the `persistence` schema in
`http-api/groups/status.ts` from `Schema.Literal(true)` to `Schema.Boolean` so
the endpoint can represent both healthy and failed persistence states.
- Around line 77-79: The health check in status handling drops the failure
details because the catch in the adapter health flow ignores the error. Update
the `adapter.healthCheck().pipe(Effect.catch(...))` path in `status.ts` so the
handler captures the error and returns a down result with `details` populated,
matching the diagnostics catch behavior and allowing `toDetails` to surface the
message in the response.

In `@packages/backend/test/routes/status.test.ts`:
- Around line 44-83: Add coverage in status.test.ts for the diagnostics error
paths in the handler: the current tests only verify the forbidden subject case
and the healthy adapter path. Extend the status route tests around
makeRuntime()/handler to assert that a failing adapter healthCheck() is reported
as down, and add a separate test for the diagnostics() failure catch path if
that branch is reachable from the same diagnostics flow. Use the existing
DiagnosticsEnvelope expectations and the adapter fixture setup (for example the
notifications fixture) so the new tests clearly exercise the adapterDown
fallback and error handling in the diagnostics route.

In `@packages/cli/test/e2e/doctor.e2e.test.ts`:
- Around line 165-281: Add e2e coverage in doctor.e2e.test.ts for the missing
adapter classification branches in checkRegisteredAdapters. Introduce helper
fetch fixtures alongside makeRuntimeFetch, such as a degraded adapter response
and a down adapter response, then add tests under describe("doctor command")
that call runDoctorJson with E2E_API_TOKEN and assert adapters.health returns
warn for degraded and fail for down, with the expected exitCode values 0 and 1.
Use the existing runDoctorJson, findCheck, and makeRuntimeFetch symbols to keep
the new cases consistent with the current suite.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9fa9e194-3b2f-44b2-8135-b199544b64f5

📥 Commits

Reviewing files that changed from the base of the PR and between 3fcf26a and 378240b.

⛔ Files ignored due to path filters (2)
  • packages/backend/test/__snapshots__/openapi.test.ts.snap is excluded by !**/*.snap
  • packages/cli/test/__snapshots__/help.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (17)
  • .changeset/cli-doctor-diagnostics.md
  • docs/reference/developer/cli.mdx
  • packages/backend/src/http-api/groups/status.ts
  • packages/backend/src/routes/status.ts
  • packages/backend/test/e2e/tenant-isolation.test.ts
  • packages/backend/test/routes/status.test.ts
  • packages/cli/README.md
  • packages/cli/src/commands/audit-tail.ts
  • packages/cli/src/commands/doctor.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/types.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/help.test.ts
  • packages/cli/test/parity.test.ts
  • packages/internals/persistence/src/index.ts
  • packages/internals/persistence/src/services/persistence.ts
  • packages/internals/persistence/src/services/persistence/migrations.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/backend/src/http-api/groups/status.ts
  • packages/cli/test/help.test.ts
  • packages/internals/persistence/src/index.ts
  • packages/backend/test/e2e/tenant-isolation.test.ts
  • packages/cli/src/types.ts
  • packages/backend/src/routes/status.ts
  • packages/backend/test/routes/status.test.ts
  • packages/internals/persistence/src/services/persistence/migrations.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/src/commands/audit-tail.ts
  • packages/internals/persistence/src/services/persistence.ts
  • packages/cli/src/commands/doctor.ts
  • packages/cli/src/runtime.ts
  • packages/cli/test/parity.test.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types instead of relying on Oxlint + Oxfmt to catch naming issues
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/backend/src/http-api/groups/status.ts
  • packages/cli/test/help.test.ts
  • packages/internals/persistence/src/index.ts
  • packages/backend/test/e2e/tenant-isolation.test.ts
  • packages/cli/src/types.ts
  • packages/backend/src/routes/status.ts
  • packages/backend/test/routes/status.test.ts
  • packages/internals/persistence/src/services/persistence/migrations.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/src/commands/audit-tail.ts
  • packages/internals/persistence/src/services/persistence.ts
  • packages/cli/src/commands/doctor.ts
  • packages/cli/src/runtime.ts
  • packages/cli/test/parity.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,jsx,ts,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/cli/test/help.test.ts
  • packages/backend/test/e2e/tenant-isolation.test.ts
  • packages/backend/test/routes/status.test.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/cli/test/parity.test.ts
**/index.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/internals/persistence/src/index.ts
🪛 markdownlint-cli2 (0.22.1)
.changeset/cli-doctor-diagnostics.md

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🔇 Additional comments (15)
packages/cli/src/commands/doctor.ts (2)

222-263: LGTM!

Also applies to: 265-335, 337-423, 424-472, 480-509


117-121: 🩺 Stability & Availability

Check the API error message format before relying on these regexes. If HTTP errors no longer include status codes in parentheses, these guards will stop classifying unavailable/forbidden diagnostics responses.

packages/cli/src/runtime.ts (1)

15-81: LGTM!

Also applies to: 111-133, 150-184, 242-301

packages/cli/src/commands/audit-tail.ts (1)

230-233: LGTM!

packages/cli/test/e2e/doctor.e2e.test.ts (1)

1-163: LGTM!

packages/cli/test/help.test.ts (1)

6-14: LGTM!

Also applies to: 33-50

packages/cli/README.md (1)

20-20: LGTM!

Also applies to: 44-47, 57-61

docs/reference/developer/cli.mdx (1)

19-24: LGTM!

Also applies to: 53-77, 107-115

packages/cli/src/types.ts (1)

97-103: LGTM!

Also applies to: 114-117

packages/internals/persistence/src/index.ts (1)

2-8: LGTM!

Also applies to: 9-12

packages/internals/persistence/src/services/persistence.ts (1)

54-55: LGTM!

Also applies to: 72-80, 134-138, 1427-1427

packages/internals/persistence/src/services/persistence/migrations.ts (1)

43-64: LGTM!

Also applies to: 98-117, 196-231

packages/backend/test/e2e/tenant-isolation.test.ts (1)

1462-1467: LGTM!

packages/cli/test/parity.test.ts (1)

8-8: LGTM!

Also applies to: 29-32

packages/backend/src/routes/status.ts (1)

66-69: 🎯 Functional Correctness

Check currentPersistenceMigrationStatus() against the diagnostics migrations schema. If the fallback shape differs, the status route can fail schema validation.

Comment thread packages/backend/src/http-api/groups/status.ts
Comment thread packages/backend/src/routes/status.ts Outdated
Comment thread packages/backend/src/routes/status.ts Outdated
Comment on lines +77 to +79
const health = yield* adapter
.healthCheck()
.pipe(Effect.catch(() => Effect.succeed(adapterDown)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Health check error details are silently lost.

The Effect.catch(() => Effect.succeed(adapterDown)) ignores the error parameter. When healthCheck() fails, the error message is not included in the response, making it harder to diagnose why an adapter is down. The diagnostics catch handler (lines 81-87) does capture errors — the asymmetry is notable.

🔍 Proposed fix to preserve health check error details
 const health = yield* adapter
 	.healthCheck()
-	.pipe(Effect.catch(() => Effect.succeed(adapterDown)));
+	.pipe(
+		Effect.catch((error) =>
+			Effect.succeed({
+				details: { healthCheckError: messageFromError(error) },
+				ok: false,
+				status: "down" as const,
+			})
+		)
+	);

This way health.details is populated and flows into the response via toDetails.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const health = yield* adapter
.healthCheck()
.pipe(Effect.catch(() => Effect.succeed(adapterDown)));
const health = yield* adapter
.healthCheck()
.pipe(
Effect.catch((error) =>
Effect.succeed({
details: { healthCheckError: messageFromError(error) },
ok: false,
status: "down" as const,
})
)
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/backend/src/routes/status.ts` around lines 77 - 79, The health check
in status handling drops the failure details because the catch in the adapter
health flow ignores the error. Update the
`adapter.healthCheck().pipe(Effect.catch(...))` path in `status.ts` so the
handler captures the error and returns a down result with `details` populated,
matching the diagnostics catch behavior and allowing `toDetails` to surface the
message in the response.

Comment thread packages/backend/test/routes/status.test.ts
Comment thread packages/cli/test/e2e/doctor.e2e.test.ts
@devcool20

Copy link
Copy Markdown
Author

hey @KayleeWilliams, are you working on this currently?? let me know if any fix is needed!

@devcool20

Copy link
Copy Markdown
Author

Summary of Diagnostics & Test Coverage Fixes

I've resolved the outstanding review issues regarding the dsar doctor diagnostics command and backend endpoint:

  1. Fixed TypeScript compiler type mismatch: Resolved strict TS 6.x build errors inside webhook-secret-encryption.ts by replacing the type-casting overrides with clean Uint8Array casts on Node.js crypto inputs.
  2. Flexible Reachability Schema: Updated the HTTP diagnostics payload schema in status.ts (Schema) to define persistence as a boolean reachable with an optional error message string rather than a hardcoded literal true.
  3. Graceful Database Unreachability: Modified status.ts (Routes) to catch errors during database migration queries using .pipe(Effect.catch(...)), returning a reachable: false diagnostics status instead of crashing the endpoint.
  4. Improved Integration Test Coverage:
    • Added tests in status.test.ts asserting that the diagnostics route handles persistence migration failures and degraded/down adapter states gracefully (returning status 200 with the correct status/errors).
    • Updated the generated OpenAPI snapshot tests to reflect the new dynamic diagnostics contract.
  5. E2E CLI Test Coverage: Added E2E tests in doctor.e2e.test.ts validating CLI exits with 0 (status "warn") when adapters are degraded, and exits with 1 (status "fail") when adapters are completely down.
  6. Code Documentation: Added comments in doctor.ts documenting the parenthesis-wrapped status error code convention mapped by the @dsar/guards's toApiError client utility.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important

The backend now reports persistence outages gracefully (persistence.reachable: false + error), but the CLI half of the same commit can't parse that shape — a real outage surfaces as a generic "did not match expected shape" error instead of the backend's actual message. One inline comment.

Reviewed changes — the single commit a917ea2 since the prior pullfrog review (378240b), which reworks the backend diagnostics schema to represent persistence failure, hardens the endpoint's error handling, and adds test coverage (addresses CodeRabbit's round-7 findings).

  • Made persistence failure representablepackages/backend/src/http-api/groups/status.ts changes the diagnostics persistence schema from Schema.Literal(true) to Schema.Boolean plus an optional error string.
  • Graceful persistence-failure handlingpackages/backend/src/routes/status.ts wraps the migration-status effect in Effect.catch, returning empty migrations + persistence.reachable: false with the error message while keeping the endpoint at 200; adapterDown now carries details: undefined and the diagnostics-failure fallback sets version: undefined.
  • Test coverage — backend status.test.ts gains persistence-failure and adapter-failure cases; CLI doctor.e2e.test.ts adds degraded-adapter (warn, exit 0) and down-adapter (fail, exit 1) fixtures; OpenAPI snapshot updated to the new persistence shape.
  • Unrelated type churnpackages/internals/persistence/src/services/persistence/webhook-secret-encryption.ts adds as Uint8Array widening casts around crypto calls (runtime no-op, Buffer is a Uint8Array), likely a typecheck fix pulled in with this commit.

⚠️ Persistence-outage details are discarded by the CLI

The backend change in this commit makes a persistence outage a first-class, well-formed 200 response — empty migrations, persistence.reachable: false, and a human-readable error. The CLI never gets to use any of it.

Because the CLI's diagnostics type and guard still require persistence.reachable === true, the whole payload is rejected as malformed:

  • the migrations check fails with Diagnostics response did not match expected shape. instead of the backend's real error (e.g. Database connection failed)
  • the adapters check fails the same way, even though the adapter statuses in the payload are valid

The exit code is still 1, so this isn't a correctness break, but the operator sees a message that reads like a CLI/version mismatch rather than a database outage — the exact scenario the backend change was written to surface. No CLI test exercises the reachable: false path.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread packages/cli/src/commands/doctor.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/backend/src/routes/status.ts (1)

14-14: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Health check error details are still silently lost.

adapterDown now explicitly sets details: undefined, and the health check catch at line 99 (Effect.catch(() => Effect.succeed(adapterDown))) still ignores the error parameter. When healthCheck() fails but diagnostics() succeeds, the adapter is reported as "down" with no explanation. The diagnostics catch (lines 100-108) correctly captures errors — the asymmetry persists.

🔍 Proposed fix to preserve health check error details
 const health = yield* adapter
 	.healthCheck()
-	.pipe(Effect.catch(() => Effect.succeed(adapterDown)));
+	.pipe(
+		Effect.catch((error) =>
+			Effect.succeed({
+				...adapterDown,
+				details: { healthCheckError: messageFromError(error) },
+			})
+		)
+	);

This flows through toDetails at line 115 as health.detailsdetails.health in the response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/backend/src/routes/status.ts` at line 14, The health-check failure
path in status.ts is still dropping useful error details: `adapterDown` is
initialized with `details: undefined`, and the `Effect.catch` around
`healthCheck()` ignores the error value before returning `adapterDown`. Update
the `healthCheck()` catch branch to capture the thrown error and populate
`details` consistently with the existing diagnostics error handling, so
`toDetails` can surface it through `health.details` in the response.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/backend/src/routes/status.ts`:
- Line 14: The health-check failure path in status.ts is still dropping useful
error details: `adapterDown` is initialized with `details: undefined`, and the
`Effect.catch` around `healthCheck()` ignores the error value before returning
`adapterDown`. Update the `healthCheck()` catch branch to capture the thrown
error and populate `details` consistently with the existing diagnostics error
handling, so `toDetails` can surface it through `health.details` in the
response.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9b080b12-73b0-4056-bad9-ee7c357f1e07

📥 Commits

Reviewing files that changed from the base of the PR and between 378240b and a917ea2.

⛔ Files ignored due to path filters (1)
  • packages/backend/test/__snapshots__/openapi.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • packages/backend/src/http-api/groups/status.ts
  • packages/backend/src/routes/status.ts
  • packages/backend/test/routes/status.test.ts
  • packages/cli/src/commands/doctor.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/internals/persistence/src/services/persistence/webhook-secret-encryption.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/backend/test/routes/status.test.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/backend/src/http-api/groups/status.ts
  • packages/backend/src/routes/status.ts
  • packages/cli/src/commands/doctor.ts
  • packages/internals/persistence/src/services/persistence/webhook-secret-encryption.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types instead of relying on Oxlint + Oxfmt to catch naming issues
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/backend/test/routes/status.test.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
  • packages/backend/src/http-api/groups/status.ts
  • packages/backend/src/routes/status.ts
  • packages/cli/src/commands/doctor.ts
  • packages/internals/persistence/src/services/persistence/webhook-secret-encryption.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,jsx,ts,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/backend/test/routes/status.test.ts
  • packages/cli/test/e2e/doctor.e2e.test.ts
🔇 Additional comments (10)
packages/backend/src/http-api/groups/status.ts (1)

54-55: LGTM!

packages/backend/src/routes/status.ts (1)

67-89: LGTM!

packages/backend/test/routes/status.test.ts (1)

49-150: LGTM!

packages/cli/src/commands/doctor.ts (1)

117-119: LGTM!

packages/cli/test/e2e/doctor.e2e.test.ts (3)

7-131: LGTM!


165-231: LGTM!


309-374: LGTM!

packages/internals/persistence/src/services/persistence/webhook-secret-encryption.ts (3)

116-118: LGTM!


138-147: LGTM!


160-170: LGTM!

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — the single commit 53d4dca since the prior pullfrog review (a917ea2), which closes the round-7 open risk where the CLI could not parse the backend's persistence-outage payload, and captures adapter health-check error details on the backend.

  • CLI consumes persistence.reachable: falsepackages/cli/src/commands/doctor.ts widens DiagnosticsData.persistence to { error?: string; reachable: boolean }, relaxes isDiagnosticsData to accept a boolean reachable with optional-string error, and has checkMigrations short-circuit on reachable === false to fail with the backend's actual error message instead of the generic shape-mismatch error.
  • Backend captures health-check errorspackages/backend/src/routes/status.ts replaces the static adapterDown constant (and its AdapterHealth import) with an Effect.catch that records details: { error } on healthCheck() failure, so the real error flows through toDetails into details.health.
  • Test coverage — CLI doctor.e2e.test.ts adds a makeOutagePersistenceFetch fixture asserting exit 1, persistence.migrations failing with Persistence outage: Database connection failed., and adapters.health still passing; backend status.test.ts asserts the captured details.health error.

The round-7 finding is addressed exactly as suggested — the type, guard, and checkMigrations branch line up with the backend's 200-with-reachable: false contract, and the new e2e fixture locks in the behaviour. The backend and CLI halves of the outage path are now coherent.

Pullfrog  | View workflow run | Using Claude Opus𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[cli] Command coverage and dsar doctor diagnostic command

2 participants