Skip to content

fix(sdlc-launcher): spawn conductor in new console window, drop --web-bg - #302

Merged
PolyphonyRequiem merged 1 commit into
mainfrom
fix/sdlc-launcher-new-console
May 11, 2026
Merged

fix(sdlc-launcher): spawn conductor in new console window, drop --web-bg#302
PolyphonyRequiem merged 1 commit into
mainfrom
fix/sdlc-launcher-new-console

Conversation

@PolyphonyRequiem

Copy link
Copy Markdown
Owner

Summary

PR #300 used --web-bg for the detached launch path. Conductor's
�g_runner spawns the workflow child with stdin=DEVNULL
(cli/bg_runner.py:172,178,210), which kills any agent that reads
stdin — most notably gate agents waiting for the operator's
stdin-fallback answer. The dashboard's Answer button POSTs
successfully but no listener is alive to consume it because the gate
subworkflow dies with EOFError before it can register one. The failure
cascades up through subworkflow_failedfor_each_item_failed.

Repro / observed failure

AB#3071 dogfood 2026-05-11: two parallel plan-level open-questions
gates (items 3073, 3074) failed within 14ms of being presented.
Dashboard event timeline:

09:51:12.204 agent_started open_questions_gate 09:51:12.208 gate_presented open_questions_gate 09:51:12.222 workflow_failed open_questions_gate EOFError 09:51:12.240 → cascade: plan_level_dispatch → dispatch_items → for_each_item_failed

Operator's Answer click reached the API as Answer · sent · awaiting… but no agent ever consumed it.

Fix

Always pass --web (not --web-bg). Detached path now spawns conductor inside a new PowerShell console window via Start-Process pwsh -NoExit -Command …. The new window has its own console, so conductor inherits a real TTY (stdin attached). Foreground --web works, gate agents can read stdin fallback, and the operator's launching shell stays free. The new window keeps -NoExit so post-mortem stack traces stay visible.

Output also tee'd to a transcript log under %TEMP%\polyphony-sdlc-runs\apex-{id}-{ts}-transcript.log.

Test

Dry-run from sibling worktree confirms args and worktree resolution. Live restart of AB#3071 from polyphony-3071 worktree validates the gate-stdin-EOF cascade is gone.

Trade-offs

  • Visible PowerShell window per run (operator can minimize). Acceptable — preferable to broken gates.
  • Operator must close the post-mortem window manually. Acceptable — keeps stack traces visible after crashes.

PR #300 used --web-bg for the detached launch path. Conductor's bg_runner
spawns the workflow child with stdin=DEVNULL (cli/bg_runner.py:172,178,210),
which kills any agent that reads stdin — most notably gate agents waiting
for the operator's stdin-fallback answer. The web dashboard's 'Answer'
button POSTs successfully but no listener is alive to consume it because
the gate subworkflow dies with EOFError before it can register one. The
failure cascades up through subworkflow_failed → for_each_item_failed.

Observed during AB#3071 dogfood 2026-05-11: two parallel plan-level
open-questions gates failed within 14ms of being presented; the user's
answer never reached an agent.

Fix: always pass --web (not --web-bg). Detached path now spawns conductor
inside a *new* PowerShell console window via Start-Process pwsh -NoExit.
The new window has its own console, so conductor inherits a real TTY
(stdin attached). --web foreground works, gate agents can read stdin
fallback, and the operator's launching shell stays free. The new window
keeps -NoExit so post-mortem stack traces stay visible.

Output is also tee'd to a transcript log under
%TEMP%\polyphony-sdlc-runs\apex-{id}-{ts}-transcript.log.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PolyphonyRequiem
PolyphonyRequiem merged commit 1b994fb into main May 11, 2026
1 check passed
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>
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