Correctness bugs (OpenCode adversarial review of PR #1)
Surfaced by an OpenCode adversarial self-review of the conversion work, triaged by Claude Code. Line numbers are from the reviewed revision — verify against current before fixing.
1. opencode-companion.mjs — enqueueBackgroundTask spawns child before persisting job
The detached child is spawned before writeJobFile/upsertJob. If persistence throws, the child is already running but has no job record and dies with "No stored job found". Persist the job record before spawning the child that reads it.
2. opencode-companion.mjs — findLatestResumableTaskJob treats failed/cancelled as resumable
Accepts any task with status !== "queued" && status !== "running", so a failed/cancelled task whose session is in a broken state is silently offered for resume. (Directly testable: our smoke-test left a failed job — confirm whether it's now offered as a resume candidate.)
3. lib/claude-session-transfer.mjs — buildOpenCodeImportDocumentFromClaudeJsonl threading
Assistant messages pass latestUserMessageID as parentID. With consecutive assistant messages (possible after sidechain stripping), the second reuses the first's parentID instead of threading after the previous assistant — violates OpenCode's expected threading.
4. opencode-companion.mjs — buildTaskRunMetadata marker false-positive
Classifies a task by prompt.includes(STOP_REVIEW_TASK_MARKER). A user prompt that happens to contain that literal phrase is mislabeled as a stop-gate review with wrong metadata. Use an explicit flag/param instead of substring matching.
Ref: PR #1.
Correctness bugs (OpenCode adversarial review of PR #1)
Surfaced by an OpenCode adversarial self-review of the conversion work, triaged by Claude Code. Line numbers are from the reviewed revision — verify against current before fixing.
1.
opencode-companion.mjs—enqueueBackgroundTaskspawns child before persisting jobThe detached child is spawned before
writeJobFile/upsertJob. If persistence throws, the child is already running but has no job record and dies with "No stored job found". Persist the job record before spawning the child that reads it.2.
opencode-companion.mjs—findLatestResumableTaskJobtreatsfailed/cancelledas resumableAccepts any task with
status !== "queued" && status !== "running", so a failed/cancelled task whose session is in a broken state is silently offered for resume. (Directly testable: our smoke-test left afailedjob — confirm whether it's now offered as a resume candidate.)3.
lib/claude-session-transfer.mjs—buildOpenCodeImportDocumentFromClaudeJsonlthreadingAssistant messages pass
latestUserMessageIDasparentID. With consecutive assistant messages (possible after sidechain stripping), the second reuses the first'sparentIDinstead of threading after the previous assistant — violates OpenCode's expected threading.4.
opencode-companion.mjs—buildTaskRunMetadatamarker false-positiveClassifies a task by
prompt.includes(STOP_REVIEW_TASK_MARKER). A user prompt that happens to contain that literal phrase is mislabeled as a stop-gate review with wrong metadata. Use an explicit flag/param instead of substring matching.Ref: PR #1.