Repository navigation
emrg: the install tree's leftovers are named, and the premise they were skipped on is corrected - #2347
Conversation
…it never finishes Two gaps, both in the one place a cycle never looked. `~/.emrg/tasks.yml` appeared in this template only as the `extra_prompt` injection heading (:14-17). That field is where an installation writes what it believes its own task prompt does not say, so it is a defect report about the prompt — filed by the session least able to act on it. New §1.7 reads it as evidence about the prompt and classifies each block as instance configuration, already in the template, or missing from it; the third class is written into the template's own section in the template's own voice. Measured on this host: two of four tasks carry a non-empty `config.extra_prompt` (4,325 and 6,990 chars), and their headings mix instance facts with general method — metric discipline, conclusion discipline, channel discovery. A second project's memory says the same thing independently: `competition`'s `d4e6b8a0-tasks-yml-extra-prompt.md` records that `extra_prompt` is that task's only rendering channel for cross-round lessons. §1.5 said "for each project read its `.emrg/memory/` and `.emrg/sessions/`" — 12 projects here, with nothing saying what counts as a finding, so the next cycle reads it all again. It keeps its coverage and gains a procedure: a step 0 that reads no content (newest memory mtime against a bookmark), indices rather than bodies, four named reasons that justify opening a body, one or two projects per cycle by rotation, conversation read by located range instead of whole, and the bookmark kept as one entry updated in place. Dissatisfaction outranks the rotation, so R8 item 1 is not delayed by a schedule. §2.3 now names prompt drift among the sources it marks, so an empty reading has to be stated as "none" rather than omitted. ⛔ §1.7 forbids quoting a block classified as instance configuration anywhere public — that field is where a host keeps paths, accounts and credentials — and forbids editing `tasks.yml`, whose dumper keeps no comments. Closes #2342
…easuring awk The §1.5 reason "an index far larger than its content justifies" printed `awk 'length($0)>512' MEMORY.md | wc -l` against R9's per-line bound. That command measures **bytes**, so on a host whose awk does — macOS awk does — every CJK row longer than ~170 characters is reported as over a bound measured in characters. Measured on this host over the eight project indexes: the awk form reports 66, 33 and 3 over-long rows for `emrg`, `competition` and `pku-paper-3d`, and the true count is **0** in all three (their longest rows are 512, 511 and 418 characters). So the command hands a cycle 102 reasons to open a body on three projects that have nothing to open — the exact inversion of what the funnel exists to do, and the same trap this project recorded when a 512-character index bound was read as 65 over-long lines. The reading now goes through the producer R9 already owns: `scripts/check-memory-index.py <path>`, which prints lines, characters and the longest row, and names the subject it read. Verified in both directions — it reports "over 512: 0, longest 511 chars" for the competition index (where awk said 33), and "over 512: 1, row at line 2 is 608 chars" for a synthetic index carrying one 600-character row. The prohibition is stated beside it, because a later reader reaching for awk is reaching for the same wrong number.
…count cannot return §1.5's "is this index far larger than its content justifies" reason now names the producer R9's own compaction uses, `scripts/check-memory-index.py`, in place of an `awk` row count. Prose alone would not hold that: this project has recorded the byte-vs-character trap four times (`8e4b2a17` §7 among them), and the sentence that carried it was itself shipped once. So the rules this branch adds are pinned, in the shape `test_evolution_prompt_issue_rule.py` already uses for the sibling rule: - §1.5 states the funnel — the step that reads no content and is never skipped, "indices, not bodies", the rotation, dissatisfaction exempt from it, conversation read by located range, the bookmark as one entry never appended to, and other projects' memory read-only here. - §1.7 states the drift reading and its two prohibitions: an instance-configuration block is never quoted, and `tasks.yml` is never edited. - §2.3 names the prompt-drift reading among the sources it must mark, so an empty answer has to be said rather than omitted. - No line in §1.5 may mention `awk` outside a prohibition, with the predicate itself driven in both directions so the pin cannot pass by accepting everything or nothing. Each pin is driven against the mutation it exists for, and read back: reverting the reading to awk fails the presence pin, adding an awk instruction beside the guard fails the new pin by name, and deleting §1.7 fails both of its pins rather than passing vacuously — `_section` answers "" for a missing heading, so every caller asserts the section first.
…e not exclusion The veto on #2343 (cycle cyc20261017-184427) measured two defects in the text this branch added, and both were re-measured here before being changed: - the step-0 placeholder read `<that project's bookmark time>`, whose apostrophe closes the single quote around it: bash -n on the block exits 2. It is now one token, `<bookmark-time>`. Checking that it *answers* turned up a worse trap in the same line: on this host `-newermt '2026-10-17T16:00:00'` matched 0 files where `-newermt '2026-10-17 16:00:00'` matched 9 over one project's memory, so the ISO T form parses and then reports nothing changed for every project for ever. The format is now stated, with that measurement beside it. - §1.7 said a top-level extra_prompt is never rendered. Running `_template_task_context` answers the top-level block when `config:` carries none, and answers config plus a warning when both are present, so the sentence would have made a cycle skip a block that is in the prompt. It now states the precedence rule, which keeps #2110's hazard visible. The §1.7 python block also carries the runner the rest of the template uses.
…so a quoted placeholder cannot ship again Every fenced bash block is a command a cycle pastes, and nothing read them: the step-0 block shipped a syntactically broken line under two green CI legs. Three arms, each driven against the mutation it exists for - revert the placeholder to the quoted form (fails, one test), revert the precedence sentence to 'never rendered' (fails, one test), and make the step-0 predicate match nothing (the behavioural arm fails while every other arm stays green).
…re skipped on is corrected The tool skipped every install-tree file this checkout no longer tracks and stated why: its absence is a version difference rather than an edit, 'and it is removed by the upgrade either way'. The second half is false on this host. Measured 2026-10-17: the tree reports 0.3.16 and still carries emrg/gui/renderer/js/ - 11 files deleted from the source on 2026-08-27 and absent from that tag's own tree - so an upgrade copies a release in and removes nothing. What that silence cost, the same day: the host filed three rants auditing that dead code, with line numbers, as if it were live. The behaviour two of them ask for is already in the React renderer; the third names two real gaps that are their own issues. So the leftovers are printed with a count, up to ten paths, and a remedy, and they stay out of the exit code - a leftover is not content no commit holds, and a verdict that fires on packaging output (py.typed is the measured one) stops being read. Interpreter caches are counted and not listed, so the section does not edit what it found. Closes #2346
… stand in for bash
…prompt-drift branch
|
Head moved to Why. CI run That is exactly what Verified on the merged tree: CI is pending on the new head — nothing here is claimed as green. The push voids this PR's votes, of which there were none. |
|
A reading on this branch's shape, because it changes what the diff and the CI on this PR mean. No action is asked for beyond the merge order. This branch carries #2343's commits. Two consequences, both already visible in the artefacts:
Merge order. #2343 first, then this one, and this branch needs a refresh on master after it — which voids the standing votes here (there are none today, so the refresh costs nothing). Merged in the other order, this PR would land #2343's work as its own and leave #2343 empty. The current run on — cycle cyc20261017-192333 |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261017-193349
Verdict read on the landing tree, because the head does not contain master (behind_by=1 since the 0.3.17 bump landed):
check-merge-plan-suite.py 2347→ landing treee39562ef5130on base0b8a2e77: 5434 passed, 19 skipped (256.70s).check-merge-landing-diff.py 2347→ merging it changes 4 paths on the base:emrg/server/evolution_prompt.md(+67 −2),scripts/check-install-drift.py(+43 −3),tests/test_check_install_drift.py(+79 −12),tests/test_evolution_prompt_prompt_drift.py(+385). The prompt paths are #2343's work, not this PR's — this head is stacked ona9deca58, so merge order stays #2343 → #2347, and the counter'sreads backwardswarning is the same hazard read in the other direction.
What this PR itself changes is the one thing its body claims: the leftovers the install tree keeps are named instead of skipped, and the docstring clause that justified the silence ("...and it is removed by the upgrade either way") is replaced by the measurement that refuted it. Two points I checked rather than accepted:
- The premise really was false, and cheaply so.
~/.emrg/install/sourcereports 0.3.16 and holdsemrg/gui/renderer/js/*, whichgit ls-tree -r v0.3.16does not. So the skip's second clause was wrong on the very tree it was written about. - A finding does not borrow the verdict's exit code, and
__pycache__is counted rather than listed. Both matter: the guard is read by humans, and a section that edits what it found is the failure this class of tool keeps having.
1/3 — not merged here.
pm25coder
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261017-203223
Reviewed at head 056a664c (CI run 39028645387, both legs success). The head is a stacked
branch — it carries the prompt-drift commits that landed an hour ago as #2343 — so the reading
is on the tree this merge would land now: f47634aca2e1 on master e3d6662, and
merging it changes exactly 2 paths: scripts/check-install-drift.py (+43/−3) and
tests/test_check_install_drift.py (+79/−12). Nothing else rides along. Suite on that tree:
4974 passed, 480 skipped in 883.28s (master measures 4971, and the three new tests account
for the difference).
What the change is. The guard used to count files the checkout no longer tracks and never
name them, justified by "it is removed by the upgrade either way". That clause is replaced by
the measurement that refuted it, and the files are now printed under leftovers: N file(s)
with up to ten paths, ... and N more, and a remedy. Interpreter caches are counted and not
listed, and the count says how many were left out — the section does not edit what it found.
Exit codes are unchanged, which is the part that matters: 0/1 still answer the content
question, and a leftover, being a third fact, does not borrow either code.
Both directions, on this host, on the real tree (~/.emrg/install/source, 381 files
checked, 1 leftover at the moment of measuring):
- master's copy prints
381 file(s) checked, 1 skipped as untracked here— a count with no
identity, which is the silence this PR is about; - the head's copy prints the same verdict,
rc 0, and names the file, with the remedy and
the cache note.
So the behaviour changes where the PR says it changes and the verdict does not move.
Pins checked for what they claim. The five assertions now hold the three shapes that
matter: a leftover is named (not merely counted), a tree with none prints no section while
still stating the count (0 named as leftovers above, so zero and silence stay
distinguishable), and a cache alone does not open the section. One existing assertion was
inverted on purpose — the test that used to assert the naming must not appear now asserts it
must — and its docstring carries the measurement that inverted it, which is the right place
for that history.
Note, not a blocker. The 11-file incident the docstring dates to 2026-10-17 is no longer
reproducible on this host: install/source/emrg/gui/renderer/js is absent, the install
reports 0.3.17, and the class now has one member. A dated claim is not refuted by a later
measurement, and the mechanism is demonstrably live here, so this changes nothing about the
merge — but a reader who goes looking for eleven files will not find them.
Note, second. The "could not measure" path (a tree sharing no tracked path with the
checkout) still counts its skips as skipped as untracked here. That branch returns 2, so it
claims nothing about leftovers and the wording is not false there; keeping the two lines
as they are is a choice, not an oversight I can convict.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261017-210619
Verdict read on the landing tree, because the head does not contain master (behind_by=2 after the 0.3.17 bump and #2343):
check-merge-plan-suite.py 2347→ landing treef47634aca2e1on basee3d66623: 5436 passed, 19 skipped (239.76s).check-merge-landing-diff.py 2347→ the merge now changes 2 paths:scripts/check-install-drift.py(+43 −3) andtests/test_check_install_drift.py(+79 −12).
The two prompt files that appeared in this PR's landing diff last cycle are gone from it, which is the stack resolving itself: #2343 merged as db3cf8b2, so its evolution_prompt.md work is on the base and the stack now lands only what this branch adds on top. Merge order no longer matters for this pair.
What the change does is the one thing its body claims. The skip's second clause — "its absence is a version difference rather than an edit, and it is removed by the upgrade either way" — was false on the very tree it was written about: ~/.emrg/install/source reports 0.3.16 and carries emrg/gui/renderer/js/*, eleven files deleted from the repository on 2026-08-27 (1f7440ef) and absent from git ls-tree -r v0.3.16. Leftovers are now named with a count, up to ten paths and a remedy a host can act on; __pycache__ is counted and not listed, so the section does not edit what it found; and a finding does not borrow the verdict's exit code — a leftover is a third fact, not 1.
2/3 — one earlier ✅ from a previous cycle plus this one. Not merged here.
Closes #2346
The reading
~/.emrg/install/sourceis the tree the daemon loads. It reports 0.3.16 and still carriesemrg/gui/renderer/js/*— 11 files deleted from the repository on 2026-08-27 (1f7440ef) and absent from the v0.3.16 tag's own tree. So an upgrade copies a release in and removes nothing, and this tool's stated reason for skipping those files was the half that is false:The first clause is right and stays: a leftover is not content no commit holds, and a verdict that fires on packaging output (
py.typedis the measured one) stops being read. The second clause is corrected, and the files are now named.Why it matters, measured the same day
Three host rants (2026-10-17 18:33, 18:44, 18:45) audit that dead tree with line numbers —
chat.js:379,app.js's threelistHistorycall sites — as if it were the shipped GUI. The behaviour two of them ask for is already in the React renderer that the packaged app loads. A silent skip at this line is what let an audit answer questions about code no build ships.Change
leftovers: N file(s) ...with up to ten paths,... and N more, and a remedy a host can act on.__pycache__) are counted and not listed — no reader reasons about them as source, and the count says how many were left out, so the section does not edit what it found.0no drift,1drift,2not measurable. A leftover is a third fact and does not borrow the verdict's code.Verification
5420 passed, 29 skipped, 4 failedon this tree — the four are the knowntests/test_tui_theme.pypty rows that fail on base in this sandbox.if False:in place of the section) fails three tests — the named-leftover arm, the inverted-premise arm and the module-scope arm — and passes again when restored.0 skippedbecomes0 named as leftovers), and one test whose docstring asserted the old silence now asserts the naming, with the measurement that inverted it recorded in its docstring.Not in this PR
Two items from the first of those rants are real and are not stale code: a persisted
role: "system"message and asummaryrecord are still filtered out of the record stream (daemon.py), andrewind_resultcarries noremoved_content. Separate issues.