{"record":{"id":"55ec6eaf30e89ff8","repo":"can1357/oh-my-pi","slug":"error-55ec6e","errorCode":null,"errorMessage":"error","messagePattern":"error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/commit/agentic/index.ts","lineNumber":310,"sourceCode":"\t\t\t\tdetails: commit.details,\n\t\t\t\tissueRefs: commit.issueRefs,\n\t\t\t};\n\t\t\tconst message = formatCommitMessage(analysis, commit.summary);\n\t\t\tprocess.stdout.write(`Commit ${index + 1}:\\n${message}\\n`);\n\t\t\tconst changeSummary = commit.changes.map(change => formatFileChangeSummary(change.path, change)).join(\", \");\n\t\t\tprocess.stdout.write(`Changes: ${changeSummary}\\n`);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (!(await confirmSplitCommitPlan(plan))) {\n\t\tprocess.stdout.write(\"Split commit aborted by user.\\n\");\n\t\treturn;\n\t}\n\n\tconst order = computeDependencyOrder(plan.commits);\n\tif (\"error\" in order) {\n\t\tthrow new Error(order.error);\n\t}\n\n\tprocess.stdout.write(\"● Creating split commits...\\n\");\n\tconst stagedDiff = await repo.diffText({ cached: true, binary: true });\n\tawait repo.unstage([]);\n\tfor (const [position, commitIndex] of order.entries()) {\n\t\tconst commit = plan.commits[commitIndex];\n\t\tawait repo.stageHunks(commit.changes, stagedDiff);\n\t\tconst analysis: ConventionalAnalysis = {\n\t\t\ttype: commit.type,\n\t\t\tscope: commit.scope,\n\t\t\tdetails: commit.details,\n\t\t\tissueRefs: commit.issueRefs,\n\t\t};\n\t\tconst message = formatCommitMessage(analysis, commit.summary);\n\t\ttry {\n\t\t\tawait repo.commitCreate(message, {});\n\t\t} catch (error) {","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/commit/agentic/index.ts#L292-L328","documentation":"computeDependencyOrder(plan.commits) returns a discriminated result; when it contains an `error` field (a cycle or unresolvable ordering among the planned commits), runSplitCommit() rethrows it. This happens after user confirmation but before any commits are created, so the index is still intact.","triggerScenarios":"The agent's split plan contains commits whose file changes depend on each other in a cyclic or unorderable way (e.g. commit A touches a file commit B also touches with conflicting dependency edges), making a sequential stage-hunks order impossible.","commonSituations":"Overlapping file changes across planned commits; the LLM splits one logical change into two commits that each need the other's hunks; lockfile/hunk interdependencies the planner cannot serialize.","solutions":["Re-run and request a different split, or edit the plan so each commit's changes are independent","Merge the conflicting planned commits into a single commit","Abort split mode and make one regular commit containing all staged changes","Check the order.error message — it names the specific dependency conflict to untangle"],"exampleFix":"// before: plan has commit 'feat: api' and 'fix: api types' touching the same hunks cyclically\n// after: combine them\n{ \"commits\": [{ \"type\": \"feat\", \"scope\": \"api\", \"summary\": \"add endpoint with types\", \"changes\": [/* both file sets */] }] }","handlingStrategy":"try-catch","validationCode":"const order = computeDependencyOrder(plan.commits);\nif (\"error\" in order) {\n  console.error(\"Plan not executable:\", order.error);\n  // fall back to single commit before staging anything\n}","typeGuard":"function isOrderError(order: ReturnType<typeof computeDependencyOrder>): order is { error: string } {\n  return \"error\" in order;\n}","tryCatchPattern":"try {\n  await runSplitCommit(plan, ctx);\n} catch (err) {\n  // nothing was committed yet (throw happens pre-staging); safe to retry as one commit\n  await runSingleCommit(generateFallbackProposal(numstat), ctx);\n}","preventionTips":["Keep planned commits disjoint — one file per commit where possible","Review the plan for commits touching the same files","Prefer merging tightly coupled changes into one planned commit"],"tags":["commit","split-commit","dependency-order","cyclic-dependency"],"backgroundTag":"cyclic-dependency-in-commit-plan","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}