Commit Graph

67 Commits

Author SHA1 Message Date
ejclaw
f5c3393c32 runners: share protocol and reviewer policy 2026-04-11 05:07:05 +09:00
ejclaw
4e05f60400 refactor: land approved runtime cleanup and room binding cutover 2026-04-10 21:04:23 +09:00
ejclaw
2e62e125ae Audit outbound delivery and fix reviewer turn routing 2026-04-10 15:22:45 +09:00
ejclaw
0f994ab2ce fix: harden paired runtime turn coordination 2026-04-09 13:52:42 +09:00
ejclaw
10e10b499c Complete paired-room SSOT cleanup and logger singleton 2026-04-07 05:12:22 +09:00
ejclaw
b8e8c9dabf Unify paired status transitions and retry handling 2026-04-07 02:49:02 +09:00
ejclaw
cbb6bc97c7 Refactor paired execution flow boundaries 2026-04-07 00:45:17 +09:00
ejclaw
5b832042da Format files touched by executor refactor 2026-04-06 19:40:36 +09:00
ejclaw
24ffa3d2f1 Refactor paired turn transitions and scheduling 2026-04-06 19:32:36 +09:00
ejclaw
d75d26c23d Stabilize paired reviewer recovery and owner follow-up 2026-04-06 07:49:26 +09:00
ejclaw
994e957767 Enable unsafe host paired runtime 2026-04-06 02:40:15 +09:00
ejclaw
2983e0501c Serialize merge-ready owner finalize handoff 2026-04-05 20:11:14 +09:00
Eyejoker
bf3ed696fe Preserve paired review state after infra failures 2026-04-05 07:43:40 +09:00
Eyejoker
3dd772c229 Refactor local memory and role-fixed runtime routing 2026-04-04 03:50:28 +09:00
Eyejoker
60f360b5ea fix: preserve handoff roles during failover 2026-04-01 02:54:35 +09:00
Eyejoker
757e33c58e fix: prevent DONE↔DONE infinite loop and add AGENT_LANGUAGE setting
- Fix source_ref mismatch: update to workspace HEAD on first owner run
  so change detection compares against the correct repo
- Treat hasNewChanges === null as "no changes" at finalize to prevent
  infinite re-review when source_ref is unresolvable
- Add AGENT_LANGUAGE env var: when set, appends language instruction to
  all paired room prompts (owner, reviewer, arbiter)
2026-03-31 13:55:41 +09:00
Eyejoker
dd28ac6223 fix: fallback to proceed on unrecognized arbiter verdict
Previously unknown verdicts caused arbiter_escalated (task terminated).
Now falls back to proceed so the loop continues — a parse failure
should not kill the task.
2026-03-31 09:03:20 +09:00
Eyejoker
94184c137d fix: parse arbiter verdict with optional VERDICT: prefix
Codex arbiter sometimes outputs "VERDICT: PROCEED" instead of
"PROCEED". The regex now handles optional "VERDICT:" prefix,
preventing unknown verdict → false arbiter_escalated.
2026-03-31 08:51:01 +09:00
Eyejoker
196c453ccf fix: skip enqueueMessageCheck when task is already completed (ESCALATE/done) 2026-03-31 04:59:27 +09:00
Eyejoker
636c54702a fix: prevent ESCALATE → new task loop (only create tasks on human messages) 2026-03-31 04:58:26 +09:00
Eyejoker
2753849343 chore: update Claude Agent SDK 0.2.87, Codex SDK 0.117.0 2026-03-31 04:47:42 +09:00
Eyejoker
d0416489c5 fix: escalate finalize blockers without reviewer bounce 2026-03-31 04:32:10 +09:00
Eyejoker
af550a2aab fix: prevent infinite loops in paired review (merge_ready oscillation, arbiter re-invocation)
- Owner finalize with concerns now checks deadlock threshold before
  looping back — prevents merge_ready ↔ active infinite oscillation
- Arbiter verdict resets round_trip to threshold-1 instead of 0,
  giving agents one round before re-triggering arbiter
2026-03-31 04:13:26 +09:00
Eyejoker
e1b9501e87 feat: add completion_reason to paired_tasks (done/escalated/stopped/arbiter_escalated)
- owner can summon arbiter via BLOCKED/NEEDS_CONTEXT verdict
- completion_reason tracks why task ended: done (success), escalated
  (reviewer gave up), stopped (/stop), arbiter_escalated
2026-03-31 04:10:33 +09:00
Eyejoker
b02c509eb8 feat: owner can also summon arbiter via BLOCKED/NEEDS_CONTEXT verdict 2026-03-31 04:05:26 +09:00
Eyejoker
25cec18ce8 fix: clear arbiter session on each invocation to prevent verdict bias 2026-03-30 22:30:42 +09:00
Eyejoker
45fe80f5f5 fix: route BLOCKED/NEEDS_CONTEXT through arbiter before escalating
BLOCKED and NEEDS_CONTEXT verdicts went straight to completed,
bypassing the arbiter entirely. Now when arbiter is enabled, these
verdicts trigger arbiter intervention first — the arbiter may
resolve the block or decide to escalate to the user (ESCALATE).
2026-03-30 22:26:51 +09:00
Eyejoker
a043f2b79a feat: implement MAGI 3-agent arbiter system for deadlock resolution
Introduces a third agent role (arbiter) that is summoned on-demand
when owner and reviewer reach a deadlock (same verdict 3+ rounds).

Architecture:
- 3 Discord bots: owner (codex), reviewer (claude), arbiter (claude/codex)
- Arbiter is NOT always-on — only invoked when deadlock detected
- Arbiter renders binding verdict: PROCEED/REVISE/RESET/ESCALATE
- Non-escalate verdicts reset round_trip_count and resume ping-pong
- Backward compatible: ARBITER_AGENT_TYPE unset = existing 2-agent mode

Changes across 13 source files + 7 test files:
- types.ts: PairedRoomRole += 'arbiter', new statuses, ArbiterVerdict type
- config.ts: ARBITER_AGENT_TYPE, ARBITER_SERVICE_ID, ARBITER_DEADLOCK_THRESHOLD
- db.ts: schema migration (arbiter columns in channel_owner + paired_tasks)
- service-routing.ts: arbiter_service_id in lease
- room-role-context.ts: arbiter role detection
- paired-execution-context.ts: deadlock->arbiter, verdict handling
- message-runtime.ts: arbiter turn routing, cursor, sender labeling
- message-agent-executor.ts: arbiter mode, failover
- agent-runner.ts + environment.ts: arbiter container mode
- platform-prompts.ts: arbiter prompt loading

New files:
- prompts/arbiter-paired-room.md: arbiter system prompt
- src/arbiter-context.ts: builds conversation context for arbiter judgment
2026-03-30 22:20:42 +09:00
Eyejoker
7ee915bbeb fix: only reset round_trip_count on human messages
The counter was being reset to 0 on every owner turn, including
bot-only ping-pong turns. This prevented the 3-round-trip echo
loop breaker from ever triggering. Now only human messages reset
the counter.
2026-03-30 21:09:41 +09:00
Eyejoker
27bf36c833 fix: break DONE_WITH_CONCERNS echo loop after 3 round trips
When both owner and reviewer keep echoing DONE_WITH_CONCERNS without
making progress, the system now stops the ping-pong after 3 round
trips and sets the task to completed, escalating to the user.
2026-03-30 21:00:31 +09:00
Eyejoker
78fa078921 fix: only reset merge_ready to active when human message is present
The finalize turn (auto-triggered after reviewer approval) was being
treated as a new working turn because merge_ready was unconditionally
reset to active. Now merge_ready is only reset when a human message
is in the batch, preserving the finalize flow for bot-only turns.
2026-03-30 19:48:25 +09:00
Eyejoker
fa8ca476d8 fix: reset task status to active on new human message
When a user sends a new message while the task is in merge_ready,
review_ready, or in_review status, the owner's turn was incorrectly
treated as a finalize turn. This caused premature task completion
(DONE → completed) even when the user wanted to continue working.

Now resets status to active alongside round_trip_count, ensuring
the owner gets a fresh working turn instead of a finalize turn.
2026-03-30 17:59:27 +09:00
Eyejoker
e13c1df520 feat: skip auto-review when active CI watcher exists
When the owner registers a CI watcher and completes the turn, the
review loop no longer triggers. The watcher result will be posted
via the reviewer bot, which the owner picks up and acts on, then
the normal review loop resumes.
2026-03-30 04:11:30 +09:00
Eyejoker
5221fb8b33 style: fix prettier drift after merge 2026-03-30 03:44:58 +09:00
Eyejoker
5e4f1fa8da Merge pull request #1 from phj1081/codex/remove-explicit-paired-review-command-path
refactor: remove dead paired review and output suppression paths
2026-03-30 03:35:34 +09:00
Eyejoker
e78f0b1968 fix: remove .claude nesting from reviewer session dir path
CLAUDE_CONFIG_DIR included .claude suffix, but the container mounts
the parent directory at /home/node/.claude. This caused double nesting:
/home/node/.claude/.claude/CLAUDE.md — SDK never found the prompts.
2026-03-30 03:20:29 +09:00
Eyejoker
6edf5aebbd refactor: remove explicit paired review command path 2026-03-30 01:43:48 +09:00
Eyejoker
aa6477cf2b fix: respect owner verdict during finalize turn
When the reviewer approves (merge_ready) and the owner finalizes,
the system previously only checked for code changes. If the owner
raised concerns (DONE_WITH_CONCERNS, BLOCKED, NEEDS_CONTEXT) during
finalize — e.g. push failed due to detached HEAD — the system
ignored it and auto-completed the task.

Now the owner's verdict is checked first. If the owner raises
concerns, the task goes back to active and re-triggers the reviewer
so the issue can be addressed collaboratively.
2026-03-30 01:37:30 +09:00
Eyejoker
29ab284c60 fix: use stable per-channel owner worktree to preserve session across tasks
Owner worktree path was per-task (data/workspaces/{folder}/tasks/{taskId}/owner/),
causing Claude SDK to treat each new task as a different project and lose session
context. Now uses a stable per-channel path (data/workspaces/{folder}/owner/).

- Channel isolation preserved (different folders get different worktrees)
- Session persists across tasks (same path = same Claude SDK project)
- Reviewer snapshot still reads from owner worktree correctly
- Fix stale approvedHead reference from cherry-pick conflict
2026-03-29 23:31:14 +09:00
Eyejoker
504be9e41a refactor: use tree hash + git diff for post-approval change detection
- Replace commit hash comparison with git tree hash (HEAD^{tree}) to
  avoid false re-review triggers on commit-only operations
- Use git diff --quiet for actual file change detection
- Update source_ref on failed reviewer execution with done verdict
- Add tests for empty-commit finalize and code-change re-review
- Document Codex reviewer bash mutation gap in reviewer-runtime
2026-03-29 23:24:48 +09:00
Eyejoker
2e4de9cca8 fix: isolate reviewer Claude config dir from owner
Reviewer was picking up owner's cached session from the shared
.claude directory, causing "No conversation found" errors. Now uses
data/sessions/{folder}-reviewer/.claude/ as a separate config dir.
2026-03-29 23:05:24 +09:00
Eyejoker
c28fba0478 feat: re-review on post-approval changes, container improvements
- Compare git HEAD at reviewer approval vs owner finalize to detect
  new code changes after DONE verdict. Re-trigger reviewer if changed,
  complete if unchanged (commit-only is fine).
- Record approved HEAD in source_ref when reviewer says DONE
- Add pnpm store mount, pre-flight checks, idle timeout for containers
- Clean up orphaned containers on shutdown
2026-03-29 23:00:56 +09:00
Eyejoker
33baf2970d fix: strip <internal> tags before verdict detection, add Approved/LGTM as done markers 2026-03-29 21:34:08 +09:00
Eyejoker
8119b0bb8f fix: treat execution as success when output was delivered despite null result 2026-03-29 21:24:49 +09:00
Eyejoker
f28b8861bf fix: match verdict markers only at start of first line to prevent false positives 2026-03-29 21:22:45 +09:00
Eyejoker
b8075be92d fix: check reviewer verdict on failed execution to prevent infinite loop 2026-03-29 21:20:16 +09:00
Eyejoker
9127841359 fix: /clear resets paired task to prevent reviewer auto-triggering after session clear 2026-03-29 21:07:34 +09:00
Eyejoker
d8cb4b691e feat: verdict-based ping-pong control with merge_ready finalization
- DONE → merge_ready → owner final turn (commit/push) → completed
- DONE_WITH_CONCERNS → active → owner addresses → ping-pong continues
- BLOCKED/NEEDS_CONTEXT → completed (escalate to user, stop ping-pong)
- Regular feedback → active → ping-pong continues
- Owner detects merge_ready status and finalizes autonomously
2026-03-29 20:59:08 +09:00
Eyejoker
16d20fe627 feat: paired review system overhaul — unified service, configurable agents, silent output removal
- Remove UNIFIED_MODE legacy: single service manages all 3 Discord bots
- Add OWNER_AGENT_TYPE / REVIEWER_AGENT_TYPE env vars for configurable agent selection
- Fix Discord channel routing: reviewer output goes through correct bot (discord/discord-review)
- Fix channel name assignment: explicit names prevent agentTypeFilter collision
- Remove silent output suppression system: harness-level protections replace prompt workarounds
- Add reviewer approval detection: DONE marker on first line stops ping-pong
- Include user's original message in reviewer prompt for context
- Fix round_trip_count auto-reset on new user message
- Fix session ID conflict: reviewer doesn't reuse owner's session
- Fix pending progress text flush in runner on close sentinel
- Promote buffered intermediate text to final result when result event has no text
- Remove legacy files: .env.codex.example, .env.codex-review.example, migrate-unify.cjs
- Update CLAUDE.md: server-side build deployment, unified architecture docs
2026-03-29 20:50:32 +09:00
Eyejoker
4ec7b55105 fix: reset task to active on failed execution to prevent stuck state 2026-03-29 19:17:19 +09:00