Repository navigation
Conversation
Open a picture, let the agent rewrite it in place and deliver it again, then open the new delivery card: the viewer showed the picture as it was before the rewrite. The file on disk held the new bytes and the gateway was never asked for them. A document that has drawn a picture from one URL draws it again from memory for that URL without a request -- the HTML list of available images -- and no Cache-Control directive reaches that layer. The viewer named a picture by its path alone, so a re-open after a rewrite asked for a URL the document had already drawn. The no-store directive on the download routes covers a fresh document only. Each picture URL now carries a version that moves when the bytes may have. The viewer's picture is versioned by the open, its file record's seq, so a re-open reads the file as it stands now and a repaint asks for nothing. A delivery card's picture is versioned by the delivery's own stamp: a path delivered again keeps its token, and a thumb is named by its path. pageURL builds its version through the same helper, and DeliveryRow declares the stamp it already carried. Co-authored-by: Claude (claude-opus-5-5[1m]) <noreply@anthropic.com>
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Reviewed github/main...HEAD and the relevant workspace, desk, transcript, delivery-registry, and gateway paths. The per-open seq and per-delivery monotonic delivered_at versions produce distinct image URLs while preserving resource resolution, authorization, repaint behavior, legacy unstamped rows, and existing deck versioning. The added tests cover both image/SVG pane reopens and PNG/PDF redeliveries without weakening existing assertions.
Coverage: AGENTS.md, CLAUDE.md, CONTEXT-MAP.md, ui-web/CONTEXT.md, and ui-web/CONTRIBUTING.md rules; the complete diff; callers and data provenance; relevant history; backward compatibility; test integrity; and UI architecture/import constraints.
Verification: full UI suite passed (214 files, 3,236 tests); focused affected suites passed (4 files, 291 tests); architecture gates passed (46 files, 205 tests); TypeScript and changed-file ESLint passed; git diff --check passed. The test process emitted Happy DOM iframe teardown diagnostics but completed with exit 0 and no failed tests.
|
No blockers in the reviewed scope. Scope: I reviewed the full PR diff (6 changed files), including tests and documentation, and traced affected callers and contracts at Checked per-open file.seq, FileBody remounting, the producer's monotonic delivered_at stamp, delivery parsing, the URL consumers, and legacy unstamped rows. A new open or delivery gets a fresh image URL while repainting the same open preserves its URL. Verification environment: native Windows; isolated source snapshots. Frontend verification:
|
|
Windows compatibility review: no new issue found in the inspected scope. Reviewed all 6 changed files at head Verification in an isolated detached checkout on native Windows, Node 25.9.0: npm.cmd ci --ignore-scripts --no-audit --no-fund
node node_modules/vitest/vitest.mjs run --no-file-parallelism src/features/desk/DeskSurface.test.tsx src/features/transcript/TranscriptPage.test.tsx src/features/workspace/WorkspacePage.test.tsx
# 3 files / 265 tests passed, exit 0.
node ../../pr907/probe_urls.cjs
# 42 encoded Windows path/version checks passed; download token preserved.The scratch probe extracts and transpiles the actual URL helpers from this head. It covers drive-letter and UNC paths, spaces, non-ASCII characters, literal query metacharacters, changing versions and the unstamped fallback. Happy DOM emitted iframe-abort diagnostics during the passing component tests. Limits: mocked browser components and URL round trips only; no real Windows browser pixel/cache behavior, UNC filesystem access, rendering application or full UI suite was tested. This is not a full compatibility certification. |
Summary
Open a picture in the web viewer, let the agent rewrite that file in
place and deliver it again, then open the new delivery card: the viewer
showed the picture as it was before the rewrite. The file on disk held
the new bytes and the gateway was never asked for them.
The cause is the document's own memory of what it has drawn, not the
HTTP cache. A document that has drawn a picture from one URL draws it
again for the same URL without a request -- the HTML list of available
images -- and no Cache-Control directive reaches it. The viewer
named a picture by its path alone (
/file?path=...&session=...), so are-open after a rewrite asked for a URL the document had already drawn.
#838 added
no-storeto the download routes. That directive governsthe HTTP cache, which is what a reload reads; it never reaches this
memory, so the same report came back.
Measured against a stand-in route sending the real route's exact
headers,
no-storeincluded, and the file rewritten between two loadsof one URL:
Which is why, before this change:
and mounts the new one in one commit, so the old one is still alive
when the new one asks;
existence probe is a
HEADto the same URL, then the<img>-- soit drew the old picture in Firefox, and looked fresh in Chromium only
because the probe happens to evict the entry there;
render=thumb, named by its path) wasstale in Chromium too, since the probe asks a different URL.
Every picture URL now carries a version that moves when the bytes may
have, through one helper,
versioned(url, version):seq. A re-open reads the file as it stands now, which is what thetext views already get from their own fetch, and a repaint of the
same open asks for nothing;
delivered_at. A path delivered again keeps its token and a thumb isnamed by its path, so the stamp is what tells two cards apart. The
stamp and not the turn, because a delegated stream numbers its turns
from one as well;
pageURLbuilds its version through the same helper, andDeliveryRowdeclares thewhenstamp the registry already carried,which retires the cast
DeckBodyused to read it.Both routes ignore the extra
vquery, so the gateway is unchanged.The
no-storefrom #838 stays: it is still what keeps a reload honestand an agent's output out of the reader's disk cache.
Deliberately unchanged:
itself; opening it again from the card or the shelf does. Text panes
behave the same way;
its pages are still versioned by the delivery stamp only;
never writes a path twice (a uuid, or a numbered name claimed with
O_EXCL), so there is no second drawing to go stale.
Type
Verification
The reported flow, in a real browser against this change's own gateway
and web UI: an isolated
raven webwith its ownRAVEN_HOME, two realturns on glm-5.3-flash, Playwright Chromium 151. Turn one copies a red
PNG to A and delivers it, and the card is opened; turn two copies a
blue PNG over A and delivers it again, and the new card is opened.
Pixels are read off the rendered elements, and "asked" is the gateway's
own access log after the rewrite.
The bundle built from the final tree is byte-identical (md5) to the
one that run used.
The tests were written first and confirmed red for the reason they
name, then green:
Each new construct was then removed on its own and the three test files
that reach it were run (265 tests):
Commands and results at the pushed head:
Two of those were shown able to fail before their green was trusted:
the source-language gate exited 1 on a probe CJK line and named its
file and line, and commitlint exited 1 on a malformed header. The
vitest run set
NODE_OPTIONS=--localstorage-file=<file>, which node 26needs for happy-dom's localStorage; CI's node 22 does not.
No user-facing doc describes how a delivered picture is fetched, so
none changes.
Risk
Security: no route, header, authorization or path fence changes; the
version is a query both routes ignore.
Behaviour and cost: a picture's URL gains
&v=<n>. Nothing on mainreads a picture's URL back, and the open drag-and-drop change (#900)
parses dropped URLs with
searchParams, so the extra query does notreach it. A row with no stamp (a manifest from before
delivered_at,or a row recovered from the registry) keeps the bare URL. The viewer
now fetches a picture once per open, where a re-open used to be
answered from memory; a repaint still fetches nothing, and
/filekeeps its view-size ceiling.
Rollback: revert the commit.
Related Issues
#838 -- the HTTP-cache half of the same report. Nothing closes here.