1e02661598
The two items deferment.md §0.1 named as the remaining untracked engineering. adminui-followups (19 pending / 0 completed) — CLOSED by the overlap audit the plan itself asks for first, with no code written. All 19 tasks are shipped, superseded by v3, or moot. WS1's premise had also expired: it assumed driver-embedded tag lists in DriverConfig are the runtime source of truth, which v3 ended (the artifact populates RawTags). Its capability shipped in the v3 shape — TagConfigEditorMap + DeviceFormMap, both verified reachable from RawTagModal/DeviceModal rather than merely present. Live gates on docker-dev (image rebuilt: the rig was running a build 3 h older than the last code commit; parity asserted per container plus a positive check that the symbols under test are in the shipped DLLs): - R2-03 T11 PASSED — build 0 errors, Runtime.Tests 555/555, RoslynVirtualTagEvaluator 20/20. - R2-03 T12 PASSED — VT 42 -> 0x80020000 -> 42, staged WITHOUT a deployment (a Modbus register flipped on the fixture) so the VT child survived; a deploy-driven trip creates a fresh child with no last value, which is correct-by-design and masked the result twice. P7 confirmed: two byte-identical redeploys, zero disturbance. - driver-reconfigure Task 3 PASSED — a faulted driver adopted a corrected config and connected with the node's startedAt unchanged and RestartCount=0. - R2-10 T10 still OPEN, but the recorded cause was wrong. Not ConnectionBackoff throttling (the breaker opens on 2 failures / 30 s): the dead-endpoint failure mode never enters the resilience pipeline. IDriver.InitializeAsync is not invoker-wrapped (DriverInstanceActor.cs:707) and ModbusDriver swallows per-tag failures in BOTH directions, so even the plan's fallback trigger cannot work. Live-proven: a driver timing out every read against a blackhole reported ConsecutiveFailures=0 while the panel read "All targets healthy." Finding from T12: the Bad publish's documented "carrying the last-known value" is unobservable by any client — subscription and a raw Read service call both return NULL. The actor is correct; every existing failure assertion checked StatusCode alone, so the value half was asserted nowhere. Adds VirtualTagActorTests.The_Bad_result_carries_the_last_known_value, which proves the actor emits it. The documentation is what overstates.
106 lines
5.7 KiB
JSON
106 lines
5.7 KiB
JSON
{
|
|
"planPath": "archreview/plans/R2-03-vt-failure-quality-plan.md",
|
|
"tasks": [
|
|
{
|
|
"id": "R2-03-T1",
|
|
"subject": "S13 stale-Good repro test at host level (RED \u2014 must fail on f6eaa267): fail-after-success evaluator, publish probe sees Good then expects Bad AttributeValueUpdate",
|
|
"status": "completed",
|
|
"blockedBy": []
|
|
},
|
|
{
|
|
"id": "R2-03-T2",
|
|
"subject": "Add OpcUaQuality Quality (default Good) to VirtualTagActor.EvaluationResult; bridge passes result.Quality into AttributeValueUpdate; historize maps Bad to 0x80020000u BadInternalError (RED bridge tests then GREEN)",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T1"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T3",
|
|
"subject": "VirtualTagActor failure/throw publishes Bad EvaluationResult once per transition, gated on all dependencyRefs arrived; recovery bypasses value-dedup; update Evaluator_failure_publishes_ScriptLogEntry_warning expectation (turns T1 green)",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T2"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T4",
|
|
"subject": "S13 transition-semantics unit guards: second consecutive failure publishes nothing; same-value recovery republishes Good; evaluator-threw path also degrades",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T3"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T5",
|
|
"subject": "S13 cold-start suppression guards: missing-dep failure publishes no Bad; failure after all deps arrived publishes Bad (inputs-ready gate)",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T3"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T6",
|
|
"subject": "S12 sequential pin: Evaluate_after_ClearCompiledScripts_recompiles_and_succeeds (green baseline the T8 retry-loop restructure must not regress)",
|
|
"status": "completed",
|
|
"blockedBy": []
|
|
},
|
|
{
|
|
"id": "R2-03-T7",
|
|
"subject": "S12 concurrent stress repro (RED): 300 compiled evaluations racing ClearCompiledScripts, WaitAsync-bounded, assert zero disposed-reason failures",
|
|
"status": "completed",
|
|
"blockedBy": []
|
|
},
|
|
{
|
|
"id": "R2-03-T8",
|
|
"subject": "S12 fix: retry-once on ObjectDisposedException in RoslynVirtualTagEvaluator.Evaluate (re-fetch via GetOrCompile; no retry when _disposed or second hit); update xmldoc (turns T7 green)",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T6",
|
|
"R2-03-T7"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T9",
|
|
"subject": "P7 wiring-guard rewrite (RED): ApplyVirtualTags clears the compile cache only when the expression set changes \u2014 identical redeploy must NOT clear; expression edit must; shared-expression removal must not",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T3"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T10",
|
|
"subject": "P7 fix: gate the OnApply ClearCompiledScripts on HashSet.SetEquals of desired vs _planByVtag expression sets (ordinal), with explanatory comment (turns T9 green)",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T9"
|
|
]
|
|
},
|
|
{
|
|
"id": "R2-03-T11",
|
|
"subject": "Full-suite sweep (Runtime.Tests whole project + RoslynVirtualTagEvaluatorTests + solution build) and STATUS.md / tasks.json bookkeeping",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T4",
|
|
"R2-03-T5",
|
|
"R2-03-T8",
|
|
"R2-03-T10"
|
|
],
|
|
"note": "integration/full sweep; serialized heavy pass (build clean, Runtime.Tests 372/372, RoslynVirtualTagEvaluatorTests 20/20 verified locally; whole-solution/cross-suite sweep deferred per controller memory constraint)",
|
|
"openNote": "STILL OPEN \u2014 live-blocked on a data-less rig: every materialised node reads Bad_WaitingForInitialData because no driver data flows, so a VT cannot be staged Good->Bad. Needs a reachable driver fixture feeding the VT. Unit-verified meanwhile.",
|
|
"closureNote": "PASSED 2026-08-07. Solution build 0 errors; Runtime.Tests 555/555 (3 deliberate EquipmentDeviceBindingRetired skips); RoslynVirtualTagEvaluatorTests 20/20. Note the suite lives in Host.IntegrationTests, which a solution-wide --filter does not reach. Evidence: docs/plans/2026-08-07-adminui-followups-and-live-gates.md \u00a72."
|
|
},
|
|
{
|
|
"id": "R2-03-T12",
|
|
"subject": "Live-/run gate on docker-dev (rebuild BOTH centrals): author working VT, break it, Client.CLI read shows StatusCode Bad with last value, fix and read Good; P7 no-recompile spot-check on identical redeploy",
|
|
"status": "completed",
|
|
"blockedBy": [
|
|
"R2-03-T11"
|
|
],
|
|
"note": "docker-dev live-/run; serial live pass",
|
|
"openNote": "STILL OPEN \u2014 same blocker as T11. Confirmed still open 2026-07-27 (deferment.md \u00a78.5).",
|
|
"closureNote": "PASSED 2026-08-07 on docker-dev (both centrals rebuilt; image parity asserted per container). Good(42) -> Bad(0x80020000 BadInternalError) -> Good(42), staged WITHOUT a deployment by flipping a Modbus holding register on the fixture, so the VT child survived the transition (a deploy-driven trip creates a fresh child with no last value \u2014 correct per the inputs-ready gate). P7: two byte-identical redeploys (identical revisionHash) caused zero disturbance, Ever-went-BAD=0. FINDING: the Bad publish does NOT carry the last-known value to the client (subscription AND raw Read both return NULL), contradicting VirtualTagActor.cs:22 and this plan STATUS row. The actor is correct \u2014 new test VirtualTagActorTests.The_Bad_result_carries_the_last_known_value proves it emits 42; the value is lost in the OPC UA layer. No existing test asserted that half. Evidence: docs/plans/2026-08-07-adminui-followups-and-live-gates.md \u00a73."
|
|
}
|
|
],
|
|
"lastUpdated": "2026-08-07"
|
|
} |