Skip to content

feat(opencode): add db doctor and repair commands#32093

Open
pascalandr wants to merge 11 commits into
anomalyco:devfrom
Pagecran:feat/db-doctor-repair
Open

feat(opencode): add db doctor and repair commands#32093
pascalandr wants to merge 11 commits into
anomalyco:devfrom
Pagecran:feat/db-doctor-repair

Conversation

@pascalandr

@pascalandr pascalandr commented Jun 12, 2026

Copy link
Copy Markdown

Issue for this PR

Related issues (does not automatically close): #29908, #31204, #19191, #29581, #31597, #23594, #30157, #14970, #24780.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds native database health commands for local OpenCode SQLite databases:

  • opencode db doctor and opencode db doctor --json
  • opencode db repair --dry-run and opencode db repair --apply

The commands inspect local OpenCode SQLite databases directly, without opening them through the app runtime on diagnostic/dry-run paths. They diagnose/repair rows by comparing persisted data shapes against the invariants required by the OpenCode binary currently running the command.

This is not a generic legacy repair toolbox. The repair contract is: doctor checks whether the existing local DB schema and persisted rows conform to the session/message/part specs that this binary expects, without performing migrations. repair --apply only applies explicitly cataloged row-shape fixes that have deterministic target values and precondition checks.

The supported repair catalog is exported from @opencode-ai/core/database/health as SUPPORTED_REPAIRS and is included in doctor / repair --dry-run JSON output. Each catalog entry declares the target OpenCode version/invariant, known target migration when applicable, source evidence if known, repair behavior, and safety constraints. The report also includes a compatibility block with the current binary version, expected migrations for that binary, applied DB migrations, and observed session.version distribution.

Supported repair catalog

This PR currently supports exactly these repair codes:

  • part_legacy_id_prefix: renames part_<suffix> IDs to prt_<suffix> only when the target ID does not already exist. This fixes the observed load failure: Expected a string starting with "prt", got "part_..." at [0]["parts"][0]["id"].
  • assistant_message_missing_agent: copies assistant session_message.data.mode to data.agent with original-JSON precondition checks.
  • session_agent_missing: fills session.agent only when one unambiguous value can be derived from assistant or agent-switched messages.
  • session_model_missing: fills session.model only when one unambiguous model object can be derived from assistant or model-switched messages.
  • session_path_missing: fills session.path from the same row's non-empty session.directory.
  • message_assistant_missing_parent: fills missing assistant parentID from the immediately preceding message in the same session.
  • message_user_missing_agent: fills missing user agent only when one unambiguous agent is derivable.
  • message_user_missing_model: fills missing user model only when one unambiguous model is derivable.
  • part_step_finish_missing_reason: fills missing step-finish.reason with stop.
  • part_compaction_missing_auto: fills missing compaction.auto with false.
  • part_tool_completed_missing_metadata: fills missing completed-tool state.metadata with {}.
  • part_tool_completed_missing_title: fills missing completed-tool state.title from data.tool only when present.
  • part_tool_completed_missing_time: fills missing completed-tool state.time.start/end from the part row timestamp while preserving any existing start/end value.

Versioning model

doctor and repair validate a DB against the schema and persisted data shapes expected by the current binary. They do not require that the DB was previously opened by this exact OpenCode version. A DB that has been opened/migrated by a newer OpenCode may no longer be openable by older OpenCode versions; this tool is therefore about conformity to the current OpenCode binary, not about restoring historical row formats.

Creation/source version information remains useful when it is known. It can help target repairs and explain why a row shape exists, especially when a specific SDK/spec change or migration boundary is known. But source versions are evidence, not the primary repair criterion. The primary criterion is whether the row violates a cataloged invariant of the current migrated target.

If an exact first-required OpenCode release, SDK version, or migration is known, the catalog must cite it. If only affected persisted shapes are known, the catalog must say that explicitly and include observed source evidence without pretending to know the exact boundary.

Safety behavior

The diagnostic and dry-run paths avoid creating, opening through the app runtime, migrating, checkpointing, backing up, or writing to the DB. repair --apply is the only write path; it creates a SQLite snapshot backup first, runs repairs in a transaction, checks row preconditions, and reruns a post-check.

Existing opencode db query/path behavior is preserved.

How to update this when SDK/session specs change

For each future persisted-shape change that can break migrated sessions:

  1. Add a SUPPORTED_REPAIRS entry describing the target OpenCode version/invariant, known migration or SDK boundary if known, source evidence if known, repair, and safety constraints.
  2. Add a detector that emits one issue code from that catalog when a row violates that target invariant.
  3. Add repair-plan generation only when the target value is unambiguous.
  4. Add apply logic with row preconditions and collision checks.
  5. Add a fixture test that reproduces the non-conforming persisted shape and verifies doctor, repair --dry-run, repair --apply, and idempotency.
  6. If a repair is unsafe or ambiguous, keep it diagnostic-only with repairable: false and explain why.

How did you verify your code works?

From packages/opencode:

bun test test/db/health.test.ts test/db/cli.test.ts test/db/full-cli.test.ts
bun typecheck
bun run build

From the repo root / pre-push hook:

bun turbo typecheck

Compiled Windows CLI smoke tests:

dist/opencode-windows-x64/bin/opencode.exe db doctor --json
# missing DB: exits 2 and does not create the DB

dist/opencode-windows-x64/bin/opencode.exe db repair --dry-run --json
# missing DB: exits 2 and does not create the DB

dist/opencode-windows-x64/bin/opencode.exe db repair --dry-run --json
# repairable DB: exits 1 and lists safe operations

dist/opencode-windows-x64/bin/opencode.exe db repair --apply --json
# repairable DB: exits 0, applies operations, creates backup

dist/opencode-windows-x64/bin/opencode.exe db doctor --json
# repaired DB: exits 0

Real local DB dry-run, without applying repairs:

OPENCODE_DB=C:\Users\Admin\.local\share\opencode\opencode.db dist/opencode-windows-x64/bin/opencode.exe db repair --dry-run --json
# exits 1
# target is the current binary/migration set
# plans 1462 total operations
# session_path_missing: 1330
# part_legacy_id_prefix: 100
# message_assistant_missing_parent: 13
# part_step_finish_missing_reason: 13
# message_user_missing_agent: 3
# message_user_missing_model: 3
# no changes made

Manual real-user DB repair validation:

OPENCODE_DB=C:\Users\Admin\.local\share\opencode\opencode.db bun run --conditions=browser ./src/index.ts db repair --apply --json
# success: true
# backup: C:\Users\Admin\.local\share\opencode\opencode.db.backup.2026-06-13T08-31-16-749Z
# operationsApplied: 1462
# operationsFailed: 0
# postCheckIssues: 0

After applying repairs to that real local user DB:

OPENCODE_DB=C:\Users\Admin\.local\share\opencode\opencode.db bun run --conditions=browser ./src/index.ts db repair --dry-run --json
# exits 0
# operations: 0
# unrepairableErrors: 0

OPENCODE_DB=C:\Users\Admin\.local\share\opencode\opencode.db bun run --conditions=browser ./src/index.ts db doctor --json
# exits 0
# schemaSupported: true
# remaining issues are warning-only diagnostic session metadata gaps without deterministic repair values

This manually validated the tool against a real local user database and confirmed it repaired the targeted damaged session rows that caused session loading failures.

Follow-up

A good follow-up would be to design how this capability should be exposed outside the local CLI, for example through the SDK and/or an API surface. That should be a separate PR because it needs an explicit contract for permissions, dry-run/apply separation, backup reporting, and safety around running repairs from non-interactive clients.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Adds native db doctor and repair flows with JSON output, dry-run and apply modes, safe/aggressive repair planning, backup-before-apply safeguards, transactional preconditions, and targeted DB tests.
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Jun 12, 2026
@pascalandr pascalandr marked this pull request as draft June 12, 2026 19:15
@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Jun 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

# Conflicts:
#	packages/opencode/src/cli/cmd/db.ts
#	packages/opencode/src/index.ts
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.

1 participant