Drop unused agent_messages.read_at column via migration v49 (M1)
The `agent_messages.read_at` column has had no production writer since v12 moved read tracking into the per-viewer `agent_message_reads` receipts table. It survived anyway, carrying a NULL through every SELECT list and begging the next maintainer to accidentally read stale data from it. - v49 migration: `ALTER TABLE agent_messages DROP COLUMN read_at` (idempotent: skips if absent). - messages.ts: SELECTs no longer fetch the column; per-viewer `readAt` is computed from `agent_message_reads` as before, with `null` for call-sites that have no viewer context (getAgentMessage / searchMessages / listAgentInboxUnread). - runtime-bridge.ts / runtime-message-injector.ts: comments referencing the dropped column updated to name the read-receipts table instead.
This commit is contained in:
1 parent
dade5eb333
commit
d7e267031f
6 files changed
+90
-36
No files matched your search
@@ -562,16 +562,16 @@ export class RuntimeBridge {
|
||||
// as plain user turns in its context.
|
||||
//
|
||||
// Replay safety lives entirely on the `agent_message_projections`
|
||||
// ledger. We deliberately do NOT touch `agent_messages.read_at`
|
||||
// here even though that column exists: "we put the message into
|
||||
// the agent's transcript" and "the agent has acknowledged the
|
||||
// message" are two different facts, and welding them onto one
|
||||
// column made every projected message immediately invisible to
|
||||
// the agent's `?unreadOnly=true` API call. The agent then read
|
||||
// its IC prompt ("respond to ALL unread messages"), called the
|
||||
// API, got an empty list, and posted a status comment instead of
|
||||
// replying. The explicit POST /messages/{id}/read is now the
|
||||
// sole signal that flips `read_at`.
|
||||
// ledger. "We put the message into the agent's transcript" and
|
||||
// "the agent has acknowledged the message" are two different
|
||||
// facts, tracked in two different tables: projections are append-
|
||||
// only on dispatch, while reads are inserted into
|
||||
// `agent_message_reads` only when the agent POSTs
|
||||
// /messages/{id}/read. Conflating the two (as an earlier build
|
||||
// that wrote to `agent_messages.read_at` at projection time did)
|
||||
// made every projected message immediately invisible to
|
||||
// `?unreadOnly=true`, so agents posted status comments instead of
|
||||
// replies. The explicit read endpoint is the sole signal.
|
||||
const store = this.getOrCreateStore(payload.taskSessionId);
|
||||
const inboxRecords = this.deps.db.listAgentInboxUnread(payload.companyId, payload.agentId);
|
||||
if (inboxRecords.length > 0) {
|
||||
|
||||
@@ -134,10 +134,10 @@ export class RuntimeMessageInjector {
|
||||
* the recipient is woken so the next `prepareRun` picks the message
|
||||
* up through the regular inbox projection.
|
||||
*
|
||||
* `read_at` is intentionally NOT touched here: "the worker queued
|
||||
* this message onto the agent" is not "the agent replied". The
|
||||
* agent flips `read_at` itself by POSTing /messages/{id}/read once
|
||||
* it has actually processed the row.
|
||||
* The read receipt is intentionally NOT written here: "the worker
|
||||
* queued this message onto the agent" is not "the agent replied".
|
||||
* The agent inserts into `agent_message_reads` itself by POSTing
|
||||
* /messages/{id}/read once it has actually processed the row.
|
||||
*/
|
||||
handleSteerAck(correlationId: string, accepted: boolean): void {
|
||||
this.resolvePending(correlationId, accepted, "worker_ack");
|
||||
|
||||
Reference in new issue
Block a user