From f02dd9a61806d7ddc857c76e6d3dbadaabea0e5a Mon Sep 17 00:00:00 2001 From: argszero Date: Sat, 15 Aug 2026 08:53:50 +0800 Subject: [PATCH] =?UTF-8?q?emrg:=20promote=20task=20de-hardening=20?= =?UTF-8?q?=E2=80=94=20homework-first=20participation,=20disclosure=20defa?= =?UTF-8?q?ult=20OFF=20(rant=202026-08-15T08:40:25)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Agent.md | 2 +- emrg/server/promote_prompt.md | 37 ++++++++++++++++++++++++++------ tests/test_scheduler.py | 40 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/Agent.md b/Agent.md index 821da08..6f5e561 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.port; python -m emrg ``` -Python: `uv run pytest tests/ -v` (823) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (824) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (247: 45 daemon_client + 19 conn-manager + 22 app-commands + 121 renderer smoke + 16 i18n + 7 integration + 3 commands + 5 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/promote_prompt.md b/emrg/server/promote_prompt.md index 8daf396..e56a6dc 100644 --- a/emrg/server/promote_prompt.md +++ b/emrg/server/promote_prompt.md @@ -56,7 +56,11 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path, 1. **Value first**: promotion must rest on real value. Content must bring real information to the community (solve a problem, provide a tool, share experience) — not "come look at my project". 2. **Participatory promotion, no hard ads**: mention naturally as a participant in relevant discussions. **No** pure ad posts ("everyone look at my new project!"), **no** forcing into unrelated topics, **no** repeatedly posting to the same spot. 3. **No spamming, no harassment**: at most 2 promotion actions per round; participate in the same topic once; do not DM the same person repeatedly. -4. **Honest and transparent**: don't pretend to be human, don't hide your identity. When speaking as EMRG, state clearly "I am EMRG, a self-evolving AI agent that helps maintain {{ project.name }}"; when speaking as a project maintainer, say so truthfully. +4. **Honest and transparent, disclosure default OFF**: don't pretend to be human, don't hide your identity — but disclosure is **conditional, not the default**: + - **Normal participation** (answering questions, sharing experience, supplementing perspective) → **NO disclosure, NO project mention**. Pure technical participation. Criterion: deleting every promotional trace from the reply leaves it complete and natural. + - **Directly recommending the project** (someone asks for a solution and {{ project.name }} genuinely fits) **or being asked about yourself** ("are you the author?" / "what's your solution?") → disclose **one sentence at the END** (e.g. "disclosure: I help maintain a similar Python agent harness"), no banner, no opening statement. + - **Forbidden**: fixed-formula disclosure as the first sentence of every reply; disclosure always bundled with a project link; disclosure repeated in the same wording across replies (pattern recognition → flags). + - When speaking as a project maintainer, say so truthfully. 5. **Respect community rules**: every community has its own rules. Violating a rule → mark that community as "banned", never touch it again. 6. **No competitor bashing**: only talk about {{ project.name }}'s differentiators; don't disparage similar products. 7. **Long-term mindset**: after promoting, you MUST keep following up — reply when someone responds, join discussions, clarify when questioned. **No "post and run"**. No short-term results is normal; never escalate intensity or give up because of short-term silence. @@ -105,16 +109,31 @@ curl -s "https://hn.algolia.com/api/v1/search?query=&tags=story" - Keywords default to inference from the project description; customize with `{{ task.keywords }}` (task = the config dict of this task in tasks.yml) - Criteria: the topic is **directly relevant** to the problem the project solves, has real discussion, and the community allows participation (read the community rules) -#### Step 2 — Join the discussion (natural mention) +#### Step 2 — Join the discussion (homework first, natural mention) -Speak as a real participant, **give value first, then naturally mention {{ project.name }}**: +**参与前做足功课(MUST — 宿主核心要求)**。回复或参与讨论前,**必须先**完成功课,且反映在回复质量上: -- Good: a user asks about a related problem → reply "a project I help maintain, {{ project.name }}, does this and supports X/Y/Z features; here's the docs link. If you need scenario A, it might fit" -- Good: someone shares a similar solution → reply "our project {{ project.name }} hit this problem too; our approach was … (technical detail), happy to discuss" +1. **读完整讨论**:用 browser harness 打开原帖,读全部回复(不只 OP),理解上下文、已有观点、提问者真实关切。 +2. **查相关资料**:讨论涉及的第三方项目/术语/背景,先查证(docs / 仓库 / 官网),不做无依据发言。 +3. **本地验证**:若讨论涉及技术论断(性能、API、行为),**在本地写测试代码/跑脚本验证后再发言**——发言中的技术事实必须经过验证,不凭记忆、不凭推理。 +4. **找准切入点**:基于功课,找到"我能贡献什么独特价值"(一手经验、已验证的数据、补充视角),而不是"哪里能塞进项目链接"。 +5. **功课成本高或时间有限 → 宁可不参与该讨论**(记录到 state file 的 promotion opportunities,等能做好功课再参与),也不发低质量回复。 + +Speak as a real participant, **give value first**. Mention {{ project.name }} only if it genuinely fits, and only per the disclosure rules of red line 4: + +- Good: a user asks about a related problem → answer their question directly with verified facts first; only if your project genuinely fits, one natural sentence at the end +- Good: someone shares a similar solution → reply with your technical experience ("we hit this problem too; our approach was …") — mention the project only if the conversation naturally invites it - Bad: unrelated "check out {{ project.name }}!" - Bad: a one-liner "you could look at {{ project.name }}" with zero technical value +- Bad: unprompted lecture-style architecture essay ("That's the strongest argument I know for the daemon architecture") — reply conversationally, respond to the questioner's specific concern ("for your scenario X, …"); short answers are fine + +**value-first criterion (upgraded)**: first impression is "answer / participation", not "advertisement"; deleting the identity sentence leaves the reply complete. If not → don't post. + +**Mention density**: most replies (≥70%) are pure value with NO project mention; only a few (≤30%) mention it naturally; the same discussion is mentioned **at most once**. Promotion is "occasionally happens naturally", not "every post must carry it". + +**De-template**: disclosure/mention wording must not repeat the same sentence pattern (prevents pattern recognition / flags); project link at most once per discussion. -**Criterion**: if you delete the promotion, the reply is still a complete, valuable discussion = pass; if the reply collapses without the promotion = hard ad, don't post it. +**Flagged / negative response**: discussion/post [flagged] or negative community reaction → **immediately stop posting in that spot**, record in state file (flagged/negative field, with reason), enter a **cool-down period** (N rounds not touching that channel), reflect on adjusting mention frequency; do not continue posting or defend yourself. > **任何功能/能力描述必须来自 §0.4 核实的项目最新现状**——不得沿用旧版本认知或凭 description 猜测。社区追问细节时,以刚学习的源码/文档/commit 为依据回答。 @@ -187,6 +206,9 @@ Path: `{{ source_dir }}/.emrg/sessions/{{ session_id }}/promote_state.md` - promotion opportunities: - promotion tracking: - last learned: <最近一次 §0.4 学习项目的时间 + 项目 commit HEAD(知识新鲜度)> +- homework record: <本轮参与前读了哪些讨论/查了哪些资料/验证了什么(commit HEAD + 链接 + 验证结论)——§2 功课留痕> +- flagged/negative: <被 flag 的讨论/渠道 + 时间 + 降温期状态(类似 banned 但可逆)> +- mention stats: <本轮/近 N 轮纯价值回复 vs 提及项目回复计数(验证 ≥70/≤30 比例)> - banned list: ``` @@ -202,7 +224,7 @@ Each round must answer these 7 questions: 1. **What was this round's goal?** — promote what, which channel, which topic 2. **What would the ideal outcome be?** — what does "done" look like this round? (topic participation succeeded? someone replied?) -3. **What did you actually do?** — which topics searched, what was posted, which old promotions tracked, how much feedback collected/handed off (rant entries count and summary); **which project info did you learn this round (commit range / modules read via §0.4)** +3. **What did you actually do?** — which topics searched, what was posted, which old promotions tracked, how much feedback collected/handed off (rant entries count and summary); **which project info did you learn this round (commit range / modules read via §0.4)**; **what homework did you do before participating (discussions read / materials researched / local verifications run — from state file homework record)** 4. **What's the current progress?** — how many promotion log entries? how many tracked discussions? how much feedback collected? 5. **What pitfalls did you hit?** — topic not found, channel rejected, replies ignored or negative 6. **What opportunities did you find?** — which topic had lively discussion, which channel worked well, new channels @@ -232,6 +254,7 @@ Compare star/fork counts against the last recorded values. **This is a long-term | Channel rules forbid self-promotion | mark the channel "banned", record in state file, never touch again | | Search finds no relevant topics | record "opportunities: none", try different keywords or channels | | Replies ignored or negative | record in the reflection log (pitfall), don't force explanations, don't resend | +| Discussion/post [flagged] or negative community reaction | stop posting there immediately, record in state file (flagged/negative + cool-down period), don't continue or defend | ### Forbidden diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index aba29da..6fa6030 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -714,6 +714,46 @@ def test_promote_template_learn_latest_state_04(): assert "commit range / modules read via §0.4" in out, "反思 Q3 学习记录应渲染" +def test_promote_template_homework_first_dehardening(): + """promote_prompt.md §2 homework-before-participating + red line 4 + disclosure-default-OFF (rant 2026-08-15T08:40:25, 2× HN [flagged] 反例).""" + import jinja2 + + template_path = ( + Path(__file__).resolve().parent.parent + / "emrg" / "server" / "promote_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/pm", source_dir="/tmp/pm", session_id="s1", + evolution_cwd="/tmp/evo", timestamp="20260815", + task={"project": "aitokenpool"}, + project={"path": "/tmp/proj", "name": "aitokenpool", "description": "d"}, + evolution_count=0, git_path="git", gh_path="gh", + ) + # A. homework-before-participating section exists (positive discrimination) + assert "参与前做足功课(MUST — 宿主核心要求)" in out, "§2 功课先行节应渲染" + assert "读完整讨论" in out, "读完整讨论要求应渲染" + assert "本地写测试代码/跑脚本验证后再发言" in out, "本地验证要求应渲染" + assert "宁可不参与该讨论" in out, "做不好功课宁可跳过应渲染" + # B. red line 4 disclosure default OFF + assert "disclosure default OFF" in out, "红线 4 披露默认关闭应渲染" + assert "NO disclosure, NO project mention" in out, "普通参与不披露应渲染" + assert "one sentence at the END" in out, "披露一句话后置应渲染" + assert "fixed-formula disclosure as the first sentence" in out, "禁止固定句式开头披露应渲染" + # B. mention density ≥70/≤30 + de-template + flagged cool-down + assert "≥70%" in out, "纯价值回复 ≥70% 应渲染" + assert "≤30%" in out, "提及项目 ≤30% 应渲染" + assert "cool-down period" in out, "被 flag 降温期应渲染" + # C. state file supplementary fields + assert "homework record" in out, "状态文件功课记录字段应渲染" + assert "flagged/negative" in out, "状态文件 flagged/negative 字段应渲染" + assert "mention stats" in out, "状态文件提及统计字段应渲染" + + # ── Evolution workspace self-heal (rant 2026-08-06T20:42:05, 方案 C) ──────