# File Download Mapping Precheck Date: 2026-07-10 ## Goal Determine whether `isphere_receive_files` can safely move from list mode to download mode. This precheck uses only sanitized counts, table/column names, source refs, booleans, extension counts, and path-shape descriptions. It does not commit local file paths, file contents, decrypted message bodies, raw DB rows, DB credentials, or attachment contents. ## Current product behavior `isphere_receive_files` currently supports list mode only. Current list source: - `internal/isphere.ListFilesFromMessages` extracts file candidates from normalized PacketReader messages. - It returns metadata such as `file_id`, `message_id`, `conversation_id`, `file_name`, `mime_type`, `created_at`, `source`, and `raw_ref`. - `download_ref`, `saved_path`, and `sha256` remain empty. - `internal/tools/isphere_files.go` rejects non-list modes and rejects `output_dir` until download mode is implemented. ## Evidence inventory ### PacketReader file-transfer evidence Safe count evidence from C12: | Source | Parsed message evidence | Cache/download signal | | --- | --- | --- | | `PacketReader.ProcessPacket` | 107 file-candidate messages; 123 `FILE_TRANSFER` hits; extension counts include `.doc`, `.docx`, `.pdf`, `.png`, `.xlsx`, `.zip`. | 0 importal-hash path hits; 0 download-keyword hits. | | `Smark.SendReceive` | 5 file-candidate messages; extension counts include `.doc`, `.docx`, `.pdf`, `.zip`. | 0 importal-hash path hits; 0 download-keyword hits. | | `SaveToDB` | 9 generic file-extension hits, but no parseable XMPP message candidates. | 0 importal-hash path hits; 0 download-keyword hits. | Conclusion: PacketReader is sufficient for a file list, but not sufficient for local file resolution. ### MsgLib file-record evidence Validated copied-DB table metadata: - `TD_ReceiveFileRecord`: `ReceiveMsgGuid`, `FileName`, `FileSize`, `FilePath`, `SourceID`, `SourceName`, `FileType`, `SendPersonJid`, `SendPersonName`, `SendTime`. - `TD_SendFileRecord`: `SendMsgGuid`, `FileName`, `FileSize`, `FilePath`, `SourceID`, `SourceName`, `FileType`, `ReceivePersonJid`, `ReceivePersonName`, `ReceiveTime`. Current sidecar behavior in `native/MsgLibReadSidecar/Program.cs`: - Joins `TD_ReceiveFileRecord` by `ReceiveMsgGuid`. - Returns `file_id`, `file_name`, `size_bytes`, and an empty `download_ref`. - Uses `SafeFileName(...)` for file names. - Does not return `FilePath`; smoke output keeps `file_paths_returned=false`. Conclusion: MsgLib can provide stronger received-file metadata than PacketReader, but it still does not prove a cache-file path or client download operation. ### Cache path-shape evidence Ignored archive metadata shows: ```json { "importal_hash_shape_files": 11, "hash_dir_length_set": [32], "extension_counts": { ".doc": 2, ".docx": 3, ".jpg": 2, ".pdf": 2, ".xlsx": 2 }, "raw_paths_printed": false } ``` Conclusion: local cache files exist under a stable hash-directory shape, but no committed evidence maps a message id, `ReceiveMsgGuid`, `SourceID`, filename, or size to a specific cache file. ## Candidate mappings | Candidate | Evidence strength | Status | | --- | --- | --- | | `PacketReader message_id + body filename` -> file list row | Medium for list mode. | Already implemented for metadata listing. | | `TD_ReceiveFileRecord.ReceiveMsgGuid` -> MsgLib message id | Strong for DB attachment-to-message relation. | Usable for metadata enrichment after source reconciliation. | | `TD_ReceiveFileRecord.FileName + FileSize` -> cache file filename/size | Medium if a local diagnostic proves unique matches. | Not validated yet. | | `TD_ReceiveFileRecord.SourceID` -> cache hash directory or download token | Unknown. | Needs focused diagnostic; do not use as `download_ref` yet. | | `TD_ReceiveFileRecord.FilePath` -> local file path | Potentially direct but sensitive. | Do not return or commit; may only be used in a local diagnostic that prints counts/booleans, not values. | | UI/client operation -> trigger download | Unknown. | Later fallback if cache mapping fails. | ## Decision Do not implement R4 download mode yet. R3 chooses option 3 from the acceptance gate: **additional evidence request**, concretely a new R3b local-only cache mapping diagnostic. Reason: - There is enough evidence to list received files. - There is enough evidence to identify DB attachment records. - There is not enough evidence to safely copy or download the file because no validated mapping exists between message/file metadata and a local cache object. ## R3b diagnostic requirements The next node should add or run a local-only diagnostic that outputs only sanitized evidence: - Inputs: - copied `MsgLib.db` and bundled SQLite DLL env already used by MsgLib verification; - operator-local cache root or ignored archive-list source. - Allowed output: - count of `TD_ReceiveFileRecord` rows inspected; - count of rows with filename, size, source id, and receive message id present; - cache candidate counts by extension and hash-directory shape; - match counts by safe strategy: filename-only, filename+size, source-id-shape, message-id-linked; - booleans: `raw_paths_printed=false`, `file_contents_read=false`, `file_paths_returned=false`. - Not allowed output: - local paths; - raw DB rows; - real message bodies; - attachment contents; - copied file names if they are not explicitly redacted. ## Next implementation node Next node: **R3b file cache mapping diagnostic**. Possible R3b outcomes: 1. If filename+size or source-id mapping is unique and repeatable, proceed to R4 cache-file resolver/download implementation. 2. If cache mapping is ambiguous but the client exposes a safe UI/API download action, proceed to a UI/client download connector node. 3. If neither mapping is proven, request additional operator evidence and keep `isphere_receive_files` in list-only mode.