124de57e6f
Answers Task 0 with file:line citations against master 2e46d054.
The STOP condition does not fire: PayloadJson is TEXT, no BLOB column, so
alarm_sf_events can be registered for replication as-is.
Two findings reshape the plan's assumptions:
- The drain worker is not a hosted service or an actor. It is a
self-rescheduling Timer owned by the sink and started from the DI
factory, so the Primary gate has to live inside DrainOnceAsync as an
injected delegate -- Core.AlarmHistorian cannot reference
PrimaryGatePolicy, which lives in Runtime.
- A Primary gate already exists on the enqueue side
(HistorianAdapterActor.ShouldHistorize), using a different policy than
the one the plan specifies for the drain. That gate is why today's
ungated drain is safe: the Secondary never enqueues, so its queue is
empty. Replicating the table breaks that invariant, which makes the
drain gate mandatory in the same commit rather than a refinement.
Records deviations D-1 (deterministic content-hash ids so a boot-window
double-enqueue converges instead of duplicating), D-2 (gate denial must be
observable or a snapshot identity mismatch silently stops alarm history),
D-3 (Tasks 2+3 land as one commit) and D-4 (the rig will dead-letter in
~5 minutes at MaxAttempts 10 with no gateway).
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
79 lines
2.2 KiB
JSON
79 lines
2.2 KiB
JSON
{
|
|
"planPath": "docs/plans/2026-07-20-localdb-adoption-phase2.md",
|
|
"tasks": [
|
|
{
|
|
"id": 0,
|
|
"subject": "Task 0: Recon \u2014 sink schema, seam, drain lifecycle, role-view bridge (STOP conditions)",
|
|
"status": "completed",
|
|
"note": "STOP condition does NOT fire (no BLOB; PayloadJson TEXT). Recon doc: docs/plans/2026-07-20-localdb-phase2-recon.md. Key finding: the drain worker is an internal Timer inside the sink (not a hosted service/actor), so the gate is a Func<bool> ctor param; and HistorianAdapterActor already primary-gates ENQUEUE with a different policy (ShouldHistorize) - which is why today's ungated drain is safe and why replication breaks it. Deviations D-1..D-4 recorded."
|
|
},
|
|
{
|
|
"id": 1,
|
|
"subject": "Task 1: alarm_sf_events schema + registration (+ exact-set pin update)",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"id": 2,
|
|
"subject": "Task 2: Rewire sink onto ILocalDb + delete bespoke file management (cutover 1/2)",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
1
|
|
]
|
|
},
|
|
{
|
|
"id": 3,
|
|
"subject": "Task 3: Primary-gated drain via PrimaryGatePolicy (cutover 2/2 \u2014 may co-commit with Task 2)",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
2
|
|
]
|
|
},
|
|
{
|
|
"id": 4,
|
|
"subject": "Task 4: One-time alarm-historian.db legacy migrator",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
3
|
|
]
|
|
},
|
|
{
|
|
"id": 5,
|
|
"subject": "Task 5: Convergence + failover scenarios in the pair harness (+ positive control)",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
3
|
|
]
|
|
},
|
|
{
|
|
"id": 6,
|
|
"subject": "Task 6: Rig config + docs",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
3
|
|
]
|
|
},
|
|
{
|
|
"id": 7,
|
|
"subject": "Task 7: DoD sweep (offline) \u2014 STOP and report after this",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
4,
|
|
5,
|
|
6
|
|
]
|
|
},
|
|
{
|
|
"id": 8,
|
|
"subject": "Task 8: Live gate on the docker-dev rig (needs explicit user go-ahead)",
|
|
"status": "pending",
|
|
"blockedBy": [
|
|
7
|
|
]
|
|
}
|
|
],
|
|
"lastUpdated": "2026-07-21T00:00:00Z"
|
|
}
|