feat(pending-updates): short-circuit an unchanged fleet on a DB rowversion watermark (#62)
Owner decision (b), 2026-11-09. PendingUpdatesEvaluator re-flattened every deployed instance on each cache-TTL expiry even when nothing had changed. - Migration AddConfigGraphRowVersions: a non-concurrency rowversion column + index on the 18 configuration tables the evaluation reads (Templates + 5 member tables, Instances + 4 override/binding tables, DataConnections, DeployedConfigSnapshots, Sites, SharedScripts, ExternalSystemDefinitions, ExternalSystemMethods, DatabaseConnectionDefinitions). SQL Server only in the model; SQLite test contexts are untouched. Script: docs/plans/sql/AddConfigGraphRowVersions.sql. Joins the coordinated central-pair migration window (#107 item 4). - IConfigGraphWatermarkReader / ConfigGraphWatermarkReader: ONE query of MAX(RowVersion) + COUNT_BIG(*) per table (count catches deletes, which raise no rowversion). rowversion is engine-bumped for any writer, so a peer central node's edit moves it — not the per-process watermark MG-3 removed. - The secret store (outside the DB) gets its own stamp: SHA-256 over ListAsync(includeDeleted: true) metadata. - Evaluator re-serves the last CLEAN snapshot while watermark + secret stamp are unchanged; every PendingUpdatesFullEvaluationEvery'th (default 10, validated >= 1, 1 = off) is full regardless — the safety net for a same-KEK re-wrap or an input table missing from the set. Always full when the token is unavailable/unreadable, after an evaluation that could not compute a site's artifact hash, on Re-check, and after a deploy completion. It only re-serves a real earlier answer, never manufactures one. Tests: SQL Server (real migrated DB) — token stable without writes, moves for a peer-connection INSERT/UPDATE and a non-max DELETE, moves for a local EF write, a detached Update still saves (not a concurrency token), and a guard that every table the evaluator's repository reads touch is covered. Evaluator — reuse without flatten (re-served answer still shows the stale instance), watermark move, 4 secret changes, every-Nth, 5 no-token modes, unclean evaluation not reused, cache Re-check and deploy completion force full. Mutation-proven: token compare, clean check, cache force flag, row count, and an uncovered read each turn tests red. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -569,9 +569,23 @@ at once; one run through the peer central clears within the TTL. See
|
||||
the Sites-page badge/re-check UI and the rail-footer indicator
|
||||
(Component-CentralUI.md → *Site & Data Connection Management* and *Technology*).
|
||||
|
||||
Not in scope for this slice (deferred-work register rows 124–125): a
|
||||
template-graph-watermark short-circuit so an unchanged fleet costs no re-flatten
|
||||
per TTL, and a `deploy` CLI / Health-dashboard KPI surface for the counts.
|
||||
**Unchanged-fleet short-circuit (Gitea #62, register row 124).** Inside a flight the
|
||||
evaluator first reads a change token — `IConfigGraphWatermarkReader` (one query of
|
||||
`MAX(RowVersion)` + `COUNT_BIG(*)` over the 18 tables the evaluation reads, the
|
||||
`rowversion` columns added by migration `AddConfigGraphRowVersions`; the covered set is
|
||||
`ConfigGraphRowVersions.EntityTypes`) plus a SHA-256 stamp over the secret store's
|
||||
metadata listing — and re-serves the last clean snapshot when it is unchanged.
|
||||
`rowversion` is bumped by the engine for any writer, so an edit through the peer central
|
||||
node is detected (the per-process template-graph watermark would not be — arch-review
|
||||
2026-09-09 MG-3). Every `ScadaBridge:DeploymentManager:PendingUpdatesFullEvaluationEvery`th
|
||||
evaluation (default 10, validated ≥ 1; 1 disables the short-circuit) is full regardless,
|
||||
the safety net for a same-KEK secret re-wrap and for an input table missing from the set.
|
||||
A *Re-check* (`forceRefresh`), a deploy completion, an unavailable watermark or secret
|
||||
listing, and an evaluation that could not compute a site's artifact hash all force a full
|
||||
evaluation. Only a real earlier answer is ever re-served.
|
||||
|
||||
Not in scope for this slice (deferred-work register row 125): a `deploy` CLI /
|
||||
Health-dashboard KPI surface for the counts.
|
||||
|
||||
## Instance Lifecycle Commands
|
||||
|
||||
|
||||
Reference in New Issue
Block a user