Files
isphere-ai-bridge/docs/source-discovery/2026-07-10-msglib-message-source-precheck.md
2026-07-10 08:30:46 +08:00

117 lines
8.3 KiB
Markdown

# MsgLib.db message-table source precheck
Date: 2026-07-10
## Question
Can copied `MsgLib.db` message tables become a future DB-backed source for `isphere_receive_messages`, and what is the safest next implementation slice?
## Evidence used
Committed evidence:
- `docs/source-discovery/2026-07-10-msglib-readonly-schema-extraction.md`
- `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md`
- `docs/msglib-read-sidecar-contract.md`
Ignored local evidence consulted in this loop:
- C26 schema-only x86 JSON under `runs/offline-evidence-intake/.../metadata/`.
Scope of this loop:
- Read table names, column names, schema SQL, and row counts only.
- Do not read or print message row values.
- Do not read or print message bodies, file paths, contact/group values, or raw rows.
- Do not add code that exposes DB message rows yet.
## Candidate DB tables
| Table | Safe evidence | Candidate role | C35 decision |
| --- | --- | --- | --- |
| `tblPersonMsg` | Present in all opened copied DBs; count-only evidence shows thousands of rows in inspected copies | direct/person-to-person messages | strong candidate for future DB-backed direct messages |
| `tblMsgGroupPersonMsg` | Present in all opened copied DBs; count-only evidence shows hundreds/thousands of rows in inspected copies | group/discussion messages | strong candidate for future DB-backed group messages |
| `TD_SystemMessageRecord` | Present with count-only evidence | system/auth/notification messages | secondary candidate after direct/group message flow |
| `TD_GroupReceiptMessage` | Present in richer schema | per-person group receipt state by `MsgGuid`/`PersonID` | useful join candidate for receipt enrichment |
| `TD_ReceiveFileRecord` | Present with message-guid and file metadata columns | received-file metadata linked by message guid | useful for attachment metadata, but `FilePath` must not be exposed by default |
| `TD_SendFileRecord` | Present with message-guid and file metadata columns | sent-file metadata linked by message guid | later outbound/file-source evidence only |
| `tblRecent` | Maintained by triggers from person/group message inserts | recent conversation index | useful for conversation ordering/display, not primary message body source |
## Field mapping hypothesis
### Direct messages: `tblPersonMsg`
| MCP receive field | Candidate DB column | Confidence | Notes |
| --- | --- | --- | --- |
| `message_id` / `id` | `Id` | high | primary key in schema |
| `conversation_type` | constant `direct` | high | table is direct/person message source |
| `conversation_id` | `ObjPersonId`, fallback normalized `SndPersonId|RecvPersonId` | medium | trigger writes `ObjPersonId` into `tblRecent.PersonId`; need row-level validation before finalizing |
| `sender_id` | `SndPersonId` | high | schema names sender identity explicitly |
| `sender_name` | `SndPerson` or optional display-entity map | high | value exposure should follow existing display-name policy |
| `receiver_id` | `RecvPersonId` | high | schema names receiver identity explicitly |
| `text` / `content_text` | `MsgText` or `MessageBody` | medium | body columns exist, but C35 does not read values; future body read needs strict limit/audit contract |
| `content_type` | `MsgType` | medium | values not inspected in C35 |
| `timestamp` / `created_at` | `ActionTime` | high | direct message timestamp column |
| `read` | `MsgReadState` | medium | boolean-like column; semantics need row-level validation |
| `receipt_id` / receipt state | `IsReceipt`, `MsgReceiptState`, `ReceiptTime`, `MsgRecaptionState` | low/medium | schema supports state but not the same as PacketReader receipt id |
| `subject` | none | low | direct DB table does not expose PacketReader `<subject>` equivalent in schema |
| `attachments` | join `TD_ReceiveFileRecord.ReceiveMsgGuid = tblPersonMsg.Id` | medium | `FilePath` is sensitive and should remain hidden unless a separate download/cache contract exists |
### Group messages: `tblMsgGroupPersonMsg`
| MCP receive field | Candidate DB column | Confidence | Notes |
| --- | --- | --- | --- |
| `message_id` / `id` | `Id` | high | primary key in schema |
| `conversation_type` | constant `group` | high | table is group/discussion message source |
| `conversation_id` | `MsgGroupId` | high | group id column and recent trigger key |
| `conversation.display_name` | `MsgGroupName` or `SessionTitle`, plus optional display-entity map | high | use existing MsgLib display source priority where possible |
| `sender_id` | `SndPersonId` | high | schema names sender identity explicitly |
| `sender_name` | `SndPerson` or optional display-entity map | high | value exposure should follow existing display-name policy |
| `receiver_id` | `MsgGroupId` | medium | group id is the receive target in MCP contract terms |
| `text` / `content_text` | `MsgText` or `MessageBody` | medium | body columns exist, but C35 does not read values; future body read needs strict limit/audit contract |
| `content_type` | `MsgType`, possibly `GroupType` for conversation class | medium | values not inspected in C35 |
| `timestamp` / `created_at` | `MsgTime` | high | group message timestamp column |
| `read` | `MsgReadState` | medium | boolean-like column; semantics need row-level validation |
| `receipt_id` / receipt state | `IsReceipt`, `MsgReceiptState`, `MsgRecaptionState`; optional join `TD_GroupReceiptMessage.MsgGuid` | low/medium | DB state exists but PacketReader receipt id equivalence is unproven |
| `subject` | none | low | group DB table does not expose PacketReader `<subject>` equivalent in schema |
| `attachments` | join `TD_ReceiveFileRecord.ReceiveMsgGuid = tblMsgGroupPersonMsg.Id` | medium | hide `FilePath`; list only safe file metadata until cache/download mapping exists |
### System messages: `TD_SystemMessageRecord`
| MCP receive field | Candidate DB column | Confidence | Notes |
| --- | --- | --- | --- |
| `message_id` / `id` | `MsgGuid` | high | primary key in schema |
| `conversation_type` | constant `system` | medium | source is system/auth record table |
| `sender_id` / `sender_name` | `SendPersonJid` / `SendPersonName` | medium | values not inspected in C35 |
| `text` / `content_text` | `MsgText` | medium | body-like column exists; future body read requires a strict contract |
| `subject` | `MsgTitle` | medium | title-like field exists |
| `timestamp` | `MsgTime` | high | system message timestamp column |
| `read` | `MsgReadState` | medium | bit-like field exists |
## Important gaps
1. `MsgText` and `MessageBody` are body columns. C35 confirms only that they exist, not whether their values are safe, decoded, complete, or aligned with PacketReader bodies.
2. `MsgLib.db` may not contain every received message. Earlier SaveToDB evidence noted some messages may not be stored to the small DB, so DB-backed receive should not replace PacketReader as the only source until reconciliation is tested.
3. `subject` is strong in PacketReader XML but not clearly represented in `tblPersonMsg`/`tblMsgGroupPersonMsg` schema.
4. Receipt semantics are not identical yet. DB columns show receipt/read state, but C35 does not prove the PacketReader receipt id mapping.
5. Attachment metadata can likely join through `TD_ReceiveFileRecord`, but `FilePath` is sensitive and should remain hidden by default.
6. Row ordering and incremental pagination need an explicit timestamp/id strategy before DB-backed listing is exposed.
## Decision
`MsgLib.db` is a strong future source for DB-backed `isphere_receive_messages`, but it should not jump directly to body-returning message listing.
Recommended next implementation slice:
1. Add a metadata-only sidecar operation for message-source readiness, for example `message_sources`.
2. Return table availability, required/present columns, count-only summaries, and the committed field-map shape.
3. Wire a Go wrapper and verification script for this metadata-only operation.
4. Keep message body values, raw rows, local file paths, and DB row dumps out of scope until the metadata operation is verified.
## Proposed C36 acceptance gate
- Default sidecar smoke still passes with `self_check` only.
- Evidence-backed sidecar smoke prints only `message_source_count`, table names, required/present columns, and row counts.
- No `MsgText`, `MessageBody`, `FilePath`, entity values, raw rows, sends, downloads, hooks, injection, or DB writes.
- Capability matrix records whether C37 may safely design a bounded DB-backed receive source.