chore(contract): remove obsolete phase artifacts
- commit
- 8086da1fbc78504ba9a17e7764a340c6ce622899
- author
- brice · · 2026-08-03 08:49 UTC
- committer
- brice · · 2026-08-04 03:19 UTC
- parent
- 0cbba84
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
7 files · +9 -194
M docs/performance.md +3 -65
| @@ -48,10 +48,9 @@ retransmits, pending, ACK RTT) remain separate from duration calculations. | |||
| 48 | 48 | ||
| 49 | 49 | ### Historical proxy ANSI baseline | |
| 50 | 50 | ||
| 51 | - | Before the structured path, proxied state-bearing screen updates transported ANSI | |
| 52 | - | and were applied through the local proxy VT parser. In the candidate, proxied | |
| 53 | - | state-bearing frames are `MsgScreenUpdate`; this parser benchmark remains a | |
| 54 | - | historical diagnostic. Ordinary local output remains the ANSI `MsgOutput` | |
| 51 | + | Before this refactor, proxied state-bearing screen updates transported ANSI | |
| 52 | + | and were applied through the local proxy VT parser. This parser benchmark remains | |
| 53 | + | a historical diagnostic. Ordinary local output remains the ANSI `MsgOutput` | |
| 55 | 54 | guardrail. | |
| 56 | 55 | ||
| 57 | 56 | The binaries were built from clean, exact commits in temporary clones so their | |
| @@ -101,67 +100,6 @@ go test ./pkg/renderer -run '^$' -bench '^BenchmarkRenderer' -benchmem -count=10 | |||
| 101 | 100 | The candidate guardrail completed with Go 1.26.5; its ten-repetition output is | |
| 102 | 101 | retained at `/tmp/vev-perf-results/candidate-2b48abf9-renderer.txt`. | |
| 103 | 102 | ||
| 104 | - | ### Comparable proxy pipeline benchmark | |
| 105 | - | ||
| 106 | - | `BenchmarkProxyPipeline` is a local comparison harness, not a network or | |
| 107 | - | public-CLI result. Its four fixtures—one-cell, full-line, styled-line, and | |
| 108 | - | full-width scroll—use semantically paired initial and mutated `renderer.Frame` | |
| 109 | - | values. Snapshot/full-paint setup is completed before the timed steady-state | |
| 110 | - | loop; the loop applies the same mutation and consecutive state transitions on | |
| 111 | - | both sides. | |
| 112 | - | ||
| 113 | - | The `ansi-pipeline` slice measures `Renderer.Prepare`/bytes, | |
| 114 | - | `MarshalOutput`, a real benchmark sender that performs the simulated transport, | |
| 115 | - | `UnmarshalOutput`, `proxyANSIApplyState.apply`, and `Commit`. The | |
| 116 | - | `structured-pipeline` slice measures `structuredOutputStream.prepare` (including | |
| 117 | - | `MarshalScreenUpdate`), a real benchmark sender that performs the simulated | |
| 118 | - | transport, `UnmarshalScreenUpdate`, `proxyScreenState.Apply`, damage | |
| 119 | - | acknowledgement, and `prepared.send` commit. Both slices are local and exclude | |
| 120 | - | network effects. `wirebytes/op` is the complete message payload size excluding | |
| 121 | - | connection framing; unlike the historical table above, it includes the | |
| 122 | - | `MsgOutput` or `MsgScreenUpdate` payload header. `B/op` is the benchmark | |
| 123 | - | allocator metric; explicitly, `B/op != wirebytes/op`. `spans/op` is reported | |
| 124 | - | separately for structured updates. Run it with: | |
| 125 | - | ||
| 126 | - | ```sh | |
| 127 | - | cd /tmp/vev-perf-candidate-2b48abf9-clone | |
| 128 | - | go test ./internal/usecase/daemon -run '^$' \ | |
| 129 | - | -bench '^BenchmarkProxyPipeline$' -benchmem -count=10 \ | |
| 130 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-proxy-pipeline.txt | |
| 131 | - | ``` | |
| 132 | - | ||
| 133 | - | Measured candidate medians from that command (Go 1.26.5, Linux/amd64): | |
| 134 | - | ||
| 135 | - | | fixture | ANSI ns/op | structured ns/op | ANSI B/op | structured B/op | ANSI wirebytes/op | structured wirebytes/op | | |
| 136 | - | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | |
| 137 | - | | one-cell | 530.55 | 1,016.5 | 192 | 888 | 37 | 71 | | |
| 138 | - | | full-line | 8,637.5 | 22,187.5 | 674 | 19,928 | 154 | 190 | | |
| 139 | - | | styled-line | 10,565.5 | 25,682 | 1,652 | 24,952 | 388 | 432 | | |
| 140 | - | | full-width-scroll | 55,713.5 | 73,858 | 760 | 19,944 | 177 | 196 | | |
| 141 | - | ||
| 142 | - | The component diagnostics completed ten repetitions with separate | |
| 143 | - | commands; their raw output is retained under `/tmp/vev-perf-results/`: | |
| 144 | - | ||
| 145 | - | ```sh | |
| 146 | - | cd /tmp/vev-perf-candidate-2b48abf9-clone | |
| 147 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkProxyANSIApply$' -benchmem -count=10 \ | |
| 148 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-proxy-ansi.txt | |
| 149 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkStructuredOutputPrepare$' -benchmem -count=10 \ | |
| 150 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-structured-prepare.txt | |
| 151 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkProxyScreenStateApply$' -benchmem -count=10 \ | |
| 152 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-screen-apply.txt | |
| 153 | - | ``` | |
| 154 | - | ||
| 155 | - | Their medians are respectively 107.45/5,107/6,561.5/251,126.5 ns/op for | |
| 156 | - | ANSI one-cell/full-line/styled-line/scroll rows as reported in the raw file; | |
| 157 | - | structured prepare medians are 673/16,928/23,220.5/61,424.5 ns/op and decoded | |
| 158 | - | apply medians are 53.29/1,225/1,234/3,659.5 ns/op. These remain component | |
| 159 | - | diagnostics, not head-to-head pipeline comparisons. | |
| 160 | - | ||
| 161 | - | The 35-scenario public-CLI harness A/B matrix remains the adoption gate. This | |
| 162 | - | local pipeline benchmark does not replace that gate and this document records | |
| 163 | - | no unmeasured result or conclusion. | |
| 164 | - | ||
| 165 | 103 | ### Public-CLI transport runs | |
| 166 | 104 | ||
| 167 | 105 | The adoption gate requires a 10-second warmup, a 30-second measured interval, | |
| @@ -48,10 +48,9 @@ retransmits, pending, ACK RTT) remain separate from duration calculations. | |||||
| 48 | 48 | ||||
| 49 | ### Historical proxy ANSI baseline | 49 | ### Historical proxy ANSI baseline | ||
| 50 | 50 | ||||
| 51 | - | Before the structured path, proxied state-bearing screen updates transported ANSI | 51 | + | Before this refactor, proxied state-bearing screen updates transported ANSI |
| 52 | - | and were applied through the local proxy VT parser. In the candidate, proxied | 52 | + | and were applied through the local proxy VT parser. This parser benchmark remains |
| 53 | - | state-bearing frames are `MsgScreenUpdate`; this parser benchmark remains a | 53 | + | a historical diagnostic. Ordinary local output remains the ANSI `MsgOutput` |
| 54 | - | historical diagnostic. Ordinary local output remains the ANSI `MsgOutput` | |||
| 55 | guardrail. | 54 | guardrail. | ||
| 56 | 55 | ||||
| 57 | The binaries were built from clean, exact commits in temporary clones so their | 56 | The binaries were built from clean, exact commits in temporary clones so their | ||
| @@ -101,67 +100,6 @@ go test ./pkg/renderer -run '^$' -bench '^BenchmarkRenderer' -benchmem -count=10 | |||||
| 101 | The candidate guardrail completed with Go 1.26.5; its ten-repetition output is | 100 | The candidate guardrail completed with Go 1.26.5; its ten-repetition output is | ||
| 102 | retained at `/tmp/vev-perf-results/candidate-2b48abf9-renderer.txt`. | 101 | retained at `/tmp/vev-perf-results/candidate-2b48abf9-renderer.txt`. | ||
| 103 | 102 | ||||
| 104 | - | ### Comparable proxy pipeline benchmark | |||
| 105 | - | ||||
| 106 | - | `BenchmarkProxyPipeline` is a local comparison harness, not a network or | |||
| 107 | - | public-CLI result. Its four fixtures—one-cell, full-line, styled-line, and | |||
| 108 | - | full-width scroll—use semantically paired initial and mutated `renderer.Frame` | |||
| 109 | - | values. Snapshot/full-paint setup is completed before the timed steady-state | |||
| 110 | - | loop; the loop applies the same mutation and consecutive state transitions on | |||
| 111 | - | both sides. | |||
| 112 | - | ||||
| 113 | - | The `ansi-pipeline` slice measures `Renderer.Prepare`/bytes, | |||
| 114 | - | `MarshalOutput`, a real benchmark sender that performs the simulated transport, | |||
| 115 | - | `UnmarshalOutput`, `proxyANSIApplyState.apply`, and `Commit`. The | |||
| 116 | - | `structured-pipeline` slice measures `structuredOutputStream.prepare` (including | |||
| 117 | - | `MarshalScreenUpdate`), a real benchmark sender that performs the simulated | |||
| 118 | - | transport, `UnmarshalScreenUpdate`, `proxyScreenState.Apply`, damage | |||
| 119 | - | acknowledgement, and `prepared.send` commit. Both slices are local and exclude | |||
| 120 | - | network effects. `wirebytes/op` is the complete message payload size excluding | |||
| 121 | - | connection framing; unlike the historical table above, it includes the | |||
| 122 | - | `MsgOutput` or `MsgScreenUpdate` payload header. `B/op` is the benchmark | |||
| 123 | - | allocator metric; explicitly, `B/op != wirebytes/op`. `spans/op` is reported | |||
| 124 | - | separately for structured updates. Run it with: | |||
| 125 | - | ||||
| 126 | - | ```sh | |||
| 127 | - | cd /tmp/vev-perf-candidate-2b48abf9-clone | |||
| 128 | - | go test ./internal/usecase/daemon -run '^$' \ | |||
| 129 | - | -bench '^BenchmarkProxyPipeline$' -benchmem -count=10 \ | |||
| 130 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-proxy-pipeline.txt | |||
| 131 | - | ``` | |||
| 132 | - | ||||
| 133 | - | Measured candidate medians from that command (Go 1.26.5, Linux/amd64): | |||
| 134 | - | ||||
| 135 | - | | fixture | ANSI ns/op | structured ns/op | ANSI B/op | structured B/op | ANSI wirebytes/op | structured wirebytes/op | | |||
| 136 | - | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | |||
| 137 | - | | one-cell | 530.55 | 1,016.5 | 192 | 888 | 37 | 71 | | |||
| 138 | - | | full-line | 8,637.5 | 22,187.5 | 674 | 19,928 | 154 | 190 | | |||
| 139 | - | | styled-line | 10,565.5 | 25,682 | 1,652 | 24,952 | 388 | 432 | | |||
| 140 | - | | full-width-scroll | 55,713.5 | 73,858 | 760 | 19,944 | 177 | 196 | | |||
| 141 | - | ||||
| 142 | - | The component diagnostics completed ten repetitions with separate | |||
| 143 | - | commands; their raw output is retained under `/tmp/vev-perf-results/`: | |||
| 144 | - | ||||
| 145 | - | ```sh | |||
| 146 | - | cd /tmp/vev-perf-candidate-2b48abf9-clone | |||
| 147 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkProxyANSIApply$' -benchmem -count=10 \ | |||
| 148 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-proxy-ansi.txt | |||
| 149 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkStructuredOutputPrepare$' -benchmem -count=10 \ | |||
| 150 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-structured-prepare.txt | |||
| 151 | - | go test ./internal/usecase/daemon -run '^$' -bench '^BenchmarkProxyScreenStateApply$' -benchmem -count=10 \ | |||
| 152 | - | | tee /tmp/vev-perf-results/candidate-2b48abf9-screen-apply.txt | |||
| 153 | - | ``` | |||
| 154 | - | ||||
| 155 | - | Their medians are respectively 107.45/5,107/6,561.5/251,126.5 ns/op for | |||
| 156 | - | ANSI one-cell/full-line/styled-line/scroll rows as reported in the raw file; | |||
| 157 | - | structured prepare medians are 673/16,928/23,220.5/61,424.5 ns/op and decoded | |||
| 158 | - | apply medians are 53.29/1,225/1,234/3,659.5 ns/op. These remain component | |||
| 159 | - | diagnostics, not head-to-head pipeline comparisons. | |||
| 160 | - | ||||
| 161 | - | The 35-scenario public-CLI harness A/B matrix remains the adoption gate. This | |||
| 162 | - | local pipeline benchmark does not replace that gate and this document records | |||
| 163 | - | no unmeasured result or conclusion. | |||
| 164 | - | ||||
| 165 | ### Public-CLI transport runs | 103 | ### Public-CLI transport runs | ||
| 166 | 104 | ||||
| 167 | The adoption gate requires a 10-second warmup, a 30-second measured interval, | 105 | The adoption gate requires a 10-second warmup, a 30-second measured interval, | ||
M internal/ports/wire_size.go +0 -4
| @@ -21,7 +21,3 @@ func ValidateSize(size domain.Size) error { | |||
| 21 | 21 | } | |
| 22 | 22 | return nil | |
| 23 | 23 | } | |
| 24 | - | ||
| 25 | - | func validWireSize(size domain.Size) bool { | |
| 26 | - | return ValidateSize(size) == nil | |
| 27 | - | } | |
| @@ -21,7 +21,3 @@ func ValidateSize(size domain.Size) error { | |||||
| 21 | } | 21 | } | ||
| 22 | return nil | 22 | return nil | ||
| 23 | } | 23 | } | ||
| 24 | - | ||||
| 25 | - | func validWireSize(size domain.Size) bool { | |||
| 26 | - | return ValidateSize(size) == nil | |||
| 27 | - | } | |||
M internal/usecase/daemon/performance_benchmark_test.go +0 -71
| @@ -306,77 +306,6 @@ func proxyANSIBenchmarkFixtures() []proxyANSIBenchmarkFixture { | |||
| 306 | 306 | } | |
| 307 | 307 | } | |
| 308 | 308 | ||
| 309 | - | type proxyPipelineFixture struct { | |
| 310 | - | name string | |
| 311 | - | newFrame func() renderer.Frame | |
| 312 | - | damage []renderer.Damage | |
| 313 | - | mutate func(renderer.Frame, int) | |
| 314 | - | } | |
| 315 | - | ||
| 316 | - | func proxyPipelineANSISender(state *proxyANSIApplyState) func(ports.Frame) error { | |
| 317 | - | return func(frame ports.Frame) error { | |
| 318 | - | if frame.Type != ports.MsgOutput { | |
| 319 | - | return fmt.Errorf("ANSI benchmark sender received frame type %d", frame.Type) | |
| 320 | - | } | |
| 321 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 322 | - | if err != nil { | |
| 323 | - | return err | |
| 324 | - | } | |
| 325 | - | ack, reset, changed := state.apply(out) | |
| 326 | - | if ack != out.New || reset || !changed { | |
| 327 | - | return fmt.Errorf("ANSI benchmark apply = ack %d, reset %t, changed %t; want ack %d", ack, reset, changed, out.New) | |
| 328 | - | } | |
| 329 | - | return nil | |
| 330 | - | } | |
| 331 | - | } | |
| 332 | - | ||
| 333 | - | func benchmarkProxyANSIPipeline(b *testing.B, fixture proxyPipelineFixture) { | |
| 334 | - | b.Helper() | |
| 335 | - | frame := fixture.newFrame() | |
| 336 | - | ansiRenderer := renderer.New(renderer.Capabilities{}) | |
| 337 | - | ansiState := newProxyANSIApplyState(b) | |
| 338 | - | ansiSender := proxyPipelineANSISender(ansiState) | |
| 339 | - | initial, err := ansiRenderer.Prepare(frame, nil, true) | |
| 340 | - | if err != nil { | |
| 341 | - | b.Fatal(err) | |
| 342 | - | } | |
| 343 | - | if err := ansiSender(ports.Frame{ | |
| 344 | - | Type: ports.MsgOutput, | |
| 345 | - | Payload: ports.MarshalOutput(ports.Output{ | |
| 346 | - | Base: 0, | |
| 347 | - | New: 1, | |
| 348 | - | Data: initial.Bytes(), | |
| 349 | - | }), | |
| 350 | - | }); err != nil { | |
| 351 | - | b.Fatal(err) | |
| 352 | - | } | |
| 353 | - | initial.Commit() | |
| 354 | - | ||
| 355 | - | var wireBytes int | |
| 356 | - | b.ReportAllocs() | |
| 357 | - | b.ResetTimer() | |
| 358 | - | for i := 0; i < b.N; i++ { | |
| 359 | - | fixture.mutate(frame, i) | |
| 360 | - | draw, err := ansiRenderer.Prepare(frame, fixture.damage, false) | |
| 361 | - | if err != nil { | |
| 362 | - | b.Fatal(err) | |
| 363 | - | } | |
| 364 | - | next := ansiState.appliedState + 1 | |
| 365 | - | payload := ports.MarshalOutput(ports.Output{ | |
| 366 | - | Base: ansiState.appliedState, | |
| 367 | - | New: next, | |
| 368 | - | Data: draw.Bytes(), | |
| 369 | - | }) | |
| 370 | - | if err := ansiSender(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | |
| 371 | - | b.Fatal(err) | |
| 372 | - | } | |
| 373 | - | draw.Commit() | |
| 374 | - | wireBytes += len(payload) | |
| 375 | - | } | |
| 376 | - | b.StopTimer() | |
| 377 | - | b.ReportMetric(float64(wireBytes)/float64(b.N), "wirebytes/op") | |
| 378 | - | } | |
| 379 | - | ||
| 380 | 309 | func TestPerformanceFixtureCounters(t *testing.T) { | |
| 381 | 310 | fixture := newPerformanceFixture(t, performanceConfig{}) | |
| 382 | 311 | ||
| @@ -306,77 +306,6 @@ func proxyANSIBenchmarkFixtures() []proxyANSIBenchmarkFixture { | |||||
| 306 | } | 306 | } | ||
| 307 | } | 307 | } | ||
| 308 | 308 | ||||
| 309 | - | type proxyPipelineFixture struct { | |||
| 310 | - | name string | |||
| 311 | - | newFrame func() renderer.Frame | |||
| 312 | - | damage []renderer.Damage | |||
| 313 | - | mutate func(renderer.Frame, int) | |||
| 314 | - | } | |||
| 315 | - | ||||
| 316 | - | func proxyPipelineANSISender(state *proxyANSIApplyState) func(ports.Frame) error { | |||
| 317 | - | return func(frame ports.Frame) error { | |||
| 318 | - | if frame.Type != ports.MsgOutput { | |||
| 319 | - | return fmt.Errorf("ANSI benchmark sender received frame type %d", frame.Type) | |||
| 320 | - | } | |||
| 321 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |||
| 322 | - | if err != nil { | |||
| 323 | - | return err | |||
| 324 | - | } | |||
| 325 | - | ack, reset, changed := state.apply(out) | |||
| 326 | - | if ack != out.New || reset || !changed { | |||
| 327 | - | return fmt.Errorf("ANSI benchmark apply = ack %d, reset %t, changed %t; want ack %d", ack, reset, changed, out.New) | |||
| 328 | - | } | |||
| 329 | - | return nil | |||
| 330 | - | } | |||
| 331 | - | } | |||
| 332 | - | ||||
| 333 | - | func benchmarkProxyANSIPipeline(b *testing.B, fixture proxyPipelineFixture) { | |||
| 334 | - | b.Helper() | |||
| 335 | - | frame := fixture.newFrame() | |||
| 336 | - | ansiRenderer := renderer.New(renderer.Capabilities{}) | |||
| 337 | - | ansiState := newProxyANSIApplyState(b) | |||
| 338 | - | ansiSender := proxyPipelineANSISender(ansiState) | |||
| 339 | - | initial, err := ansiRenderer.Prepare(frame, nil, true) | |||
| 340 | - | if err != nil { | |||
| 341 | - | b.Fatal(err) | |||
| 342 | - | } | |||
| 343 | - | if err := ansiSender(ports.Frame{ | |||
| 344 | - | Type: ports.MsgOutput, | |||
| 345 | - | Payload: ports.MarshalOutput(ports.Output{ | |||
| 346 | - | Base: 0, | |||
| 347 | - | New: 1, | |||
| 348 | - | Data: initial.Bytes(), | |||
| 349 | - | }), | |||
| 350 | - | }); err != nil { | |||
| 351 | - | b.Fatal(err) | |||
| 352 | - | } | |||
| 353 | - | initial.Commit() | |||
| 354 | - | ||||
| 355 | - | var wireBytes int | |||
| 356 | - | b.ReportAllocs() | |||
| 357 | - | b.ResetTimer() | |||
| 358 | - | for i := 0; i < b.N; i++ { | |||
| 359 | - | fixture.mutate(frame, i) | |||
| 360 | - | draw, err := ansiRenderer.Prepare(frame, fixture.damage, false) | |||
| 361 | - | if err != nil { | |||
| 362 | - | b.Fatal(err) | |||
| 363 | - | } | |||
| 364 | - | next := ansiState.appliedState + 1 | |||
| 365 | - | payload := ports.MarshalOutput(ports.Output{ | |||
| 366 | - | Base: ansiState.appliedState, | |||
| 367 | - | New: next, | |||
| 368 | - | Data: draw.Bytes(), | |||
| 369 | - | }) | |||
| 370 | - | if err := ansiSender(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | |||
| 371 | - | b.Fatal(err) | |||
| 372 | - | } | |||
| 373 | - | draw.Commit() | |||
| 374 | - | wireBytes += len(payload) | |||
| 375 | - | } | |||
| 376 | - | b.StopTimer() | |||
| 377 | - | b.ReportMetric(float64(wireBytes)/float64(b.N), "wirebytes/op") | |||
| 378 | - | } | |||
| 379 | - | ||||
| 380 | func TestPerformanceFixtureCounters(t *testing.T) { | 309 | func TestPerformanceFixtureCounters(t *testing.T) { | ||
| 381 | fixture := newPerformanceFixture(t, performanceConfig{}) | 310 | fixture := newPerformanceFixture(t, performanceConfig{}) | ||
| 382 | 311 | ||||
M internal/usecase/daemon/proxy_input.go +0 -37
| @@ -6,7 +6,6 @@ import ( | |||
| 6 | 6 | "github.com/bnema/vev/internal/domain" | |
| 7 | 7 | "github.com/bnema/vev/internal/ports" | |
| 8 | 8 | "github.com/bnema/vev/internal/usecase/keys" | |
| 9 | - | "github.com/bnema/vev/internal/usecase/layout" | |
| 10 | 9 | "github.com/bnema/vev/internal/usecase/mouse" | |
| 11 | 10 | "github.com/bnema/vev/internal/usecase/palette" | |
| 12 | 11 | ) | |
| @@ -222,39 +221,3 @@ func proxiedNavConfig(cfg domain.NavConfig) domain.NavConfig { | |||
| 222 | 221 | } | |
| 223 | 222 | ||
| 224 | 223 | func proxiedJumpSearchesOtherSessions(proxied bool) bool { return !proxied } | |
| 225 | - | ||
| 226 | - | // focusDirProxied performs ordinary pane and tab overflow on the remote daemon, | |
| 227 | - | // but never follows OverflowSessions. The local proxy daemon is the only owner | |
| 228 | - | // allowed to change the selected session. | |
| 229 | - | func (d *Daemon) focusDirProxied(sess *session, ac *attachedClient, dir layout.Direction) error { | |
| 230 | - | target := resolveDaemonActionTargetForAttachment(sess, ac) | |
| 231 | - | oldFocus := layout.PaneID("") | |
| 232 | - | if target.pane != nil { | |
| 233 | - | oldFocus = target.pane.id | |
| 234 | - | } | |
| 235 | - | span, err := d.focusDirAt(sess, target.tab, target.pane, dir, ac) | |
| 236 | - | if err == nil { | |
| 237 | - | if ac != nil { | |
| 238 | - | d.finishPaneFocusForClient(sess, ac, target.tab, oldFocus, "proxy_input.go") | |
| 239 | - | } | |
| 240 | - | return nil | |
| 241 | - | } | |
| 242 | - | if !errors.Is(err, errNoNeighbor) || target.tab == nil || !overflowSourceEligible(sess, ac, target.tab) { | |
| 243 | - | return err | |
| 244 | - | } | |
| 245 | - | ||
| 246 | - | position, count := sess.tabIndexForAttachment(ac) | |
| 247 | - | step := resolveOverflow(dir, proxiedNavConfig(d.currentNavConfig()), position, count) | |
| 248 | - | if step.kind != overflowTabs { | |
| 249 | - | return errNoNeighbor | |
| 250 | - | } | |
| 251 | - | candidate, ok := d.prepareTabOverflowForAttachment(sess, ac, target.tab, dir, span, step.delta) | |
| 252 | - | if !ok || !d.commitTabOverflowForAttachment(sess, ac, candidate) { | |
| 253 | - | return errNoNeighbor | |
| 254 | - | } | |
| 255 | - | sess.selectAttachmentTab(ac, domain.TabStableID(candidate.target.stableID)) | |
| 256 | - | if ac != nil { | |
| 257 | - | d.finishPaneFocusForClient(sess, ac, candidate.target, candidate.targetOldFocus, "proxy_input.go") | |
| 258 | - | } | |
| 259 | - | return nil | |
| 260 | - | } | |
| @@ -6,7 +6,6 @@ import ( | |||||
| 6 | "github.com/bnema/vev/internal/domain" | 6 | "github.com/bnema/vev/internal/domain" | ||
| 7 | "github.com/bnema/vev/internal/ports" | 7 | "github.com/bnema/vev/internal/ports" | ||
| 8 | "github.com/bnema/vev/internal/usecase/keys" | 8 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 9 | - | "github.com/bnema/vev/internal/usecase/layout" | |||
| 10 | "github.com/bnema/vev/internal/usecase/mouse" | 9 | "github.com/bnema/vev/internal/usecase/mouse" | ||
| 11 | "github.com/bnema/vev/internal/usecase/palette" | 10 | "github.com/bnema/vev/internal/usecase/palette" | ||
| 12 | ) | 11 | ) | ||
| @@ -222,39 +221,3 @@ func proxiedNavConfig(cfg domain.NavConfig) domain.NavConfig { | |||||
| 222 | } | 221 | } | ||
| 223 | 222 | ||||
| 224 | func proxiedJumpSearchesOtherSessions(proxied bool) bool { return !proxied } | 223 | func proxiedJumpSearchesOtherSessions(proxied bool) bool { return !proxied } | ||
| 225 | - | ||||
| 226 | - | // focusDirProxied performs ordinary pane and tab overflow on the remote daemon, | |||
| 227 | - | // but never follows OverflowSessions. The local proxy daemon is the only owner | |||
| 228 | - | // allowed to change the selected session. | |||
| 229 | - | func (d *Daemon) focusDirProxied(sess *session, ac *attachedClient, dir layout.Direction) error { | |||
| 230 | - | target := resolveDaemonActionTargetForAttachment(sess, ac) | |||
| 231 | - | oldFocus := layout.PaneID("") | |||
| 232 | - | if target.pane != nil { | |||
| 233 | - | oldFocus = target.pane.id | |||
| 234 | - | } | |||
| 235 | - | span, err := d.focusDirAt(sess, target.tab, target.pane, dir, ac) | |||
| 236 | - | if err == nil { | |||
| 237 | - | if ac != nil { | |||
| 238 | - | d.finishPaneFocusForClient(sess, ac, target.tab, oldFocus, "proxy_input.go") | |||
| 239 | - | } | |||
| 240 | - | return nil | |||
| 241 | - | } | |||
| 242 | - | if !errors.Is(err, errNoNeighbor) || target.tab == nil || !overflowSourceEligible(sess, ac, target.tab) { | |||
| 243 | - | return err | |||
| 244 | - | } | |||
| 245 | - | ||||
| 246 | - | position, count := sess.tabIndexForAttachment(ac) | |||
| 247 | - | step := resolveOverflow(dir, proxiedNavConfig(d.currentNavConfig()), position, count) | |||
| 248 | - | if step.kind != overflowTabs { | |||
| 249 | - | return errNoNeighbor | |||
| 250 | - | } | |||
| 251 | - | candidate, ok := d.prepareTabOverflowForAttachment(sess, ac, target.tab, dir, span, step.delta) | |||
| 252 | - | if !ok || !d.commitTabOverflowForAttachment(sess, ac, candidate) { | |||
| 253 | - | return errNoNeighbor | |||
| 254 | - | } | |||
| 255 | - | sess.selectAttachmentTab(ac, domain.TabStableID(candidate.target.stableID)) | |||
| 256 | - | if ac != nil { | |||
| 257 | - | d.finishPaneFocusForClient(sess, ac, candidate.target, candidate.targetOldFocus, "proxy_input.go") | |||
| 258 | - | } | |||
| 259 | - | return nil | |||
| 260 | - | } | |||
M internal/usecase/daemon/proxy_input_test.go +1 -1
| @@ -216,7 +216,7 @@ func TestProxyInputAttentionOwnership(t *testing.T) { | |||
| 216 | 216 | }) | |
| 217 | 217 | } | |
| 218 | 218 | ||
| 219 | - | func TestProxyInputProxiedRemoteOwnershipGuards(t *testing.T) { | |
| 219 | + | func TestProxyInputRemoteOwnershipGuards(t *testing.T) { | |
| 220 | 220 | _, proxy, _, link, _ := newProxyInputHarness(t) | |
| 221 | 221 | require.True(t, proxy.caps.cannotAcceptMoves, "a proxy must reject move destinations locally") | |
| 222 | 222 | require.True(t, proxy.caps.cannotYieldMoves, "a proxy must reject move sources locally") | |
| @@ -216,7 +216,7 @@ func TestProxyInputAttentionOwnership(t *testing.T) { | |||||
| 216 | }) | 216 | }) | ||
| 217 | } | 217 | } | ||
| 218 | 218 | ||||
| 219 | - | func TestProxyInputProxiedRemoteOwnershipGuards(t *testing.T) { | 219 | + | func TestProxyInputRemoteOwnershipGuards(t *testing.T) { |
| 220 | _, proxy, _, link, _ := newProxyInputHarness(t) | 220 | _, proxy, _, link, _ := newProxyInputHarness(t) | ||
| 221 | require.True(t, proxy.caps.cannotAcceptMoves, "a proxy must reject move destinations locally") | 221 | require.True(t, proxy.caps.cannotAcceptMoves, "a proxy must reject move destinations locally") | ||
| 222 | require.True(t, proxy.caps.cannotYieldMoves, "a proxy must reject move sources locally") | 222 | require.True(t, proxy.caps.cannotYieldMoves, "a proxy must reject move sources locally") | ||
M internal/usecase/daemon/proxy_lifecycle_test.go +5 -5
| @@ -231,7 +231,7 @@ func TestProxyWarmReattachCancelsAndStaleTimerCannotRemoveProxy(t *testing.T) { | |||
| 231 | 231 | ||
| 232 | 232 | ac := &attachedClient{} | |
| 233 | 233 | proxy.sessionCore.mu.Lock() | |
| 234 | - | proxy.sessionCore.registerAttachmentLocked(ac) | |
| 234 | + | proxy.registerAttachmentLocked(ac) | |
| 235 | 235 | proxy.sessionCore.mu.Unlock() | |
| 236 | 236 | d.cancelProxyWarmForAttachment(proxy, ac) | |
| 237 | 237 | awaitTestCompletion(t, firstToken.done, "first proxy warm lifecycle did not complete") | |
| @@ -242,8 +242,8 @@ func TestProxyWarmReattachCancelsAndStaleTimerCannotRemoveProxy(t *testing.T) { | |||
| 242 | 242 | d.mu.Unlock() | |
| 243 | 243 | ||
| 244 | 244 | proxy.sessionCore.mu.Lock() | |
| 245 | - | for _, attachment := range proxy.sessionCore.snapshotAttachmentsLocked() { | |
| 246 | - | proxy.sessionCore.unregisterAttachmentLocked(attachment) | |
| 245 | + | for _, attachment := range proxy.snapshotAttachmentsLocked() { | |
| 246 | + | proxy.unregisterAttachmentLocked(attachment) | |
| 247 | 247 | } | |
| 248 | 248 | proxy.sessionCore.mu.Unlock() | |
| 249 | 249 | d.armProxyWarm(proxy) | |
| @@ -440,7 +440,7 @@ func TestProxyLinkStateDisplayAndExactGeneration(t *testing.T) { | |||
| 440 | 440 | require.Equal(t, proxy.name+" [dead]", proxy.statusSegments(false).session) | |
| 441 | 441 | } | |
| 442 | 442 | ||
| 443 | - | func TestIncomingDirectAttachPreservesProxiedRemoteAttachment(t *testing.T) { | |
| 443 | + | func TestIncomingDirectAttachTerminatesRemoteAttachment(t *testing.T) { | |
| 444 | 444 | d := newTestDaemon(t, nil, newProxyLifecycleClock()) | |
| 445 | 445 | sess := &session{sessionCore: sessionCore{id: "work", name: "work"}} | |
| 446 | 446 | oldTransport := newProxyTestTransport() | |
| @@ -1293,7 +1293,7 @@ func proxyWarmToken(p *proxySession) (*proxyWarmTimer, uint64) { | |||
| 1293 | 1293 | ||
| 1294 | 1294 | func setProxyLifecycleClient(p *proxySession, ac *attachedClient) { | |
| 1295 | 1295 | p.sessionCore.mu.Lock() | |
| 1296 | - | p.sessionCore.registerAttachmentLocked(ac) | |
| 1296 | + | p.registerAttachmentLocked(ac) | |
| 1297 | 1297 | p.sessionCore.mu.Unlock() | |
| 1298 | 1298 | } | |
| 1299 | 1299 | ||
| @@ -231,7 +231,7 @@ func TestProxyWarmReattachCancelsAndStaleTimerCannotRemoveProxy(t *testing.T) { | |||||
| 231 | 231 | ||||
| 232 | ac := &attachedClient{} | 232 | ac := &attachedClient{} | ||
| 233 | proxy.sessionCore.mu.Lock() | 233 | proxy.sessionCore.mu.Lock() | ||
| 234 | - | proxy.sessionCore.registerAttachmentLocked(ac) | 234 | + | proxy.registerAttachmentLocked(ac) |
| 235 | proxy.sessionCore.mu.Unlock() | 235 | proxy.sessionCore.mu.Unlock() | ||
| 236 | d.cancelProxyWarmForAttachment(proxy, ac) | 236 | d.cancelProxyWarmForAttachment(proxy, ac) | ||
| 237 | awaitTestCompletion(t, firstToken.done, "first proxy warm lifecycle did not complete") | 237 | awaitTestCompletion(t, firstToken.done, "first proxy warm lifecycle did not complete") | ||
| @@ -242,8 +242,8 @@ func TestProxyWarmReattachCancelsAndStaleTimerCannotRemoveProxy(t *testing.T) { | |||||
| 242 | d.mu.Unlock() | 242 | d.mu.Unlock() | ||
| 243 | 243 | ||||
| 244 | proxy.sessionCore.mu.Lock() | 244 | proxy.sessionCore.mu.Lock() | ||
| 245 | - | for _, attachment := range proxy.sessionCore.snapshotAttachmentsLocked() { | 245 | + | for _, attachment := range proxy.snapshotAttachmentsLocked() { |
| 246 | - | proxy.sessionCore.unregisterAttachmentLocked(attachment) | 246 | + | proxy.unregisterAttachmentLocked(attachment) |
| 247 | } | 247 | } | ||
| 248 | proxy.sessionCore.mu.Unlock() | 248 | proxy.sessionCore.mu.Unlock() | ||
| 249 | d.armProxyWarm(proxy) | 249 | d.armProxyWarm(proxy) | ||
| @@ -440,7 +440,7 @@ func TestProxyLinkStateDisplayAndExactGeneration(t *testing.T) { | |||||
| 440 | require.Equal(t, proxy.name+" [dead]", proxy.statusSegments(false).session) | 440 | require.Equal(t, proxy.name+" [dead]", proxy.statusSegments(false).session) | ||
| 441 | } | 441 | } | ||
| 442 | 442 | ||||
| 443 | - | func TestIncomingDirectAttachPreservesProxiedRemoteAttachment(t *testing.T) { | 443 | + | func TestIncomingDirectAttachTerminatesRemoteAttachment(t *testing.T) { |
| 444 | d := newTestDaemon(t, nil, newProxyLifecycleClock()) | 444 | d := newTestDaemon(t, nil, newProxyLifecycleClock()) | ||
| 445 | sess := &session{sessionCore: sessionCore{id: "work", name: "work"}} | 445 | sess := &session{sessionCore: sessionCore{id: "work", name: "work"}} | ||
| 446 | oldTransport := newProxyTestTransport() | 446 | oldTransport := newProxyTestTransport() | ||
| @@ -1293,7 +1293,7 @@ func proxyWarmToken(p *proxySession) (*proxyWarmTimer, uint64) { | |||||
| 1293 | 1293 | ||||
| 1294 | func setProxyLifecycleClient(p *proxySession, ac *attachedClient) { | 1294 | func setProxyLifecycleClient(p *proxySession, ac *attachedClient) { | ||
| 1295 | p.sessionCore.mu.Lock() | 1295 | p.sessionCore.mu.Lock() | ||
| 1296 | - | p.sessionCore.registerAttachmentLocked(ac) | 1296 | + | p.registerAttachmentLocked(ac) |
| 1297 | p.sessionCore.mu.Unlock() | 1297 | p.sessionCore.mu.Unlock() | ||
| 1298 | } | 1298 | } | ||
| 1299 | 1299 | ||||
M internal/usecase/daemon/render.go +0 -11
| @@ -281,17 +281,6 @@ func (b *runtimeMarkBatch) span(start, end ports.RuntimeMarkKind, bytes uint64) | |||
| 281 | 281 | } | |
| 282 | 282 | } | |
| 283 | 283 | ||
| 284 | - | // diagnostic records a completed measurement for observer I/O after the | |
| 285 | - | // render transaction releases attachment ownership. | |
| 286 | - | func (b *runtimeMarkBatch) diagnostic(kind ports.RuntimeMarkKind, bytes, fragments uint64) { | |
| 287 | - | if b == nil || b.observer == nil { | |
| 288 | - | return | |
| 289 | - | } | |
| 290 | - | mark := ports.NewRuntimeMark("daemon", kind, bytes, true) | |
| 291 | - | mark.Fragments = fragments | |
| 292 | - | b.marks = append(b.marks, mark) | |
| 293 | - | } | |
| 294 | - | ||
| 295 | 284 | func (b *runtimeMarkBatch) flush() { | |
| 296 | 285 | if b == nil || b.observer == nil { | |
| 297 | 286 | return | |
| @@ -281,17 +281,6 @@ func (b *runtimeMarkBatch) span(start, end ports.RuntimeMarkKind, bytes uint64) | |||||
| 281 | } | 281 | } | ||
| 282 | } | 282 | } | ||
| 283 | 283 | ||||
| 284 | - | // diagnostic records a completed measurement for observer I/O after the | |||
| 285 | - | // render transaction releases attachment ownership. | |||
| 286 | - | func (b *runtimeMarkBatch) diagnostic(kind ports.RuntimeMarkKind, bytes, fragments uint64) { | |||
| 287 | - | if b == nil || b.observer == nil { | |||
| 288 | - | return | |||
| 289 | - | } | |||
| 290 | - | mark := ports.NewRuntimeMark("daemon", kind, bytes, true) | |||
| 291 | - | mark.Fragments = fragments | |||
| 292 | - | b.marks = append(b.marks, mark) | |||
| 293 | - | } | |||
| 294 | - | ||||
| 295 | func (b *runtimeMarkBatch) flush() { | 284 | func (b *runtimeMarkBatch) flush() { | ||
| 296 | if b == nil || b.observer == nil { | 285 | if b == nil || b.observer == nil { | ||
| 297 | return | 286 | return | ||