diff --git a/docs/plans/2026-07-20-localdb-adoption-phase2.md b/docs/plans/2026-07-20-localdb-adoption-phase2.md index 943bcc48..5188b0e0 100644 --- a/docs/plans/2026-07-20-localdb-adoption-phase2.md +++ b/docs/plans/2026-07-20-localdb-adoption-phase2.md @@ -56,6 +56,29 @@ auth already in place, no in-memory SQLite in tests, cp-triplet-only rig inspect (**STOP condition:** a BLOB payload column cannot be registered — it must become base64 TEXT in the new schema, and the recon must size the largest realistic payload against the 171 KB-ish chunk guidance; alarm events are small JSON, so expect this to be fine, but verify). + + > **PRE-ANSWERED 2026-07-21 (verified against `master` `d218282c`) — the STOP condition does NOT + > fire.** Re-verify cheaply during recon, but do not expect a surprise: + > + > - **Executed DDL:** `SqliteStoreAndForwardSink.cs:657-667`. It matches the class doc-comment at + > `:17-26` exactly — no drift between the documented and executed schema. + > - **No BLOB.** All 8 columns are TEXT/INTEGER; the payload column is **`PayloadJson TEXT NOT + > NULL`**. So no base64 conversion is needed and the chunk-size sizing is moot. + > - **Payload is small and bounded by shape.** `PayloadJson` is a serialized + > `AlarmHistorianEvent` — 10 scalar fields (`AlarmId`, `EquipmentPath`, `AlarmName`, + > `AlarmTypeName`, `Severity`, `EventKind`, `Message`, `User`, `Comment?`, `TimestampUtc`). + > No collections, no nesting. Realistic worst case is low single-digit KB (operator `Comment` + > is the only unbounded-ish field), far under the 171 KB chunk guidance. + > - **PK IS autoincrement** — `RowId INTEGER PRIMARY KEY AUTOINCREMENT`. This confirms the + > plan's own prediction: LocalDb cannot replicate an autoincrement key, so the migrator + > **must** mint deterministic `mig-{node}-{legacyId}` ids, and the new table needs a TEXT + > GUID PK as already specified in the Architecture note. + > - **One index to carry across:** `IX_Queue_Drain ON Queue (DeadLettered, RowId)` (`:667`) — + > the drain's covering index. The `alarm_sf_events` equivalent wants the same shape over + > (dead-lettered flag, insertion order) so the drain query stays index-covered. + > - **Legacy column list for the migrator's `pragma_table_info` intersection check:** + > `RowId, AlarmId, EnqueuedUtc, PayloadJson, AttemptCount, LastAttemptUtc, LastError, + > DeadLettered`. 2. The public seam: the interface the drain worker and producers use (e.g. `IAlarmHistorianSink` / enqueue+dequeue+markDelivered+deadLetter methods), so the rewire can keep it byte-compatible. 3. Semantics to preserve: `Capacity` (1,000,000) enforcement, `MaxAttempts` (10), dead-letter