Record why the drawer's post-close inert window stays unfixed #141

Merged
rob merged 3 commits from task-197-drawer-inert-after-modal-close into main 2026-08-12 10:42:58 +00:00
Owner

Task 197. No production or test code changes — the fix attempted here doesn't hold up, and this records why rather than shipping something unproven.

Tried five candidates against the removed-workaround repro (25 runs each): releasing OverlayFocusTrap from ModalOverlay.CloseAsync after OnClose rather than before (25/25 still failed — the disposal that matters had usually already run by then); the same plus an explicit yield to the renderer (25/25); giving the previously-unkeyed add-mode PlaceFormPanel in Drawer.razor an explicit @key (24/25); replacing InvokeAsync(StateHasChanged) with a direct call at the three places this app subscribes to a shared service's Changed event (measurably better, ~75-80% still failed, residual traced to bUnit's own click dispatch completing before the handler runs); and making ExitAsync's JS interop fire-and-forget (no further change).

ADR-0119 records the mechanism found, all five attempts and why each fell short, and answers ADR-0116's own deferred question. HomeAndDrawerSharedGroupStateTests keeps both WaitForAssertion wrappers unchanged — removing them doesn't currently produce a deterministic pass.

Task 197. No production or test code changes — the fix attempted here doesn't hold up, and this records why rather than shipping something unproven. Tried five candidates against the removed-workaround repro (25 runs each): releasing `OverlayFocusTrap` from `ModalOverlay.CloseAsync` after `OnClose` rather than before (25/25 still failed — the disposal that matters had usually already run by then); the same plus an explicit yield to the renderer (25/25); giving the previously-unkeyed add-mode `PlaceFormPanel` in `Drawer.razor` an explicit `@key` (24/25); replacing `InvokeAsync(StateHasChanged)` with a direct call at the three places this app subscribes to a shared service's `Changed` event (measurably better, ~75-80% still failed, residual traced to bUnit's own click dispatch completing before the handler runs); and making `ExitAsync`'s JS interop fire-and-forget (no further change). ADR-0119 records the mechanism found, all five attempts and why each fell short, and answers ADR-0116's own deferred question. `HomeAndDrawerSharedGroupStateTests` keeps both `WaitForAssertion` wrappers unchanged — removing them doesn't currently produce a deterministic pass.
Record why the drawer's post-close inert window stays unfixed
All checks were successful
CI / build (pull_request) Successful in 3m6s
CI / container-images (pull_request) Has been skipped
CI / e2e (pull_request) Successful in 1m56s
c81fa05b18
rob left a comment

Verdict: changes needed

Not on the investigation — it's sound and the write-up earns its keep — but ADR-0119's own frontmatter has a real defect, and I found one untried direction worth naming before this closes the ticket.

1. Genuinely revert-clean. Diffed merge-base (06d10f3) against head directly: exactly three files touched, all docs (0116 metadata, new 0119, one README row), zero production or test files anywhere in the diff. HomeAndDrawerSharedGroupStateTests.cs isn't in the diff at all — bit-identical to main. No debris.

2. Five attempts, but not a fully explored space — one direction I don't see tried. Attempts 1/2/5 are timing variants within ModalOverlay.CloseAsync's own lifecycle; 3 and 4 test genuinely different hypotheses (keying, dispatcher queueing), so this isn't "five copies of one idea." But all five still assume the fix lives in when OverlayFocusTrap releases and propagates. Not attempted, as far as I can find: moving the release out of ModalOverlay/DisposeAsync entirely, into each host's own close-decision method (PlaceFormPanel.DiscardAndCloseAsync, GroupFormPanel.ConfirmDeleteAsync, etc.), synchronous with the host's own _closing = true — decoupling from Blazor's async dispose schedule rather than racing a different point inside it. That's structurally distinct from the PR #137 same-tick attempt (which stayed inside ModalOverlay.CloseAsync), though it costs the "share one shell uniformly" property ADR-0116 was built for, which may be exactly why it wasn't tried — worth saying so explicitly if it's rejected on that basis rather than left unmentioned.

3. Descriptions are specific enough, with one exception: attempts 1, 2, 3 and 5 all give exact X/25 counts; attempt 4 gives "roughly 75–80%" with no stated run count backing that range — unclear whether that's one batch of 25 or several. For the one attempt that "mostly worked," that's the case needing the most precision, not the least.

4. 25 runs is adequate for the clear results, thin for attempt 4. 0/25 and 24/25 against a baseline the record itself measured at ~90% failure are both easily distinguished from a "fixed" outcome. Attempt 4's ~20–25% pass rate is a real, distinguishable effect from baseline, but a 95% CI on that from 25 runs is roughly ±16 points — wide enough that "roughly 75-80%" is a fair qualitative claim but not a tight measurement, which the record should say plainly rather than imply more precision than 25 runs (or however many, per point 3) actually gives.

5. ADR-0116's own annotation is correct; ADR-0119's own is not. 0116's new Answered by: ADR-0119 is properly placed and quotes its own frozen "Tracked separately..." text accurately — genuine explicit deferral, correctly answered. But 0119 has also given itself an Answered by: this record, for the question ADR-0116's own Consequences explicitly left open field. That's backwards: per the template and ADR-0107, Answered by belongs on the record that posed the question, naming what answered it — "the answering record needs no field pointing back," verbatim. 0119 is the answering record here; it shouldn't carry this field at all. It happens to pass AdrIndexTests.AdrFiles_AnsweredBy_NamesARecordThatExists only because the explanatory prose incidentally contains a well-formed "ADR-0116" reference elsewhere in the same field text — the mechanical check can't and doesn't verify direction, by its own documented design. Remove the field from 0119.

Also: current head doesn't merge cleanly against main — confirmed by test-merge, sole conflict is docs/adr/README.md's table (adjacent-row insertion, from #140 merging first). Mechanical, needs a rebase and regenerated table before merge, not a content concern.

CI confirmed independently: build (722) and e2e (723) both success against head c81fa05.

Verdict: changes needed Not on the investigation — it's sound and the write-up earns its keep — but ADR-0119's own frontmatter has a real defect, and I found one untried direction worth naming before this closes the ticket. **1. Genuinely revert-clean.** Diffed merge-base (`06d10f3`) against head directly: exactly three files touched, all docs (`0116` metadata, new `0119`, one README row), zero production or test files anywhere in the diff. `HomeAndDrawerSharedGroupStateTests.cs` isn't in the diff at all — bit-identical to `main`. No debris. **2. Five attempts, but not a fully explored space — one direction I don't see tried.** Attempts 1/2/5 are timing variants within `ModalOverlay.CloseAsync`'s own lifecycle; 3 and 4 test genuinely different hypotheses (keying, dispatcher queueing), so this isn't "five copies of one idea." But all five still assume the fix lives in *when* `OverlayFocusTrap` releases and propagates. Not attempted, as far as I can find: **moving the release out of `ModalOverlay`/`DisposeAsync` entirely**, into each host's own close-decision method (`PlaceFormPanel.DiscardAndCloseAsync`, `GroupFormPanel.ConfirmDeleteAsync`, etc.), synchronous with the host's own `_closing = true` — decoupling from Blazor's async dispose schedule rather than racing a different point inside it. That's structurally distinct from the PR #137 same-tick attempt (which stayed inside `ModalOverlay.CloseAsync`), though it costs the "share one shell uniformly" property ADR-0116 was built for, which may be exactly why it wasn't tried — worth saying so explicitly if it's rejected on that basis rather than left unmentioned. **3. Descriptions are specific enough**, with one exception: attempts 1, 2, 3 and 5 all give exact X/25 counts; attempt 4 gives "roughly 75–80%" with no stated run count backing that range — unclear whether that's one batch of 25 or several. For the one attempt that "mostly worked," that's the case needing the most precision, not the least. **4. 25 runs is adequate for the clear results, thin for attempt 4.** 0/25 and 24/25 against a baseline the record itself measured at ~90% failure are both easily distinguished from a "fixed" outcome. Attempt 4's ~20–25% pass rate is a real, distinguishable effect from baseline, but a 95% CI on that from 25 runs is roughly ±16 points — wide enough that "roughly 75-80%" is a fair qualitative claim but not a tight measurement, which the record should say plainly rather than imply more precision than 25 runs (or however many, per point 3) actually gives. **5. ADR-0116's own annotation is correct; ADR-0119's own is not.** `0116`'s new `Answered by: ADR-0119` is properly placed and quotes its own frozen "Tracked separately..." text accurately — genuine explicit deferral, correctly answered. But `0119` has also given *itself* an `Answered by: this record, for the question ADR-0116's own Consequences explicitly left open` field. That's backwards: per the template and ADR-0107, `Answered by` belongs on the record that *posed* the question, naming what answered it — "the answering record needs no field pointing back," verbatim. `0119` is the answering record here; it shouldn't carry this field at all. It happens to pass `AdrIndexTests.AdrFiles_AnsweredBy_NamesARecordThatExists` only because the explanatory prose incidentally contains a well-formed "ADR-0116" reference elsewhere in the same field text — the mechanical check can't and doesn't verify direction, by its own documented design. Remove the field from `0119`. **Also:** current head doesn't merge cleanly against `main` — confirmed by test-merge, sole conflict is `docs/adr/README.md`'s table (adjacent-row insertion, from #140 merging first). Mechanical, needs a rebase and regenerated table before merge, not a content concern. CI confirmed independently: `build` (722) and `e2e` (723) both `success` against head `c81fa05`.
Merge main and add attempt six to the drawer-inert investigation
All checks were successful
CI / build (pull_request) Successful in 2m53s
CI / container-images (pull_request) Has been skipped
CI / e2e (pull_request) Successful in 2m0s
c76e110c97
Resolves the ADR index conflict with #140's own in-tree regeneration
script. ADR-0119: removes the spurious self-referential Answered-by
field, gives attempt 4 a crisp run count, and records a sixth attempt
(host-driven, pre-animation trap release) that proves the failure is
not an OverlayFocusTrap timing problem after all.
Author
Owner

Addressed at c76e110:

  1. Attempt six tried and measured (25 runs), fails — but changes what the deferral says. Moved the trap release out of ModalOverlay/DisposeAsync entirely: new ModalOverlay.ReleaseFocusTrapAsync(), called by every host (PlaceFormPanel, GroupFormPanel, GroupMembersPanel) at its own synchronous decision-to-close point, before CloseAsync even starts the animation. Traced directly: it genuinely releases ~200ms earlier than any prior attempt. Still 25/25 fail, same as baseline. That's the real finding — OverlayFocusTrap's own timing isn't the controlling variable for this repro at all; the trace points at a Blazor render-batch collision between removing the old panel and adding the new one, independent of trap state. Not shipped for a second reason too: releasing that early makes the drawer clickable while the old panel is still fully visible, not fading — a real regression traded for no measured benefit. Production code fully reverted; only ADR-0119 changed.
  2. Removed the spurious self-referential Answered by field from ADR-0119.
  3. Merged main and resolved the README conflict with #140's own in-tree scripts/regenerate-adr-readme.cs, as instructed. Attempt 4 now has a crisp, clean number: 23/25 fail (2 pass), no diagnostic overhead in the run.

Full suite green (1785 non-E2E + 7 E2E skip-locally = 1792, matching #140's own count), dotnet format --verify-no-changes clean, architecture tests 123/123.

Addressed at c76e110: 1. **Attempt six tried and measured (25 runs), fails — but changes what the deferral says.** Moved the trap release out of `ModalOverlay`/`DisposeAsync` entirely: new `ModalOverlay.ReleaseFocusTrapAsync()`, called by every host (`PlaceFormPanel`, `GroupFormPanel`, `GroupMembersPanel`) at its own synchronous decision-to-close point, before `CloseAsync` even starts the animation. Traced directly: it genuinely releases ~200ms earlier than any prior attempt. **Still 25/25 fail, same as baseline.** That's the real finding — `OverlayFocusTrap`'s own timing isn't the controlling variable for this repro at all; the trace points at a Blazor render-batch collision between removing the old panel and adding the new one, independent of trap state. Not shipped for a second reason too: releasing that early makes the drawer clickable while the old panel is still fully visible, not fading — a real regression traded for no measured benefit. Production code fully reverted; only ADR-0119 changed. 2. Removed the spurious self-referential `Answered by` field from ADR-0119. 3. Merged main and resolved the README conflict with #140's own in-tree `scripts/regenerate-adr-readme.cs`, as instructed. Attempt 4 now has a crisp, clean number: 23/25 fail (2 pass), no diagnostic overhead in the run. Full suite green (1785 non-E2E + 7 E2E skip-locally = 1792, matching #140's own count), `dotnet format --verify-no-changes` clean, architecture tests 123/123.
rob left a comment

Verdict: changes needed

The deferral itself is right — don't ship an unproven fix — and everything mechanical checks out. But I ran the one experiment the ticket most needed (a plain close, nothing else happening, 25 times) and it contradicts a specific causal claim this record makes. That needs fixing before this becomes the reference the next person starts from.

3. I tested it directly — the inert window is real and separate, not an artifact of the two-panel repro. Built a minimal variant of the existing fixture: render Drawer, open GroupFormPanel, submit it, read aside.drawer's own inert attribute the instant Submit() returns — no WaitForAssertion, no second panel, nothing else. 25/25 runs: inert is present immediately after the close. The plain post-close inert window is real, reproducible, and needs no second panel to demonstrate. Task 197's premise and ADR-0116's own consequence both hold. (First pass gave 25/25 absent — my own bug: GetAttribute returns null when a boolean attribute is omitted and "" when present-true, and naive string interpolation prints both as empty. Fixed the check, reran, got the result above.)

That same direct measurement contradicts this record's own account of why attempts 1 and 2 failed. The write-up says the explicit release was redundant because "the disposal that matters had usually already run by then... in the common case." My check reads inert at the equivalent point (immediately after the outer Submit() returns, which is after everything CloseAsync does, including OnClose.InvokeAsync()) and finds it still present, 25/25 — the opposite of "usually already run." Attempts 1/2's own conclusion was inferred from a null result (adding a call made no difference), not from a direct trace of disposal's own timing the way attempt 6 later did properly. That inference should be corrected, not carried forward.

1. Confirmed: it leads with the trap-timing story, and the record itself says so. Context still states the OverlayFocusTrap/DisposeAsync mechanism as settled fact. The revised finding only appears inside "What was tried" (attempt six) and in Consequences, which admits outright: "this record's own title undersells that shift, and would need revisiting if this becomes the reference future work builds on." An admitted, unfixed structural problem is still a blocking one.

2. Given point 3, the record's own instruction for what to do next overreaches. Consequences tells the next investigator to "start from a Drawer-tree render-batch collision... not from OverlayFocusTrap at all." My own evidence says that's wrong for the general defect: the trap-timing mechanism is real and independently reproducible for a plain close. Attempt six's finding is narrower and still worth keeping — for this specific automated repro (a close chained immediately into a different panel's open), releasing the trap ~200ms earlier didn't change the failure rate, which does implicate something else for that compound scenario. But that's additive to the trap-timing defect, not a replacement for it, and the write-up needs to say both rather than steering the next person away from a mechanism I've just confirmed is real.

4. Attempt 4's count is now crisp (23/25, no instrumentation in the test itself) — the earlier "roughly 75–80%" vagueness is fixed.

5. Everything else holds. Revert-clean against the current base (31611c6): three doc files, zero production/test files. The spurious self-referential Answered by on 0119 is gone; 0116's own reciprocal field is unchanged and correct. AdrIndexTests (all 15, including the new prose-floor and table-match checks from #140) pass, confirming the README's row set matches the file set exactly. Full suite: 1792 total / 1781 passing / 11 skipped, dotnet build and dotnet format --verify-no-changes clean. CI independently confirmed: build (726) and e2e (727) both success against head c76e110.

Net: don't accept the deferral as written. Restructure to lead with what attempt six actually shows, correct the attempts-1/2 explanation against direct measurement, and state plainly that the plain-close inert window is confirmed real and independent of the render-batch question — then it's ready.

Verdict: changes needed The deferral itself is right — don't ship an unproven fix — and everything mechanical checks out. But I ran the one experiment the ticket most needed (a plain close, nothing else happening, 25 times) and it contradicts a specific causal claim this record makes. That needs fixing before this becomes the reference the next person starts from. **3. I tested it directly — the inert window is real and separate, not an artifact of the two-panel repro.** Built a minimal variant of the existing fixture: render `Drawer`, open `GroupFormPanel`, submit it, read `aside.drawer`'s own `inert` attribute the instant `Submit()` returns — no `WaitForAssertion`, no second panel, nothing else. 25/25 runs: `inert` is present immediately after the close. The plain post-close inert window is real, reproducible, and needs no second panel to demonstrate. Task 197's premise and ADR-0116's own consequence both hold. (First pass gave 25/25 *absent* — my own bug: `GetAttribute` returns `null` when a boolean attribute is omitted and `""` when present-true, and naive string interpolation prints both as empty. Fixed the check, reran, got the result above.) **That same direct measurement contradicts this record's own account of why attempts 1 and 2 failed.** The write-up says the explicit release was redundant because "the disposal that matters had usually already run by then... in the common case." My check reads `inert` at the equivalent point (immediately after the outer `Submit()` returns, which is after everything `CloseAsync` does, including `OnClose.InvokeAsync()`) and finds it still present, 25/25 — the opposite of "usually already run." Attempts 1/2's own conclusion was inferred from a null result (adding a call made no difference), not from a direct trace of disposal's own timing the way attempt 6 later did properly. That inference should be corrected, not carried forward. **1. Confirmed: it leads with the trap-timing story, and the record itself says so.** Context still states the `OverlayFocusTrap`/`DisposeAsync` mechanism as settled fact. The revised finding only appears inside "What was tried" (attempt six) and in Consequences, which admits outright: "this record's own title undersells that shift, and would need revisiting if this becomes the reference future work builds on." An admitted, unfixed structural problem is still a blocking one. **2. Given point 3, the record's own instruction for what to do next overreaches.** Consequences tells the next investigator to "start from a `Drawer`-tree render-batch collision... not from `OverlayFocusTrap` at all." My own evidence says that's wrong for the general defect: the trap-timing mechanism is real and independently reproducible for a plain close. Attempt six's finding is narrower and still worth keeping — for *this specific automated repro* (a close chained immediately into a different panel's open), releasing the trap ~200ms earlier didn't change the failure rate, which does implicate something else for *that* compound scenario. But that's additive to the trap-timing defect, not a replacement for it, and the write-up needs to say both rather than steering the next person away from a mechanism I've just confirmed is real. **4. Attempt 4's count is now crisp** (23/25, no instrumentation in the test itself) — the earlier "roughly 75–80%" vagueness is fixed. **5. Everything else holds.** Revert-clean against the current base (`31611c6`): three doc files, zero production/test files. The spurious self-referential `Answered by` on `0119` is gone; `0116`'s own reciprocal field is unchanged and correct. `AdrIndexTests` (all 15, including the new prose-floor and table-match checks from #140) pass, confirming the README's row set matches the file set exactly. Full suite: 1792 total / 1781 passing / 11 skipped, `dotnet build` and `dotnet format --verify-no-changes` clean. CI independently confirmed: `build` (726) and `e2e` (727) both `success` against head `c76e110`. Net: don't accept the deferral as written. Restructure to lead with what attempt six actually shows, correct the attempts-1/2 explanation against direct measurement, and state plainly that the plain-close inert window is confirmed real and independent of the render-batch question — then it's ready.
Separate the confirmed inert window from the repro's own unexplained failure
All checks were successful
CI / build (pull_request) Successful in 3m10s
CI / container-images (pull_request) Has been skipped
CI / e2e (pull_request) Successful in 1m49s
4eba2ff183
Author
Owner

Addressed at 4eba2ff — ADR-0119 rewritten, no code changes.

  1. Restructured to lead with "What is believed now, and on what evidence": the inert window is real and independently confirmed (your direct experiment, cited explicitly), OverlayFocusTrap remains the live mechanism for it, and the repro's own extra failure is a separate, unexplained phenomenon layered on top — not the same result as the inert window, and not to be read as one.
  2. Withdrew the attempts 1–2 explanation ("disposal already ran by then"). It was an inference from trace-line ordering, not a direct measurement, and your experiment at the equivalent point shows the opposite. Both failures are now labelled unexplained.
  3. Removed every "start from a render-batch collision, not OverlayFocusTrap" instruction. Decision and Consequences now say plainly that OverlayFocusTrap is still where a real fix for the inert window belongs, and that the six attempts only rule out three specific relocations of its release against this one repro — not the mechanism itself. Also softened attempt six's own render-batch-collision claim to a stated hypothesis, since it's exactly the same shape of overreach as the attempts 1–2 story, just not yet caught.

No further attempts, no other files touched.

Addressed at 4eba2ff — ADR-0119 rewritten, no code changes. 1. Restructured to lead with "What is believed now, and on what evidence": the inert window is real and independently confirmed (your direct experiment, cited explicitly), `OverlayFocusTrap` remains the live mechanism for it, and the repro's own extra failure is a separate, unexplained phenomenon layered on top — not the same result as the inert window, and not to be read as one. 2. Withdrew the attempts 1–2 explanation ("disposal already ran by then"). It was an inference from trace-line ordering, not a direct measurement, and your experiment at the equivalent point shows the opposite. Both failures are now labelled unexplained. 3. Removed every "start from a render-batch collision, not `OverlayFocusTrap`" instruction. Decision and Consequences now say plainly that `OverlayFocusTrap` is still where a real fix for the inert window belongs, and that the six attempts only rule out three specific relocations of its release against this one repro — not the mechanism itself. Also softened attempt six's own render-batch-collision claim to a stated hypothesis, since it's exactly the same shape of overreach as the attempts 1–2 story, just not yet caught. No further attempts, no other files touched.
rob left a comment

Verdict: mergeable

All five points from last round hold up.

1–2. Separation is clean, and correctly ordered. "What is believed now, and on what evidence" leads the record, before Context — no longer buried. It states the inert window as confirmed (citing the 25/25 plain-close measurement accurately: no second panel, read the instant Submit() returns), states the repro's own extra failure as a separate phenomenon, and says plainly "this record does not know what it is." A reader can't come away conflating the two — every place attempt six's finding is discussed keeps the two apart, including Decision's own "the next attempt should treat closing the inert window and making that specific two-panel repro pass as two separate problems, not one."

3. Reading cold, I'd start in the right place. "What this does not rule out... OverlayFocusTrap itself" is explicit: the inert window is real, the trap's own release timing is still the correct live mechanism for it, and the six attempts only rule out three specific placements against this repro, not the trap as an approach. That's the correction that mattered — nothing here would send the next investigator away from a mechanism I independently confirmed is real.

4. Withdrawal is complete, not softened, and I don't see another unsupported inference anywhere else. Checked every remaining mention of the old "disposal already ran" explanation (lines 37–45, 93, 98, 101) — all consistently marked withdrawn/unexplained, none left standing. The render-batch-collision hypothesis for attempt six is now explicitly hedged as a hypothesis, contrasted directly against the mistake attempts 1–2 made ("stating it as more than a hypothesis would repeat the same mistake"). Scanned for proves/proven/established elsewhere — the two remaining uses of "proven" (attempt six's own ~200ms-earlier release) are backed by direct timestamped trace, not inference, so they're earned.

5. Mechanical, all confirmed. Diffed against current base (31611c6): three doc files, zero production/test files, still genuinely revert-clean. 0116's reciprocal Answered by is unchanged and correctly placed; 0119 carries none. All 15 AdrIndexTests pass, confirming the README table matches the file set and the prose floor holds. Full suite: 1792 total / 1781 passing / 11 skipped. dotnet build and dotnet format --verify-no-changes clean. CI independently confirmed: build and e2e both success against head 4eba2ff (run #598).

Verdict: mergeable All five points from last round hold up. **1–2. Separation is clean, and correctly ordered.** "What is believed now, and on what evidence" leads the record, before Context — no longer buried. It states the inert window as confirmed (citing the 25/25 plain-close measurement accurately: no second panel, read the instant `Submit()` returns), states the repro's own extra failure as a *separate* phenomenon, and says plainly "this record does not know what it is." A reader can't come away conflating the two — every place attempt six's finding is discussed keeps the two apart, including Decision's own "the next attempt should treat closing the inert window and making that specific two-panel repro pass as two separate problems, not one." **3. Reading cold, I'd start in the right place.** "What this does *not* rule out... `OverlayFocusTrap` itself" is explicit: the inert window is real, the trap's own release timing is still the correct live mechanism for it, and the six attempts only rule out three specific placements against *this repro*, not the trap as an approach. That's the correction that mattered — nothing here would send the next investigator away from a mechanism I independently confirmed is real. **4. Withdrawal is complete, not softened, and I don't see another unsupported inference anywhere else.** Checked every remaining mention of the old "disposal already ran" explanation (lines 37–45, 93, 98, 101) — all consistently marked withdrawn/unexplained, none left standing. The render-batch-collision hypothesis for attempt six is now explicitly hedged as a hypothesis, contrasted directly against the mistake attempts 1–2 made ("stating it as more than a hypothesis would repeat the same mistake"). Scanned for `proves`/`proven`/`established` elsewhere — the two remaining uses of "proven" (attempt six's own ~200ms-earlier release) are backed by direct timestamped trace, not inference, so they're earned. **5. Mechanical, all confirmed.** Diffed against current base (`31611c6`): three doc files, zero production/test files, still genuinely revert-clean. `0116`'s reciprocal `Answered by` is unchanged and correctly placed; `0119` carries none. All 15 `AdrIndexTests` pass, confirming the README table matches the file set and the prose floor holds. Full suite: 1792 total / 1781 passing / 11 skipped. `dotnet build` and `dotnet format --verify-no-changes` clean. CI independently confirmed: `build` and `e2e` both `success` against head `4eba2ff` (run #598).
rob merged commit 2cadb90dd5 into main 2026-08-12 10:42:58 +00:00
rob deleted branch task-197-drawer-inert-after-modal-close 2026-08-12 10:42:58 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rob/PlaceMark!141
No description provided.