Record being wrong about which change broke a test

A UI test went red in the same run that adopted three new APIs. The one
touching that screen was reverted; the test still failed. A modifier
order was corrected; still failed. Simulator data was wiped; still
failed. Running it against a clean checkout — which should have been the
first move, not the fourth — it failed there too, with none of the work
present.

The scrolling entry had already been rewritten to explain the fault in
confident detail. That write-up was fiction, so it now says what actually
happened: the API was convicted on circumstance and remains unproven
here, and the one claim that survives is about its two-way binding
costing invalidations.

xcode-practice gets the general lesson, since it will outlive this
particular test: stash and rerun before reasoning about which edit did
it, and a note recording a false cause is worse than no note, because
the next person believes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
TomUviandClaude Opus 5 committed 2026-08-17 01:04:24 +02:00
1 parent f5a3d932fa
commit 542dd925d0
4 files changed
+46 -5

No files matched your search

@@ -25,9 +25,29 @@ following the offset while the user drags.
to reach `proxy.scrollTo` from a `.task`. In our card list that is the
filter chip strip, which scrolls the active chip into view.
**Step forward?** Modest but real. One layer of nesting disappears and the
scroll position stops being write-only. Not urgent — the existing code
works — so worth doing when that view is touched for another reason.
**Step forward? Unproven — we backed it out.** Swapping `ScrollViewReader`
for `.scrollPosition(id:)` coincided with the UI test for that strip
failing, so it looked like the culprit and was reverted. It was not:
the same test fails on a completely clean tree, with none of the change
present. Something in the environment broke that test, and the swap was
convicted on circumstance.
The revert stands anyway, because it was never worth much here — this
strip only ever *writes* a scroll target, which is exactly what the proxy
already does. But the reasoning above is worth keeping, because being
wrong about it taught the real lesson: **when a change and a failure
arrive together, check the failure against an unchanged tree before
concluding.** Two rounds of edits went into explaining a fault that was
not there.
One thing that does hold, independent of all that:
- **`scrollPosition` is two-way, so it costs invalidations.** It writes to
its binding on every scroll, where the proxy only takes commands. It
therefore belongs in a small view. Ours would have sat in a screen whose
body derives a sorted, grouped card list — every drag of the strip would
have recomputed all of it. Extracting the strip into its own view was
worth keeping regardless of which scrolling API ends up inside it.
**Available since.** iOS 17, so nothing blocks it at our deployment
target. `onScrollGeometryChange` needs iOS 18.