feat: side-thread task kind (Muse role alignment phase 2)
ci / test (push) Successful in 25m2s

Tasks gain kind='main'|'side' (NULL=main). A side thread hangs under a
parent task, defaults to the local executor, never builds a worktree,
branch or container unless explicitly asked, and writes its conclusion
back to the parent via task_followups on terminal transition.

- server: kind validation + side-thread gates (parent required, no
  coordinator_parts/upload_id/environment_id, parent must not be a
  coordinator), local executor default, GET /tasks kind filter,
  /worktree 404 and /fork /merge /pr 409 for side threads.
- worker: side-default shunt in _run_attempt (no-worktree scratch cwd,
  in-memory plan=1 when a repo is present, seed/checkpoint skipped),
  _writeback_side_thread, marker task-create kind field + inheritance,
  side threads excluded from marker spawn counts.
- host/sandbox: --no-worktree plumbing for dispatch/goal/popen
  (Local + Docker), scratch cwd work/side-threads/<task-id>.
- console (classic only): kind filter + [旁聊] rows + '开旁聊' entry,
  side-thread dispatch mode, side-thread list in detail, merge/PR/fork
  hidden for side threads; build exit 0, console.html sha df39db5a.
- tests: new test_sidethread.py (29 tests) + kind backfill tests in
  test_p2_migrations.py; full cloud suite 3900 tests OK (skipped=13).

Design: verification/codex-muse-role-alignment-design-20261108.md
Summary: verification/codex-muse-role-align-p1p2-20261108.md
Local only: not pushed, not merged, not deployed.
This commit is contained in:
host committed 2026-11-07 20:51:23 +00:00
1 parent f6df76ee8f
commit 7983567491
24 files changed
+1244 -100

No files matched your search

+6 -1
View File
@@ -236,7 +236,12 @@ def migrate_sqlite_to_postgres(sqlite_path, pg_conn=None, tables=None):
# 的 `or 0` 兜底拦不住,audit_loop=0 的
# 历史任务会被悄悄当成启用(Audit batch 1)。
("audit_loop", "INTEGER"),
("audit_loop_packet", "TEXT")):
("audit_loop_packet", "TEXT"),
# 旁聊(Muse 角色对齐 P2):kind 列须与
# db.py POSTGRES_SCHEMA、server
# migrate_tasks_table 同步;NULL = 老行
# = 主聊,无回填。
("kind", "TEXT")):
if _col not in _existing:
try:
pg_conn.execute(