@remit/drizzle-service 0.0.76 → 0.0.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/drizzle-service",
3
- "version": "0.0.76",
3
+ "version": "0.0.77",
4
4
  "description": "Drizzle ORM service over SQLite",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -470,7 +470,7 @@ export const describeRepairContract = (
470
470
  "ahead:",
471
471
  "fan-out:",
472
472
  "orphans:",
473
- "not-yet-classified:",
473
+ "uncategorized:",
474
474
  "divergent per mailbox:",
475
475
  "category tally:",
476
476
  ]) {
@@ -53,10 +53,9 @@
53
53
  * `message.category` is still `uncategorized`, so the pending exclusion
54
54
  * above refuses the row outright.
55
55
  *
56
- * Only the fourth is interesting, and it is not impossible. It is unreachable
57
- * through `backfillClassification`, which returns early once the category is
58
- * decided. It is reachable through the primary path, which is re-enterable: the
59
- * skip guard is `if (message.bodyStorageKey && !force)` (`body-sync.ts`), and
56
+ * Only the fourth is interesting, and it is not impossible. It is reachable
57
+ * through the one path that classifies, which is re-enterable: the skip guard
58
+ * is `if (hasStoredBody(message.bodyStorageKey) && !force)` (`body-sync.ts`), and
60
59
  * `force` is a live event flag — the read-miss re-arm cue, resolved in the
61
60
  * imap-worker's `sync-message-body.ts`. A forced re-fetch re-runs
62
61
  * `classifyByHeaders` over the same bytes, so it normally rewrites the value it
@@ -351,7 +350,7 @@ export const formatCheckReport = (
351
350
  ` ahead: ${report.ahead} ${plural(report.ahead)} classified against a pending message — after #326 body-sync writes the row before the message, so this is a classification in flight. Not repaired: pushing it back to pending would undo a correct classification and serve Unclassified for mail that is already classified. Expected non-zero on a live instance mid-sync, zero on a quiescent one.`,
352
351
  `fan-out: ${report.fanOutMessages} messages holding ${report.fanOutRows} thread_message rows — the multi-row shape #326 hardens against. Expected zero: deriveMessageId and deriveThreadMessageId are both mailbox-independent, so a message in two mailboxes collapses to one row, and the reachable case is thread-root drift.`,
353
352
  `orphans: ${report.orphanRows} ${plural(report.orphanRows)} with no message row — not repaired, nothing to copy. Expected zero.`,
354
- `not-yet-classified: ${report.notYetClassified} ${plural(report.notYetClassified)} pending against a pending message — not classified yet. Not a defect, not touched by the repair, and unchanged by it. Expected non-zero on a live instance.`,
353
+ `uncategorized: ${report.notYetClassified} ${plural(report.notYetClassified)} uncategorized against an uncategorized message — the row agrees with its message, so there is nothing to repair and this figure is untouched by the repair. It is NOT the same as "not classified yet": it mixes mail the classifier has not reached with mail it reached and had nothing to say about. Only \`message.classification_state\` separates them (\`SELECT classification_state, count(*) FROM message WHERE category = 'uncategorized' GROUP BY 1\`), and a large \`NotExamined\` count is the cohort worth acting on. Expected non-zero on a live instance.`,
355
354
  `divergent per mailbox: ${
356
355
  report.divergentByMailbox.length === 0
357
356
  ? "none"
@@ -59,6 +59,7 @@ function toMessageItem(row: typeof messageTable.$inferSelect): MessageItem {
59
59
  status: row.status,
60
60
  syncStatus: row.syncStatus,
61
61
  category: row.category,
62
+ classificationState: row.classificationState,
62
63
  authenticityVerdict: row.authenticityVerdict,
63
64
  hasListUnsubscribe: row.hasListUnsubscribe,
64
65
  movedByRemit: row.movedByRemit,
@@ -185,6 +186,8 @@ export class DrizzleMessageRepository implements IMessageRepository {
185
186
  status: input.status ?? ("active" as const),
186
187
  syncStatus: input.syncStatus ?? ("pending" as const),
187
188
  category: input.category ?? ("uncategorized" as const),
189
+ classificationState:
190
+ input.classificationState ?? ("NotExamined" as const),
188
191
  authenticityVerdict:
189
192
  input.authenticityVerdict ?? ("NotEvaluated" as const),
190
193
  hasListUnsubscribe: input.hasListUnsubscribe ?? false,
@@ -368,6 +371,9 @@ export class DrizzleMessageRepository implements IMessageRepository {
368
371
  ? { syncStatus: input.syncStatus }
369
372
  : {}),
370
373
  ...(input.category !== undefined ? { category: input.category } : {}),
374
+ ...(input.classificationState !== undefined
375
+ ? { classificationState: input.classificationState }
376
+ : {}),
371
377
  ...(input.authenticityVerdict !== undefined
372
378
  ? { authenticityVerdict: input.authenticityVerdict }
373
379
  : {}),