fix(task-input): make interview-answers.json a main-checkout accumulator to stop parallel squash-merge conflicts (#516) - #528
Conversation
…tor to stop parallel squash-merge conflicts (andresharpe#516)
|
@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 Dotbot already has a canonical place for questions: the task itself.
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 Concretely:
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.
|
@carlospedreira , thanks, you're right, and I've reworked the PR to fix the ownership boundary instead of patching the symptom. |
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>
…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>
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_conflictand escalating the task toneeds-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 checkout —
Dotbot.TaskInput.psm1Get-TaskInputProductDirno longer resolves a per-task worktree path; it alwaysreturns the main checkout's
workspace/product.Write-TaskInputInterviewAnswerserialises appends with a cross-process lock (
Invoke-WithTaskLock, constant keyinterview-answers) to prevent read-modify-write lost updates. The answer alsobecomes visible in the Product tab the moment it's recorded, instead of after merge.
2. Exclude the accumulator from worktree git tracking —
Dotbot.Worktree.psm1Ensure-DotbotWorktreeExcludesadds.bot/workspace/product/interview-answers.jsonso 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 branches —
Dotbot.Worktree.psm1Apply-TaskBranchPatchnow auto-merges an unresolvedinterview-answers.jsonconflict instead of escalating:
Merge-DotbotInterviewAnswersunions both sidesby
question_id(latestanswered_atwins, deterministic ordering) and stages theresult. Covers worktrees/branches created before the exclude existed. Any other
conflict stays unresolved.
Tests
Test-Components.ps1Apply-TaskBranchPatchauto-merges two task branches' answers withouta
rebase_conflict; merged file contains bothquestion_ids.Ensure-DotbotWorktreeExcludespinsinterview-answers.jsoninto.git/info/excludewhile leaving the rest of
product/tracked.Test-TaskActions.ps1from all tasks in the run coexist.
Closes #516