Partially addresses #4522: document NeedsLayout invariant + lock in layout-convergence guards#5500
Draft
harder wants to merge 1 commit into
Draft
Partially addresses #4522: document NeedsLayout invariant + lock in layout-convergence guards#5500harder wants to merge 1 commit into
harder wants to merge 1 commit into
Conversation
…-read, add layout-convergence guards Addresses the safe, verifiable portion of tui-cs#4522 (`NeedsLayout` is buggy) and documents — with measurements — why the remaining "convergence redesign" is not warranted after the tui-cs#4973-era fixes (tui-cs#5357/tui-cs#5358/tui-cs#5359). Library: - View.Layout.cs: replace the "bogus" NeedsLayout region comment (called out in the issue) with an accurate description of the real invariant and the internal write sites; note why the setter is internal (test seam) pending full removal. - View.Layout.cs: LayoutSubViews now re-reads GetContentSize() after the SubViewLayout *event* too (it already did after the OnSubViewLayout virtual, tui-cs#4863), so a handler on that event that calls SetContentSize is honored. Tests: - StaleContentSizeCaptureTests: +1 regression test for the SubViewLayout-event content-size case. - LayoutConvergenceTests (new): permanent guards locking in the deterministic properties established by tui-cs#5357/tui-cs#5358/tui-cs#5359 — single-pass convergence, no spurious FrameChanged, bounded ancestor-chain fan-out (no subtree fan-out), Dim.Auto growth correctness, and Pos.Right sibling repositioning. - AllViewsRenderFingerprintTests (new): all-views smoke guard (every concrete View lays out + draws in design mode without throwing); also the harness used to prove the LayoutSubViews change is byte-identical in rendering across all 61 view types. Verification: UnitTestsParallelizable 17,382 passed; UnitTests.NonParallelizable 74 passed; all-views Driver.ToString() fingerprint identical with/without the library change. See plans/4522-needslayout-lifecycle.md for the full assessment and measured fan-out numbers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Partially addresses #4522 (
NeedsLayoutis buggy).Summary
This PR delivers the safe, verifiable portion of #4522 and — critically — measures the current layout-convergence behavior to determine whether the long-feared
NeedsLayout/SetFrameconvergence redesign is still warranted after the #4973-era fixes (#5357 / #5358 / #5359). It is not, and this PR locks in the good behavior with regression guards instead of taking on a high-risk rewrite.What changed
Library (
View.Layout.cs)NeedsLayoutregion comment — which the issue explicitly calls "bogus" ("We expose no setter…") — with an accurate description of the real invariant and the internal write sites, and a note on why the setter staysinternal(test seam) pending full removal.LayoutSubViewsnow re-readsGetContentSize()after theSubViewLayoutevent as well. It already did so after theOnSubViewLayoutvirtual (Partially Fixes #4522 - StaleContentSizecapture #4863); this closes the symmetric gap so a handler on the event that callsSetContentSizeis honored.Tests
StaleContentSizeCaptureTests: +1 regression test for theSubViewLayout-event content-size case.LayoutConvergenceTests(new): permanent guards that pin the deterministic properties established by Split upward layout propagation from downward subtree invalidation #5357/Stop child-only redraws from escalating into full parent redraws #5358/Fix NeedsDrawRect accumulation so partial invalidations stay partial #5359 — single-pass convergence, no spuriousFrameChanged, bounded ancestor-chain fan-out (no subtree fan-out),Dim.Autogrowth correctness, andPos.Rightsibling repositioning (each asserted single-pass).AllViewsRenderFingerprintTests(new): an all-views smoke guard (every concreteViewlays out + draws in design mode without throwing), and the harness used to prove render-neutrality below.Measured convergence (the key finding)
Fan-out of a single property change on current
develop:LayoutSubViewsFrameChangedFrameChanged == 1) — Bug There is a problem with the high-intensity colors, they are not showing up #1's spurious churn gone.≈ depth+2), far below total view count (Split upward layout propagation from downward subtree invalidation #5357).Dim.Autoparents still converge in one pass; the upwardSetFrame → NeedsLayoutmark is load-bearing for that.The only residual is O(depth) ancestor re-layout that changes no frame. Removing it needs dependency-aware invalidation, which is high-risk to
Dim.Autocorrectness for an already-single-pass gain.What this deliberately does NOT do
SetFrameself-dirtying guard / dependency-aware invalidation (Bug There is a problem with the high-intensity colors, they are not showing up #1/Bug in FindDeepestView #6) — the measurements show it is not warranted and the upward mark is load-bearing forDim.Auto.Layout()workaround calls — those are convergence crutches that need individual, visually-verified treatment.NeedsLayoutsetter — it has a legitimate test seam; full removal needs a replacement.These remain as deferred, now data-backed as low priority (see
plans/4522-needslayout-lifecycle.md).Verification
Driver.ToString()for all 61 concrete view types with theLayoutSubViewschange applied vs. reverted → byte-identical (combined hashCCF30A9EA3C45AB5both ways). The change is provably render- and layout-neutral across all views.AllViewsDrawTestspasses (every view draws with exactly one layout pass).UnitTestsParallelizable: 17,382 passed, 0 failed.UnitTests.NonParallelizable: 74 passed, 0 failed.To pull down this PR locally
🤖 Generated with Claude Code