feat(worktree): add worktree create verb (AB#3096, PR 1b3) - #312
Merged
Conversation
This was referenced May 12, 2026
Adds `polyphony worktree create --apex N --branch B [--ref R]` — the per-item worktree creation primitive used by all workflow steps that need an impl/, plan/, mg/, or evidence/ worktree under an apex run. Mirrors the structure of `worktree init-apex` (PR #311 / PR 1b2): branch-grammar validation, bootstrap-dependency check, race-tolerant idempotent recovery. Rubber-duck-validated decisions: - Bootstrap dependency is structural: `{apex_root}/feature-{N}` must be a registered worktree on `feature/{N}`, not just Directory.Exists. Catches partial-init in one signal. - Reject `feature/{N}` branches with `unsupported_branch_kind`: init-apex is the canonical path; otherwise create becomes an unprotected back-door. - `remote_branch_exists` always wins (even with `--ref`): workflow-rerun safety; operator must explicitly fetch+branch first to avoid silent fork. - No cwd-refusal: path is self-derived from runs_root; cwd has no impact on safety. Stacked on PR #311. Branch off `feature/worktree-init-apex` tip; rebase onto main once #311 merges. Part of AB#3085 (bare-repo + per-run worktree epic). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PolyphonyRequiem
force-pushed
the
feature/worktree-create
branch
from
May 12, 2026 01:11
63e4b18 to
da9f782
Compare
PolyphonyRequiem
pushed a commit
that referenced
this pull request
May 12, 2026
PR 3 of AB#3085. Replaces the legacy launcher (whose
`WorktreeRoot = (Get-Location).Path` default was the root cause of the
main-worktree hijack bug) with a self-derivation contract over the
existing CLI verbs.
11-phase preflight chain:
1. cwd is in a git worktree (fail-fast with link to layout doc)
2. bare-repo layout preflight (refuses non-bare clones with link to
Migrate-ToBareRepo.ps1; -SkipLayoutCheck escape hatch)
3. polyphony worktree init-apex (--dry-run on -DryRun) — self-derive
the apex worktree path; surface every failure reason with
remediation text
4. hijack refusal (defense-in-depth: refuse if derived path is or is
inside the main worktree)
5. -WorktreeRoot override validation (must canonicalize to derived
path; OrdinalIgnoreCase on Windows, normalized trailing slash)
6. intent semantics (-Intent resume + outcome=created refused)
7. .twig/ propagation (gitignored, so freshly-added apex worktrees
lack it; copied from main on first launch; never clobbered)
8. assert-clean integration (skipped on -DryRun; surfaces dirty /
wrong-branch / git-op-in-progress with remediation text)
9. metadata derivation (platform + repository auto-detected from
main worktree's git remote)
10. conductor command construction (6 -m flags + apex/intent/platform/
repo inputs; git_repo defaults to main_worktree_path)
11. conductor launch (PR #302's new-console-window pattern preserved
for TTY-attached gate stdin)
Subsumes PR #302 per Daniel's call. Stacked on PR #311 (init-apex
extensions: --dry-run flag, runs_root/main_worktree_path output
fields). Will rebase clean once #311+#312 merge.
C# extensions to polyphony worktree init-apex:
- New --dry-run flag (read-only mirror of create/attach matrix; emits
same hard-refusal envelopes; emits outcome=dry_run on success)
- New output fields on WorktreeInitApexResult: runs_root,
main_worktree_path, dry_run (surface on success AND on
after-resolution failures so launcher can format errors uniformly)
- New outcome enum value: dry_run
Tests:
- 32 new Pester tests / 32 pass — real bare-repo + git-worktree
fixtures per test (mirrors Migrate-ToBareRepo.Tests pattern); no
init-apex/assert-clean mocking
- 8 new xUnit tests / 29 InitApex tests pass total
Rubber-duck-validated design (see PR body for the 11 design
decisions).
Closes AB#3098.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PolyphonyRequiem
added a commit
that referenced
this pull request
May 12, 2026
…314) * feat(worktree): add `worktree create` verb (AB#3096, PR 1b3) Adds `polyphony worktree create --apex N --branch B [--ref R]` — the per-item worktree creation primitive used by all workflow steps that need an impl/, plan/, mg/, or evidence/ worktree under an apex run. Mirrors the structure of `worktree init-apex` (PR #311 / PR 1b2): branch-grammar validation, bootstrap-dependency check, race-tolerant idempotent recovery. Rubber-duck-validated decisions: - Bootstrap dependency is structural: `{apex_root}/feature-{N}` must be a registered worktree on `feature/{N}`, not just Directory.Exists. Catches partial-init in one signal. - Reject `feature/{N}` branches with `unsupported_branch_kind`: init-apex is the canonical path; otherwise create becomes an unprotected back-door. - `remote_branch_exists` always wins (even with `--ref`): workflow-rerun safety; operator must explicitly fetch+branch first to avoid silent fork. - No cwd-refusal: path is self-derived from runs_root; cwd has no impact on safety. Stacked on PR #311. Branch off `feature/worktree-init-apex` tip; rebase onto main once #311 merges. Part of AB#3085 (bare-repo + per-run worktree epic). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(launcher): bare-repo + per-run-worktree rework (AB#3098, PR 3) PR 3 of AB#3085. Replaces the legacy launcher (whose `WorktreeRoot = (Get-Location).Path` default was the root cause of the main-worktree hijack bug) with a self-derivation contract over the existing CLI verbs. 11-phase preflight chain: 1. cwd is in a git worktree (fail-fast with link to layout doc) 2. bare-repo layout preflight (refuses non-bare clones with link to Migrate-ToBareRepo.ps1; -SkipLayoutCheck escape hatch) 3. polyphony worktree init-apex (--dry-run on -DryRun) — self-derive the apex worktree path; surface every failure reason with remediation text 4. hijack refusal (defense-in-depth: refuse if derived path is or is inside the main worktree) 5. -WorktreeRoot override validation (must canonicalize to derived path; OrdinalIgnoreCase on Windows, normalized trailing slash) 6. intent semantics (-Intent resume + outcome=created refused) 7. .twig/ propagation (gitignored, so freshly-added apex worktrees lack it; copied from main on first launch; never clobbered) 8. assert-clean integration (skipped on -DryRun; surfaces dirty / wrong-branch / git-op-in-progress with remediation text) 9. metadata derivation (platform + repository auto-detected from main worktree's git remote) 10. conductor command construction (6 -m flags + apex/intent/platform/ repo inputs; git_repo defaults to main_worktree_path) 11. conductor launch (PR #302's new-console-window pattern preserved for TTY-attached gate stdin) Subsumes PR #302 per Daniel's call. Stacked on PR #311 (init-apex extensions: --dry-run flag, runs_root/main_worktree_path output fields). Will rebase clean once #311+#312 merge. C# extensions to polyphony worktree init-apex: - New --dry-run flag (read-only mirror of create/attach matrix; emits same hard-refusal envelopes; emits outcome=dry_run on success) - New output fields on WorktreeInitApexResult: runs_root, main_worktree_path, dry_run (surface on success AND on after-resolution failures so launcher can format errors uniformly) - New outcome enum value: dry_run Tests: - 32 new Pester tests / 32 pass — real bare-repo + git-worktree fixtures per test (mirrors Migrate-ToBareRepo.Tests pattern); no init-apex/assert-clean mocking - 8 new xUnit tests / 29 InitApex tests pass total Rubber-duck-validated design (see PR body for the 11 design decisions). Closes AB#3098. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Daniel Green <dangreen@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the
polyphony worktree create --apex N --branch B [--ref R]verb — the per-item worktree-creation primitive used by every workflow step that needs animpl/,plan/,mg/, orevidence/worktree under an apex run. Mirrors the structure ofworktree init-apex(PR #311 / PR 1b2) with branch-grammar validation, bootstrap-dependency checks, and explicit--refhandling.Closes AB#3096. Part of AB#3085 (bare-repo + per-run worktree epic).
Stacking
Stacked on PR #311 (PR 1b2:
worktree init-apex). Branchfeature/worktree-createis offfeature/worktree-init-apextip. The diff against main will be clean once #311 merges; please merge #311 first.What this PR does
Implements:
Behavior:
--apex > 0and that--branchparses against the canonical grammar (fromBranchSlug.TryParse:feature/{r},plan/{r}[-{item_id}],mg/{r}_{mg_path},impl/{r}-{item_id},evidence/{r}-{item_id}).feature/{N}branches withunsupported_branch_kind—init-apexis the canonical path for the apex feature worktree.parsed.RootId == --apex(elsebranch_apex_mismatch).runs_rootandmain_pathviaRunsRootResolver(from PR 1b1).{runs_root}/apex-{N}/{slug}/lives underruns_rootAND not undermain_pathviaPathBoundary(from PR 1b2). The hijack is structurally impossible.{runs_root}/apex-{N}/feature-{N}must already be a registered worktree onfeature/{N}. Otherwiseapex_not_initialized(catches partial-init, missing apex root, manualmkdir).Reason taxonomy
reasoninvalid_apex<= 0invalid_branchBranchSlug.TryParsebranch_apex_mismatch--apexunsupported_branch_kindfeature/{N}(useinit-apex)common_dir_unavailablegit rev-parse --git-common-dirfailedfilesystem_failureapex_not_initialized{apex_root}/feature-{N}is not a registered worktree onfeature/{N}git_failurepath_exists_wrong_branchpath_exists_not_worktreebranch_in_useremote_branch_existsorigin/{branch}exists (refused regardless of--ref)ref_required--refempty (after remote check passed)outcomeis one of:created,attached,idempotent,failed.Rubber-duck-validated decisions
Directory.Exists). The check that{apex_root}/feature-{N}is a worktree onfeature/{N}is derived from the samegit worktree list --porcelaincall we already make for path-existence — no extra git invocations. Catches partial-init, manualmkdir, and missing apex root in one signal.feature/{N}branches.BranchSlug.TryParseaccepts theFeaturekind (and other verbs need that), butcreaterejects it withunsupported_branch_kind. Otherwisecreatewould become an unprotected back-door aroundinit-apex's remote-branch + always-root-from-main safety.remote_branch_existsalways wins, even with--ref. Workflow-rerun safety: if the local branch is missing butorigin/{branch}exists, refuse regardless of what was passed for--ref. The operator must explicitly fetch + branch first to avoid silent fork.runs_root; cwd has no impact on safety.init-apexlegitimately runs from main during bootstrap, and the same logic applies tocreate.ref_unresolvablepre-check. Git is the authoritative resolver; a bad ref naturally surfaces asgit_failurewith stderr.ref(notref_spec).refis valid JSON and doesn't collide with JSON Schema's$ref.kind/separator is replaced.impl/3085-3072→impl-3085-3072;mg/3085_pg-foo→mg-3085_pg-foo(underscores preserved).Files
src/Polyphony/Models/WorktreeCreateResult.cs(new) — result record. Doc-comment is the authoritative reason taxonomy.src/Polyphony/Commands/WorktreeCommands.Create.cs(new) — partial verb. Reuses static helpers fromWorktreeCommands.InitApex.cs(FindByPath,NormalizePath,PathExists,GitStderrOrFallback,ProbeIdempotentAsync,ParsePorcelain).src/Polyphony/PolyphonyJsonContext.cs—[JsonSerializable(typeof(WorktreeCreateResult))].src/Polyphony/Commands/WorktreeCommands.cs—<see cref="Create"/>doc-line.tests/Polyphony.Tests/Commands/WorktreeCommandsCreateTests.cs(new) — 27 tests covering arg validation, branch grammar (incl.feature/Nrefusal), partial-init detection, path-exists matrix, branch-state matrix (incl.ref_required, remote-refusal-with-ref, attach-without-ref), race tolerance, JSON contract.artifacts/verb-output-schemas.json— regenerated; addsworktree createentry.What this PR does NOT do
worktree createfrom any workflow YAML or PowerShell helper. That's PR 4 (workflow integration + driver pre-flight).worktree gc. That's PR 7.polyphony-branch-model.Validation
worktree createentry contains apex/branch/ref inputs andPolyphony.WorktreeCreateResultresult type