Weigh a deferred click's position, and cancel it on a marker drag (task 229) #165
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/task-229-deferred-click-position-and-drag"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes task 229 — the two gaps review of task 228 (PR #161, ADR-0144) left out.
Gap 2: a picker marker's
dragstart/dragendnow cancel a pending click. Previously, tapping the picker's map to place the pin then immediately dragging it to adjust could see the tap's own deferred callback (ADR-0144) fire mid-drag or after, overwriting the dragged position with the stale tapped coordinate. Cancelled ondragstart(closes the mid-drag window) anddragend(defence in depth).Gap 1:
deferSingleClick's second-click cancellation now checks position, not only timing. A second click withinDOUBLE_TAP_WINDOW_MSonly cancels the pending click it lands withinCLICK_CANCEL_SLOP_PIXELS(5, GTK's owngtk-double-click-distancedefault) of — a second click further away is deferred in its own right, rather than both being silently discarded.ADR-0145 records both, and partially supersedes ADR-0144's own claim that a marker drag "has no ambiguity... to be confused with."
Both gaps now proven with real Chromium input, watched failing first.
MarkerDragCancelsPendingClickJourneyTests— an initial version raced click-then-drag against the 300ms window and passed even with the fix reverted, becausedragend's own report always lands last regardless of cancellation; rewritten to hold the drag deliberately past the deferral window before releasing, checking the state a reader would see mid-drag. Reddened against the real defect (await latitudeField.InputValueAsync() should be "38.272688535980976" but was "38.273510817496465"— the seeded coordinate silently overwritten mid-hold).DistantMapClicksBothSurviveJourneyTests(added on review: gap 1 had no real-input E2E case, and unlike this file's other "reasoned, not reproduced" gaps, nothing here needed CDP touch — two ordinaryILocator.ClickAsyncclicks prove it directly). Watched failing against a temporarily reverted distance check:Locator expected to be visible... waiting for Locator("#place-form-latitude")— the add-place panel never opened at all, both clicks having cancelled each other with nothing scheduled for either.docs/adr/README.md's index is regenerated; diff outside the 0144/0145 rows is empty. Rebased onto currentmain(task 226/223 merges); no conflicts.Test plan
CI run #697, pinned SDK 10.0.100, head
13b70c1:build:PlaceMark.Domain.Tests12,PlaceMark.Contracts.Tests139,PlaceMark.Architecture.Tests123,PlaceMark.WebUI.Tests751 passed/4 skipped/755 total,PlaceMark.Infrastructure.Tests321,PlaceMark.Api.Tests605 — all passed.e2e: 22 passed, 0 failed, 0 skipped.dotnet format --verify-no-changesclean.Fix two gaps in the deferred map click (task 229)to Weigh a deferred click's position, and cancel it on a marker drag (task 229)Verdict: mergeable
Reviewed at head
2be0523(matches PR's own reported head).Red-run claim, verified against job logs, not the diff. Forgejo's run-
id-vs-html_urlnumbering is inconsistent here (querying/actions/runs/595directly returns an unrelated 2026-08-12 run whose ownhtml_urlisruns/503, even though the tool that reported #687's URL saidruns/595) — matched onhead_shainstead, per the brief. Run #687 (b0f60e3,e2ejob 1036) failed on the final assertion (Not.ToHaveValueAsync— the drag itself hadn't landed, an unrelated locator bug), not the guarded defect. Run #689 (3115e4f, job 1042) is the one that actually reddens on the claimed line:await latitudeField.InputValueAsync() should be "38.272688535980976" but was "38.273510817496465", atMarkerDragCancelsPendingClickJourneyTests.cs:108— confirmedmap.jsat that commit still has the pre-fix, undeferreddragendhandler (leafletMarker.on("dragend", () => reportPick(...)), no cancellation), so this is a genuine failure against unfixed code, not a stale/misleading status. Also confirmed the first test version (97562c9) asserts only the settled value after a back-to-back click-then-drag-then-wait — exactly the shape that lets a marker's unconditionaldragendwrite win regardless of cancellation, and that version's run (#685) reportssuccessagainst the same unfixed code, corroborating the "passed even reverted" claim. The lesson is real, not merely reasoned.Suite totals in the PR body match job 1044/1045's logs exactly (12/139/123/751+4/321/605, e2e 21) — genuinely re-derived, not carried over.
map.jslogic review (deferSingleClick/cancelPendingClick/toLeafletMarkers): the pending-clicks-as-list redesign is correct —cancelPendingClickiterates and clears every entry (not just the nearest), sodispose()still fully drains both channels with no leak; the timeout callback removes only its own entry by identity (indexOf(entry)), so two independently-pending clicks at different points each fire on their own schedule without clobbering each other's bookkeeping. Markerdragstart/dragendboth cancel both channels unconditionally, which is harmless (the inactive channel'scancelPendingClickis a no-op).Gap 1 (positional check) has no E2E coverage, and I don't think that's the same problem as this file's three prior "reasoned, not reproduced" burns. Those were all cases of a genuine environmental limitation (CDP touch input not reaching a DOM listener) forcing an untested claim. Two real mouse clicks at different screen positions have no such limitation — Playwright's
ClickAsyncat two positions is entirely reliable here, so this gap is closer to "didn't write the test" than "couldn't." That said, the ticket explicitly permitted recording gap 1 as a judged, non-blocking decision rather than closing it, and ADR-0145 does exactly that, with reasoning specific to why it wasn't added (no existing journey shape touches it, would need new plumbing). I'd take this as a good candidate for a quick follow-up rather than a blocker for this PR — the multi-pending-click list is a real behavioural change on every click and would benefit from a positive-case E2E proof, even a narrow one.ADR annotations, README index diff, and British English all check out.
2be052302d3c9c630109Verdict: mergeable
Confirmation pass at new head
13b70c1(matches PR's own reported head).Job 1057's log genuinely shows the discarded-both defect, not a locator bug. Matched run 694 to
head_sha96a01f9(not to any id-derived URL, per the earlier lesson in this same PR). Failure:Locator expected to be visible... waiting for Locator("#place-form-latitude")at line 75 of the new test — the same#place-form-latitudelocator dozens of other passing tests (including this PR's ownMarkerDragCancelsPendingClickJourneyTests) use successfully, so the selector itself isn't in question. Confirmedmap.jsat96a01f9has the distance check itself stubbed topending.length > 0 ? 0 : -1(any pending entry matches, regardless of position) rather than an unrelated typo elsewhere — a targeted reversion of exactly the thing under test, producing exactly the "both clicks cancel each other, neither schedules" failure mode the PR describes.Discriminates the shipped code, not just the stub.
mainat118e1bdstill has ADR-0144's original single-slotdeferSingleClick— any second click within the window unconditionally clears the pending slot and returns, scheduling nothing — behaviourally identical to the96a01f9stub for this scenario. So the new test would redden against currentmaintoo, not only against a straw-man revert.ADR-0145 correction is accurate. The "Gap 1 has no equivalent real-input E2E coverage" paragraph is replaced with one correctly describing
DistantMapClicksBothSurviveJourneyTests, its watched-red run, and the exact failure message — matches the job log. No other paragraph in the record still claims an absent proof.Rebase disturbed nothing.
src/PlaceMark.WebUI/wwwroot/js/map.js,docs/adr/0144-...md, andMarkerDragCancelsPendingClickJourneyTests.csare byte-identical to the previously-reviewed head (2be0523) — my earlier findings on the list-based pending-click redesign stand unchanged.docs/adr/README.md's diff is still confined to the 0144/0145 rows.