Repository navigation
sessions: a message's files come into the archive with it - #753
Conversation
A message's `attachments` ({name, media_type, size, sha256, path}), its
files' bytes the archive's `media/<sha256>.<ext>`: kept once by their
hash, a blob at 1 MiB or more, at most 25 MiB each, counted toward the
archive's bytes. The export reader takes them from the export's messages
(path under chats/), each checked against its hash and size, one that is
not left out of its message, said. The writer sends the files the
archive lacks before the conversations that name them. The reader shows
a picture with its message and links any other file.
Hermes' state.db carries no file's bytes (v0.21.7 writes rows through a
text-only projection, and its caches go in a day): its marks stay.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alexlwn123
left a comment
There was a problem hiding this comment.
Fail for now at 36ff9429d6569c579bab536d9c342fd326c97826, reviewing this layer against #752 at a01cddcc6c6bd7219bc4065884f201b585c2f79e.
The media format and reader fit the existing fragment/file primitives, and the implementation is appropriately scoped. Two importer boundaries need fixing.
Blocking:
-
Media bypasses conversation selection.
cli/src/session/chats.rs:127callsmedia()beforeSpool::add()applies--kind, validates the conversation, and selects the newer copy.cli/src/session/mod.rs:373then uploads every spooled media path, independently of accepted conversations. An import with--kind cronuploads attachments from excluded chats; conversely--kind chatreads/counts/uploads excluded cron files. Enough excluded media can also abort an otherwise valid filtered import at the byte limit. Refused conversations and superseded copies have the same orphan-media path. A temporary regression test using the existing export fixture and a picture on its excluded chat fails: the chat entry is absent but its media remains in the upload spool. Apply selection before media side effects and scope uploads/accounting to retained attachments; cover filtering, refusal and superseded copies. -
A media-enriched read does not update an already imported conversation. The export reader still uses
READER = 10(cli/src/session/chats.rs:33), the same value as the pre-media reader. With unchanged message timestamps,Entry::newerandsession::mergediscard the conversation even though its new JSON contains attachments. The media bytes upload, but the archived message never references or displays them. I reproduced this by importing a fixture without attachments, adding a valid attachment without changing timestamps, and merging the next import: no conversation write is selected. This also affects retrying an import after restoring a previously missing attachment file. Advance the reader revision for this improved read and handle attachment recovery on replay without allowing older history to replace newer history. Cover the previous-reader upgrade, missing-file recovery, and an unchanged replay.
Validation: clean-head cargo test -p fragment-cli -p fragment-core session:: passes (27 passed, one fixture-regeneration test ignored). Both temporary regression tests above fail as described and were removed afterward. CI check and images check are green; e2e shards and real-Hermes Docker checks were still pending. I did not run e2e locally. The external engineering-style file named by AGENTS.md was unavailable on this machine.
… into claude/session-archive-media # Conflicts: # cli/src/session/chats.rs # cli/src/session/mod.rs # crates/core/src/session.rs # templates/sessions/README.md
alexlwn123
left a comment
There was a problem hiding this comment.
Fail for now at 40bef7e0b0e3288a5323dc4d8d52fcce1ac4c8ff, reviewing this layer against #752 at 056ba2f0cd0ff7f30de46377ab2d68b7952c1288.
Both blockers from my previous review remain. This head merges the updated base, but does not fix the media selection or replay boundaries. The media format and reader remain appropriately scoped to existing fragment/file primitives.
Blocking:
-
Media still bypasses conversation selection.
cli/src/session/chats.rs:176callsmedia()beforeSpool::add()filters--kind, validates the conversation, or chooses the newer copy.add_media()counts and spools those bytes immediately, andwrite()uploads every missing path inspool.media, regardless of retained conversations. Thus--kind cronstill uploads excluded chats' attachments; refused or superseded conversations can also leave orphan media, and excluded media can exhaust the import byte budget. Apply selection before media side effects and restrict accounting/uploads to retained attachments, covering filters, refusal and superseded copies. -
Attachment enrichment still selects no conversation update. The export's
READERremains10(cli/src/session/chats.rs:40), whileEntry::newercompares only(when, reader)(crates/core/src/session.rs:417). Importing a conversation already archived by the previous reader, or retrying after restoring a missing attachment, leaves its timestamps and reader unchanged:merge()discards the enriched conversation even though its hash differs. Its media uploads but is never referenced/displayed. Advance the reader revision for the improved read and support attachment recovery on replay without replacing newer history with older history. Cover the previous-reader upgrade, missing-file recovery and unchanged replay.
Validation: both temporary regression tests fail on this head: an excluded chat still leaves media in the spool, and adding a valid attachment without changing timestamps selects no conversation write. Removed the temporary tests, then cargo test -p fragment-cli -p fragment-core session:: passed (31 passed, one fixture-regeneration test ignored). CI check and images check pass; e2e and real-Hermes Docker checks remain pending. I did not run e2e locally. The external engineering-style file named by AGENTS.md is unavailable on this machine.
…chive-media # Conflicts: # cli/src/session/mod.rs
alexlwn123
left a comment
There was a problem hiding this comment.
Fail for now at 85277e75afba80329ef5c60004f6a5d93b01d27a, reviewing this layer against #752 at 6b42a1753264287daefb72cffc556900a0717c1f.
Both blockers from my previous review remain. This head incorporates the base's index-recovery fix; it does not change the media selection or attachment-replay boundaries. The media format and reader remain appropriately scoped to the existing fragment/file primitives.
Blocking:
-
Media still bypasses conversation selection.
cli/src/session/chats.rs:176callsmedia()beforeSpool::add()filters--kind, validates the conversation, or selects the newer copy.add_media()immediately counts and spools the bytes;write()atcli/src/session/mod.rs:435uploads every missing spooled media path independently of retained conversations ormerge.writes. Consequently,--kind cronuploads excluded chats' attachments; refused and superseded conversations can leave orphan files too, and excluded media can exhaust the import byte budget. Apply selection before media side effects and scope accounting/uploads to retained attachments. Cover filtering, refusal, and superseded copies, including copies rejected against an existing archive. -
Attachment enrichment still does not update an existing conversation. The export's
READERis still10(cli/src/session/chats.rs:40), the same as the pre-media reader.Entry::newercompares only(when, reader)(crates/core/src/session.rs:417), andmerge()rejects an incoming copy when that pair is unchanged even if its hash differs. Reimporting an already archived conversation with newly available attachments—or retrying after restoring a missing attachment file—uploads the media without updating the conversation to reference/display it. Advance the reader revision for the improved read and support attachment recovery on replay without replacing newer history with older history. Cover the previous-reader upgrade, missing-file recovery, and unchanged replay.
Validation: traced both failures on this head; the export reader and core merge code are unchanged from the previously reviewed head. cargo test -p fragment-cli -p fragment-core session:: passes (33 passed, one fixture-regeneration test ignored). CI check, images check, e2e shards, and real-Hermes Docker checks are pending. I did not run e2e locally. The external engineering-style file named by AGENTS.md is unavailable on this machine.
Alex's review of #753: - Media bypassed selection: the export's reader read and spooled each message's files before `Spool::add` applied `--kind`, refused a conversation or kept the newer of two copies, counted their bytes toward the import there, and `write` sent every spooled file. Now a conversation of a kind not asked for has none of its files read; a file counts toward the archive with the conversation that keeps it (`Entry::media`, in `add`); and `write` sends only the files the conversations it writes name (`Spool::attached`), so a refused one's, or a copy set aside for a newer one (the import's own or the archive's), never go up. The spool bounds what it reads on the way apart from the archive's limits (twice its bytes). - A read with more of a conversation's files did not update it: the export's reader stayed at 10 and `Entry::newer` compared (when, reader) alone. The reader is now 11 (it reads files; 10 read none), and `newer` also prefers, as late and from as good a read, the copy holding more of its files (one missing before, found since), so an older history still never replaces a newer one. Tests (each fails before): a kept chat's picture goes up, an older copy's, a refused one's and an archived newer copy's older rival's do not, and only the kept count; the export read for its runs reads no chat's picture; a chat archived by reader 10, read again by 11 with its picture missing, then found, updates each time, the same read again writes nothing, and an older copy holding the picture changes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Fixed at 1b4defa: 1. Media bypassed conversation selection.
2. A media-enriched read didn't update an existing conversation.
The README's "An import" section says what goes with what. One limit, unchanged by this PR: Hermes' own database stores no file bytes, so a later Hermes read (reader 20) replaces an export copy without its attachments. Only the export carries bytes.
|
alexlwn123
left a comment
There was a problem hiding this comment.
Pass for this stack layer at 1b4defac549ceb250a18906c5e2cf6a025e8a501, against #752 at 359b96faae2b95f5deee4024fcfa397ec3fa12b9.
Both earlier blockers are fixed: excluded kinds read no media, retained conversations alone count toward the archive, and only conversations selected for writing upload their referenced files. Reader 11 updates pre-media imports; attachment recovery updates an equally recent read, while older histories and unchanged replays remain excluded. The new regression tests cover filtering, refused/superseded copies, previous-reader upgrades, missing-file recovery and replay.
The importer and reader changes remain appropriately scoped to the existing fragment/file primitives. I see no blocking regression in this layer.
Validation: cargo test -p fragment-cli -p fragment-core session:: passed (39 passed, one fixture-regeneration test ignored). CI check and images check pass; e2e shards and real-Hermes Docker checks are still pending. I did not run e2e locally. The external engineering-style file named by AGENTS.md is unavailable on this machine.
|
Merged #752's new head (fdae79e, its |
alexlwn123
left a comment
There was a problem hiding this comment.
Pass for this stack layer at ab84ffae520117c993004bbf17535780926d39c7, against #752 at fdae79e5232069bc8cd303840263ec0eabf60751.
Both earlier blockers remain fixed: media follows retained conversations and selected writes; reader upgrades and recovered attachments update equally recent histories without replacing newer histories or rewriting unchanged replays.
This head merges the updated base. All nine files in this layer are unchanged from my approved head 1b4defac549ceb250a18906c5e2cf6a025e8a501. The implementation remains appropriately scoped to existing fragment/file primitives, and I see no blocking regression in this layer.
Validation: cargo test -p fragment-cli -p fragment-core session:: passed (39 passed, one fixture-regeneration test ignored). CI images check passes; check, e2e shards and real-Hermes Docker checks remain pending. I did not run e2e locally. The external engineering-style file named by AGENTS.md is unavailable on this machine.
Media, importer side: the files a message held come into the Session Archive with it, when the store carries their bytes. Stacked on #752.
What it adds
attachments: [{name, media_type, size, sha256, path}]. The bytes are the archive'spath,media/<sha256>.<ext>:MEDIA_FILE_MAX_BYTES); a larger one is left out and its message kept;media) toward the archive's 1 GiB (ARCHIVE_MAX_BYTES).attachmentsfrom the export's messages, withpathunderchats/:chats/, bounded) and checked against itssha256andsize;state.db(sessions: Hermes' own state.db as a source forfragment session import#750) carries no files, and won't. v0.21.7 writes rows through a text-only projection: an image becomes[screenshot], with[Image attached at: <path>]in the text. Its gateway caches are cleaned after 24 hours, so the bytes are almost never there. Those messages keep their marks.Complexity ledger
Attachment,media_path,Entry.mediacrates/core/src/session.rs(~45 lines + test)attachmentscli/src/session/mod.rs(add_media, upload before conversations),chats.rs(media)templates/sessions/site/sessions.js(~30 lines),sessions.css(3 lines)Tests
chats/are each left out and said;sessions: a picture a message held is kept in the archive by its hash;sessions-ui: the picture loads with the person's message in the reader.cargo xtask checkpasses.🤖 Generated with Claude Code