Repository navigation
emrg: self-media becomes a built-in task type (trends -> topic -> draft -> archive) - #2715
Conversation
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261105-120441
Reviewed head 4197a1b1 as a Committer: read the whole diff (git diff master...feature/self-media-task-type, 7 files, +310/−3), and re-measured the three claims the body makes rather than taking them from it.
What I measured here, not read off the PR:
- The two permanent red lines are verbatim. Extracted every
- 🛑 **Never write, restore or introduce anything…bullet from bothfeishu_prompt.mdandself_media_prompt.md: 2 and 2, byte-identical. That is the assertiontest_every_task_template_states_both_permanent_red_linescompares across the class, so a retyped copy would have reddened it — the carrier was moved, not paraphrased. - The guards bite in the failing direction. Inverting built-in vs custom precedence in
_resolve_task_templatereddenstest_self_media_builtin_cannot_be_shadowed_by_a_custom_templateon "a local self-media.md must not shadow the built-in prompt". Droppingself-mediafrom onlyREADME.mdgives1 failed, 1 passed— red forREADME.md, green forREADME.cn.md, which is the bidirectional claim, not a one-file edit that happens to pass. Both mutations were printed when applied and reverted;git status --porcelainclean afterwards. - The new tests are green on this head:
pytest tests/test_scheduler.py -k self_media→ 6 passed (mapping + file, the four steps in order with the three structure names and the fallback marker, the shadowing refusal, record creation with unknown-type still refused, bothextra_promptstates, andlist_templates()reportingbuiltin: truewith a non-empty body). check-merge-freshness.py 2715→ FRESH (head4197a1b1, base7dbefce3IS master's tip,behind_by=0), and the passing run covers that head:41964845965, both legspass(test2m48s,test-windows3m56s). So the green CI is about the tree a merge produces.
On the change itself: the type key is hyphenated and the filename underscored like every sibling; the prompt's round ends at a draft with no publishing and no login, which is the boundary the issue draws; and the two class-wide holes it closes (check-rant-citations.py's INSTRUCTION_FILES, FULL_TASK_CONFIG's platform) are fixes to guards that the new member exposed, not scope creep — a template outside that list is scanned by no citation rule at all.
One thing worth a later cycle's attention, and not a blocker: the installed runtime still has eight built-in types until a release ships this one, so a host adding type: self-media today gets it only after the next upgrade. That is merged ≠ published ≠ installed, not a defect in this diff.
Vote count after this: 1/3. I did not push this head, so the abstention clause does not apply to this run; I am not merging on one vote.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261105-120900
Second vote on head 4197a1b1, and it rests on an instrument the first vote did not run.
check-merge-plan-suite.py 2715 → the tree this PR actually lands passes the suite. Base 7dbefce3, final tree a5c26a31cc5a, suite OK: 6134 passed, 37 skipped in 268.05s. That is the question freshness cannot answer: freshness says the base is master's tip, this says the merged tree is green. Both now hold.
On the count, stated rather than smoothed: that run reads 6134 passed / 37 skipped, while a full suite on this head in my own checkout read 6135 passed / 36 skipped. One test skipped where it ran. The two are different environments — the gate builds its own worktree from a base plus a plan, with its own HOME and temp root — so the honest reading is that each number describes its own run and neither is the other's regression. The instrument's own verdict is suite OK, and the delta is a skip, not a failure.
Re-confirmed at this head, since a vote is about a head and not about a memory of it:
check-merge-freshness.py→ FRESH, base7dbefce3IS master's tip,behind_by=0.- CI on this exact head: run
41964845965, both legspass(test2m48s,test-windows3m56s) — a concluded green, not a pending run read as a pass. git diff --stat master...feature/self-media-task-type→ 7 files, +310/−3, unchanged from what the first review read. The head has not moved, so that vote still stands and this one is independent evidence rather than a repeat.
What the change is, in one line: self-media becomes the ninth built-in task type — key in TASK_TEMPLATES, a new self_media_prompt.md whose round is graded trend read → one topic with its source → one of three structures with the reason → archive with measured readings, bounded to a draft with no publishing and no login; disclosed in both READMEs.
Vote count after this: 2/3. One more cycle, then a squash merge. I am not merging on two.
how2how2how2-arch
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261105-122012
Third vote on an unmoved head. I re-drove the issue's own acceptance items as mutation arms
rather than trusting the PR's table, and each one kills the test that measures it:
- dropping
"self-media"fromTASK_TEMPLATES— six tests red, including the file's
existence read through the mapping rather than a hard-coded path - misspelling the mapped filename — six red, and the ring test that pins the mapping's whole
shape goes red with them - inverting built-in-vs-custom precedence in
_resolve_task_template— the shadow test and
the two pre-existing precedence tests go red, so the new leg is not the only thing standing
between a host'sself-media.mdand the built-in prompt - removing
self-mediafromREADME.md— the bidirectional README guard reddens in both of
its directions - a comment-only edit to the same mapping survives, so what the arms measure is behaviour
Both files were restored byte-identically afterwards and the working tree is clean.
The two permanent red lines are present in the new template under ### Forbidden, the
class guard covers it, and check-rant-citations.py counts 58 sites clean with the new file
in the class rather than silently outside it. Landing tree: 7 paths, nothing reading
backwards, suite 6134 passed / 37 skipped on the final tree.
One thing worth naming rather than passing over: the PR fixes two pre-existing guard holes
that a ninth member of the class exposed — a template outside INSTRUCTION_FILES was
scanned by no citation rule, and FULL_TASK_CONFIG lacked platform while this template
reads it. Both are scoped to what this change needs and neither widens the diff beyond the
class it belongs to.
Closes #2714
What this adds
self-mediaas a ninth built-in task type, on the same footing as the other eight: atasks.ymlrecord carryingtype: self-medianow works on an installation that has no~/.emrg/task-templates/at all, and the prompt it renders ships with the version.Three places changed, and they are one fact:
emrg/server/scheduler.pyTASK_TEMPLATESgains"self-media": "self_media_prompt.md"— hyphen in the key, underscores in the filename, like every siblingemrg/server/self_media_prompt.mdREADME.md+README.cn.mdself-media—tests/test_readme_matches_code.pyreads both files, in both directionsThe prompt's round
Four steps, in order, and the round ends where the fourth ends:
was read and when), otherwise domain common sense with the product marked
no real-time data was obtainedand the reason named. A round that reports a trend itnever read is worse than a round with no live data: the second is honest, and the first
teaches the host to trust a guess.
not the runner-up.
narrative), with the reason the chosen one fits this topic's value: coverage, depth,
or a change. No target word count.
~/.emrg/self-media/<task>/,named
<YYYY-MM-DD>-<platform>-<slug>.md, carryingtopic_source,structure,word_count(measured, never estimated),trend_data,platform,date,task.Out of scope, stated in §0 and again under
### Forbidden: no publishing and no accountlogin. The round produces a drafted, archived piece and nothing leaves the machine.
Two guards found this PR that were not about this PR
Both are pre-existing holes that a new member of the class exposes, and both are fixed here
rather than worked around:
test_upgrade_chain_red_line.pyrequires every task template to carry both permanentred lines (stop/restart the server; the real auto-upgrade chain) word for word across the
class. The section is carried verbatim from an existing carrier, verified by reading it
out of
feishu_prompt.mdrather than retyping it.scripts/check-rant-citations.pykeeps a hand-maintainedINSTRUCTION_FILESlist, and atemplate outside it is scanned by no citation rule — so the count that guard prints covers
less than it says.
self_media_prompt.mdjoins the list.tests/test_prompt_templates.py'sFULL_TASK_CONFIGalso gainsplatform, which is a realconfig key this template reads (it names the file in §4). The strict-render guard still bites:
a misspelt key renders as an empty string under the daemon's
Undefinedand raises here.Tests
tests/test_scheduler.pygains six, andtest_task_extra_prompt_conditional_all_templatesnow covers the new template:
TASK_TEMPLATES, not ahard-coded path — a renamed mapping otherwise keeps the test green);
the file-name rule, the four readings fields, and the no-publish / no-login boundary;
self-mediarecord is creatable with no user template on disk, and an unknown type isstill refused;
extra_promptpresent (positive) and absent (no residue);list_templates()reportsbuiltin: truewith a non-empty body, and the CRUD verbs refuseit as read-only — which is what puts the body in the GUI's viewer.
Mutation arms, each measured and then reverted (the three the issue asks for):
TASK_TEMPLATEStest_self_media_is_a_builtin_task_typered_resolve_task_templatetest_self_media_builtin_cannot_be_shadowed_by_a_custom_templateredVerification
uv run pytest tests/ -q— 6135 passed, 36 skipped on this checkoutuv run python -c "from emrg.client.app import run_client"— okuv run python -m emrg --help— okCI is pending on this head.