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
4 changes: 2 additions & 2 deletions emrg/server/promote_prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ Every field below is REPLACED every round — this is a snapshot, not a log:
```markdown
- last completed: <what was done last round>
- next step: <what this round plans to do>
- blocked: <what is blocking progress? empty = no blocker; one line per channel, and every channel gets one — one that did nothing this round says "not run" and why, so a channel that went quiet on purpose and one nobody noticed are told apart>
- blocked: <one line per channel — every channel the account holds gets a line, and one that did nothing this round says "not run" and why, so a channel that went quiet on purpose and one nobody noticed are told apart; the field is empty only when the account holds no channel at all>
- 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>
Expand Down Expand Up @@ -403,7 +403,7 @@ Organize the fields into four zones and keep each zone consistent:

- **A. Round snapshot** (replaced every round, never accumulated): `last completed`, `next step`
- **B. Active state** (live facts only): `blocked`, `promotion target`, `promotion opportunities`, `promotion tracking`, `last learned`, `homework record`
- **C. Channel status** (one source of truth): `blocked` is the single field that records current channel availability, incl. a one-line per-channel summary — and a channel that was not run is still a line, "not run" plus the reason, because a missing line and a channel that went quiet on purpose read the same. `flagged/negative` and the `banned list` entry keep only the historical record + cool-down state — never re-state what `blocked` already says. When a channel's status changes: update `blocked` first, then update/cross-reference the other two or drop the stale entry.
- **C. Channel status** (one source of truth): `blocked` is the single field that records current channel availability, and §4.1 states how each of its lines reads. `flagged/negative` and the `banned list` entry keep only the historical record + cool-down state — never re-state what `blocked` already says. When a channel's status changes: update `blocked` first, then update/cross-reference the other two or drop the stale entry.
- **D. Stats & output** (each independent, no mixing): `mention stats` — this round's line in the summary, the cumulative trend in the memory entry; `promotion metrics` — this round's measured effect signals (§6 Check), the trend in the memory entry; `blog posts` — published only; `blog drafts` — queue only. Never mix published articles into drafts or vice versa.

---
Expand Down
86 changes: 86 additions & 0 deletions tests/test_prompt_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2642,3 +2642,89 @@ def test_the_reflection_count_pin_reads_its_own_section_and_both_directions() ->
assert len(_reflection_questions(_reflection_section(after))) == listed, (
"a numbered item added past the reflection section entered its count"
)


# ── the `blocked` field states one availability rule, in the field that owns it ───────────
#
# The round snapshot's `blocked` field used to carry two clauses about one string: "empty = no
# blocker", and "every channel gets one". An account that holds a channel owes that channel a
# line every round, so the field could be empty only for an account holding none — a round
# obeying the first clause wrote nothing, a round obeying the second never wrote an empty field,
# and no reading of the line satisfied both. The rule then had a second home as well: the §4.4
# zone list restated how the field reads, a dozen lines under the template's own rule that a
# fact lives in exactly one place, because a fact written twice eventually disagrees with itself.
#
# The two halves are pinned separately, each against the place that owns it, so that neither can
# regress behind the other's assertion: the field states the rule and the one state that leaves
# it empty, and the zone list names the owner without restating how the field reads.

_BLOCKED_FIELD = re.compile(r"^- blocked: <(.*)>$", re.M)
_CHANNEL_STATUS_ZONE = re.compile(r"^- \*\*C\. Channel status\*\*.*$", re.M)


def _blocked_field(text: str) -> str:
"""The `blocked` field's own spec, or a failure to measure rather than an empty string."""
found = _BLOCKED_FIELD.search(text)
assert found, (
"the round snapshot carries no `blocked` field spec, so a reading of what it owes "
"would be comparing against nothing"
)
return found.group(1)


def _channel_status_zone(text: str) -> str:
"""The §4.4 bullet that names which field owns channel status."""
found = _CHANNEL_STATUS_ZONE.search(text)
assert found, (
"the §4.4 zone list has no channel-status bullet, so nothing says which field owns "
"that fact"
)
return found.group(0)


def test_the_blocked_field_states_one_rule_a_round_can_obey() -> None:
"""A line per channel, and the one state that leaves the field empty."""
field = _blocked_field(_PROMOTE_TEMPLATE.read_text(encoding="utf-8"))

assert "every channel the account holds gets a line" in field, (
"the field no longer owes a line per channel, which is the rule the zone list points "
"at and the reason a silent channel is told apart from one nobody noticed"
)
assert '"not run"' in field, (
"the field no longer says what a channel that did nothing this round writes, so a "
"round has to invent the wording and the next round cannot read it"
)
assert "empty only when the account holds no channel at all" in field, (
"the field states no satisfiable condition for being empty; an account holding one "
"channel owes it a line, so a clause that empties the field for any other reason can "
"never be obeyed alongside the per-channel rule"
)
assert "empty = no blocker" not in field, (
"the unsatisfiable clause is back: it empties the field on a round that holds a "
"channel, which the same sentence forbids — two instructions, one string"
)


def test_the_not_run_rule_has_one_home_and_the_zone_list_points_at_it() -> None:
"""`"not run"` is defined once, and the zone list says who owns it rather than restating it."""
text = _PROMOTE_TEMPLATE.read_text(encoding="utf-8")
occurrences = text.count('"not run"')
assert occurrences == 1, (
f'`"not run"` is defined {occurrences} times; the template states its own rule that a '
"fact lives in exactly one place, and a fact stated twice is how a reader ends up "
"holding two answers with no way to choose between them"
)

zone = _channel_status_zone(text)
assert "`blocked` is the single field that records current channel availability" in zone, (
"the zone list no longer says which field owns channel availability, so the ownership "
"it exists to record is gone even though the field still exists"
)
assert '"not run"' not in zone, (
"the zone list restates how the field reads; it must point at the field that defines "
'the wording instead, or the two copies drift apart'
)
assert "§4.1" in zone, (
"the zone list names the owner but not where its lines are defined, so a reader who "
"follows it still has to search"
)
Loading