diff --git a/Agent.md b/Agent.md index 0353e54a..c9b7c1f1 100644 --- a/Agent.md +++ b/Agent.md @@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design: pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg ``` -Python: `uv run pytest tests/ -v` (1039) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (1040) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (259: 45 daemon_client + 20 conn-manager + 22 app-commands + 129 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/emrg/server/open_source_prompt.md b/emrg/server/open_source_prompt.md index 3399a5a5..5e082b46 100644 --- a/emrg/server/open_source_prompt.md +++ b/emrg/server/open_source_prompt.md @@ -142,7 +142,7 @@ State file format: ```markdown # Open-Source State: {{ owner }}/{{ repo }} - role: Committer | Contributor -- current stage: Prep | Recon | Contribute | Track | Review +- current stage: Prep | Recon | Contribute | Track | Track+Recon | Review - last completed: - active PRs: - in progress: @@ -206,6 +206,13 @@ Is "in progress" non-empty in the state file? Are there open items in "active PRs"? → Phase Tracking (check PR status, respond to reviews) + All open PRs healthy (MERGEABLE + CI green, no conflicts, no pending + review feedback) AND no rebase maintenance due this round (≤1 round + since last maintenance)? + → May run Recon in parallel this round (stage = Track+Recon): + scan issues/PRs for a new contribution direction; found one → + enter Phase Contribution next round (recon this round, implement + next round). See Phase C.1.5. No active work? → Phase Recon (scan issues/PRs for something to do) @@ -214,7 +221,8 @@ Role = Committer and many PRs awaiting review? → May move to Phase Review after recon ``` -**Only one phase per cycle. Don't aim for completeness, just for progress.** +**One primary phase per cycle. Don't aim for completeness, just for progress.** +**Exception**: during Phase Tracking, when all open PRs are healthy (MERGEABLE + CI green, no conflicts, no pending review feedback) and no rebase maintenance is due this round, Recon may run **in parallel** (stage = `Track+Recon`) — see Phase C.1.5. Parallel Recon must still respect the output cap and direction-diversity rules there. --- @@ -420,10 +428,38 @@ For each open PR: | **Closed (unmerged)** | Understand why → record in memory file → remove from active PR list | | **No feedback for 7+ days** | May politely ask on the PR "any updates or feedback?" | +#### C.1.5 Parallel Recon (healthy-PR rule, rant 2026-08-24T14:05:06) + +Tracking is **not maintenance-only**. When **all** open PRs are healthy and this round needs no maintenance, you may run Recon in parallel instead of finishing the cycle — a long-lived healthy PR (MERGEABLE + CI green) must not lock the task out of producing new contributions. + +**Healthy** = for **every** open PR in the active list: +- **MERGEABLE** — no conflicts (`gh pr view -R {{ owner }}/{{ repo }} --json mergeable,mergeableState`) +- **CI green** — `gh pr checks -R {{ owner }}/{{ repo }}`: no failed/pending checks reported (a PR with **zero** checks reported means the push event was dropped — re-trigger, do not count as healthy) +- **No unaddressed feedback** — no unanswered change requests / bot / maintainer comments (`gh api repos/{{ owner }}/{{ repo }}/pulls//reviews` + `/issues//comments`) +- **No rebase maintenance due** — last maintenance round ≤ 1 round ago + +When healthy (all of the above), in the **same round**: +1. Run Phase A Recon steps (A.1 scan issues, A.2 scan PRs) to find a new contribution direction +2. Direction found → update the state file (stage = `Track+Recon`; keep all active PRs; set in-progress = new candidate), enter **Phase Contribution next round** +3. Nothing found → update the state file (stage = `Track+Recon`, next step = continue recon), finish this cycle + +**Maintenance duty is NOT waived**: any open PR that needs rebase / review-feedback response / 7-day nudge → do Tracking maintenance first (C.1 table), and only then consider parallel Recon. + +**Parallel output cap**: while Tracking+Recon runs in parallel, hold at most **3 total same-day open PRs** (avoid stacking PRs that overload maintainers; PRs accumulated across days are not capped by this rule, but keep the total prudent). + +**Direction diversity**: if a Recon candidate's topic conflicts with existing open PR themes, prefer a contribution in a different module/type (broaden coverage rather than stacking similar work). + +**State file when parallel**: +- `current stage: Track+Recon` +- `active PRs:` keeps all healthy open PRs (one per line) +- `in progress:` records the new candidate (issue URL / next contribution) alongside + #### C.2 Exit condition - No open PRs → state file (active PRs = none), enter Phase Recon next round -- Still have open PRs → update the state file, finish this cycle +- Still have open PRs: + - All healthy + no maintenance due (per C.1.5) → run parallel Recon (stage = `Track+Recon`); found a direction → enter Phase Contribution next round; otherwise finish the cycle + - Any PR needs maintenance (rebase / feedback / nudge) → do it, update the state file, finish this cycle --- diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index d5bb8899..8cf38e28 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -1057,6 +1057,43 @@ def test_open_source_template_full_code_study_b2b(): assert "Only when you understand the author's design intent should you consider how to contribute" in out, "理解设计意图后才可贡献应渲染" +def test_open_source_template_parallel_recon_c15(): + """open_source_prompt.md Phase C.1.5 allows parallel Recon when all open + PRs are healthy (rant 2026-08-24T14:05:06): a long-lived healthy PR must + not lock the task out of producing new contributions.""" + import jinja2 + + template_path = ( + Path(__file__).resolve().parent.parent + / "emrg" / "server" / "open_source_prompt.md" + ) + env = jinja2.Environment(undefined=jinja2.Undefined) + template = env.from_string(template_path.read_text(encoding="utf-8")) + out = template.render( + instance_id="test", host_name="host", uptime="0h 0m", + repo_url="https://github.com/x/y.git", owner="x", repo="y", + local_source="/tmp/os", source_dir="/tmp/os", session_id="s1", + evolution_cwd="/tmp/evo", timestamp="20260824", + task={"role": "committer", "project": "aitokenpool"}, + project={}, evolution_count=0, git_path="git", gh_path="gh", + ) + # 1) the new section exists + assert "C.1.5 Parallel Recon" in out, "C.1.5 并行 Recon 节应渲染" + assert "not maintenance-only" in out, "Tracking 非纯维护说明应渲染" + # 2) healthy = MERGEABLE + CI green + no unaddressed feedback + no rebase due + assert "MERGEABLE" in out, "健康判定含 MERGEABLE" + assert "CI green" in out, "健康判定含 CI 绿" + assert "No unaddressed feedback" in out, "健康判定含无未处理评审反馈" + assert "No rebase maintenance due" in out, "健康判定含无需 rebase 维护" + # 3) parallel output cap + direction diversity rules render + assert "3 total same-day open PRs" in out, "同日 open PR 上限 3 个应渲染" + assert "Direction diversity" in out, "方向多样性规则应渲染" + # 4) state file stage value Track+Recon is documented in the format spec + assert "Track+Recon" in out, "Track+Recon stage 值应渲染" + # 5) the state machine no longer hard-locks open PRs into Tracking-only + assert "May run Recon in parallel this round" in out, "状态机应允许并行 Recon" + + def test_promote_template_learn_latest_state_04(): """promote_prompt.md §0.4 requires learning the project's latest state before promoting (rant 2026-08-14T22:13:57, mirrors open-source B.2b #790)."""