docs: deferred-table closure, stale-comment sweep, as-built execution record

This commit is contained in:
Joseph Doherty
2026-08-15 21:33:28 -04:00
parent bb7aa6209f
commit e1ff05c605
5 changed files with 83 additions and 8 deletions
+5 -1
View File
@@ -136,7 +136,11 @@ cost stays bounded: a pure-event pass — the event hot path — still pays
exactly one flush however many frames drain together, a run of control
frames still pays one for the whole run (never one per heartbeat, the
syscall-per-frame cost the coalescing removed), and only a pass that actually
mixes both classes pays a second.
mixes both classes pays a second. Mixed passes are not exotic: command replies
travel at Control priority alongside heartbeats and faults, so a session under
sustained command traffic concurrent with event streaming can hit them
routinely. The cost stays bounded either way — one extra flush per class
transition present in the pass, not per frame.
One consequence of the boundary flush is worth stating: a control frame whose
run has already been flushed and completed is out of the drain's
@@ -308,3 +308,67 @@ Push the branch to origin, then on windev (`ssh windev`, clone `C:\build\mxacces
| Structural alarm-truncation degraded-status signal | Contract-level design (proto change candidate) — separate effort. |
| SEC-25 per-session dashboard event ACL | Security roadmap item; Task 6 deliberately preserves the current posture. |
| `MxAccessWriteCompletionCache` clone | Different lifecycle than the value cache; consciously kept (Task 12.5). |
---
## As-built notes (execution record)
Where the delivered work differs from the task text above, or where the route to it
is worth keeping, this is the record.
**Task 3 — `ReadEventsAsync` retained.** The method was not removed after
`MapWorkerEventsAsync` inlined the read-then-map chain: a second caller reaches it
through `ISessionManager.ReadEventsAsync`. That interface member itself has zero
production call sites — only test fakes implement and exercise it. Deleting it is a
mechanical but wide change (~15 test-fake touches), so it is recorded as a follow-up
rather than done here.
**Task 5 — dashboard event feed, two review rounds.** Review caught two races that
the first cut did not have. First, subscription lifetime: subscriptions are now
generation-tagged, a generation ends at the time the fault is *observed* (not when it
is raised), `Reset` is scoped to the dying generation so it cannot cancel its
successor, and a backstop restart covers the case where no subscriber is left to
drive recovery. Second, `UnsubscribeAsync` needed a generation-scoped idle gate so a
teardown for an old generation cannot tear down the new one. Both fixes are pinned by
tests verified against mutations of the fixed code.
**Task 6 — subscribe API placement.** The subscribe surface lives on
`IDashboardSessionEventSubscriber`, with DI forwarding to a single instance so every
consumer shares one feed. Batches that arrive for a session the renderer has already
moved off are dropped by a subscription identity check inside the renderer dispatch,
which is what makes a stale batch harmless rather than a cross-session leak.
**Task 10 — the delivered property is the delivery point, not awaited latency.** The
spec asked for control-frame completion to be observable before the pass's event
writes. That is unachievable in the enqueue-then-contend shape: a caller that loses
the write-lock race does not run again until the winning drainer releases the lock,
so its `await` cannot return early no matter when its frame completes. What shipped
is the honest half: control frames are written *and flushed* at the class-transition
boundary, so the priority class governs the frame's delivery point rather than only
its byte order. Getting the awaited-latency win too requires unparking the lock-race
loser from the winner's pass — a change to the write-lock shape, recorded as a
follow-up. One extra `FlushFileBuffers` per mixed pass is the accepted cost.
**Task 11 — teardown ordering and unconditional fault observation.** Teardown disposes
the session-owned transport first, then observes the read that dispose abandoned.
Fault observation is unconditional — a `ContinueWith(..., TaskContinuationOptions.OnlyOnFaulted)`
continuation, so the budget that bounds the wait is diagnostics-only and can never be
the reason a fault goes unobserved. The same continuation covers heartbeat and drain
overrun. `DisposeTransportStream` is exception-total: no dispose path can throw out of
teardown.
**Task 12 — three clones removed, plan rationale corrected in-code.** All three
`OnDataChange` value-cache clones are gone. The plan's stated reason for keeping the
`MxAccessWriteCompletionCache` clone ("different lifecycle than the value cache") is
wrong and was corrected where the code documents it: the clone is kept on
*provenance* grounds — the cached payload comes from a caller-supplied object the
worker does not own — not on lifecycle grounds.
**Task 13 — windev verification.** Solution build 0 warnings / 0 errors after
clearing stale `Contracts` `obj` artifacts (an infrastructure problem on the box, not
a regression from this branch). Worker x86: 509/509 (+8 new). Gateway: 1059/1059,
including `SecretsStorePathGuardTests` — the first fully green Windows gateway run,
that suite having been red before this branch. One load flake
(`InvokeAsync_WhenWorkerHandshakingThenReadyWithinTimeout_Succeeds`) passed in
isolation and on re-run, consistent with the load-sensitivity caveat documented in
`docs/GatewayTesting.md`.
@@ -619,6 +619,11 @@ Commit anything found: `docs: remediation plan doc sweep`
| Event-path triple async-iterator flattening | LOW-rated; touches the most invariant-dense code in the gateway for two `MoveNextAsync` hops per event. Reconsider after Tasks 3/4 land and if profiling still shows it. |
| `SessionEventDistributor._subscribers` `ConcurrentDictionary` → plain `Dictionary` (Task 25 / Task 3 review) | Every mutation is already inside `_lifecycleLock`, so the concurrent type buys nothing. Behavior-neutral refactor with no measurable win, proposed after the windev gate was already green — not worth re-running the verification matrix for. Comment cleanups from the same review landed; this swap did not. |
All six rows above were resolved on 2026-08-15 by the follow-up plan
[`docs/plans/2026-08-15-deferred-remediation.md`](2026-08-15-deferred-remediation.md)
(branch `perf/deferred-remediation`), which also fixed the pre-existing Windows
`SecretsStorePathGuardTests` failure.
## Execution notes for the orchestrator
- Branch: `git checkout -b perf/review-remediation` before Task 1.