Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions emrg/server/promote_prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,19 @@ if a platform forbids automated publishing, comply or mark the platform blocked.

#### Step 1 — Find topics (recon)

Search for topics related to {{ project.name }}:
Recon has two directions, and **the inbound one comes first**: read what is already waiting on this account before looking for anything new.

```bash
# the threads this account opened elsewhere — its own open pull requests and issues
gh search prs --author @me --state open --limit 20 --json repository,number,title,updatedAt
gh search issues --author @me --state open --limit 20 --json repository,number,title,updatedAt
# then the newest comment on each one that is not this account's own
gh api repos/<owner>/<repo>/issues/<n>/comments --jq '.[-1] | "\(.user.login) @ \(.created_at): \(.body)"'
```

A maintainer who asks for a rebase, a test, clearer wording, or an answer has addressed a **request to this account**, and carrying it out is the round's first work — ahead of any new participation. A thread left waiting while the same account opens another costs twice from one cause: the request stands unanswered, and there is one more thread to keep up with. A request this round cannot carry out does not drop out of sight — it enters `promotion tracking` as the to-do, with the link and what was asked (§4.1).

Then look outward. Search for topics related to {{ project.name }}:

```bash
# Reddit example: search topics related to the project's domain
Expand All @@ -230,7 +242,7 @@ curl -s "https://hn.algolia.com/api/v1/search?query=<keywords>&tags=story"

1. **Read the full discussion**: open the original post with the browser harness, read all replies (not just the OP), understand the context, existing viewpoints, and the asker's real concern.
2. **Research related material**: verify third-party projects/terms/background involved in the discussion first (docs / repos / official sites) — no unfounded claims.
3. **Verify locally**: if the discussion involves technical claims (performance, API, behavior), **write a test script / run a local verification before replying** — technical facts in your reply must be verified, not from memory or reasoning alone.
3. **Verify locally**: if the discussion involves technical claims (performance, API, behavior), **write a test script / run a local verification before replying** — technical facts in your reply must be verified, not from memory or reasoning alone. **A count is such a claim**: how many tests a file holds, how many files a directory has, how many commits, versions, users or bytes — each is a number a command produced in this round, and it is quoted from that output. A count that no command produced, one carried over from an earlier round included, is taken out rather than softened, because a wrong count reads exactly like a verified one and the reader has no way to tell them apart.
4. **Find your angle**: based on the homework, find "what unique value can I contribute" (first-hand experience, verified data, an added perspective) — not "where can I squeeze in a project link".
5. **If homework is too costly or time is limited → skip that discussion** (record it in this round's closing summary as a `promotion opportunities` entry, join when you can do it properly) rather than posting a low-quality reply.

Expand Down Expand Up @@ -322,7 +334,7 @@ Every field below is REPLACED every round — this is a snapshot, not a log:
- promotion target: <project repo URL>
- promotion log: <last 5 promotion actions: time + channel + link + result>
- promotion opportunities: <topics found during recon but not yet acted on>
- promotion tracking: <posted promotions with replies / ongoing discussions / questions awaiting clarification; each with link and to-do>
- promotion tracking: <posted promotions with replies / ongoing discussions / questions awaiting clarification / requests addressed to this account that it has not answered yet; each with link and its to-do>
- last learned: <timestamp of the most recent §0.4 project learning + project commit HEAD (knowledge freshness)>
- homework record: <which discussions were read / what materials researched / what was verified locally before this round's participation (commit HEAD + link + verification conclusion) — §2 homework trail, last 3 rounds>
- flagged/negative: <flagged discussions/channels + time + cool-down status (like banned but reversible)>
Expand Down
59 changes: 59 additions & 0 deletions tests/test_prompt_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2124,3 +2124,62 @@ def test_the_published_contribution_pin_answers_both_ways():
f"removing {phrase!r} did not make exactly that phrase read as missing, so this "
"pin would not notice its own rule being deleted"
)


# --------------------------------------------------------------------------- the inbound half
#
# A round of the promotion task is written as four outward steps: find a topic, join it,
# follow the threads it started, hand the feedback on. Every list such a round carries is
# therefore a list of what it sent out, and nothing in the template answered the opposite
# question — what has someone else asked this account to do, and is it still waiting.
#
# Measured cost, on a pull request this account had opened in another project: a maintainer
# asked for a rebase in a comment, no round read it, and the request sat unanswered for nine
# days while later rounds opened new threads instead. Carrying it out took minutes.
#
# The second half is the same defect one level down. A changelog entry published in that pull
# request said a test file held "7 tests"; the file had held six since the branch was created,
# and no command had counted anything. Step 2 already requires technical claims to be verified
# locally, and a count does not read as a claim, so it passed under a rule written for prose.
#
# Pinned as verbatim phrases for the reason the pin above states: the file and the *render*
# are two carriers, and a rewrite that keeps the surrounding paragraphs while dropping these
# leaves every keyword in place.

PROMOTE_INBOUND_PHRASES = (
"the inbound one comes first",
"addressed a **request to this account**",
"it enters `promotion tracking` as the to-do",
"requests addressed to this account that it has not answered yet",
"**A count is such a claim**",
"A count that no command produced",
)


def test_the_promote_prompt_reads_what_is_asked_of_it_and_counts_what_it_publishes():
"""Both halves of a round the template was missing: inbound work, and measured numbers.

What this measures and what it does not: it pins that the two rules are still **stated**.
Whether a round ran the reading is that round's closing summary — not something a text
assertion can answer, so this guard has no verdict on behaviour.
"""
text = _PROMOTE_TEMPLATE.read_text(encoding="utf-8")
missing = _missing_phrases(text, PROMOTE_INBOUND_PHRASES)
assert not missing, (
"the promote template no longer states what its four outward steps leave out: "
f"{missing}. Without the first, every list a round carries is one-directional and a "
"maintainer's request can wait indefinitely while the round finds new topics; without "
"the second, a published count is a number nothing counted."
)


def test_the_inbound_pin_answers_both_ways():
"""The control: removing one phrase makes exactly that phrase read as missing."""
text = _PROMOTE_TEMPLATE.read_text(encoding="utf-8")
for phrase in PROMOTE_INBOUND_PHRASES:
stripped = text.replace(phrase, "")
assert stripped != text, f"{phrase!r} is pinned but absent, so this arm measured nothing"
assert _missing_phrases(stripped, PROMOTE_INBOUND_PHRASES) == [phrase], (
f"removing {phrase!r} did not make exactly that phrase read as missing, so this "
"pin would not notice its own rule being deleted"
)
Loading