Follow-up tracking for Yoga layout-engine work intentionally deferred from #658 / #670 (the layout-cache-guards + inline-per-node-arrays perf PR). Filing so the deferred items and one residual correctness gap surfaced by the pre-GO audit aren't lost. Scope: src/Reactor/Yoga/ only.
Deferred perf optimizations (each: why deferred / what it'd take)
Residual correctness gap surfaced by the pre-GO stale-state audit (please triage)
Flagged as correctness, not just perf — included here for traceability but may warrant its own priority/label.
Cross-axis measure-cache staleness after the #138 setter guards. The #138 equality guards + FlexPanel no longer re-dirtying every child each MeasureOverride correctly enable the layout cache, but they remove the implicit per-frame refresh that used to keep measure-backed leaves fresh. The #140 ComputeMinContent probe re-dirties a leaf only on a MAIN-axis min-content change — ResolveMinDimension returns Undefined for the cross axis (no probe). So a content change that alters a flex child's cross-axis size (e.g. wrapping-text height when the longest word is unchanged), or the size of a flex-basis:0 / explicit-min child, without changing main-axis min-content, leaves the Yoga leaf clean → the input-keyed measurement cache (CachedLayout/CachedMeasurements) serves a stale size. Pre-#138, the accidental per-frame re-dirty masked this. Same risk class as the already-fixed ComputedFlexBasis regression (#670), but for the measure cache rather than the resolved basis.
Exposure: narrow but real and non-self-correcting — flex items with multi-line/wrapping text whose height changes from content updates, or content-driven cross-axis sizing under basis:0/explicit-min. Common single-line cases (grid cells, labels, numbers) stay correct because their main-axis min-content tracks the change.
Candidate fixes: (a) host/reconciler → YogaNode.MarkDirty bridge when measure-backed child content changes — the faithful Yoga contract; cross-cutting (Core/Reconciler + a FlexPanel notify API), preserves the perf win. (b) FlexPanel-local: re-measure each measure-leaf at its last-resolved constraint and compare, dirtying on change — fully correct but adds a measure/child/pass (perf-sensitive, wobble/LayoutCycleException care needed). (c) Probe both axes in ComputeMinContent — changes CSS cross-axis-min semantics, not acceptable as-is.
A repro selftest (mutate a wrapping-text flex child's content without touching its Yoga style; assert the panel height updates) would pin this; the fixture lives outside src/Reactor/Yoga/.
Refs: #658, #670. Exposed by the #138 setter-equality guards.
Follow-up tracking for Yoga layout-engine work intentionally deferred from #658 / #670 (the layout-cache-guards + inline-per-node-arrays perf PR). Filing so the deferred items and one residual correctness gap surfaced by the pre-GO audit aren't lost. Scope:
src/Reactor/Yoga/only.Deferred perf optimizations (each: why deferred / what it'd take)
Skip clean children in
ApplyAttachedProperties(finding fix(selftest): stabilize HostControlMountFunc + Tab/RadioButtons selection flakes #139).Why deferred: the per-child min-content re-measure (samples(demo-script-tool): generate/re-gen fixes + session logging #140 below) is load-bearing for dirtying a leaf on content change, so blindly skipping "clean" children would drop genuine relayouts. What it'd take: maintain a precise dirty-children
HashSetfromOnChildPropertyChangedplus a host content-change signal, then skip only provably-clean children. The flagship chore(deps): bump Microsoft.WindowsAppSDK 2.0.0-preview2 → 2.0.1 #138 setter guards + build: migrate from .NET 9 to .NET 10 (LTS) #147 attached-prop cache already removed the bulk of the per-frame cost, so this is incremental.Cache / skip the
ComputeMinContentre-measure (finding samples(demo-script-tool): generate/re-gen fixes + session logging #140).Why deferred: it is currently the only mechanism that dirties a Yoga leaf when a measure-backed child's main-axis content changes (
node.MinWidth = ComputeMinContent(...)→ equality-guarded setter dirties on change). Removing it would drop genuine relayouts. What it'd take: a host/reconciler→YogaNode.MarkDirtybridge on measure-backed content change (the real-Yoga contract), after which the per-pass probe can be cached perUIElementand skipped when clean.Delete
LayoutResults.Reset()(finding fix(cli): correct scaffolder project path and drop stale WindowsSdkPackageVersion #146).Why deferred: dead code (no callers); the GC concern it addressed is superseded by [Bug] Controls with readonly dependency properties are not supported #142 making
CachedMeasurementa struct. What it'd take: confirm no references and delete (or gate behind the dirty-prop work).Residual correctness gap surfaced by the pre-GO stale-state audit (please triage)
Cross-axis measure-cache staleness after the #138 setter guards. The #138 equality guards + FlexPanel no longer re-dirtying every child each
MeasureOverridecorrectly enable the layout cache, but they remove the implicit per-frame refresh that used to keep measure-backed leaves fresh. The #140ComputeMinContentprobe re-dirties a leaf only on a MAIN-axis min-content change —ResolveMinDimensionreturnsUndefinedfor the cross axis (no probe). So a content change that alters a flex child's cross-axis size (e.g. wrapping-text height when the longest word is unchanged), or the size of aflex-basis:0/ explicit-minchild, without changing main-axis min-content, leaves the Yoga leaf clean → the input-keyed measurement cache (CachedLayout/CachedMeasurements) serves a stale size. Pre-#138, the accidental per-frame re-dirty masked this. Same risk class as the already-fixedComputedFlexBasisregression (#670), but for the measure cache rather than the resolved basis.Exposure: narrow but real and non-self-correcting — flex items with multi-line/wrapping text whose height changes from content updates, or content-driven cross-axis sizing under
basis:0/explicit-min. Common single-line cases (grid cells, labels, numbers) stay correct because their main-axis min-content tracks the change.Candidate fixes: (a) host/reconciler →
YogaNode.MarkDirtybridge when measure-backed child content changes — the faithful Yoga contract; cross-cutting (Core/Reconciler + a FlexPanel notify API), preserves the perf win. (b) FlexPanel-local: re-measure each measure-leaf at its last-resolved constraint and compare, dirtying on change — fully correct but adds a measure/child/pass (perf-sensitive, wobble/LayoutCycleExceptioncare needed). (c) Probe both axes inComputeMinContent— changes CSS cross-axis-min semantics, not acceptable as-is.A repro selftest (mutate a wrapping-text flex child's content without touching its Yoga style; assert the panel height updates) would pin this; the fixture lives outside
src/Reactor/Yoga/.Refs: #658, #670. Exposed by the #138 setter-equality guards.