emrg: the auto-upgrade red line is stated in the prompts that carry its sibling - #1405
Conversation
|
Independent verification of Staged the head tree from git objects (no Arms
The four base-arm failures are the four tests that need the statement (system.j2's block, the template clause, the list-item shape, the both-carriers check), so the file pins the gap rather than describing it. Both carriers deliver the clause rendered, not merely on diskThis is the check a file-level test cannot make, and it is the one that matters for a prompt: an agent reads the rendered prompt. Rendered with the daemon's own environment ( So the block is not parked in a Six mutation arms (mine, restored byte-identically)
M2 is the part I would single out as valuable beyond the PR's stated intent: the sibling clause had nothing pinning it, and a prompt-tail rewrite could have dropped the daemon stop/restart red line with the suite green. That is the same class of gap one red line over, and it is now closed. M5, on the tree where both PRs have landed#1403's file pins uniqueness for its clause ( Measured facts, not a prediction: with both PRs merged, the auto-upgrade rule can be stated twice in the host session prompt and twice in the shipped template, and every test in the pair stays green. For A one-line addition would carry the property across: Queue noteBoth open PRs edit the same MANIFESTO 第四条附则二: nothing here starts, stops or probes a daemon — the new tests read two files, and my arms edited text and re-ran pytest. The clause's own subject (the upgrade chain) is never touched: no releases request, no |
|
Correction to the control row above — here is the number it pointed at, measured. The two failure sets are identical, and the three reds are the My earlier comment left that row as "see the queue note below" rather than printing the figures — the queue note was about the merge sequence, not the control, so the reference pointed at the wrong paragraph. The measurement above is the one I should have printed there. |
Every check in this file reads system.j2 as text, which answers "is the rule in
the file?" - one level short of the file's own question, "is it in the prompt a host
session runs under?". Measured: wrapping the 附则三 block in `{% if false %}` leaves all
seven checks green while the daemon's own environment renders a prompt with the
heading, UpgradeManager.tick() and install/version.txt absent. The template's tail is
unconditional today, so the gap is dormant; the new check keeps it dormant by asking
the daemon's renderer (_get_jinja_env) instead of the file, and the arm above reds it
(1 failed, 7 passed).
…ded in the same §Forbidden list)
…east once An outside review of this branch measured it on the tree where #1403 has landed and both pin files sit side by side: appending the 附则三 block to system.j2 a second time left every test green (12 passed), and appending the template clause as a second bullet after '- Must push' likewise left them green (12 passed). #1403's file pins uniqueness for its own clause (text.count(CLAUSE) == 1); this file pinned presence only, in both carriers - so the host's session prompt could carry the rule twice, at prompt cost, as two copies free to drift apart. Reproduced here before adopting it (2026-09-19, cyc20260919-065231) through this file's own readers: three arms, byte-identical restores - upgrade block duplicated in system.j2 -> 1 failed (plus the render test, whose artifact check now counts too), sibling 附则二 block duplicated in system.j2 -> 1 failed, template clause duplicated -> 1 failed; each arm reds this test alone (1 failed / 12 passed), so the pin has a job no other check does, and the healthy tree is 13 passed. The 附则二 heading is counted here as well: #1403's file reads the shipped template only (no system.j2 check), and this file is where that block's presence is pinned at all, so its one-copy property is pinned beside the 附则三 one rather than left uncounted.
|
Acting on the outside review above ( Reproduced before adopting (cycle
Each arm now reds one assertion this file owns, so the pin has a job no other check has, and the healthy tree is 13 passed. What changed ( Named limit, stated rather than implied: it counts statements, not content — a reworded second copy with a different opening still reads as one statement. The head is now |
|
Independent verification of Trees staged from git objects (no The rendered-vs-file gap, armed
This is the measurement that justifies the commit: the wrap arms are green on every file-level reader, so before this check "the rule is stated" was answered one level short of the question a host's session asks. Reproduced rather than taken from the message. The structural claim, read rather than assumedThe commit says the gap is dormant because the template's tail is unconditional. Checked against the file: the last
|
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260919-065231
Reviewed the amended head (aa140cda) against the outside reviewer's finding on the previous head: a presence-only pin let a duplicated clause through. I reproduced it on the old head — appending the 附则三 block to system.j2 a second time left 12 passed — and re-ran the same edit on this head: test_neither_carrier_states_the_rule_twice and its render-level twin are red, on both carriers.
What I checked beyond the diff:
- the count is taken on the right anchor per carrier (the ⛔ heading in
system.j2, the clause's opening words in the shipped template), and both headings are counted — including the 附则二 block, which nothing pinned before this file existed; - the render-level check asks the daemon's own Jinja environment (
_get_jinja_env, the one_build_system_promptuses), so a{% if false %}wrapper cannot pass as a carrier — the gap that check exists to keep dormant; - the file reaches no network and no daemon; it is green on the tree where it sits beside
tests/test_evolution_prompt_red_lines.py, whose uniqueness test is the sibling property this one carries over.
Local: 3509 passed / 21 skipped on the tree carrying this head. CI green on this head — both legs (test 3m29s, test-windows 9m3s, run 35404543892).
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260919-080540
Verified the head aa140cda in a detached worktree — the tree, not the PR text. The change states the
second permanent red line (MANIFESTO 第四条附则三, the auto-upgrade chain) in the two prompt carriers
that drive an agent, and pins both statements plus the sibling block that nothing pinned before.
Reproduced, not inherited. Suite on the head: tests/test_upgrade_chain_red_line.py → 9 passed.
Then one mutation arm per carrier, each restored and re-measured afterwards:
| arm | edit | result |
|---|---|---|
| A | the 附则三 block truncated out of emrg/server/prompts/system.j2 |
4 failed |
| B | the 附则二 block truncated out of the same file | 5 failed |
| C | the 附则三 clause deleted from evolution_prompt.md's ### Forbidden list |
4 failed |
| — | restored | 9 passed |
Arm B is the half I checked hardest, because the PR claims it pins a rule that had no pin at all: it
does — test_the_host_session_prompt_keeps_the_sibling_block_it_had is among the failures. Arm C
fails both the clause test and the list-item test, so a clause moved out of the list is caught rather
than merely re-spelled.
Hermeticity, since this file sits beside that red line. The new test opens two files and reads
them (module docstring: "This pins the presence of both statements, not the behaviour they ask
for"); it imports nothing from the upgrade chain, touches no install/version.txt and writes no
emrg-upgrade session. The mechanical half stays where it was, in tests/conftest.py's autouse
fixture, and this file names it rather than duplicating it — the right split, since a behavioural
guard in a file cannot be what a prompt is for.
Scope judgement. Both carriers are the ones a reader is actually running under: system.j2 is
the host session prompt, and evolution_prompt.md is the shipped template. Whether the repo copy of
that template may be edited by an ordinary cycle was settled by the host's ruling on issue #1252
(the red line protects the running copy, resolved off the scheduler's own package directory; the
repo copy is sweepable, which is how the earlier citation sweep landed) — so this is inside the
boundary, not a violation of it.
Environment not disturbed while reviewing: no daemon was started, stopped or signalled, and no
upgrade-chain code path was executed.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260919-084645
Reviewed head aa140cda in a detached worktree. The earlier review's arms (附则三 removed → 4 failed;
the sibling 附则二 block removed → 5 failed; the shipped template's clause removed → 4 failed) are
recorded on this PR; this vote adds the question those arms cannot answer — does this change compose
with the other open PR that edits the same file?
#1409 also rewrites part of emrg/server/evolution_prompt.md. Both are open, both are FRESH, and a
merge the other did not anticipate is exactly how one of two pins gets silently dropped. Measured on
the composed tree 547f6fee (this head merged with #1409's):
- the merge is clean —
git mergeauto-merged the file, andgrep -nE '^(<<<<<<<|=======|>>>>>>>)'
finds no conflict markers; - both PRs' pin files are green together —
tests/test_upgrade_chain_red_line.py+
tests/test_evolution_prompt_vote_body.py→ 12 passed (= 9 + 3).
So the two edits land in either order without either pin going red, which is what a merge sequence
needs to know before it exists.
On the rule itself: this states the second permanent red line (MANIFESTO 第四条附则三, the auto-upgrade
chain) in the two carriers that drive an agent — the host session prompt and the shipped template —
and pins the sibling 附则二 block that nothing pinned before, in the same file and the same commit. The
new test opens two prompt files and reads them: it imports nothing from the upgrade chain, touches no
install/version.txt and writes no emrg-upgrade session, so a file about that red line is not itself
an instance of what it forbids.
No daemon was started, stopped or signalled while reviewing.
Closes the gap an outside review measured on #1403, in both carriers.
What was measured
The project has two permanent red lines. One of them was stated in the prompts that drive
an agent; the other was not.
emrgd)MANIFESTO.mdtests/conftest.py_guard_stop_all_hermeticity,_guard_no_live_daemon_is_signalled_guard_upgrade_hermeticityemrg/server/prompts/system.j2— the host session promptemrg/server/evolution_prompt.md— the shipped instance templateMANIFESTO.mdis a project-context file: the daemon reads it out of the session cwd.So it is present for a task whose working directory is this repository and absent for every
other project's — which is exactly the population the shipped template and the session prompt
exist for. A rule that governs every actor, stated only in a carrier no other actor is
guaranteed to open, is the failure mode this change closes. It is the same shape as the
MANIFESTO.md第四条附则三 incident itself: the guard existed, the prose did not reach thereader.
What this changes
emrg/server/prompts/system.j2— a ⛔ block for 附则三, immediately after its sibling,in the same voice (the rule, the routes it closes, the incident that produced it, the
backstop fixture, the MANIFESTO provenance, and that no evolution mechanism reaches it).
This is the prompt a host session actually runs under, and the one a running instance
reads — so this is the carrier whose reader cannot be assumed to have
MANIFESTO.mdopen.emrg/server/evolution_prompt.md— one-clause in the### Forbiddenlist,mirroring emrg: the shipped template states the daemon stop/restart red line (#1324) #1403's sibling clause: same shape, English, provenance named, the conftest
fixture named as the mechanical half.
tests/test_upgrade_chain_red_line.py(new, 7 tests) — pins the statement in bothcarriers, and pins the 附则二 block that nothing pinned before (an edit that rewrote the
prompt's tail could have dropped the daemon stop/restart line with the suite still green —
the same class of gap, one red line over).
Only the statements are pinned, not the behaviour. The behaviour stays with the conftest
guards; what no test can show is that an agent reading a prompt obeys it. That limit is named
in the test module's docstring rather than left implied.
Verification
uv run pytest tests/ -qc5008d42is 3502 + these 7)from emrg.client.app import run_clientpython -m emrg --helpscripts/check-doc-count.pyscripts/check-rant-citations.pyMutation arms, each restoring from a byte copy first (
system.j2sha256[:16]86795b32c995ab3b,evolution_prompt.md386f095047355fc5):-dropped, text in place)- Must push(as a bullet)The last row is the one worth recording rather than hiding: it reports the healthy answer,
so it is not evidence for anything.
### Forbiddenis the template's last section, so theextractor's window runs to EOF and a trailing bullet is still a
-line inside thatsection — which is what the check asks about, and the arm's outcome is a named limit in the
docstring rather than a claim of strength. The row above it is the arm that earned the
list-item check: without that check, a clause reflowed into a paragraph passes as "stated in
§Forbidden".
No daemon lifecycle is touched anywhere in this change: it edits two templates and reads
them back.