MegaTask umbrella e2e scenario + batch root-subtask completion fix; comms dead-code deletion (#296)

* chore(panel): delete the five dead comms components

The comms audit found communications-view, channel-sidebar,
channel-item, message-list, and message-item exported but rendered by
no page — the live /communications page and the session detail render
their own inline content and import only MessageComposer and
MessageTypeBadge, which stay. Verified zero consumers outside the dead
cluster before deletion; panel gates green (tsc, lint, 187 tests).

* feat(tests): e2e scenario 4 — MegaTask umbrella; fix batch root-subtask completion wall

Scenario 4 seeds an umbrella + two dependency-linked root-subtasks:
sequencing hold proven (unmet_dependency on RS2's i_will_plan while RS1
lives), RS1 completed through the entire real chain to a master merge,
hold lifts, RS2 completes, umbrella closes branchless via ceo-approve
and never carries a PR.

Product fix it surfaced on first run: _main_pm_complete_guard and
escalate_to_ceo refused ANY parented task as 'not a root', but a batch
root-subtask is parented (the umbrella) BY DESIGN — both sites now
consult is_batch_root_subtask, plain subtasks stay refused. Live
root-subtasks previously needed CEO god-mode to close. Regression
tests added; built subagent-driven (Sonnet 5) and reviewed.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-07-02 22:02:39 +02:00
committed by GitHub
co-authored by Renn F
parent d1cf6ecbf3
commit 48f2944086
14 changed files with 622 additions and 426 deletions
@@ -704,6 +704,7 @@ async def test_main_pm_complete_rejects_non_root_task() -> None:
status="awaiting_pm_review",
assigned_to=main_pm_id,
parent_task_id=uuid4(), # has parent -> not a root task
batch_id=None, # a plain subtask, NOT a MegaTask root-subtask
)
task_svc = AsyncMock()
task_svc.get.return_value = t
@@ -716,6 +717,46 @@ async def test_main_pm_complete_rejects_non_root_task() -> None:
assert "root tasks" in body["message"]
@pytest.mark.asyncio
async def test_main_pm_complete_allows_batch_root_subtask() -> None:
"""A MegaTask root-subtask IS parented (the umbrella) yet carries its own
project/branch/PR and behaves as a root for git/CEO purposes — the
parent_task_id refusal above must NOT fire for it (is_batch_root_subtask)."""
main_pm_id = uuid4()
root_task_id = uuid4()
t = MagicMock(
id=root_task_id,
status="awaiting_pm_review",
assigned_to=main_pm_id,
pr_number=42,
branch_name="feature/main_pm/rootsub1",
parent_task_id=uuid4(), # the umbrella
batch_id=uuid4(), # batch_id + parent_task_id -> is_batch_root_subtask
team="main_pm",
)
after = MagicMock(**{**t.__dict__, "status": "awaiting_ceo_approval"})
task_svc = AsyncMock()
task_svc.get.return_value = t
task_svc.escalate_to_ceo.return_value = after
task_svc.all_subtasks_terminal.return_value = True
task_svc.uncovered_parent_acceptance_criteria.return_value = []
git_svc = AsyncMock()
git_svc.pr_target.return_value = "master"
journal_svc = AsyncMock()
journal_svc.has_decision_for_task.return_value = True
journal_svc.latest_decision_at.return_value = datetime.now(UTC)
journal_svc.has_reflect_for_task.return_value = True
deps = _make_deps(task=task_svc, git=git_svc, journal=journal_svc)
c = Choreographer(deps)
env = await c.main_pm_complete(
main_pm_id, root_task_id, notes="root-subtask reviewed and ready"
)
assert env.error is None, env.as_dict()
assert env.status == "awaiting_ceo_approval"
task_svc.escalate_to_ceo.assert_awaited_once()
@pytest.mark.asyncio
async def test_main_pm_complete_blocks_unfinished_subtasks() -> None:
main_pm_id = uuid4()