fix(layout): preserve live-paint allocation budget
- commit
- fc1ff4f514e5bdec27989d0347183ceb4084d522
- author
- brice · · 2026-07-24 15:12 UTC
- committer
- brice · · 2026-07-25 04:08 UTC
- parent
- 44c9bd0
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +9 -11
M internal/app/transport_observability_test.go +1 -0
| @@ -203,6 +203,7 @@ type runtimeObserverFunc func(ports.RuntimeMark) | |||
| 203 | 203 | func (f runtimeObserverFunc) ObserveRuntime(mark ports.RuntimeMark) { f(mark) } | |
| 204 | 204 | ||
| 205 | 205 | func TestRunAttachPropagatesOneObserverToRemoteTransportFactory(t *testing.T) { | |
| 206 | + | t.Setenv("VEV", "") | |
| 206 | 207 | t.Setenv("XDG_STATE_HOME", t.TempDir()) | |
| 207 | 208 | t.Setenv("XDG_RUNTIME_DIR", t.TempDir()) | |
| 208 | 209 | t.Setenv(envRemoteTransport, string(ports.RemoteTransportStdio)) | |
| @@ -203,6 +203,7 @@ type runtimeObserverFunc func(ports.RuntimeMark) | |||||
| 203 | func (f runtimeObserverFunc) ObserveRuntime(mark ports.RuntimeMark) { f(mark) } | 203 | func (f runtimeObserverFunc) ObserveRuntime(mark ports.RuntimeMark) { f(mark) } | ||
| 204 | 204 | ||||
| 205 | func TestRunAttachPropagatesOneObserverToRemoteTransportFactory(t *testing.T) { | 205 | func TestRunAttachPropagatesOneObserverToRemoteTransportFactory(t *testing.T) { | ||
| 206 | + | t.Setenv("VEV", "") | |||
| 206 | t.Setenv("XDG_STATE_HOME", t.TempDir()) | 207 | t.Setenv("XDG_STATE_HOME", t.TempDir()) | ||
| 207 | t.Setenv("XDG_RUNTIME_DIR", t.TempDir()) | 208 | t.Setenv("XDG_RUNTIME_DIR", t.TempDir()) | ||
| 208 | t.Setenv(envRemoteTransport, string(ports.RemoteTransportStdio)) | 209 | t.Setenv(envRemoteTransport, string(ports.RemoteTransportStdio)) | ||
M internal/usecase/layout/geometry.go +8 -11
| @@ -185,13 +185,13 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||
| 185 | 185 | remaining := total | |
| 186 | 186 | ||
| 187 | 187 | for { | |
| 188 | - | normalized, sum := normalizedActiveWeights(weights, active) | |
| 188 | + | largest, sum := activeWeightScale(weights, active) | |
| 189 | 189 | var pinned []int | |
| 190 | 190 | for i := range active { | |
| 191 | 191 | if !active[i] { | |
| 192 | 192 | continue | |
| 193 | 193 | } | |
| 194 | - | quota := float64(remaining) * normalized[i] / sum | |
| 194 | + | quota := float64(remaining) * (effectiveWeight(weights[i]) / largest) / sum | |
| 195 | 195 | if quota < float64(minimums[i]) { | |
| 196 | 196 | pinned = append(pinned, i) | |
| 197 | 197 | } | |
| @@ -206,7 +206,7 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||
| 206 | 206 | } | |
| 207 | 207 | } | |
| 208 | 208 | ||
| 209 | - | normalized, sum := normalizedActiveWeights(weights, active) | |
| 209 | + | largest, sum := activeWeightScale(weights, active) | |
| 210 | 210 | type remainder struct { | |
| 211 | 211 | index int | |
| 212 | 212 | fraction float64 | |
| @@ -217,7 +217,7 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||
| 217 | 217 | if !active[i] { | |
| 218 | 218 | continue | |
| 219 | 219 | } | |
| 220 | - | quota := float64(remaining) * normalized[i] / sum | |
| 220 | + | quota := float64(remaining) * (effectiveWeight(weights[i]) / largest) / sum | |
| 221 | 221 | whole := int(math.Floor(quota)) | |
| 222 | 222 | allocations[i] = whole | |
| 223 | 223 | allocated += whole | |
| @@ -232,23 +232,20 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||
| 232 | 232 | return allocations, true | |
| 233 | 233 | } | |
| 234 | 234 | ||
| 235 | - | func normalizedActiveWeights(weights []float64, active []bool) ([]float64, float64) { | |
| 235 | + | func activeWeightScale(weights []float64, active []bool) (float64, float64) { | |
| 236 | 236 | largest := 0.0 | |
| 237 | 237 | for i, weight := range weights { | |
| 238 | 238 | if active[i] { | |
| 239 | 239 | largest = math.Max(largest, effectiveWeight(weight)) | |
| 240 | 240 | } | |
| 241 | 241 | } | |
| 242 | - | normalized := make([]float64, len(weights)) | |
| 243 | 242 | sum := 0.0 | |
| 244 | 243 | for i, weight := range weights { | |
| 245 | - | if !active[i] { | |
| 246 | - | continue | |
| 244 | + | if active[i] { | |
| 245 | + | sum += effectiveWeight(weight) / largest | |
| 247 | 246 | } | |
| 248 | - | normalized[i] = effectiveWeight(weight) / largest | |
| 249 | - | sum += normalized[i] | |
| 250 | 247 | } | |
| 251 | - | return normalized, sum | |
| 248 | + | return largest, sum | |
| 252 | 249 | } | |
| 253 | 250 | ||
| 254 | 251 | func solveStack(n *Node, r domain.Rect, out *[]Placement) bool { | |
| @@ -185,13 +185,13 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||||
| 185 | remaining := total | 185 | remaining := total | ||
| 186 | 186 | ||||
| 187 | for { | 187 | for { | ||
| 188 | - | normalized, sum := normalizedActiveWeights(weights, active) | 188 | + | largest, sum := activeWeightScale(weights, active) |
| 189 | var pinned []int | 189 | var pinned []int | ||
| 190 | for i := range active { | 190 | for i := range active { | ||
| 191 | if !active[i] { | 191 | if !active[i] { | ||
| 192 | continue | 192 | continue | ||
| 193 | } | 193 | } | ||
| 194 | - | quota := float64(remaining) * normalized[i] / sum | 194 | + | quota := float64(remaining) * (effectiveWeight(weights[i]) / largest) / sum |
| 195 | if quota < float64(minimums[i]) { | 195 | if quota < float64(minimums[i]) { | ||
| 196 | pinned = append(pinned, i) | 196 | pinned = append(pinned, i) | ||
| 197 | } | 197 | } | ||
| @@ -206,7 +206,7 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||||
| 206 | } | 206 | } | ||
| 207 | } | 207 | } | ||
| 208 | 208 | ||||
| 209 | - | normalized, sum := normalizedActiveWeights(weights, active) | 209 | + | largest, sum := activeWeightScale(weights, active) |
| 210 | type remainder struct { | 210 | type remainder struct { | ||
| 211 | index int | 211 | index int | ||
| 212 | fraction float64 | 212 | fraction float64 | ||
| @@ -217,7 +217,7 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||||
| 217 | if !active[i] { | 217 | if !active[i] { | ||
| 218 | continue | 218 | continue | ||
| 219 | } | 219 | } | ||
| 220 | - | quota := float64(remaining) * normalized[i] / sum | 220 | + | quota := float64(remaining) * (effectiveWeight(weights[i]) / largest) / sum |
| 221 | whole := int(math.Floor(quota)) | 221 | whole := int(math.Floor(quota)) | ||
| 222 | allocations[i] = whole | 222 | allocations[i] = whole | ||
| 223 | allocated += whole | 223 | allocated += whole | ||
| @@ -232,23 +232,20 @@ func distribute(total int, minimums []int, weights []float64) ([]int, bool) { | |||||
| 232 | return allocations, true | 232 | return allocations, true | ||
| 233 | } | 233 | } | ||
| 234 | 234 | ||||
| 235 | - | func normalizedActiveWeights(weights []float64, active []bool) ([]float64, float64) { | 235 | + | func activeWeightScale(weights []float64, active []bool) (float64, float64) { |
| 236 | largest := 0.0 | 236 | largest := 0.0 | ||
| 237 | for i, weight := range weights { | 237 | for i, weight := range weights { | ||
| 238 | if active[i] { | 238 | if active[i] { | ||
| 239 | largest = math.Max(largest, effectiveWeight(weight)) | 239 | largest = math.Max(largest, effectiveWeight(weight)) | ||
| 240 | } | 240 | } | ||
| 241 | } | 241 | } | ||
| 242 | - | normalized := make([]float64, len(weights)) | |||
| 243 | sum := 0.0 | 242 | sum := 0.0 | ||
| 244 | for i, weight := range weights { | 243 | for i, weight := range weights { | ||
| 245 | - | if !active[i] { | 244 | + | if active[i] { |
| 246 | - | continue | 245 | + | sum += effectiveWeight(weight) / largest |
| 247 | } | 246 | } | ||
| 248 | - | normalized[i] = effectiveWeight(weight) / largest | |||
| 249 | - | sum += normalized[i] | |||
| 250 | } | 247 | } | ||
| 251 | - | return normalized, sum | 248 | + | return largest, sum |
| 252 | } | 249 | } | ||
| 253 | 250 | ||||
| 254 | func solveStack(n *Node, r domain.Rect, out *[]Placement) bool { | 251 | func solveStack(n *Node, r domain.Rect, out *[]Placement) bool { | ||