From dd82e7401137080e5d53417860057f3c4a88b53f Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 13 Jul 2026 10:27:08 -0400 Subject: [PATCH] docs(r2-02): record R2-02 resilience hardening pass in STATUS.md + execution deviations --- .../plans/R2-02-resilience-config-hardening-plan.md | 10 ++++++++++ ...02-resilience-config-hardening-plan.md.tasks.json | 2 +- archreview/plans/STATUS.md | 12 ++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/archreview/plans/R2-02-resilience-config-hardening-plan.md b/archreview/plans/R2-02-resilience-config-hardening-plan.md index 77c58567..70bde186 100644 --- a/archreview/plans/R2-02-resilience-config-hardening-plan.md +++ b/archreview/plans/R2-02-resilience-config-hardening-plan.md @@ -351,3 +351,13 @@ Bite-sized TDD tasks. Each carries classification, estimate, parallelism, files, 6. Task 18 rides the last PR. **Overall effort:** Small-Medium (matches 00-OVERALL action #2) — ≈ 19 bite-sized tasks, roughly one focused day including the live-`/run` session. **Overall risk:** Low — every behavior change is either strictly widening (clamps), strictly safening (write no-retry), or deletion of provably-inert surface; the two hot-path touches (write arm, pipeline key) are covered by behavioral guards and the OTOPCUA0001 analyzer keeps every dispatch site wrapped. + +--- + +## Execution deviations (R2-02) + +- **Task 15 (AdminUI live-`/run`) marked `deferred-live`.** All razor/code shipped and offline unit/bUnit-substitute suites are green; the docker-dev `:9200` `/run` pass (warning banner, input lockout, unknown-key survival) is a single-tenant serial live pass the controller runs one-at-a-time. Not blocking. +- **Task 18 whole-solution `dotnet test` sweep marked `deferred-live`.** Per a mid-execution controller constraint, the `*.IntegrationTests` / whole-solution test run has a ~16 GB/run memory leak and cannot run concurrently with other plans. I ran the impacted UNIT suites filtered (Core resilience 121/121, AdminUI form 10/10, Analyzers 32/32, Runtime wiring 2/2, full Runtime 364/364 at task 7) and the full-solution `dotnet build` (0 errors, 0 production OTOPCUA0001). The whole-solution `dotnet test` gate is left for the controller's serialized heavy pass. +- **`DriverInstanceResilienceStatus.CurrentBulkheadDepth` doc reworded to avoid the literal word "bulkhead" in free text** (Task 12). The plan permitted "one doc line on the entity" mentioning the bulkhead removal, but the Task-12 grep-must-be-empty check treats any "bulkhead" hit as a miss. Reworded to "Formerly fed a Polly concurrency-limiter strategy that was removed (R2-02/01/U-6)…" so the explanatory annotation stays while the grep is clean; the column NAME `CurrentBulkheadDepth` (excluded by the grep) still carries the historical term. The EF migration + `WedgeDetector.BulkheadDepth` were left untouched as scoped. +- **Baseline OTOPCUA0001 warnings in `AbLegacy.Tests` are pre-existing** (test code invoking the driver directly to assert wire-level behavior — the documented-acceptable case). My branch never touched those files and introduced zero new dispatch-site unwraps; production code has 0 OTOPCUA0001. +- **The worktree's local `master` ref is behind this branch's base (`1676c8f4`)**, so `git diff master..HEAD` shows unrelated base files (R2-01/03/05 plans, S7Driver, etc.). Only the 18 `fix(r2-02):`/`docs(r2-02):` commits are this plan's work. diff --git a/archreview/plans/R2-02-resilience-config-hardening-plan.md.tasks.json b/archreview/plans/R2-02-resilience-config-hardening-plan.md.tasks.json index e79a243d..12113498 100644 --- a/archreview/plans/R2-02-resilience-config-hardening-plan.md.tasks.json +++ b/archreview/plans/R2-02-resilience-config-hardening-plan.md.tasks.json @@ -19,7 +19,7 @@ { "id": 15, "subject": "C-7 razor: ParseFailed warning banner + input lockout + explicit discard button; raw pane shows the stored ResilienceConfig; live-/run on docker-dev :9200 (rebuild BOTH centrals; SQL-mangle + unknown-key survival checks; also drive task 5 warnings and task 9 disabled cells)", "status": "deferred-live", "note": "docker-dev :9200 live-/run; serial live pass", "blockedBy": [14] }, { "id": 16, "subject": "S-7 builder: add options-generation to PipelineKey + GetOrCreate(optionsGeneration=0) + thread through CapabilityInvoker; StaleGeneration_ReCache_IsNotServed_ToNewGeneration", "status": "completed", "blockedBy": [3] }, { "id": 17, "subject": "S-7 factory: Interlocked per-Create generation stamp + Respawn_interleaved_with_old_invoker_call_still_applies_new_options wiring proof; update Invalidate comment (cleanup, not correctness)", "status": "completed", "blockedBy": [16] }, - { "id": 18, "subject": "Wrap-up: whole-solution build (0 warnings, analyzer silent) + full dotnet test gate; record the pass + the two report anchor drifts in archreview/plans/STATUS.md", "status": "pending", "blockedBy": [4, 8, 9, 12, 15, 17] } + { "id": 18, "subject": "Wrap-up: whole-solution build (0 warnings, analyzer silent) + full dotnet test gate; record the pass + the two report anchor drifts in archreview/plans/STATUS.md", "status": "deferred-live", "note": "integration/full sweep; serialized heavy pass", "blockedBy": [4, 8, 9, 12, 15, 17] } ], "lastUpdated": "2026-07-12" } diff --git a/archreview/plans/STATUS.md b/archreview/plans/STATUS.md index 0271f9e9..34ec6e43 100644 --- a/archreview/plans/STATUS.md +++ b/archreview/plans/STATUS.md @@ -150,3 +150,15 @@ surface), 03/S2/S3 block-bridging, 03/P1 surgical adds (guard prerequisite in pl per-plan task counts, effort, and suggested execution order: [`00-INDEX.md`](00-INDEX.md) §"Round 2 plans". 193 bite-sized TDD tasks total, ~18–24 dev-days end-to-end; R2-01/02/03 (the re-review's new-and-sharp items) are ~2 days combined. + +## Round-2 execution — completed plans + +| Plan | Findings closed | Branch @ commit | Verification | +|---|---|---|---| +| **R2-02 — ResilienceConfig hardening** | 01/S-6 (High), 01/U-6, 01/S-8=03/S12, 04/C-7, 01/S-7=03/S13 | `r2/02-resilience-config-hardening` (18 commits `4be13429`…`d8c6357b`) | **01/S-6:** parser clamps timeout/retry/breaker overrides (timeout≤0→tier default, breaker==1→2, retry/breaker caps) with appending diagnostics + belt-and-braces `Build` clamp so a pipeline build can never throw Polly `ValidationException` (`ResiliencePolicyRanges` single-source-of-truth in Core.Abstractions); brick-repro guard + `Build_NeverThrows_ForHostileDirectOptions` + factory-seam wiring proof; AdminUI `ResilienceFormModel.Validate()` warning block. **01/S-8:** parser forces Write/AlarmAcknowledge retry overrides to 0 (spec invariant) **and** dispatch flips to `isIdempotent:false` (RED-first on `DriverInstanceActorResilienceWiringTests`); non-idempotent arm now caches the no-retry snapshot once per invoker (01/P-4) + records tracker in-flight accounting; `WriteIdempotentAttribute`'s false "reads via reflection" claim corrected; Write/Ack retry cells disabled in the form. **01/U-6:** bulkhead knob deleted end-to-end (options + parser + form + razor); stored keys become ignored unknowns (migration-free); tree-wide doc sweep; `Options_properties_are_exactly_the_pipeline_wired_set` inertness guard. **04/C-7:** `ResilienceFormModel` reworked to a `JsonObject`-bag round-trip preserving unknown top-level/capability/per-policy keys; malformed stored JSON sets `ParseFailed` → section locks + `ToJson` returns the original text verbatim + explicit discard button; raw pane shows the bound stored value. **01/S-7:** options-generation stamped per-`Create` (`Interlocked`) and threaded into the pipeline-cache key so a lingering old child's post-invalidate re-cache is unreachable by the new generation; `Invalidate` demoted to cleanup. Core resilience 121/121, AdminUI form 10/10, Analyzers 32/32, Runtime wiring 2/2 (+full Runtime 364/364 at task 7); solution builds clean, 0 production OTOPCUA0001. **Deferred to serial live pass:** task 15 (docker-dev `:9200` `/run` — warning banner, input lockout, unknown-key survival) + the whole-solution `dotnet test` sweep (integration suites excluded per the shared-rig memory-leak constraint). | + +**Report anchor drifts to fold into the next report refresh** (from the R2-02 verification pass): (1) +`01-core-composition.md` U-6 anchor `DriverResilienceOptions.cs:23-25` → the two bulkhead properties sat at +`:23` and `:29` (now deleted); (2) `01-core-composition.md` U-6 anchor +`DriverResiliencePipelineBuilder.cs:99-177` → `Build` was `:99-176`. All other cited lines were exact at +`f6eaa267`.