Skip to content

Fix locked plan transfer across worktrees - #214

Merged
bigboateng merged 9 commits into
mainfrom
fix/worktree-plan-artifact-transfer
Aug 13, 2026
Merged

Fix locked plan transfer across worktrees#214
bigboateng merged 9 commits into
mainfrom
fix/worktree-plan-artifact-transfer

Conversation

@bigboateng

@bigboateng bigboateng commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • copy the runtime-owned bound plan and approval artifacts when a delivery worktree is cut or activated
  • keep the selected plan stable after the worktree handoff
  • create a PR noninteractively while preserving the preview-bound body

Verification

  • go test ./internal/softwaredelivery/effects ./cmd/boatstack-helper
  • local delegated-flow pilot: after workspace.cut, the target worktree retained the locked plan and selected workspace.activate rather than recreating a plan
  • GitHub CLI dry-run confirmed the prior invocation failed because a title was absent

@cursor

cursor Bot commented Aug 13, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.98

The new transfer path is not bound to admitted artifact identity, allowing workspace transitions to commit after copying stale or substituted product evidence. Model-level verification is not required before merge; targeted freshness and negative transaction tests should cover this defect.

Comment thread boatstack/internal/softwaredelivery/effects/artifacts.go Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.98

The patch leaves approval substitution undetected, prevents existing schema-4 installations from updating, and introduces a concrete workspace activation zero-progress path. Model-level verification is not required to establish these defects; targeted regression tests are sufficient before merge.

Findings without inline diff anchors

[P1] Preserve the approval fingerprint result during semantic validation

Invariant: approved or locked plans remain authoritative only while the approval bytes match the durable ApprovalFingerprint. After approval, replace the artifact with different but schema-valid JSON (for example, change Actor); line 528 makes valid false, but line 535 overwrites it with semantic validity, so observation still reports the plan approved. This patch introduced the fingerprint check without composing it with the existing validation. The substituted approval can authorize later delivery transitions. Add an observer test asserting that any strict-valid approval whose bytes differ from ApprovalFingerprint makes the plan and terminal stale.

Confidence: 0.99

Location: boatstack/internal/softwaredelivery/plant/observer.go:528-535 (RIGHT)

Comment thread boatstack/internal/softwaredelivery/durable/state.go Outdated
Comment thread boatstack/internal/softwaredelivery/effects/driver.go Outdated

@bigboateng bigboateng left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycle-two update: approval-byte validation now composes with semantic validation and has an observer regression test. Existing schema-4 records remain readable; those without an approval fingerprint are observed stale and require reapproval. Focused durable, effects, plant, and helper tests passed.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.98

The patch introduces an authority/receipt violation at worktree installation, a resolver/apply disagreement, and an unversioned durable ABI change. Model-level verification is recommended after fixes, especially for interruption and workspace.reconcile behavior between worktree creation and artifact installation.

Comment on lines +343 to +347
planMutation, err := mutationFor(filepath.Join(destinationRoot, "plans", deliveryID+".source"), planRaw, 0o644, false, false)
if err != nil {
return nil, err
}
approvalMutation, err := mutationFor(filepath.Join(destinationRoot, "approvals", deliveryID+".json"), approvalRaw, 0o644, false, false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Bind destination artifacts only after establishing their actual paths

Invariant: staged mutations must bind the actual prior resource and remain inside the admitted workspace. Prepare calls this while the destination does not yet exist, so mutationFor always records PriorExists=false. Then git worktree add can check out either a tracked artifact or a .boatstack/plans/approvals symlink before installation. The former is overwritten but receipted as a create and deleted on rollback; the latter redirects the write outside the workspace while verification still succeeds through the symlink. This is introduced by the new destination writes and can corrupt external files or produce false receipts/recovery data. A regression test should cut from a base ref containing both a tracked target and a symlinked artifact directory, asserting refusal, no external write, and exact prior facts.

Confidence: 0.99

Comment on lines +313 to +314
if workspacePath == "" || expectedApprovalFingerprint == "" {
return nil, fmt.Errorf("workspace plan transfer requires destination and exact approval for a bound plan")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not require approval for every bound plan

Invariant: any workspace.cut prescribed from an admissible snapshot must pass deterministic preparation for that same snapshot. The catalog permits cutting with a draft, valid, or stale plan, but those states have a nonempty plan fingerprint and legitimately no approval fingerprint. Resolution therefore prescribes a targeted workspace.cut, preparation rejects it here, state remains unchanged, and retry repeats the refusal. Legacy approved schema-4 states accepted by this patch provide another witness because their approval fingerprint is empty. The patch introduces this disagreement by treating every bound plan as approved. A regression test should resolve and apply workspace.cut from a draft plan, and separately verify that a legacy/stale plan is refused during resolution or has a defined transfer path.

Confidence: 0.99

RuntimeFingerprint string `json:"runtime_fingerprint,omitempty"`
RuntimeSource string `json:"runtime_source_revision,omitempty"`
PlanFingerprint string `json:"plan_fingerprint,omitempty"`
ApprovalFingerprint string `json:"approval_fingerprint,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Version the durable state ABI for the new field

Invariant: equal state-schema identities must denote mutually compatible durable wire formats. Head now emits approval_fingerprint while retaining schema version 4; the base runtime's strict decoder rejects that unknown field. Thus after head commits an approval, an exact base candidate cannot even observe the state to perform an otherwise legal runtime downgrade/update, despite both pins declaring schema 4. The new legacy test checks only that the current decoder reads field-absent bytes and does not exercise the real old decoder. A regression test should use the actual base decoder against a head-emitted approved state and require either compatibility or a distinct schema identity with an explicit migration path.

Confidence: 0.96

@bigboateng
bigboateng merged commit d43fd6d into main Aug 13, 2026
18 checks passed
@bigboateng
bigboateng deleted the fix/worktree-plan-artifact-transfer branch August 13, 2026 13:01
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