Skip to content

fix(task-input): make interview-answers.json a main-checkout accumulator to stop parallel squash-merge conflicts (#516) - #528

Merged
carlospedreira merged 3 commits into
andresharpe:mainfrom
kabaogluemre:bugfix/516-interview-answers-merge-conflict
Jun 26, 2026
Merged

fix(task-input): make interview-answers.json a main-checkout accumulator to stop parallel squash-merge conflicts (#516)#528
carlospedreira merged 3 commits into
andresharpe:mainfrom
kabaogluemre:bugfix/516-interview-answers-merge-conflict

Conversation

@kabaogluemre

Copy link
Copy Markdown
Contributor

Summary

Fixes #516 — parallel tasks answering Approve/Reject decisions caused unresolvable
squash-merge conflicts on .bot/workspace/product/interview-answers.json.

This file is a run-level accumulator: every decision answer is appended to one
shared JSON array. It was being routed to each task's per-worktree copy, so
concurrent task branches diverged on the same array and collided at squash-merge,
failing with rebase_conflict and escalating the task to needs-input.

The fix moves ownership of the accumulator to the main project checkout (where
the Product UI already reads from), so concurrent task completions no longer race on
the same file.

Changes

1. Route writes to the main checkoutDotbot.TaskInput.psm1

  • Get-TaskInputProductDir no longer resolves a per-task worktree path; it always
    returns the main checkout's workspace/product.
  • Because all parallel tasks now write to the same file, Write-TaskInputInterviewAnswer
    serialises appends with a cross-process lock (Invoke-WithTaskLock, constant key
    interview-answers) to prevent read-modify-write lost updates. The answer also
    becomes visible in the Product tab the moment it's recorded, instead of after merge.

2. Exclude the accumulator from worktree git trackingDotbot.Worktree.psm1

  • Ensure-DotbotWorktreeExcludes adds .bot/workspace/product/interview-answers.json
    so git never tracks a worktree-local copy — it can't enter a task branch's
    squash-merge patch at all. Other product/ docs still flow normally.

3. Auto-resolve safety net for legacy branchesDotbot.Worktree.psm1

  • Apply-TaskBranchPatch now auto-merges an unresolved interview-answers.json
    conflict instead of escalating: Merge-DotbotInterviewAnswers unions both sides
    by question_id (latest answered_at wins, deterministic ordering) and stages the
    result. Covers worktrees/branches created before the exclude existed. Any other
    conflict stays unresolved.

Tests

  • Test-Components.ps1
    • End-to-end: Apply-TaskBranchPatch auto-merges two task branches' answers without
      a rebase_conflict; merged file contains both question_ids.
    • Ensure-DotbotWorktreeExcludes pins interview-answers.json into .git/info/exclude
      while leaving the rest of product/ tracked.
  • Test-TaskActions.ps1
    • Batch answer now lands in the main checkout and is absent from the worktree.
    • Shared accumulator assertions use containment (not array position), since answers
      from all tasks in the run coexist.

Closes #516

@carlospedreira

Copy link
Copy Markdown
Collaborator

@kabaogluemre thanks for working on this. I’m not rejecting the PR, but I don’t think it fixes the right problem.

The issue is shared mutable state across parallel tasks. If multiple tasks write to one file, that file needs to be runtime-owned with a clear concurrency model. I don’t think .bot/workspace/product/interview-answers.json is that file.

Dotbot already has a canonical place for questions: the task itself.

  • pending questions: extensions.runner.pending_question / pending_questions
  • answered questions: extensions.runner.questions_resolved

interview-answers.json is specific to start-from-prompt. It exists so that workflow can reread answers later. That makes it workflow-owned state, not runtime-owned state.

So I don’t think we should add runtime exclusions, locks, merge handling, or accumulator behavior for this file. That only fixes this one workflow path and does not solve the broader shared-state problem.

I think the fix should be to change start-from-prompt to use the existing task-level question lifecycle. If it needs more answer detail, we should enrich questions_resolved, not duplicate answers into a shared product file.

Concretely:

  1. stop writing interview-answers.json from runtime code
  2. keep question/answer state on the task that asked the question
  3. update start-from-prompt to read resolved answers from task state
  4. avoid runtime locking/merge rules for this workflow-specific file

The conflict is real, but this PR feels like a band-aid over the wrong ownership boundary.

…uct file (andresharpe#516)

Pivot the andresharpe#516 fix per review: the parallel squash-merge conflict was a
symptom of the wrong ownership boundary, not the root problem. interview-answers.json
was runtime-written shared mutable state, but the canonical answer record already
lives on the task (extensions.runner.questions_resolved). Only the start-from-prompt
workflow ever read the file, so it is workflow-owned, not runtime-owned.

This removes the previous accumulator approach (main-checkout routing, cross-process
lock, worktree exclude, and squash-merge auto-merge) and instead keeps answers solely
on the task that asked the question. Per-task state travels with the task and never
collides across parallel worktrees, so the conflict cannot occur in the first place —
no lock, exclude, or merge rule needed.

- Dotbot.TaskInput: drop Get-TaskInputProductDir and Write-TaskInputInterviewAnswer;
  stop writing the file. Enrich Add-TaskInputResolvedQuestion (questions_resolved) with
  context, answer_key, and answer_label so the workflow has the full answer detail.
- Dotbot.Worktree: revert the exclude entry, Merge-DotbotInterviewAnswers,
  Resolve-DotbotInterviewAnswersConflict, and the Apply-TaskBranchPatch auto-resolve
  block back to baseline.
- start-from-prompt/01-plan-product: read resolved answers from task state via
  task_get_context (extensions.runner.questions_resolved) instead of the product file.
- Tests: assert no interview-answers.json is written anywhere and that questions_resolved
  carries the enriched fields; remove the now-obsolete accumulator/exclude/auto-merge tests.
@kabaogluemre

Copy link
Copy Markdown
Contributor Author

@carlospedreira , thanks, you're right, and I've reworked the PR to fix the ownership boundary instead of patching the symptom.

@carlospedreira carlospedreira added type:bug Something is broken bug Something isn't working labels Jun 25, 2026 — with ChatGPT Codex Connector
@carlospedreira carlospedreira removed the type:bug Something is broken label Jun 25, 2026
@carlospedreira
carlospedreira merged commit b07b533 into andresharpe:main Jun 26, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from Inbox to Done in Dotbot Product Backlog Jun 26, 2026
mirzazekicapi pushed a commit to mirzazekicapi/dotbot that referenced this pull request Jun 26, 2026
PR andresharpe#528 (fix andresharpe#516) landed Issue B upstream using the correct ownership fix:
delete Write-TaskInputInterviewAnswer and Get-TaskInputProductDir entirely,
enrich questions_resolved on the task instead. Took upstream version.
PR andresharpe#540 (fix andresharpe#536) and PR andresharpe#541 (fix andresharpe#537) auto-merged cleanly.
All v4-runtime issues now covered by upstream -- branch has zero unique changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mirzazekicapi pushed a commit to mirzazekicapi/dotbot that referenced this pull request Jun 26, 2026
…ndresharpe#528

PR andresharpe#528 eliminated interview-answers.json entirely (answers now live on the
task in questions_resolved). The worktree exclude and Apply-TaskBranchPatch
auto-resolve block for that file are now dead code -- remove them.
v4-runtime is now identical to origin/main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

interview-answers.json causes squash-merge conflicts when parallel tasks run

2 participants