From f2049a31d0a64a69a995f72bed9d159c10f24c4c Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 21 Jul 2026 03:46:56 -0400 Subject: [PATCH] =?UTF-8?q?docs(localdb-phase2):=20pre-answer=20Task=200's?= =?UTF-8?q?=20STOP=20condition=20=E2=80=94=20it=20does=20not=20fire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2's recon carries a STOP condition: a BLOB payload column in the legacy alarm store-and-forward table could not be registered for replication and would have to become base64 TEXT, sized against the chunk guidance. Resolved ahead of execution so the answer survives into the Phase 2 session: - No BLOB. All 8 columns are TEXT/INTEGER; the payload is PayloadJson TEXT NOT NULL. No base64 conversion, no chunk sizing needed. - The executed DDL (SqliteStoreAndForwardSink.cs:657-667) matches the class doc-comment at :17-26 exactly — checked because a doc comment is not evidence. - Payload is bounded by shape: a serialized AlarmHistorianEvent is 10 scalar fields, no collections or nesting, so realistic worst case is low single-digit KB against a 171 KB guidance. - The PK IS autoincrement, confirming the plan's prediction that the migrator must mint deterministic mig-{node}-{legacyId} ids and the new table needs a TEXT GUID PK. - Also captured for reuse: the drain's covering index (DeadLettered, RowId), and the exact legacy column list the migrator's pragma_table_info intersection check compares against. Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW --- .../2026-07-20-localdb-adoption-phase2.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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