Conversation
open_source_prompt.md told the agent to keep MEMORY.md a pure index "title <=512 chars ... if the index exceeds ~50 entries". The store warns at INDEX_TITLE_MAX_CHARS = 512 and INDEX_COUNT_WARN = 100, so the entry number was wrong: an agent reading it would consolidate an index the store is not warning about, and the same defect class as #1217/#1218/#1219 - a stated number that is not the one that fires. The builder now offers index_count_warn / index_size_warn_kb / index_title_max_chars to every template, and the prompt renders them, so the numbers cannot drift from the store again. The earlier cycle that found this (cyc20260914-122910) left it alone on the grounds that the twin text lives in evolution_prompt.md, which this task is forbidden to edit, and a one-sided change would be worse than none. Measuring it this cycle: the twin phrase in evolution_prompt.md ("<=512 chars") is *correct* (the title limit is 512), and only open_source_prompt.md carried the false number. So the one-sided change is safe, and this is it. Tests: tests/test_prompt_templates.py::test_the_prompt_states_the_memory_limits_the_store_enforces - the shipped prompt states both constants, the old "~50 entries" is gone, and tuning both constants moves the rendered text (a literal cannot follow, so the tuned arm is what makes the shipped one load bearing). 4/4 mutants killed, files restored by sha256. Full suite 1956 passed, 1 skipped.
|
Superseded by #1222, following the host's directive (rant 2026-09-14T13:23:04): static text must delete the memory-index thresholds, not render them from the constants — "应删除复述,而不是改成从常量渲染". With the numbers gone there is nothing left to drift, so no rendering plumbing (nor the prompt-side guard this PR added) is needed. The diagnosis here was right and is cited in #1222's body: Closing as superseded. |
`check-vote-count.py` stated its own default twice in code and twice in prose: `Verdict.needed: int = 3`, `--min-votes`'s `default=3`, that option's hand-written help `"votes required (default 3)"`, and the docstring's exit-code spec `--min-votes (default 3)`. The help text was the live one: it describes the adjacent `default=3` and cannot follow it, so raising the default would leave `--help` reporting the old number for the number that decides whether a PR may land. Same class as #1218/#1219/#1220 — a stated number that is not the one that fires. The number now exists once, as `DEFAULT_MIN_VOTES`: the CLI default and the dataclass default read it, argparse renders the default into the help line (`ArgumentDefaultsHelpFormatter`), and the docstring's spec names the constant instead of copying the number. Tests (both arms tunable, and each dies to its own mutant): * the rendered `--help` line states the default the parser actually uses — the arm tunes `DEFAULT_MIN_VOTES` to 7 and requires the line to follow, because `main()` reads the constant while building the parser. Asserting merely that "3" appears would have passed against the hand-written text and measured nothing. * `Verdict.needed`'s default is baked when the class body runs, so patching the constant afterwards cannot move it: the arm checks the two defaults agree *and* that the class body reads the name (an AST check), since `= 3` would be a second spelling a tuned CLI default could not move. Mutants: hand-written help beside `default=`, a literal `--min-votes` default, and a literal `Verdict.needed` default — each killed by one arm, files restored by sha256. Full suite green; `--help` prints `votes required (default: 3)`. Co-authored-by: EMRG Evolution <emrg@argszero.dev>
…1222) The memory store owns the three numbers a MEMORY.md index is held to (`emrg/memory.py`: the title cap, the entry-count soft cap, the size soft cap) and states them when it warns. Nine places in static text restated them by hand, four of them wrongly — the per-round system prompt told every session to consolidate at 50 entries when the cap it fires on is 100, so the agent would merge memories it was still meant to keep, and would learn that the numbers in its own instructions cannot be trusted. Host directive (rant 2026-09-14T13:23:04): delete the restatements, do NOT render them from the constants, and do every instance in one change. Deleted: the reflection hygiene note's title limit; the soft-cap line, which named an entry count that never fired; the reflection instructions' title limit; the cap's size in the embed-truncation notice (the amount actually cut is a runtime measurement and stays); system.j2's three lines (the per-round injection — the widest-reaching copy); open_source_prompt.md's hygiene bullet; evolution_prompt.md's row rule. The rule intent — pure index, one short line per entry, update in place — is kept at every site. Kept, because they read a constant instead of restating it: the embed cap reading `INDEX_SIZE_WARN`, the store's own warnings, and the soft-cap line's actual entry count and byte size. The archiver held a second copy of the title cap (`ROW_MAX_CHARS = 512`); it now reads the store's constant, so the number has one owner. No guard was added — with the numbers deleted there is nothing left to police (also per the directive). Supersedes #1219 and #1220, which take the render-from-constants route this directive rejects and each cover only part of the class. Co-authored-by: EMRG Evolution <emrg@argszero.dev>
What
emrg/server/open_source_prompt.mdtold the agent:The memory store warns at
INDEX_TITLE_MAX_CHARS = 512andINDEX_COUNT_WARN = **100**.The entry number was simply wrong. This is the same defect class as #1217 (a merge verdict
read from a tree that is not the merge), #1218 (the embed cap re-spelling the store's
threshold) and #1219 (the reflection reminder naming
~50-entry): a stated number that isnot the one that fires. An agent following the prompt consolidates at 50 while the store
only starts warning at 100 — and, worse, learns that the threshold in its own instructions
is not the threshold it is measured against.
The change
emrg/server/scheduler.py— the builder offers the store's numbers to every template:index_count_warn,index_size_warn_kb,index_title_max_chars, imported fromemrg.memoryrather than re-typed.emrg/server/open_source_prompt.md— the line renders them(
title ≤{{ index_title_max_chars }} chars,exceeds {{ index_count_warn }} entries), witha note naming the constants so the next reader does not have to guess where the numbers
come from.
tests/test_prompt_templates.py— a new arm renders the prompt through the realbuilder (real context, real template path), asserts the shipped text states both
constants and that
~50 entriesis gone, then tunes both constants (512→256, 100→42)and asserts the rendered text follows.
Why the tuned arm is the load-bearing one
The discriminator is the one #1218/#1219 settled: if the text reads the constant, tuning the
constant has to move the text. A prompt that hard-codes
512/100passes the shippedassertions and fails the tuned ones, which is exactly the state this PR is fixing — so
without the tuned arm the test would pin the current numbers instead of the derivation.
Mutants, each applied to the working tree and restored by sha256 (verified
byte-for-byte):
~50 entriescomes backVerification
import emrg.client.appgreen;emrg --helpgreenscripts/check-doc-count.py→OK: no tracked file states the Python test count… (title ≤512 chars, …) … if the index exceeds 100 entries, …Note on the previous cycle's reasoning
cyc20260914-122910found this line and deliberately left it, recording that the twin textlives in
emrg/server/evolution_prompt.md, which this task is forbidden to edit — so aone-sided change would be worse than none. Measured this cycle, that reasoning does not
hold: the twin phrase in
evolution_prompt.mdis≤512 chars, which is correct(
INDEX_TITLE_MAX_CHARSis 512), and the only false number lived in the file I may edit.So the one-sided change is safe and complete, and this is it. The general form is worth
keeping: "the twin is elsewhere" is a reason to check the twin, not to stop.