Skip to content

fix(ui-web): draw the rail after a re-read replaces its rows - #597

Merged
0xKT merged 2 commits into
refactor/ui_web_architecturefrom
fix/rail_redraw_after_restore
Sep 21, 2026
Merged

0xKT merged 2 commits into
refactor/ui_web_architecturefrom
fix/rail_redraw_after_restore

Conversation

@gloryfromca

Copy link
Copy Markdown
Member

Summary

Restoring a conversation from the archive page put it back everywhere except the
screen. loadSessions replaced the rail's rows and never drew them, and the
restore reaches the rail only through that function, so the row came back in the
server's listing and on disk while the rail kept showing the list from before.
Reloading the page was what appeared to restore it.

Every other writer in this feature already draws after a replace -- leave.ts
does it on both of its transitions, the session registry does it after its
reconcile -- so the fix is the missing call in the one path that did not, rather
than a draw at the restore call site. At boot the rail is still held, where a
draw sets the skeleton and releaseRail paints the rows, so the other caller is
unaffected.

Found while driving the merged archive flow end to end on a real host, after
#585, #589 and #596. It is the same shape as #596: server state correct, screen
stale until a reload.

Type

  • Fix
  • Feature
  • Docs
  • CI / tooling
  • Refactor
  • Other

Verification

On a real host (raven web on an isolated RAVEN_HOME built from a real
config, driven through the browser), reading the archived flag from the last
metadata record of the session transcript rather than from the page:

Step Before After
Archive a conversation from the rail leaves the rail, archived: true on disk same
Settings, Archive page it is listed same
Restart the gateway still archived, does not come back same
Restore it from the Archive page archived: false on disk, rail still does not show it rail shows it at once
Reload the page rail shows it rail shows it

Commands:

  • npm test --prefix ui-web -- 189 files, 2470 tests, all pass
  • npm run lint --prefix ui-web -- 0 errors (4 pre-existing warnings in
    CronPage/SubagentsPage, untouched here)
  • npm run type-check --prefix ui-web -- clean
  • npm run --prefix ui-web build && python3 ui-web/build.py -- boot-snapshot OK
    (235 nodes match golden)
  • npx commitlint --from github/refactor/ui_web_architecture --to HEAD -- clean

The new case, a plain re-read draws the rows it just replaced, was run against
the unfixed module first and fails there on the assertion it is named for.

  • Relevant tests pass locally
  • Relevant lint / type checks pass locally
  • User-facing docs or screenshots are updated when needed

Risk

One added call in a function with two callers; the other one runs while the rail
is held, where the draw is a no-op beyond the skeleton it already sets. No server
change, no stored state change. Rollback is reverting one commit.

  • Security impact considered
  • Backward compatibility considered
  • Rollback path is clear for risky changes

Related Issues

N/A

gloryfromca and others added 2 commits September 21, 2026 20:40
Replacing the rows is not showing them. Every other writer in the rail knows
this -- leave.ts and the session registry both draw after their replace -- but
the plain re-read did not, and the archive page's restore reaches the rail only
through it. So a restored conversation came back in the config, on disk and in
what the server lists, and stayed off the screen until the page was reloaded:
the same shape as the archive report this fixes the other half of.

At boot the rail is still held, where a draw sets the skeleton and releaseRail
paints the rows, so the other caller is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The draw added in the commit before this one made a older defect visible.
`loadSessions` replaced the rows with the raw answer, while its sibling
`refreshList` puts the same answer through `reconcileRows` first -- which is
what carries across the two things `session.list` cannot know: which
conversation has a turn running, and the current conversation while it is too
new to be listed. Dropping those was invisible as long as nothing repainted.
With the repaint it is a running badge wiped, and the row for the conversation
the reader is in removed, every time they restore something from the archive
page.

Through the reconcile now. `currentMissing` stays `refreshList`'s business:
that answer means the open conversation was deleted under the reader, and
leaving it is the transition that owns moving them out.

Found by an adversarial review of the previous commit, reproduced against the
real store before and after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gloryfromca
gloryfromca force-pushed the fix/rail_redraw_after_restore branch from 30a5c0a to f4a09c1 Compare September 21, 2026 12:40

@gloryfromca gloryfromca left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No blockers; this can merge as far as I am concerned.

Reviewed the full target diff and the new revision delta. I checked the repository rules and ui-web vocabulary/architecture, both loadSessions callers (boot and archive restore), the parallel registry refresh path, row/store behavior, relevant history, backward compatibility, and that the tests strengthen rather than weaken coverage. The reconciliation preserves client-only running/current state before the newly visible redraw, while boot remains safe because the rail is held until release.

Verification: npm test -- src/features/rail/source.test.ts (14 passed), npm test (2,474 passed across 189 files; Happy DOM emitted aborted localhost fetch diagnostics), npm run type-check (passed), and npx eslint src/features/rail/source.ts src/features/rail/source.test.ts (passed).

@0xKT
0xKT merged commit 061e3ab into refactor/ui_web_architecture Sep 21, 2026
23 checks passed
@0xKT
0xKT deleted the fix/rail_redraw_after_restore branch September 21, 2026 13:25
gloryfromca added a commit that referenced this pull request Sep 21, 2026
## Summary

Restoring a conversation from the archive page put it back everywhere
except the
screen. `loadSessions` replaced the rail's rows and never drew them, and
the
restore reaches the rail only through that function, so the row came
back in the
server's listing and on disk while the rail kept showing the list from
before.
Reloading the page was what appeared to restore it.

Every other writer in this feature already draws after a replace --
`leave.ts`
does it on both of its transitions, the session registry does it after
its
reconcile -- so the fix is the missing call in the one path that did
not, rather
than a draw at the restore call site. At boot the rail is still held,
where a
draw sets the skeleton and `releaseRail` paints the rows, so the other
caller is
unaffected.

Found while driving the merged archive flow end to end on a real host,
after
#585, #589 and #596. It is the same shape as #596: server state correct,
screen
stale until a reload.

## Type

- [x] Fix
- [ ] Feature
- [ ] Docs
- [ ] CI / tooling
- [ ] Refactor
- [ ] Other

## Verification

On a real host (`raven web` on an isolated `RAVEN_HOME` built from a
real
config, driven through the browser), reading the archived flag from the
last
metadata record of the session transcript rather than from the page:

| Step | Before | After |
| --- | --- | --- |
| Archive a conversation from the rail | leaves the rail, `archived:
true` on disk | same |
| Settings, Archive page | it is listed | same |
| Restart the gateway | still archived, does not come back | same |
| Restore it from the Archive page | `archived: false` on disk, **rail
still does not show it** | rail shows it at once |
| Reload the page | rail shows it | rail shows it |

Commands:

- `npm test --prefix ui-web` -- 189 files, 2470 tests, all pass
- `npm run lint --prefix ui-web` -- 0 errors (4 pre-existing warnings in
  CronPage/SubagentsPage, untouched here)
- `npm run type-check --prefix ui-web` -- clean
- `npm run --prefix ui-web build && python3 ui-web/build.py` --
boot-snapshot OK
  (235 nodes match golden)
- `npx commitlint --from github/refactor/ui_web_architecture --to HEAD`
-- clean

The new case, `a plain re-read draws the rows it just replaced`, was run
against
the unfixed module first and fails there on the assertion it is named
for.

- [x] Relevant tests pass locally
- [x] Relevant lint / type checks pass locally
- [ ] User-facing docs or screenshots are updated when needed

## Risk

One added call in a function with two callers; the other one runs while
the rail
is held, where the draw is a no-op beyond the skeleton it already sets.
No server
change, no stored state change. Rollback is reverting one commit.

- [x] Security impact considered
- [x] Backward compatibility considered
- [x] Rollback path is clear for risky changes

## Related Issues

N/A

---------

Co-authored-by: gloryfromca <23442919+gloryfromca@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants