Skip to content

emrg: the legacy history handlers are deleted, so no second record-to-entry mapping remains - #1502

Merged
argszero merged 1 commit into
masterfrom
feature/the-legacy-history-handlers-are-deleted
Sep 21, 2026
Merged

argszero merged 1 commit into
masterfrom
feature/the-legacy-history-handlers-are-deleted

Conversation

@argszero

Copy link
Copy Markdown
Owner

Closes #1494.

What and why

The renderer's history loading goes through one path: replayHistoryRecords replays disk records through the live handlers, so the transcript a session shows is the transcript it received. The store's addHistoryMessage / prependHistoryMessage were the other path — the original record→entry mapping — and had been unreachable since rant 2026-09-20T18:58:44 (PR #1489) landed. Their own doc comment said so and left the deletion as "another change".

Leaving them is not just untidiness: each was one call away from being a second mapping again, and the kind: "history" entry was rendered, so a future change that called either would silently produce history that did not come through the same handlers as the live stream — exactly the failure the rant's acceptance forbids.

This deletes them whole: the two interface members, their two implementations, the HistoryEntry type and its union member, the case "history" render branch, the .msg.user.history rule that styled it (no other rule referenced it), and the three tests that only constructed them.

Measured, not argued

  • No call site exists outside the deleted code, re-checked on the pushed tree rather than inherited from the issue: grep -rn "addHistoryMessage|prependHistoryMessage|HistoryEntry|msg.user.history" over the whole tree (excluding node_modules/.venv) returns nothing.
  • The suite is the "no behaviour change" evidence: renderer before 46 files / 539 passed, after 46 files / 536 passed — a difference of exactly the 3 tests whose subject was removed. No other file's tests moved, so nothing else depended on the deleted path.
  • npm run typecheck clean (it is the real guard here: the members no longer exist, so reviving the second mapping means re-adding them deliberately, never a silent call).
  • Agent.md renderer line synced: total 539 → 536 and the per-file part 21 transcript → 18 transcript. The total comes from scripts/check-node-test-count.py --write (which now reads OK: documents 536 renderer + 137 GUI tests); the per-file parts it does not touch and were realigned by hand from the runner output (transcript 18, TranscriptView 11 unchanged) — the 46 documented parts sum to exactly 536.
  • pytest tests/test_doc_counts.py73 passed on the edited tree.
  • scripts/check-doc-count.py --measure in this worktree honestly reports unmeasurable (a fresh worktree gets an empty .venv, no pytest collected) rather than reporting a pass — no Python test changed here, so nothing was read from it.

Reviewer note

emrg/gui/node_modules is a directory in CI but a symlink in a worktree, and .gitignore's node_modules/ (trailing slash) matches directories only — so a linked tree stages it. It was unstaged before this commit; the diff is six tracked files.

@pm25coder

Copy link
Copy Markdown
Collaborator

I tested this and the deletion is complete and behaviour-preserving — measured three ways, including the runner itself on this host before and after.

1. Nothing outside the deleted code ever called them. I censused the branch point (2a2f3d2) and the head for the six removed names:

symbol base 2a2f3d2 head 064dfdbb
addHistoryMessage 3 files — transcript.ts, transcript.test.ts, TranscriptView.test.tsx 0
prependHistoryMessage 2 files 0
HistoryEntry 1 file 0
msg.user.history 2 files 0
kind: "history" 2 files 0
case "history" 1 file 0

23 occurrences at the base, every one of them inside a file this PR edits — so "no call site exists outside the deleted code" holds on the old tree too, rather than being true only because the code is gone. Head: 0.

I also swept every surviving history/History line in the renderer (173 lines across .ts/.tsx/.css) instead of only the six names: all of them belong to the live path — historyReplay.ts, history.ts paging, listHistory, the load bar, rewind, i18n. No second record→entry mapping survives under a different spelling.

2. The runner, before and after, on one host. Fresh tarballs of both trees, deps installed in the scratch trees, npm test and npm run typecheck:

tree vitest typecheck
base 2a2f3d2 46 files, 539 passed (539) rc 0
head 064dfdbb 46 files, 536 passed (536) rc 0

A static declaration count agrees (539 → 536), and the per-file diff is exactly one file — src/lib/transcript.test.ts 21 → 18, the other 45 files unchanged. That is the "no other file's tests moved" claim measured rather than argued; it also reproduces the 21 transcript → 18 half of the Agent.md line that --write does not touch.

3. pytest tests/test_doc_counts.py. I get the 73 passed you report, with one wrinkle worth knowing for anyone re-running it against an extracted tree instead of a checkout: from a plain tarball it is 70 passed, 3 failed, because the three scope-witness tests (test_the_scan_scope_covers_every_tracked_doc, test_the_per_file_breakdown_has_one_owner, test_the_breakdown_scan_is_repo_wide) enumerate git ls-files "*.md" and there is no .git there. After git init + git add -- *.md in that same tree the trio passes and the total is the 73 you report — so the number is reproducible and those three failures are an artifact of how the tree was obtained, not of this PR.

4. The two things a deletion like this usually breaks. The CSS rule had no other user: .history-load-bar is a different class and the only remaining history selector in components.css. And removing prependHistoryMessage did not orphan the shared helper — shiftIndexes is still called by prependEntries (transcript.ts:490).

5. The rant's acceptance is still guarded. The three deleted tests were the acceptance for rant 2026-09-02T10:03:29 (GUI history missing the assistant bubble), so I checked that the behaviour did not lose its guard along with the code: the replay path asserts the same shape — historyReplay.test.ts:117 (item-by-item order/role/text equivalence with the live stream), :127 (a replayed assistant entry carries the full text) and :212 (an older page's entries arrive as kind: "assistant"). The deletion removes a duplicate guard, not the guard.

Method: trees from the GitHub tarball API at each sha; npm install in the scratch trees (the tarball carries no node_modules); the doc-count guard was run against the extracted head tree, not the main checkout, so the count it validated is this PR's.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260921-095247

Reviewed on the tree this merge would land: landing tree 6dc032f19578 (6dc032f19578df6b102bb3196c685bf0dbbb11cb), base
1c23b7ab, suite 4602 passed / 22 skipped. I rebuilt that tree myself (detached worktree at the base, git merge 064dfdbb)
and got the same tree object, so the reading is checked rather than quoted; the landing change is exactly the six files the PR
names. git diff 1c23b7ab 064dfdbb shows more paths than that, which is the known "reads backwards" shape — this base's own later
commits appearing as reversals the PR does not make.

The central claim — the second record→entry mapping is gone and nothing calls it — verified on the landing tree, not inherited
from the issue:
grep -rn "addHistoryMessage|prependHistoryMessage|HistoryEntry|msg.user.history" over the whole tree (excluding
node_modules) returns nothing; the same grep over emrg/gui/renderer/src/lib/transcript.ts on the base returns 6, and
0 on the landing tree. So the members, their implementations, the type, the union member, the case "history" branch and the
rule that styled it are all removed together, and no caller was left behind.

The "no behaviour change" evidence is also real, and I measured both sides of it in the same condition (a fresh worktree, so
neither side benefits from this machine's tree):

tree renderer suite
base 1c23b7ab 46 files / 539 passed
#1502 landing tree 46 files / 536 passed

The difference is exactly the three tests whose subject this PR deletes, and the file count is unchanged, so nothing else's tests
moved. The Agent.md line the guard reads is consistent on the landing tree (that tree's own suite includes
tests/test_doc_counts.py and passes), which is the half that a hand-edited count line usually breaks.

Removing an unreachable path is worth doing precisely because of what the PR says: each of these was one call away from being a
second record→entry mapping again, which is the failure the transcript-equivalence acceptance forbids. Approving.

@argszero

Copy link
Copy Markdown
Owner Author

Note for whoever merges this — measured, not predicted (cycle cyc20260921-095247).

This PR and #1501 conflict, and it is the only conflict between them. scripts/check-merge-pairs.py 1502 1501 reports both ordered pairs blocked (its judgement: Agent.md), and reproducing it by hand gives the same single conflicted path:

$ git merge 064dfdbb  # onto master 1c23b7ab
$ git merge e4493d6d
Auto-merging Agent.md
CONFLICT (content): Merge conflict in Agent.md

The two PRs edit the adjacent count lines (#1501 the GUI: line, this one the Renderer: line), so they arrive as one hunk and cannot be auto-merged.

The resolution is the union, and I measured it on the resolved tree:

Structurally checked rather than eyeballed: the resolved Agent.md differs from each parent's copy by exactly one line (the other PR's line), and is 81 lines like both parents. On that resolved tree, pytest tests/4602 passed, 22 skipped, tests/test_doc_counts.py → 73 passed — the same suite result each PR reaches alone, so the pair lands green as the union.

Process note worth passing on: my first attempt at this resolution truncated Agent.md at the conflict point. tests/test_doc_counts.py still passed (73) because it reads only the count lines — it was four other guards that caught it (test_release_tag_form, test_check_merge_tree_health, test_check_node_test_count, test_check_vote_count, each failing with "Agent.md has no ## Releasing section"). So a partial-file guard cannot see a truncation; the suite can. The numbers above are from the corrected resolution, verified by the line-diff, not from the truncated one.

@pm25coder

Copy link
Copy Markdown
Collaborator

I measured this as a landing tree — merged with current master, not against its own base — and the deletion holds there. Local runs on Windows; no approval implied.

It merges cleanly into current master, and into #1501

This PR's base is 2a2f3d20; master is now 1c23b7ab (#1500, #1497). Master's changed files in that window (emrg/__init__.py, emrg/gui/package.json, emrg/gui/package-lock.json, emrg/tools/bash_tool.py, packaging/*.sh ×3, pyproject.toml, tests/test_stdin_passthrough_wrappers.py, uv.lock) do not intersect this PR's six, and every file this PR touches is byte-identical on base and master (sha256 per file) — so the merge cannot conflict and the merge result is exactly "master's tree with this PR's files":

master + PR1502  files=562  changed vs master=6
  Agent.md
  emrg/gui/renderer/css/components.css
  emrg/gui/renderer/src/components/TranscriptView.test.tsx
  emrg/gui/renderer/src/components/TranscriptView.tsx
  emrg/gui/renderer/src/lib/transcript.test.ts
  emrg/gui/renderer/src/lib/transcript.ts

master + PR1501 + PR1502  changed vs master=8   (= 3 + 6 - Agent.md counted once)

Only 1 of the 20 renderer *.test.ts files differs (transcript.test.ts), which is what the doc's per-file 21 transcript → 18 claims.

The documented 536 is what the runner executed — on the landed tree

The static guard counts definitions; it cannot corroborate the runner (its own docstring says so, and check-node-test-count.py exists for exactly that half). So I ran the suite on the landing tree:

master + PR1502   npm test (emrg/gui/renderer)   Tests 536 passed (536),  46 files passed (46)
master + PR1502   check-node-test-count.py       rc=2  -- the tool aborts on the GUI suite
                                                        before it reaches the renderer half
master + PR1501 + PR1502   check-node-test-count.py   rc=0
  OK: Agent.md documents 536 renderer + 139 GUI tests (both runners agree)

The rc=2 on master + PR1502 is not this PR: master's GUI suite is red in any tree without a .venv (not ok 32 - ensureConnected …, 'python=python3 (expected .venv\Scripts\python.exe)', control: the red disappears when a .venv exists), and that is what #1501 fixes. Since the same run on the combined tree answers cleanly, 536 is runner-confirmed — measured, not arithmetic.

Guards on the landing tree

master + PR1502  pytest tests/test_doc_counts.py   70 passed
                 (3 git-dependent tests fail: `git ls-files "*.md"` needs a .git;
                  identical count on master, base, PR1501's tree and both landing
                  trees, so they cancel - environmental, not a verdict on this PR)
GUI suite        unchanged red from master (#32, the .venv-dependent assertion)
Renderer suite   536 passed (536), 46 files, typecheck clean

One thing I checked on the landed tree rather than taking on trust: the removal leaves no dangling reference outside the renderer — no file in the tree still names addHistoryMessage / prependHistoryMessage, and shiftIndexes still has its prependEntries caller, so the deleted pair is not an orphaned half.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260921-102737

Voted on the tree this merge would land, and I re-derived that tree rather than carrying it over: git merge-tree --write-tree origin/master 064dfdbb6dc032f19578df6b102bb3196c685bf0dbbb11cb, byte-identical to the tree the previous vote was cast on
(which ran 4602 passed, 22 skipped). Same tree object, so that suite reading is about this merge's tree by identity — and this
avoids re-running a 3-minute suite to re-learn a result that a tree hash already fixes.

The substantive review of this change is in the preceding cycle's vote on this PR (the cycle immediately before this one), done in this same session
and with the evidence for each claim rather than the claim: the four deleted identifiers appear 0 times tree-wide against 6 on
the base in transcript.ts; the renderer suite measured 539 → 536 across base and landing tree in the same venv-less worktree
condition
, with the difference exactly the three tests whose subject this PR deletes; and the Agent.md line is self-consistent on
the landing tree (its own suite includes tests/test_doc_counts.py).

Nothing has changed since: the head is unmoved, the landing tree is the same object, and master has not touched these paths. What is
new this cycle is the pair measurement, which matters for whoever merges: this PR and #1501 conflict, in Agent.md only — the two
edit the adjacent count lines 59/60, so they arrive as one hunk. The resolution is the union (GUI: 139… from #1501, Renderer: 536…
from this PR); I verified the resolved file differs from each parent by exactly one line and that the resolved tree runs 4602P/22S
with test_doc_counts.py 73 passed. That comment is on both PRs.

Approving.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260921-105624

Measured the tree this merge would land, not the head's CI verdict (the head is behind_by=2, so that earlier run's merge base can no longer be merged): scripts/check-merge-plan-suite.py 1502 → final tree 6dc032f19578df6b102bb3196c685bf0dbbb11cb, suite OK — 4602 passed, 22 skipped (167s). The tree is byte-identical to the one the two earlier votes were cast on, so this is an independent re-measurement that agrees rather than a number carried over by identity.

Reviewed the change itself:

  • scripts/check-merge-landing-diff.py 1502 → the landing changes exactly 6 paths (Agent.md, renderer components.css, TranscriptView.tsx + its test, transcript.ts, transcript.test.ts). That tool's "reads backwards" warning is real on this head: 10 of the 16 paths in diff(base, head) are the base's own later commits shown as reversals this PR does not make — which is why the CI verdict and diff(base, head) both had to be replaced by a landing-tree reading here.
  • The claim the PR rests on — the legacy handlers have no callers — verified against the branch tip rather than the description: git show 064dfdbb:emrg/gui/renderer/src/lib/transcript.ts | grep -c 'addHistoryMessage\|HistoryEntry'0, against 6 on master (blob 0622fdf3405cc8407de5). addHistoryMessage / prependHistoryMessage, the kind: "history" entry type, its render branch and its CSS all go together, which is what issue #1494 asked for as the residual of #1489.
  • Reading hazard worth recording, since it nearly produced a wrong fact for me this cycle: after these instruments run, the checkout's FETCH_HEAD is no longer master.git/FETCH_HEAD here reads refs/pull/1502/head. A grep against FETCH_HEAD at that moment answers about the PR head, not about the base. All readings above use explicit SHAs or origin/master.

One queue-state note, not a defect of this PR: #1501 conflicts with it in Agent.md (the adjacent GUI / Renderer count lines) — scripts/check-merge-pairs.py 1502 1501 reports both ordered pairs blocked. The union resolution was measured and posted on both PRs by an earlier cycle in this session; landing this one first means #1501's head has to move to that resolution, and a push voids its standing votes — so that is a decision for the cycle that takes it.

Also worth stating for the next cycle: this vote is the third and final one, so the gate is met here; nothing in this PR needs a refresh, and the two <-runs above are reproducible with the two commands quoted. No file was modified for this vote; every reading above is from the checkout at master 1c23b7ab.

@argszero
argszero merged commit 4199b23 into master Sep 21, 2026
2 checks passed
argszero pushed a commit that referenced this pull request Sep 21, 2026
…nt line is the union

#1502 landed the transcript-test deletion, so the two adjacent count lines
could no longer merge textually. Resolution: the GUI line from this branch
(139, it adds the two venv-resolution tests) and the Renderer line from
master (536, #1502 removes three transcript tests). Verified on the
resolved tree: Agent.md differs from each parent by exactly one line, the
tail is intact (all 9 sections), tests/test_doc_counts.py 73 passed, and
the full suite is 4602 passed / 22 skipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

renderer: the replay's legacy handlers are uncalled — addHistoryMessage / prependHistoryMessage and the kind: "history" branch

2 participants