detached ec60b5c

refactor: deepen daemon, broker, and client architecture seams (#299)

* build(mocks): require mockery v3.8.0 and regenerate mocks

* refactor(daemon): route every action through one dispatch lifecycle

dispatchAction owns target resolution, the optional session dispatch boundary, no-change normalization, and the attached client's follow-up render. Palette, control, key bindings, and resize mode now only describe their request. Test spies are replaced by a mockery-generated daemonActionRunner mock.

* test(daemon): cover a complete paint publication attempt

Drive capture, compose, publish, and settle through paint and assert the transport outcome, damage acknowledgement, attachment ownership, and that send-error cleanup runs after sendMu is released.

* refactor(daemon): give the accepted attachment resize one owner

attachmentResize now owns an accepted resize epoch end to end: request entry points, the session layout transaction, attachment size publication, fenced background retries, and the single reset frame. transactional_resize.go keeps the tab/session layout transactions; the render coordinator keeps scheduling and epoch fencing.

* refactor(broker): share one durable snapshot projection

BrokerSnapshot.DurableProjection is the single rule for transient state (tombstones, checking, live failure cause, policy, tab attention). The registry writer and the offline store both use it instead of two diverging copies; the registry also drops the process-local daemon via WithoutLocal.

* refactor(broker): own the daemon start decision in the broker use case

broker.AuthorizeDaemonStart and RequireLocalDaemonTarget decide whether a failed carriage dial may start a daemon (start mode, launch authority, proven absence, local-only target). internal/app keeps only carriage validation, absence classification, and the spawn election. The decision is now table-tested without sockets or processes.

* refactor(ports): give session frontends a narrow broker navigator

Split the broker session into BrokerConnection, BrokerObservation, and BrokerHostMembership. The client use case and BrokerConnector now depend on BrokerNavigator (connection, observation, streams) and never see host mutation or stream-close plumbing. brokeripc.Connector.Navigator adapts the IPC connector; test fakes drop their unused stubs and hand-written connectors become mockery mocks.

* refactor(client): resolve a picker commit through one path

ResolveCommit replaces ResolveKey, ResolveKeyTarget, and the optional pickerTargetResolver seam: the committed row key resolves in one catalogue transaction into the exact stream request and tab, and the catalogue owns the destination-kind rule. Adds an end-to-end test from keypress through TakeOp to the resolved target, including a tab closed between commit and resolution.

* refactor(client): make the attachment resume loop read as one lifecycle

attachmentResumeBudget owns the resume bound and the stable-attachment reset, and withFreshStream owns stream-identity allocation before every swap or resume open. runResolvedAttachment now reads as attempt, classify, spend, wait, reopen. The budget rule is table-tested on its own; the existing end-to-end resume table still covers the loop.

* fix(broker): keep the foreign-carriage refusal ahead of the launch policy

Split the start decision into ClassifyDaemonDialFailure and AuthorizeDaemonLaunch so the carriage check runs between them, as before the move: an absent daemon on a foreign carriage is reported as incompatible even when the policy also forbids launching. Adds a test for that combined case.

* fix(daemon): correct dispatch boundary docs and resize render producer

Document that dispatchAction renders inside a caller-held boundary on the palette and control paths, cover that path in TestDispatchActionLifecycle, and name attachment_resize.go as the producer of its invalidations.

* perf(ports): filter local daemon without a second deep clone

WithoutLocal now only rebuilds the daemon list; DurableProjection keeps the single defensive copy per durable write.

* test(client): cover every selection kind a picker commit resolves
commit
ec60b5c822207b9e817d5b6a6f33a0f2107f3a61
author
bnema · · 2026-09-29 10:24 UTC
committer
GitHub · · 2026-09-29 10:24 UTC
parent
be54d4f
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
79 files · +3911 -1409
M .mockery.yml +7 -0
@@ -40,6 +40,13 @@ packages:
4040 OwnedSynchronousTransport:
4141 Dialer:
4242 Listener:
43+ github.com/bnema/vev/internal/usecase/daemon:
44+ interfaces:
45+ daemonActionRunner:
46+ config:
47+ dir: internal/usecase/daemon
48+ filename: action_runner_mock_test.go
49+ pkgname: daemon
4350 github.com/bnema/vev/internal/usecase/command:
4451 interfaces:
4552 Context:
M AGENTS.md +1 -1
@@ -16,7 +16,7 @@ go test ./internal/adapters/ipc ./internal/usecase/daemon -run '^$' -bench=. -be
1616 ```
1717
1818 - Format with **goimports**.
19-- Install dev tools once with `go install golang.org/x/tools/cmd/goimports@latest` and `go install github.com/vektra/mockery/v3@v3.7.4`.
19+- Install dev tools once with `go install golang.org/x/tools/cmd/goimports@latest` and `go install github.com/vektra/mockery/v3@v3.8.0`.
2020 - Use Mockery v3 consistently across Go projects.
2121 - `make test` runs `go test ./... -race`.
2222 - `make lint` checks `goimports -l`, then `go vet`.
M Makefile +2 -2
@@ -22,8 +22,8 @@ lint:
2222
2323 mocks:
2424 @version="$$(mockery version 2>/dev/null || true)"; \
25- if [ "$$version" != "v3.7.4" ]; then \
26- echo "mockery v3.7.4 required; install with: go install github.com/vektra/mockery/v3@v3.7.4" >&2; \
25+ if [ "$$version" != "v3.8.0" ]; then \
26+ echo "mockery v3.8.0 required; install with: go install github.com/vektra/mockery/v3@v3.8.0" >&2; \
2727 exit 1; \
2828 fi
2929 mockery
M docs/architecture.md +3 -3
@@ -62,7 +62,7 @@ main → app → usecase → ports
6262
6363 ## UI observation and control
6464
65-Headless UI-driver mode composes one normal `client.Supervisor`, one `uiterm` terminal, one `client.UI` service, and one bounded JSONL adapter. The supervisor obtains snapshots and opens every attachment through the single `ports.BrokerService` façade; the client does not select a daemon carriage or construct a remote registry. It does not bypass the picker, input scanners, foreground leases, navigation handoffs, output replay chain, or render publication fences. EOF cancels only that driver and detaches the attachment; it does not kill a session shell.
65+Headless UI-driver mode composes one normal `client.Supervisor`, one `uiterm` terminal, one `client.UI` service, and one bounded JSONL adapter. The supervisor obtains snapshots and opens every attachment through the broker's `ports.BrokerNavigator` surface; the client does not select a daemon carriage or construct a remote registry. It does not bypass the picker, input scanners, foreground leases, navigation handoffs, output replay chain, or render publication fences. EOF cancels only that driver and detaches the attachment; it does not kill a session shell.
6666
6767 Interactive observation is a separate opt-in composition. `term.Terminal` remains the owner of raw mode, physical geometry, terminal queries, serialized output writes, and flush success. Its optional observation sink mirrors byte prefixes and successful flush boundaries into `uiterm`; UI transaction methods are delegated through a composition wrapper so semantic context is committed atomically with the physical flush. A private per-client Unix endpoint uses the same `ports.UIService`; `--ui-control` is the only mode that permits input operations. Slow or disconnected observers cannot claim geometry or block the physical terminal.
6868
@@ -76,7 +76,7 @@ A client publishes exactly one of three presentations at a time. `picker` is the
7676
7777 Session navigation is client-owned. While attached, Alt+Space opens the daemon command palette; `SSP` / `session-picker` opens the client picker as an overlay over the live attachment. Cancel returns to the same attachment without reconnecting. Committing a different destination switches attachments through `connecting`; attachment loss or explicit detach leaves the picker as the standalone presentation. Search, sorting, cursor movement, selection, and broker-backed attachment opening are client-owned. Daemon move-destination offers still use the attached worker's separate move picker.
7878
79-The selected row owns one client-scoped live preview subscription through `ports.BrokerService`. The broker opens one long-lived observation stream over its local or remote physical pool; the daemon pushes changed `RemotePreview` frames at a broker-selected interval (33 ms local, 125 ms remote). Cursor changes are debounced for 80 ms, and the client retains eight recent previews so a selection can remain visible while refreshing. Broker loss, commit, picker close, and client exit cancel the watch. The client checks epoch, connection, generation, target, and dimensions before painting; previews remain bounded, memory-only, and are never persisted.
79+The selected row owns one client-scoped live preview subscription through `ports.BrokerNavigator`. The broker opens one long-lived observation stream over its local or remote physical pool; the daemon pushes changed `RemotePreview` frames at a broker-selected interval (33 ms local, 125 ms remote). Cursor changes are debounced for 80 ms, and the client retains eight recent previews so a selection can remain visible while refreshing. Broker loss, commit, picker close, and client exit cancel the watch. The client checks epoch, connection, generation, target, and dimensions before painting; previews remain bounded, memory-only, and are never persisted.
8080
8181 The daemon does not own the session picker or resolve cross-daemon navigation; it can offer a move-destination picker to the attached client and receives its typed selection or close reply.
8282
@@ -105,7 +105,7 @@ ensures or spawns, opens a logical stream, reconciles, or mutates. An optional
105105 codes are 0 ready, 1 internal/write, 2 arguments, 3 timeout, 4 terminal
106106 security/protocol/configuration failure, and 5 cancellation.
107107
108-The broker is the sole façade for local and remote inventory, endpoint membership, policy, observation, and logical session streams. `client.Supervisor` consumes `ports.BrokerService`; it does not import or compose a remote registry, remote adapter, endpoint factory, or direct session dialer. Host mutations and attachment requests therefore pass through the same broker authority and committed snapshot.
108+The broker is the sole façade for local and remote inventory, endpoint membership, policy, observation, and logical session streams. `client.Supervisor` consumes `ports.BrokerNavigator` (connection, observation, and streams; never host mutation); it does not import or compose a remote registry, remote adapter, endpoint factory, or direct session dialer. Host mutations and attachment requests therefore pass through the same broker authority and committed snapshot.
109109
110110 A daemon serves only the sessions on its own machine. It has no remote-directory monitor and does not compose remote transports. In production it accepts the broker's authenticated multiplexed physical carriage through `internal/adapters/daemonmux`; logical observation, control, and attachment streams share that carriage while retaining independent admission and lifetime. The daemon's Unix daemonmux listener is local-only composition infrastructure between the broker and daemon, not a public client endpoint. Ordinary clients connect to `broker.sock` and never dial a daemon socket directly.
111111
M internal/adapters/brokeripc/client.go +17 -5
@@ -36,16 +36,28 @@ func Dial(ctx context.Context, path string, cfg Config) (ports.BrokerService, er
3636 return dial(ctx, path, cfg, ipc.SameUserPeerVerifier())
3737 }
3838
39-// Connector implements ports.BrokerConnector over the private broker IPC
40-// carriage. It holds only the endpoint and its bounds, so every Connect is an
41-// independent attempt and the caller owns Close on the returned service. The
42-// client process reaches the broker use case exclusively through this seam.
39+// Connector dials the private broker IPC carriage. It holds only the endpoint
40+// and its bounds, so every Connect is an independent attempt and the caller
41+// owns Close on the returned service. Navigator adapts it to
42+// ports.BrokerConnector for session frontends.
4343 type Connector struct {
4444 path string
4545 cfg Config
4646 }
4747
48-var _ ports.BrokerConnector = (*Connector)(nil)
48+// Navigator returns c as a ports.BrokerConnector, which hands session
49+// frontends only the navigation surface of each connection.
50+func (c *Connector) Navigator() ports.BrokerConnector { return navigatorConnector{c} }
51+
52+type navigatorConnector struct{ c *Connector }
53+
54+func (n navigatorConnector) Connect(ctx context.Context) (ports.BrokerNavigator, error) {
55+ service, err := n.c.Connect(ctx)
56+ if err != nil {
57+ return nil, err
58+ }
59+ return service, nil
60+}
4961
5062 // NewConnector returns a connector for one broker endpoint. An empty path is
5163 // refused by Connect, exactly as Dial refuses it, so a misconfigured connector
M internal/adapters/brokerstore/store.go +3 -22
@@ -337,28 +337,9 @@ func (s *Store) Store(snapshot ports.BrokerSnapshot) error {
337337 if err := s.ready(); err != nil {
338338 return err
339339 }
340- // Removed tombstones and in-flight checking/failure detail are process-local
341- // fencing and observation state; the durable snapshot never carries them, so
342- // sanitize the caller's copy before validating the durable shape. Policy is
343- // membership authority, not observation state, so the durable format omits
344- // it too: membership is the single policy authority and the loader re-stamps
345- // every restored observation from the matching record.
346- snapshot = snapshot.Clone()
347- snapshot.Removed = nil
348- for i := range snapshot.Daemons {
349- snapshot.Daemons[i].Checking = false
350- snapshot.Daemons[i].LastFailure.Err = nil
351- snapshot.Daemons[i].Policy = ports.BrokerPolicy{}
352- // Attention is transient observation state, not durable identity: a
353- // bell recorded the instant before a broker restart must never
354- // resurrect on reload, so every tab's Attention is zeroed before the
355- // durable shape is validated and written.
356- for j := range snapshot.Daemons[i].Sessions {
357- for k := range snapshot.Daemons[i].Sessions[j].Tabs {
358- snapshot.Daemons[i].Sessions[j].Tabs[k].Attention = false
359- }
360- }
361- }
340+ // Sanitize the caller's copy with the shared durable rule before
341+ // validating the durable shape.
342+ snapshot = snapshot.DurableProjection()
362343 if err := ports.ValidateDurableSnapshot(snapshot); err != nil {
363344 return err
364345 }
M internal/app/attach_missing_prompt.go +1 -1
@@ -182,7 +182,7 @@ type preconnectedBrokerConnector struct {
182182 used bool
183183 }
184184
185-func (c *preconnectedBrokerConnector) Connect(ctx context.Context) (ports.BrokerService, error) {
185+func (c *preconnectedBrokerConnector) Connect(ctx context.Context) (ports.BrokerNavigator, error) {
186186 c.mu.Lock()
187187 if !c.used {
188188 c.used = true
M internal/app/broker_client.go +6 -2
@@ -570,11 +570,15 @@ func newProductionBrokerConnector() ports.BrokerConnector {
570570 // Connect connect-or-spawns one broker connection for the calling attempt,
571571 // including the first one, so every attempt is under the supervisor's retry
572572 // cadence.
573-func (c *productionBrokerConnector) Connect(ctx context.Context) (ports.BrokerService, error) {
573+func (c *productionBrokerConnector) Connect(ctx context.Context) (ports.BrokerNavigator, error) {
574574 if c == nil || c.connect == nil {
575575 return nil, errors.New("vev: broker connector is not configured")
576576 }
577- return c.connect(ctx)
577+ service, err := c.connect(ctx)
578+ if err != nil {
579+ return nil, err
580+ }
581+ return service, nil
578582 }
579583
580584 // terminalBrokerSeams are the optional observation callbacks of one terminal
M internal/app/broker_client_test.go +6 -2
@@ -12,12 +12,14 @@ import (
1212 "testing"
1313 "time"
1414
15+ "github.com/stretchr/testify/mock"
1516 "github.com/stretchr/testify/require"
1617
1718 "github.com/bnema/vev/internal/adapters/brokeripc"
1819 "github.com/bnema/vev/internal/adapters/clock"
1920 "github.com/bnema/vev/internal/domain"
2021 "github.com/bnema/vev/internal/ports"
22+ portsmocks "github.com/bnema/vev/internal/ports/mocks"
2123 "github.com/bnema/vev/internal/protocol"
2224 "github.com/bnema/vev/internal/protocol/catalogue"
2325 "github.com/bnema/vev/internal/usecase/client"
@@ -904,8 +906,10 @@ func TestTerminalCompositionCapturesSessionEnvironmentDefensively(t *testing.T)
904906 service := newTerminalCompositionService(servicesnapshot)
905907 terminal := newTerminalCompositionTerminal()
906908 navigation := localEphemeralNavigation()
909+ connector := portsmocks.NewMockBrokerConnector(t)
910+ connector.EXPECT().Connect(mock.Anything).Return(service, nil).Maybe()
907911 _, err := client.NewSupervisor(client.SupervisorConfig{
908- Connector: scriptedBrokerConnector{service: service},
912+ Connector: connector,
909913 Terminal: terminal,
910914 Clock: clock.New(),
911915 // The picker is omitted: creation alone proves the snapshot does not
@@ -1093,7 +1097,7 @@ func TestTerminalCompositionExactAttachReportsMissingLocalInventory(t *testing.T
10931097 done := make(chan error, 1)
10941098 go func() {
10951099 done <- runBrokerClient(ctx, brokerClientConfig{
1096- Connector: brokeripc.NewConnector(fixture.socket, brokeripc.Config{}),
1100+ Connector: brokeripc.NewConnector(fixture.socket, brokeripc.Config{}).Navigator(),
10971101 Terminal: terminal,
10981102 InitialNavigation: navigation,
10991103 SessionEnvironment: client.SessionEnvironment{Provenance: client.SessionEnvironmentLocalCLI},
M internal/app/broker_daemon_start.go +13 -51
@@ -11,6 +11,7 @@ import (
1111 "github.com/bnema/vev/internal/adapters/daemonmux"
1212 "github.com/bnema/vev/internal/adapters/ipc"
1313 "github.com/bnema/vev/internal/ports"
14+ "github.com/bnema/vev/internal/usecase/broker"
1415 )
1516
1617 // Broker-owned daemon start.
@@ -47,14 +48,11 @@ import (
4748 // verified by the daemonmux preamble after this function returns, so those
4849 // failures can never trigger a spawn either.
4950
50-// brokerLaunchAuthority is the broker-owned policy launch token that explicitly
51-// authorizes starting a stopped target daemon. The ports policy carries the
52-// token opaquely — it never interprets it — so the component that owns "may
53-// this daemon be started?" is the composition. The broker's own production local
54-// daemon authority names this token; an operator-provisioned registration that
55-// names something else, and every sandbox-private token, fails closed and never
56-// spawns.
57-const brokerLaunchAuthority = "explicit"
51+// The start decision itself (mode, launch authority, local-only target) is
52+// owned by broker.ClassifyDaemonDialFailure, broker.AuthorizeDaemonLaunch, and
53+// broker.RequireLocalDaemonTarget.
54+// This file keeps only the mechanics: carriage path validation, absence
55+// classification of a dial error, and the spawn election.
5856
5957 // brokerDaemonStarter owns the three facts a daemon start needs: the private
6058 // daemonmux carriage dial, the detached daemon launcher, and the exact carriage
@@ -118,8 +116,8 @@ func dialLocalDaemonCarriage(ctx context.Context, carriage string) (daemonmux.Ra
118116 // carriage: only the broker-owned local authority names the daemon this
119117 // process can start, so a configured host can never be spawned by mistake.
120118 func dialBrokerLocalDaemon(ctx context.Context, carriage string, target ports.BrokerDialTarget) (daemonmux.RawFramedTransport, error) {
121- if !target.Fence.Local {
122- return nil, localDaemonStartRefused("the target is not the broker-owned local daemon")
119+ if err := broker.RequireLocalDaemonTarget(target); err != nil {
120+ return nil, err
123121 }
124122 return dialBrokerDaemonCarriage(ctx, carriage, target)
125123 }
@@ -152,24 +150,16 @@ func dialBrokerDaemonCarriage(ctx context.Context, carriage string, target ports
152150 if err == nil {
153151 return raw, nil
154152 }
155- if target.StartMode == ports.BrokerDaemonExistingOnly {
156- // An existing-only acquisition is one dial: no lifecycle probe, no spawn
157- // lock, no process, and no fallback of any kind.
158- if daemonCarriageAbsence(err) {
159- return nil, ports.BrokerError{Code: ports.BrokerErrorNoDaemon, Cause: err}
160- }
161- return nil, err
162- }
163- // A refusal that spawning could never repair is reported unchanged: a
164- // cancelled attempt, a foreign path, a rejected peer, or a permission
165- // failure is not daemon absence.
166- if !daemonCarriageAbsence(err) {
153+ // The broker decides; nothing below runs unless it authorizes a start.
154+ // The carriage check sits between its two steps, so a foreign carriage is
155+ // reported as incompatible before any policy refusal.
156+ if err := broker.ClassifyDaemonDialFailure(target, err, daemonCarriageAbsence(err)); err != nil {
167157 return nil, err
168158 }
169159 if err := validateDaemonCarriageStart(carriage, starter); err != nil {
170160 return nil, err
171161 }
172- if err := daemonStartRefusal(target); err != nil {
162+ if err := broker.AuthorizeDaemonLaunch(target); err != nil {
173163 return nil, err
174164 }
175165 published := starter.effectivePublished()
@@ -207,34 +197,6 @@ func validateDaemonCarriageStart(carriage string, starter brokerDaemonStarter) e
207197 return nil
208198 }
209199
210-// daemonStartRefusal refuses a start-if-needed acquisition that must never reach
211-// the spawn mechanics. The condition is checked before the election, so a
212-// refused start creates no lock and launches no process.
213-//
214-// The mode is an authorization, never an obligation, and it can only narrow what
215-// the resolved policy already permits. A policy that does not name the broker's
216-// launch authority therefore refuses the start outright, which is exactly how a
217-// provisioned configuration that forbids launching stays authoritative.
218-func daemonStartRefusal(target ports.BrokerDialTarget) error {
219- if target.StartMode != ports.BrokerDaemonStartIfNeeded {
220- return localDaemonStartRefused("the acquisition does not authorize starting a daemon")
221- }
222- if target.Policy.Launch != brokerLaunchAuthority {
223- return localDaemonStartRefused("the resolved policy does not authorize launching")
224- }
225- return nil
226-}
227-
228-// localDaemonStartRefused reports a refusal to start a daemon as a typed broker
229-// policy conflict. The reason is local diagnostic authority; it is never a
230-// message the daemon produced.
231-func localDaemonStartRefused(reason string) error {
232- return ports.BrokerError{
233- Code: ports.BrokerErrorConflictingPolicy,
234- Cause: fmt.Errorf("vev: refusing to start the daemon: %s", reason),
235- }
236-}
237-
238200 // daemonCarriageAbsence reports whether a failed carriage dial means the daemon
239201 // is simply not there, so starting one is the only remaining option. It is
240202 // deliberately fail-closed: a cancelled attempt, an invalid or foreign path, a
M internal/app/broker_daemon_start_test.go +22 -0
@@ -372,6 +372,28 @@ func TestDaemonStartRefusesForeignCarriageStart(t *testing.T) {
372372 require.NoFileExists(t, filepath.Join(filepath.Dir(own), spawnLockName))
373373 }
374374
375+// TestDaemonStartForeignCarriageWinsOverPolicyRefusal pins the refusal order:
376+// an absent daemon on a foreign carriage is incompatible even when the policy
377+// also forbids launching.
378+func TestDaemonStartForeignCarriageWinsOverPolicyRefusal(t *testing.T) {
379+ isolateSandboxEnv(t)
380+ _, own := testDaemonCarriage(t)
381+ foreignDir := t.TempDir()
382+ require.NoError(t, os.Chmod(foreignDir, 0o700))
383+ foreign := filepath.Join(foreignDir, "daemonmux.sock")
384+ scripted := &scriptedDaemonStarter{carriage: own, published: own}
385+ withDaemonStarter(t, scripted.starter(fastDaemonStartBackoff))
386+
387+ target := startableLocalTarget(t, foreign, ports.BrokerDaemonStartIfNeeded)
388+ target.Policy.Launch = "sandbox-private"
389+ _, err := dialBrokerDaemonCarriage(context.Background(), foreign, target)
390+ var typed ports.BrokerError
391+ require.ErrorAs(t, err, &typed)
392+ require.Equal(t, ports.BrokerErrorIncompatible, typed.Code)
393+ _, spawns := scripted.counters()
394+ require.Zero(t, spawns)
395+}
396+
375397 // TestDaemonStartDoesNotSpawnOnNonAbsenceFailure proves only proven absence can
376398 // authorize a start: a permission, path, peer, or cancellation failure is
377399 // reported unchanged and never repaired by spawning a second daemon.
M internal/app/broker_offline_client_test_helpers_test.go +2 -2
@@ -26,7 +26,7 @@ func runOfflineClient(ctx context.Context, socket string, terminal ports.Termina
2626 log.Debug("broker_offline_client", "socket", socket)
2727 }
2828 return runBrokerClient(ctx, brokerClientConfig{
29- Connector: brokeripc.NewConnector(socket, brokeripc.Config{}),
29+ Connector: brokeripc.NewConnector(socket, brokeripc.Config{}).Navigator(),
3030 Terminal: terminal,
3131 UI: ui,
3232 // No-argument composition creates one ephemeral local session through
@@ -66,7 +66,7 @@ func runOfflineUIDriverClient(ctx context.Context, harness offlineUIDriverHarnes
6666 harness.log.Debug("broker_offline_ui_driver", "socket", harness.socket)
6767 }
6868 return runUIDriverClient(ctx, brokerClientConfig{
69- Connector: brokeripc.NewConnector(harness.socket, brokeripc.Config{}),
69+ Connector: brokeripc.NewConnector(harness.socket, brokeripc.Config{}).Navigator(),
7070 Terminal: harness.terminal,
7171 Clock: clock.New(),
7272 UI: harness.ui,
M internal/app/broker_production.go +3 -2
@@ -13,6 +13,7 @@ import (
1313 "github.com/bnema/vev/internal/ports"
1414 "github.com/bnema/vev/internal/protocol"
1515 "github.com/bnema/vev/internal/protocol/catalogue"
16+ "github.com/bnema/vev/internal/usecase/broker"
1617 "github.com/bnema/vev/pkg/safedir"
1718 )
1819
@@ -59,7 +60,7 @@ func remoteBrokerPolicy(transport string) ports.BrokerPolicy {
5960 return ports.BrokerPolicy{
6061 ProtocolVersion: protocol.Version, CatalogSchemaVersion: catalogue.RemoteCatalogSchemaVersion,
6162 EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, Transport: transport,
62- Trust: "openssh-config-v1", Launch: "explicit", Isolation: "per-user",
63+ Trust: "openssh-config-v1", Launch: broker.DaemonLaunchAuthority, Isolation: "per-user",
6364 }
6465 }
6566
@@ -101,7 +102,7 @@ func localDaemonPolicy() ports.BrokerPolicy {
101102 return ports.BrokerPolicy{
102103 ProtocolVersion: protocol.Version, CatalogSchemaVersion: catalogue.RemoteCatalogSchemaVersion,
103104 EnvironmentPolicy: protocol.EnvironmentPolicyClientOwned, Transport: "unix-mux",
104- Trust: "same-user", Launch: "explicit", Isolation: "per-user",
105+ Trust: "same-user", Launch: broker.DaemonLaunchAuthority, Isolation: "per-user",
105106 }
106107 }
107108
M internal/app/ui_driver_acceptance_test.go +0 -7
@@ -18,13 +18,6 @@ import (
1818 "github.com/stretchr/testify/require"
1919 )
2020
21-// scriptedBrokerConnector is also used by broker_client_test.go, outside this change's scope.
22-type scriptedBrokerConnector struct{ service *terminalCompositionService }
23-
24-func (c scriptedBrokerConnector) Connect(context.Context) (ports.BrokerService, error) {
25- return c.service, nil
26-}
27-
2821 // startScriptedUIDriverRun launches one driver run over a scripted broker
2922 // service, waits for its discovery response, and then waits for the run's single
3023 // logical stream admission.
M internal/app/ui_driver_client_test.go +9 -7
@@ -17,7 +17,9 @@ import (
1717 "github.com/bnema/vev/internal/adapters/uiterm"
1818 "github.com/bnema/vev/internal/domain"
1919 "github.com/bnema/vev/internal/ports"
20+ portsmocks "github.com/bnema/vev/internal/ports/mocks"
2021 "github.com/bnema/vev/internal/usecase/client"
22+ "github.com/stretchr/testify/mock"
2123 "github.com/stretchr/testify/require"
2224 )
2325
@@ -29,12 +31,12 @@ import (
2931 // so every assertion holds for the production `--ui-driver` entry point and for
3032 // the sandbox harness that delegates to the same function.
3133
32-// failingBrokerConnector is a connector whose every attempt fails, so a test can
34+// failingBrokerConnector returns a connector whose every attempt fails, so a test can
3335 // drive the non-fatal broker path without any transport.
34-type failingBrokerConnector struct{ err error }
35-
36-func (c failingBrokerConnector) Connect(context.Context) (ports.BrokerService, error) {
37- return nil, c.err
36+func failingBrokerConnector(t *testing.T, err error) ports.BrokerConnector {
37+ connector := portsmocks.NewMockBrokerConnector(t)
38+ connector.EXPECT().Connect(mock.Anything).Return(nil, err).Maybe()
39+ return connector
3840 }
3941
4042 // uidriverTestStream is an owned bidirectional JSONL stream over two private
@@ -222,7 +224,7 @@ func TestUIDriverClientReadyOnBrokerFailureKeepsServing(t *testing.T) {
222224 done := make(chan error, 1)
223225 go func() {
224226 done <- runUIDriverClient(ctx, brokerClientConfig{
225- Connector: failingBrokerConnector{err: errors.New("broker not reachable")},
227+ Connector: failingBrokerConnector(t, errors.New("broker not reachable")),
226228 Terminal: terminal,
227229 Clock: clk,
228230 UI: ui,
@@ -271,7 +273,7 @@ func TestUIDriverClientRejectsMissingCompositionInputs(t *testing.T) {
271273 clk := clock.New()
272274 stream := newUIDriverTestStream()
273275 defer func() { _ = stream.Close() }()
274- require.Error(t, runUIDriverClient(t.Context(), brokerClientConfig{Connector: failingBrokerConnector{}}, stream))
276+ require.Error(t, runUIDriverClient(t.Context(), brokerClientConfig{Connector: failingBrokerConnector(t, errors.New("unused"))}, stream))
275277 require.Error(t, runUIDriverClient(t.Context(), brokerClientConfig{Clock: clk, UI: client.NewUI(nil, clk)}, stream))
276278 require.Error(t, runUIDriverClient(t.Context(), brokerClientConfig{Clock: clk, UI: client.NewUI(nil, clk), Terminal: nil}, stream))
277279 require.Error(t, runUIDriverClient(t.Context(), brokerClientConfig{Clock: clk, UI: client.NewUI(nil, clk)}, nil))
M internal/app/ui_driver_fixture_test.go +1 -1
@@ -73,7 +73,7 @@ func startUIDriverBrokerFixture(t *testing.T) *uiDriverBrokerFixture {
7373 // broker. It is the only transport authority a sandbox harness is given: it
7474 // starts no production broker and never falls back to the production XDG layout.
7575 func (f *uiDriverBrokerFixture) Connector() ports.BrokerConnector {
76- return brokeripc.NewConnector(f.broker.socket, brokeripc.Config{})
76+ return brokeripc.NewConnector(f.broker.socket, brokeripc.Config{}).Navigator()
7777 }
7878
7979 // Streams reports one event per logical stream the fixture broker admitted.
M internal/app/web_daemon_broker_test.go +2 -2
@@ -305,7 +305,7 @@ func startWebGatewayFixture(t *testing.T) *webGatewayFixture {
305305 t.Helper()
306306 broker := startOfflineClientFixtureWithShell(t, "/bin/sh", []string{"-c", webGatewayShellScript})
307307 return startWebGatewayFixtureOver(t, broker, func() ports.BrokerConnector {
308- return brokeripc.NewConnector(broker.socket, brokeripc.Config{})
308+ return brokeripc.NewConnector(broker.socket, brokeripc.Config{}).Navigator()
309309 })
310310 }
311311
@@ -609,7 +609,7 @@ func TestWebGatewayTabReturnsToPickerOnBrokerLoss(t *testing.T) {
609609 service := newTerminalCompositionService(terminalCompositionSnapshot([]string{"work"}, nil))
610610 connector := portsmocks.NewMockBrokerConnector(t)
611611 var calls atomic.Int32
612- connector.EXPECT().Connect(mock.Anything).RunAndReturn(func(context.Context) (ports.BrokerService, error) {
612+ connector.EXPECT().Connect(mock.Anything).RunAndReturn(func(context.Context) (ports.BrokerNavigator, error) {
613613 if calls.Add(1) == 1 {
614614 return service, nil
615615 }
M internal/ports/broker.go +37 -10
@@ -826,11 +826,8 @@ type BrokerPreviewSubscription interface {
826826 Close()
827827 }
828828
829-// BrokerService is the client-facing broker façade. All clients reach
830-// local and remote daemons through it, including the local daemon.
831-// Snapshot access performs no I/O; request methods are non-blocking
832-// coalesced hints except where the context explicitly bounds them.
833-type BrokerSession interface {
829+// BrokerConnection is one client connection's identity and lifetime.
830+type BrokerConnection interface {
834831 // ConnectionID returns the ID assigned when this client connection was
835832 // accepted. Clients carry it on stream operations to fence stale requests.
836833 ConnectionID() BrokerConnectionID
@@ -848,26 +845,56 @@ type BrokerSession interface {
848845 // Err returns the terminal cause, stable once Done is closed. It is nil for
849846 // an orderly local Close and non-nil for a broker-side loss or failure.
850847 Err() error
848+ Close() error
849+}
850+
851+// BrokerObservation reads committed broker state. Snapshot access performs no
852+// I/O; RequestReconcile is a non-blocking coalesced hint.
853+type BrokerObservation interface {
851854 Snapshot() BrokerSnapshot
852855 Subscribe() (BrokerSubscription, error)
853856 SubscribePreview(request BrokerPreviewRequest) (BrokerPreviewSubscription, error)
854- CloseStream(connection BrokerConnectionID, stream BrokerStreamID) error
857+ RequestReconcile(endpoint string)
858+}
859+
860+// BrokerHostMembership mutates durable configured-host membership. Every
861+// mutation is bounded by its context.
862+type BrokerHostMembership interface {
855863 // AddHost durably adds or pins endpoint under policy and returns its authority.
856864 AddHost(ctx context.Context, endpoint string, policy BrokerPolicy) (domain.RemoteRegistration, error)
857865 // RemoveHost removes only the exact expected registration.
858866 RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error)
859867 // UpdateHostPolicy changes policy only for exact expected authority and returns the advanced registration.
860868 UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy BrokerPolicy) (domain.RemoteRegistration, error)
861- RequestReconcile(endpoint string)
862- Close() error
863869 }
864870
865-// BrokerService is the typed client-side broker connection.
871+// BrokerSession is the complete connection-scoped broker surface shared by
872+// the client IPC connection and the broker-side admitted connection.
873+type BrokerSession interface {
874+ BrokerConnection
875+ BrokerObservation
876+ BrokerHostMembership
877+ CloseStream(connection BrokerConnectionID, stream BrokerStreamID) error
878+}
879+
880+// BrokerService is the client-facing broker façade. All clients reach local
881+// and remote daemons through it, including the local daemon.
866882 type BrokerService interface {
867883 BrokerSession
868884 OpenStream(ctx context.Context, request BrokerOpenStreamRequest) (BrokerLogicalConnection, error)
869885 }
870886
887+// BrokerNavigator is what a session frontend needs from the broker: its
888+// connection, committed observations, and logical streams. It never mutates
889+// host membership. Every BrokerService is a BrokerNavigator.
890+type BrokerNavigator interface {
891+ BrokerConnection
892+ BrokerObservation
893+ OpenStream(ctx context.Context, request BrokerOpenStreamRequest) (BrokerLogicalConnection, error)
894+}
895+
896+var _ BrokerNavigator = (BrokerService)(nil)
897+
871898 // BrokerEnvelopeStream carries opaque complete session envelopes across the core.
872899 type BrokerEnvelopeStream interface {
873900 SendEnvelope([]byte) error
@@ -975,7 +1002,7 @@ type BrokerEndpointConnector interface {
9751002 // broker, so a caller that abandons the setup context (a bounded attempt) still
9761003 // owns a live connection it must Close.
9771004 type BrokerConnector interface {
978- Connect(ctx context.Context) (BrokerService, error)
1005+ Connect(ctx context.Context) (BrokerNavigator, error)
9791006 }
9801007
9811008 // BrokerAuthority admits one accepted client connection to the broker core
M internal/ports/broker_store.go +45 -0
@@ -273,6 +273,51 @@ func ValidateDurableObservation(daemon BrokerDaemonObservation) error {
273273 return ValidateDurableHostProjection(daemon)
274274 }
275275
276+// DurableProjection returns the persistable copy of a published snapshot. It
277+// is the single rule for what is transient, shared by the registry writer and
278+// every store:
279+//
280+// - Removed tombstones are process-local fencing; a restart never adopts them.
281+// - Checking and the live failure cause are in-flight observation state.
282+// - Policy is membership authority, not observation: the loader re-stamps it
283+// from the matching BrokerHostRecord, so persisting it would create a
284+// second, stale authority.
285+// - Tab Attention is a transient bell that must not resurrect on reload.
286+//
287+// Local observations are kept so ValidateDurableSnapshot still refuses them;
288+// a producer that may hold one drops it first (see WithoutLocal).
289+func (s BrokerSnapshot) DurableProjection() BrokerSnapshot {
290+ out := s.Clone()
291+ out.Removed = nil
292+ for i := range out.Daemons {
293+ daemon := &out.Daemons[i]
294+ daemon.Checking = false
295+ daemon.LastFailure.Err = nil
296+ daemon.Policy = BrokerPolicy{}
297+ for j := range daemon.Sessions {
298+ for k := range daemon.Sessions[j].Tabs {
299+ daemon.Sessions[j].Tabs[k].Attention = false
300+ }
301+ }
302+ }
303+ return out
304+}
305+
306+// WithoutLocal returns s without the process-local daemon observation. The
307+// daemon list is new, but nested data stays shared with s; chain
308+// DurableProjection (or Clone) before mutating the result.
309+func (s BrokerSnapshot) WithoutLocal() BrokerSnapshot {
310+ out := s
311+ daemons := make([]BrokerDaemonObservation, 0, len(s.Daemons))
312+ for _, daemon := range s.Daemons {
313+ if !daemon.Local {
314+ daemons = append(daemons, daemon)
315+ }
316+ }
317+ out.Daemons = daemons
318+ return out
319+}
320+
276321 // ValidateDurableSnapshot checks the shared durable snapshot shape.
277322 func ValidateDurableSnapshot(snapshot BrokerSnapshot) error {
278323 if snapshot.Epoch == 0 {
M internal/ports/broker_store_test.go +49 -0
@@ -1,14 +1,63 @@
11 package ports
22
33 import (
4+ "errors"
45 "strings"
56 "testing"
67
78 "github.com/bnema/vev/internal/domain"
89 "github.com/bnema/vev/internal/protocol"
10+ "github.com/bnema/vev/internal/protocol/catalogue"
911 "github.com/stretchr/testify/require"
1012 )
1113
14+func TestBrokerSnapshotDurableProjection(t *testing.T) {
15+ published := BrokerSnapshot{
16+ Epoch: 2, Revision: 3,
17+ Removed: []BrokerHostTombstone{{Endpoint: "gone"}},
18+ Daemons: []BrokerDaemonObservation{
19+ {Local: true, Policy: BrokerPolicy{Transport: "ssh"}},
20+ {
21+ Endpoint: "user@host:22",
22+ Checking: true,
23+ LastFailure: domain.RemoteFailure{Kind: domain.RemoteFailureTimeout, Err: errors.New("live cause")},
24+ Policy: BrokerPolicy{Transport: "ssh"},
25+ Sessions: []catalogue.RemoteCatalogSession{{Name: "work", Tabs: []catalogue.RemoteCatalogTab{
26+ {ID: "t1", Attention: true},
27+ }}},
28+ },
29+ },
30+ }
31+ tests := []struct {
32+ name string
33+ project func(BrokerSnapshot) BrokerSnapshot
34+ wantLocal bool
35+ }{
36+ {name: "durable projection keeps local for refusal", project: BrokerSnapshot.DurableProjection, wantLocal: true},
37+ {name: "producer drops local first", project: func(s BrokerSnapshot) BrokerSnapshot { return s.WithoutLocal().DurableProjection() }},
38+ }
39+ for _, tt := range tests {
40+ t.Run(tt.name, func(t *testing.T) {
41+ out := tt.project(published)
42+
43+ require.Nil(t, out.Removed)
44+ remote, ok := out.Find("user@host:22")
45+ require.True(t, ok)
46+ require.False(t, remote.Checking)
47+ require.NoError(t, remote.LastFailure.Err)
48+ require.Equal(t, domain.RemoteFailureTimeout, remote.LastFailure.Kind, "the failure kind is durable")
49+ require.Equal(t, BrokerPolicy{}, remote.Policy)
50+ require.False(t, remote.Sessions[0].Tabs[0].Attention)
51+ require.Equal(t, tt.wantLocal, out.Daemons[0].Local)
52+
53+ // The published snapshot is never mutated.
54+ require.Len(t, published.Removed, 1)
55+ require.True(t, published.Daemons[1].Checking)
56+ require.True(t, published.Daemons[1].Sessions[0].Tabs[0].Attention)
57+ })
58+ }
59+}
60+
1261 // TestValidateDurableHostProjectionIdentity pins the durable rule to the live
1362 // observation rule: an identity and incarnation must appear together, and an
1463 // observed identity must carry the protocol version it was authenticated with.
M internal/ports/mocks/broker_acquisition_mock.go +20 -2
@@ -17,10 +17,19 @@ func NewMockBrokerRouteAuthority(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockBrokerRouteAuthority {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockBrokerRouteAuthority{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
@@ -110,10 +119,19 @@ func NewMockBrokerIdentityBinder(t interface {
110119 mock.TestingT
111120 Cleanup(func())
112121 }) *MockBrokerIdentityBinder {
122+ if helper, ok := t.(interface{ Helper() }); ok {
123+ helper.Helper()
124+ }
125+
113126 mock := &MockBrokerIdentityBinder{}
114127 mock.Mock.Test(t)
115128
116- t.Cleanup(func() { mock.AssertExpectations(t) })
129+ t.Cleanup(func() {
130+ if helper, ok := t.(interface{ Helper() }); ok {
131+ helper.Helper()
132+ }
133+ mock.AssertExpectations(t)
134+ })
117135
118136 return mock
119137 }
M internal/ports/mocks/broker_mock.go +2071 -655
@@ -18,10 +18,19 @@ func NewMockBrokerSubscription(t interface {
1818 mock.TestingT
1919 Cleanup(func())
2020 }) *MockBrokerSubscription {
21+ if helper, ok := t.(interface{ Helper() }); ok {
22+ helper.Helper()
23+ }
24+
2125 mock := &MockBrokerSubscription{}
2226 mock.Mock.Test(t)
2327
24- t.Cleanup(func() { mock.AssertExpectations(t) })
28+ t.Cleanup(func() {
29+ if helper, ok := t.(interface{ Helper() }); ok {
30+ helper.Helper()
31+ }
32+ mock.AssertExpectations(t)
33+ })
2534
2635 return mock
2736 }
@@ -124,10 +133,19 @@ func NewMockBrokerPreviewSubscription(t interface {
124133 mock.TestingT
125134 Cleanup(func())
126135 }) *MockBrokerPreviewSubscription {
136+ if helper, ok := t.(interface{ Helper() }); ok {
137+ helper.Helper()
138+ }
139+
127140 mock := &MockBrokerPreviewSubscription{}
128141 mock.Mock.Test(t)
129142
130- t.Cleanup(func() { mock.AssertExpectations(t) })
143+ t.Cleanup(func() {
144+ if helper, ok := t.(interface{ Helper() }); ok {
145+ helper.Helper()
146+ }
147+ mock.AssertExpectations(t)
148+ })
131149
132150 return mock
133151 }
@@ -268,107 +286,44 @@ func (_c *MockBrokerPreviewSubscription_Latest_Call) RunAndReturn(run func() por
268286 return _c
269287 }
270288
271-// NewMockBrokerSession creates a new instance of MockBrokerSession. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
289+// NewMockBrokerConnection creates a new instance of MockBrokerConnection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
272290 // The first argument is typically a *testing.T value.
273-func NewMockBrokerSession(t interface {
291+func NewMockBrokerConnection(t interface {
274292 mock.TestingT
275293 Cleanup(func())
276-}) *MockBrokerSession {
277- mock := &MockBrokerSession{}
294+}) *MockBrokerConnection {
295+ if helper, ok := t.(interface{ Helper() }); ok {
296+ helper.Helper()
297+ }
298+
299+ mock := &MockBrokerConnection{}
278300 mock.Mock.Test(t)
279301
280- t.Cleanup(func() { mock.AssertExpectations(t) })
302+ t.Cleanup(func() {
303+ if helper, ok := t.(interface{ Helper() }); ok {
304+ helper.Helper()
305+ }
306+ mock.AssertExpectations(t)
307+ })
281308
282309 return mock
283310 }
284311
285-// MockBrokerSession is an autogenerated mock type for the BrokerSession type
286-type MockBrokerSession struct {
312+// MockBrokerConnection is an autogenerated mock type for the BrokerConnection type
313+type MockBrokerConnection struct {
287314 mock.Mock
288315 }
289316
290-type MockBrokerSession_Expecter struct {
317+type MockBrokerConnection_Expecter struct {
291318 mock *mock.Mock
292319 }
293320
294-func (_m *MockBrokerSession) EXPECT() *MockBrokerSession_Expecter {
295- return &MockBrokerSession_Expecter{mock: &_m.Mock}
296-}
297-
298-// AddHost provides a mock function for the type MockBrokerSession
299-func (_mock *MockBrokerSession) AddHost(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
300- ret := _mock.Called(ctx, endpoint, policy)
301-
302- if len(ret) == 0 {
303- panic("no return value specified for AddHost")
304- }
305-
306- var r0 domain.RemoteRegistration
307- var r1 error
308- if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
309- return returnFunc(ctx, endpoint, policy)
310- }
311- if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) domain.RemoteRegistration); ok {
312- r0 = returnFunc(ctx, endpoint, policy)
313- } else {
314- r0 = ret.Get(0).(domain.RemoteRegistration)
315- }
316- if returnFunc, ok := ret.Get(1).(func(context.Context, string, ports.BrokerPolicy) error); ok {
317- r1 = returnFunc(ctx, endpoint, policy)
318- } else {
319- r1 = ret.Error(1)
320- }
321- return r0, r1
322-}
323-
324-// MockBrokerSession_AddHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHost'
325-type MockBrokerSession_AddHost_Call struct {
326- *mock.Call
327-}
328-
329-// AddHost is a helper method to define mock.On call
330-// - ctx context.Context
331-// - endpoint string
332-// - policy ports.BrokerPolicy
333-func (_e *MockBrokerSession_Expecter) AddHost(ctx any, endpoint any, policy any) *MockBrokerSession_AddHost_Call {
334- return &MockBrokerSession_AddHost_Call{Call: _e.mock.On("AddHost", ctx, endpoint, policy)}
335-}
336-
337-func (_c *MockBrokerSession_AddHost_Call) Run(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy)) *MockBrokerSession_AddHost_Call {
338- _c.Call.Run(func(args mock.Arguments) {
339- var arg0 context.Context
340- if args[0] != nil {
341- arg0 = args[0].(context.Context)
342- }
343- var arg1 string
344- if args[1] != nil {
345- arg1 = args[1].(string)
346- }
347- var arg2 ports.BrokerPolicy
348- if args[2] != nil {
349- arg2 = args[2].(ports.BrokerPolicy)
350- }
351- run(
352- arg0,
353- arg1,
354- arg2,
355- )
356- })
357- return _c
358-}
359-
360-func (_c *MockBrokerSession_AddHost_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerSession_AddHost_Call {
361- _c.Call.Return(remoteRegistration, err)
362- return _c
363-}
364-
365-func (_c *MockBrokerSession_AddHost_Call) RunAndReturn(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerSession_AddHost_Call {
366- _c.Call.Return(run)
367- return _c
321+func (_m *MockBrokerConnection) EXPECT() *MockBrokerConnection_Expecter {
322+ return &MockBrokerConnection_Expecter{mock: &_m.Mock}
368323 }
369324
370-// Close provides a mock function for the type MockBrokerSession
371-func (_mock *MockBrokerSession) Close() error {
325+// Close provides a mock function for the type MockBrokerConnection
326+func (_mock *MockBrokerConnection) Close() error {
372327 ret := _mock.Called()
373328
374329 if len(ret) == 0 {
@@ -384,92 +339,35 @@ func (_mock *MockBrokerSession) Close() error {
384339 return r0
385340 }
386341
387-// MockBrokerSession_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
388-type MockBrokerSession_Close_Call struct {
342+// MockBrokerConnection_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
343+type MockBrokerConnection_Close_Call struct {
389344 *mock.Call
390345 }
391346
392347 // Close is a helper method to define mock.On call
393-func (_e *MockBrokerSession_Expecter) Close() *MockBrokerSession_Close_Call {
394- return &MockBrokerSession_Close_Call{Call: _e.mock.On("Close")}
348+func (_e *MockBrokerConnection_Expecter) Close() *MockBrokerConnection_Close_Call {
349+ return &MockBrokerConnection_Close_Call{Call: _e.mock.On("Close")}
395350 }
396351
397-func (_c *MockBrokerSession_Close_Call) Run(run func()) *MockBrokerSession_Close_Call {
352+func (_c *MockBrokerConnection_Close_Call) Run(run func()) *MockBrokerConnection_Close_Call {
398353 _c.Call.Run(func(args mock.Arguments) {
399354 run()
400355 })
401356 return _c
402357 }
403358
404-func (_c *MockBrokerSession_Close_Call) Return(err error) *MockBrokerSession_Close_Call {
405- _c.Call.Return(err)
406- return _c
407-}
408-
409-func (_c *MockBrokerSession_Close_Call) RunAndReturn(run func() error) *MockBrokerSession_Close_Call {
410- _c.Call.Return(run)
411- return _c
412-}
413-
414-// CloseStream provides a mock function for the type MockBrokerSession
415-func (_mock *MockBrokerSession) CloseStream(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error {
416- ret := _mock.Called(connection, stream)
417-
418- if len(ret) == 0 {
419- panic("no return value specified for CloseStream")
420- }
421-
422- var r0 error
423- if returnFunc, ok := ret.Get(0).(func(ports.BrokerConnectionID, ports.BrokerStreamID) error); ok {
424- r0 = returnFunc(connection, stream)
425- } else {
426- r0 = ret.Error(0)
427- }
428- return r0
429-}
430-
431-// MockBrokerSession_CloseStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseStream'
432-type MockBrokerSession_CloseStream_Call struct {
433- *mock.Call
434-}
435-
436-// CloseStream is a helper method to define mock.On call
437-// - connection ports.BrokerConnectionID
438-// - stream ports.BrokerStreamID
439-func (_e *MockBrokerSession_Expecter) CloseStream(connection any, stream any) *MockBrokerSession_CloseStream_Call {
440- return &MockBrokerSession_CloseStream_Call{Call: _e.mock.On("CloseStream", connection, stream)}
441-}
442-
443-func (_c *MockBrokerSession_CloseStream_Call) Run(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID)) *MockBrokerSession_CloseStream_Call {
444- _c.Call.Run(func(args mock.Arguments) {
445- var arg0 ports.BrokerConnectionID
446- if args[0] != nil {
447- arg0 = args[0].(ports.BrokerConnectionID)
448- }
449- var arg1 ports.BrokerStreamID
450- if args[1] != nil {
451- arg1 = args[1].(ports.BrokerStreamID)
452- }
453- run(
454- arg0,
455- arg1,
456- )
457- })
458- return _c
459-}
460-
461-func (_c *MockBrokerSession_CloseStream_Call) Return(err error) *MockBrokerSession_CloseStream_Call {
359+func (_c *MockBrokerConnection_Close_Call) Return(err error) *MockBrokerConnection_Close_Call {
462360 _c.Call.Return(err)
463361 return _c
464362 }
465363
466-func (_c *MockBrokerSession_CloseStream_Call) RunAndReturn(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error) *MockBrokerSession_CloseStream_Call {
364+func (_c *MockBrokerConnection_Close_Call) RunAndReturn(run func() error) *MockBrokerConnection_Close_Call {
467365 _c.Call.Return(run)
468366 return _c
469367 }
470368
471-// ConnectionID provides a mock function for the type MockBrokerSession
472-func (_mock *MockBrokerSession) ConnectionID() ports.BrokerConnectionID {
369+// ConnectionID provides a mock function for the type MockBrokerConnection
370+func (_mock *MockBrokerConnection) ConnectionID() ports.BrokerConnectionID {
473371 ret := _mock.Called()
474372
475373 if len(ret) == 0 {
@@ -487,35 +385,35 @@ func (_mock *MockBrokerSession) ConnectionID() ports.BrokerConnectionID {
487385 return r0
488386 }
489387
490-// MockBrokerSession_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
491-type MockBrokerSession_ConnectionID_Call struct {
388+// MockBrokerConnection_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
389+type MockBrokerConnection_ConnectionID_Call struct {
492390 *mock.Call
493391 }
494392
495393 // ConnectionID is a helper method to define mock.On call
496-func (_e *MockBrokerSession_Expecter) ConnectionID() *MockBrokerSession_ConnectionID_Call {
497- return &MockBrokerSession_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
394+func (_e *MockBrokerConnection_Expecter) ConnectionID() *MockBrokerConnection_ConnectionID_Call {
395+ return &MockBrokerConnection_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
498396 }
499397
500-func (_c *MockBrokerSession_ConnectionID_Call) Run(run func()) *MockBrokerSession_ConnectionID_Call {
398+func (_c *MockBrokerConnection_ConnectionID_Call) Run(run func()) *MockBrokerConnection_ConnectionID_Call {
501399 _c.Call.Run(func(args mock.Arguments) {
502400 run()
503401 })
504402 return _c
505403 }
506404
507-func (_c *MockBrokerSession_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerSession_ConnectionID_Call {
405+func (_c *MockBrokerConnection_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerConnection_ConnectionID_Call {
508406 _c.Call.Return(brokerConnectionID)
509407 return _c
510408 }
511409
512-func (_c *MockBrokerSession_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerSession_ConnectionID_Call {
410+func (_c *MockBrokerConnection_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerConnection_ConnectionID_Call {
513411 _c.Call.Return(run)
514412 return _c
515413 }
516414
517-// Done provides a mock function for the type MockBrokerSession
518-func (_mock *MockBrokerSession) Done() <-chan struct{} {
415+// Done provides a mock function for the type MockBrokerConnection
416+func (_mock *MockBrokerConnection) Done() <-chan struct{} {
519417 ret := _mock.Called()
520418
521419 if len(ret) == 0 {
@@ -533,35 +431,35 @@ func (_mock *MockBrokerSession) Done() <-chan struct{} {
533431 return r0
534432 }
535433
536-// MockBrokerSession_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
537-type MockBrokerSession_Done_Call struct {
434+// MockBrokerConnection_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
435+type MockBrokerConnection_Done_Call struct {
538436 *mock.Call
539437 }
540438
541439 // Done is a helper method to define mock.On call
542-func (_e *MockBrokerSession_Expecter) Done() *MockBrokerSession_Done_Call {
543- return &MockBrokerSession_Done_Call{Call: _e.mock.On("Done")}
440+func (_e *MockBrokerConnection_Expecter) Done() *MockBrokerConnection_Done_Call {
441+ return &MockBrokerConnection_Done_Call{Call: _e.mock.On("Done")}
544442 }
545443
546-func (_c *MockBrokerSession_Done_Call) Run(run func()) *MockBrokerSession_Done_Call {
444+func (_c *MockBrokerConnection_Done_Call) Run(run func()) *MockBrokerConnection_Done_Call {
547445 _c.Call.Run(func(args mock.Arguments) {
548446 run()
549447 })
550448 return _c
551449 }
552450
553-func (_c *MockBrokerSession_Done_Call) Return(valCh <-chan struct{}) *MockBrokerSession_Done_Call {
451+func (_c *MockBrokerConnection_Done_Call) Return(valCh <-chan struct{}) *MockBrokerConnection_Done_Call {
554452 _c.Call.Return(valCh)
555453 return _c
556454 }
557455
558-func (_c *MockBrokerSession_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerSession_Done_Call {
456+func (_c *MockBrokerConnection_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerConnection_Done_Call {
559457 _c.Call.Return(run)
560458 return _c
561459 }
562460
563-// Err provides a mock function for the type MockBrokerSession
564-func (_mock *MockBrokerSession) Err() error {
461+// Err provides a mock function for the type MockBrokerConnection
462+func (_mock *MockBrokerConnection) Err() error {
565463 ret := _mock.Called()
566464
567465 if len(ret) == 0 {
@@ -577,35 +475,35 @@ func (_mock *MockBrokerSession) Err() error {
577475 return r0
578476 }
579477
580-// MockBrokerSession_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
581-type MockBrokerSession_Err_Call struct {
478+// MockBrokerConnection_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
479+type MockBrokerConnection_Err_Call struct {
582480 *mock.Call
583481 }
584482
585483 // Err is a helper method to define mock.On call
586-func (_e *MockBrokerSession_Expecter) Err() *MockBrokerSession_Err_Call {
587- return &MockBrokerSession_Err_Call{Call: _e.mock.On("Err")}
484+func (_e *MockBrokerConnection_Expecter) Err() *MockBrokerConnection_Err_Call {
485+ return &MockBrokerConnection_Err_Call{Call: _e.mock.On("Err")}
588486 }
589487
590-func (_c *MockBrokerSession_Err_Call) Run(run func()) *MockBrokerSession_Err_Call {
488+func (_c *MockBrokerConnection_Err_Call) Run(run func()) *MockBrokerConnection_Err_Call {
591489 _c.Call.Run(func(args mock.Arguments) {
592490 run()
593491 })
594492 return _c
595493 }
596494
597-func (_c *MockBrokerSession_Err_Call) Return(err error) *MockBrokerSession_Err_Call {
495+func (_c *MockBrokerConnection_Err_Call) Return(err error) *MockBrokerConnection_Err_Call {
598496 _c.Call.Return(err)
599497 return _c
600498 }
601499
602-func (_c *MockBrokerSession_Err_Call) RunAndReturn(run func() error) *MockBrokerSession_Err_Call {
500+func (_c *MockBrokerConnection_Err_Call) RunAndReturn(run func() error) *MockBrokerConnection_Err_Call {
603501 _c.Call.Return(run)
604502 return _c
605503 }
606504
607-// NextStreamID provides a mock function for the type MockBrokerSession
608-func (_mock *MockBrokerSession) NextStreamID() (ports.BrokerStreamID, error) {
505+// NextStreamID provides a mock function for the type MockBrokerConnection
506+func (_mock *MockBrokerConnection) NextStreamID() (ports.BrokerStreamID, error) {
609507 ret := _mock.Called()
610508
611509 if len(ret) == 0 {
@@ -630,80 +528,1766 @@ func (_mock *MockBrokerSession) NextStreamID() (ports.BrokerStreamID, error) {
630528 return r0, r1
631529 }
632530
633-// MockBrokerSession_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
634-type MockBrokerSession_NextStreamID_Call struct {
531+// MockBrokerConnection_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
532+type MockBrokerConnection_NextStreamID_Call struct {
635533 *mock.Call
636534 }
637535
638536 // NextStreamID is a helper method to define mock.On call
639-func (_e *MockBrokerSession_Expecter) NextStreamID() *MockBrokerSession_NextStreamID_Call {
640- return &MockBrokerSession_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
537+func (_e *MockBrokerConnection_Expecter) NextStreamID() *MockBrokerConnection_NextStreamID_Call {
538+ return &MockBrokerConnection_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
641539 }
642540
643-func (_c *MockBrokerSession_NextStreamID_Call) Run(run func()) *MockBrokerSession_NextStreamID_Call {
541+func (_c *MockBrokerConnection_NextStreamID_Call) Run(run func()) *MockBrokerConnection_NextStreamID_Call {
644542 _c.Call.Run(func(args mock.Arguments) {
645543 run()
646544 })
647545 return _c
648546 }
649547
650-func (_c *MockBrokerSession_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerSession_NextStreamID_Call {
548+func (_c *MockBrokerConnection_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerConnection_NextStreamID_Call {
651549 _c.Call.Return(brokerStreamID, err)
652550 return _c
653551 }
654552
655-func (_c *MockBrokerSession_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerSession_NextStreamID_Call {
553+func (_c *MockBrokerConnection_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerConnection_NextStreamID_Call {
656554 _c.Call.Return(run)
657555 return _c
658556 }
659557
660-// RemoveHost provides a mock function for the type MockBrokerSession
661-func (_mock *MockBrokerSession) RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error) {
662- ret := _mock.Called(ctx, expected)
663-
664- if len(ret) == 0 {
665- panic("no return value specified for RemoveHost")
558+// NewMockBrokerObservation creates a new instance of MockBrokerObservation. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
559+// The first argument is typically a *testing.T value.
560+func NewMockBrokerObservation(t interface {
561+ mock.TestingT
562+ Cleanup(func())
563+}) *MockBrokerObservation {
564+ if helper, ok := t.(interface{ Helper() }); ok {
565+ helper.Helper()
666566 }
667567
668- var r0 bool
669- var r1 error
670- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) (bool, error)); ok {
671- return returnFunc(ctx, expected)
672- }
673- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) bool); ok {
674- r0 = returnFunc(ctx, expected)
675- } else {
676- r0 = ret.Get(0).(bool)
677- }
678- if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration) error); ok {
679- r1 = returnFunc(ctx, expected)
680- } else {
681- r1 = ret.Error(1)
682- }
683- return r0, r1
568+ mock := &MockBrokerObservation{}
569+ mock.Mock.Test(t)
570+
571+ t.Cleanup(func() {
572+ if helper, ok := t.(interface{ Helper() }); ok {
573+ helper.Helper()
574+ }
575+ mock.AssertExpectations(t)
576+ })
577+
578+ return mock
684579 }
685580
686-// MockBrokerSession_RemoveHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveHost'
687-type MockBrokerSession_RemoveHost_Call struct {
581+// MockBrokerObservation is an autogenerated mock type for the BrokerObservation type
582+type MockBrokerObservation struct {
583+ mock.Mock
584+}
585+
586+type MockBrokerObservation_Expecter struct {
587+ mock *mock.Mock
588+}
589+
590+func (_m *MockBrokerObservation) EXPECT() *MockBrokerObservation_Expecter {
591+ return &MockBrokerObservation_Expecter{mock: &_m.Mock}
592+}
593+
594+// RequestReconcile provides a mock function for the type MockBrokerObservation
595+func (_mock *MockBrokerObservation) RequestReconcile(endpoint string) {
596+ _mock.Called(endpoint)
597+ return
598+}
599+
600+// MockBrokerObservation_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
601+type MockBrokerObservation_RequestReconcile_Call struct {
688602 *mock.Call
689603 }
690604
691-// RemoveHost is a helper method to define mock.On call
692-// - ctx context.Context
693-// - expected domain.RemoteRegistration
694-func (_e *MockBrokerSession_Expecter) RemoveHost(ctx any, expected any) *MockBrokerSession_RemoveHost_Call {
695- return &MockBrokerSession_RemoveHost_Call{Call: _e.mock.On("RemoveHost", ctx, expected)}
605+// RequestReconcile is a helper method to define mock.On call
606+// - endpoint string
607+func (_e *MockBrokerObservation_Expecter) RequestReconcile(endpoint any) *MockBrokerObservation_RequestReconcile_Call {
608+ return &MockBrokerObservation_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
696609 }
697610
698-func (_c *MockBrokerSession_RemoveHost_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration)) *MockBrokerSession_RemoveHost_Call {
611+func (_c *MockBrokerObservation_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerObservation_RequestReconcile_Call {
699612 _c.Call.Run(func(args mock.Arguments) {
700- var arg0 context.Context
613+ var arg0 string
701614 if args[0] != nil {
702- arg0 = args[0].(context.Context)
703- }
704- var arg1 domain.RemoteRegistration
705- if args[1] != nil {
706- arg1 = args[1].(domain.RemoteRegistration)
615+ arg0 = args[0].(string)
616+ }
617+ run(
618+ arg0,
619+ )
620+ })
621+ return _c
622+}
623+
624+func (_c *MockBrokerObservation_RequestReconcile_Call) Return() *MockBrokerObservation_RequestReconcile_Call {
625+ _c.Call.Return()
626+ return _c
627+}
628+
629+func (_c *MockBrokerObservation_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerObservation_RequestReconcile_Call {
630+ _c.Run(run)
631+ return _c
632+}
633+
634+// Snapshot provides a mock function for the type MockBrokerObservation
635+func (_mock *MockBrokerObservation) Snapshot() ports.BrokerSnapshot {
636+ ret := _mock.Called()
637+
638+ if len(ret) == 0 {
639+ panic("no return value specified for Snapshot")
640+ }
641+
642+ var r0 ports.BrokerSnapshot
643+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerSnapshot); ok {
644+ r0 = returnFunc()
645+ } else {
646+ r0 = ret.Get(0).(ports.BrokerSnapshot)
647+ }
648+ return r0
649+}
650+
651+// MockBrokerObservation_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
652+type MockBrokerObservation_Snapshot_Call struct {
653+ *mock.Call
654+}
655+
656+// Snapshot is a helper method to define mock.On call
657+func (_e *MockBrokerObservation_Expecter) Snapshot() *MockBrokerObservation_Snapshot_Call {
658+ return &MockBrokerObservation_Snapshot_Call{Call: _e.mock.On("Snapshot")}
659+}
660+
661+func (_c *MockBrokerObservation_Snapshot_Call) Run(run func()) *MockBrokerObservation_Snapshot_Call {
662+ _c.Call.Run(func(args mock.Arguments) {
663+ run()
664+ })
665+ return _c
666+}
667+
668+func (_c *MockBrokerObservation_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerObservation_Snapshot_Call {
669+ _c.Call.Return(brokerSnapshot)
670+ return _c
671+}
672+
673+func (_c *MockBrokerObservation_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerObservation_Snapshot_Call {
674+ _c.Call.Return(run)
675+ return _c
676+}
677+
678+// Subscribe provides a mock function for the type MockBrokerObservation
679+func (_mock *MockBrokerObservation) Subscribe() (ports.BrokerSubscription, error) {
680+ ret := _mock.Called()
681+
682+ if len(ret) == 0 {
683+ panic("no return value specified for Subscribe")
684+ }
685+
686+ var r0 ports.BrokerSubscription
687+ var r1 error
688+ if returnFunc, ok := ret.Get(0).(func() (ports.BrokerSubscription, error)); ok {
689+ return returnFunc()
690+ }
691+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerSubscription); ok {
692+ r0 = returnFunc()
693+ } else {
694+ if ret.Get(0) != nil {
695+ r0 = ret.Get(0).(ports.BrokerSubscription)
696+ }
697+ }
698+ if returnFunc, ok := ret.Get(1).(func() error); ok {
699+ r1 = returnFunc()
700+ } else {
701+ r1 = ret.Error(1)
702+ }
703+ return r0, r1
704+}
705+
706+// MockBrokerObservation_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
707+type MockBrokerObservation_Subscribe_Call struct {
708+ *mock.Call
709+}
710+
711+// Subscribe is a helper method to define mock.On call
712+func (_e *MockBrokerObservation_Expecter) Subscribe() *MockBrokerObservation_Subscribe_Call {
713+ return &MockBrokerObservation_Subscribe_Call{Call: _e.mock.On("Subscribe")}
714+}
715+
716+func (_c *MockBrokerObservation_Subscribe_Call) Run(run func()) *MockBrokerObservation_Subscribe_Call {
717+ _c.Call.Run(func(args mock.Arguments) {
718+ run()
719+ })
720+ return _c
721+}
722+
723+func (_c *MockBrokerObservation_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerObservation_Subscribe_Call {
724+ _c.Call.Return(brokerSubscription, err)
725+ return _c
726+}
727+
728+func (_c *MockBrokerObservation_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerObservation_Subscribe_Call {
729+ _c.Call.Return(run)
730+ return _c
731+}
732+
733+// SubscribePreview provides a mock function for the type MockBrokerObservation
734+func (_mock *MockBrokerObservation) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
735+ ret := _mock.Called(request)
736+
737+ if len(ret) == 0 {
738+ panic("no return value specified for SubscribePreview")
739+ }
740+
741+ var r0 ports.BrokerPreviewSubscription
742+ var r1 error
743+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)); ok {
744+ return returnFunc(request)
745+ }
746+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerPreviewRequest) ports.BrokerPreviewSubscription); ok {
747+ r0 = returnFunc(request)
748+ } else {
749+ if ret.Get(0) != nil {
750+ r0 = ret.Get(0).(ports.BrokerPreviewSubscription)
751+ }
752+ }
753+ if returnFunc, ok := ret.Get(1).(func(ports.BrokerPreviewRequest) error); ok {
754+ r1 = returnFunc(request)
755+ } else {
756+ r1 = ret.Error(1)
757+ }
758+ return r0, r1
759+}
760+
761+// MockBrokerObservation_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
762+type MockBrokerObservation_SubscribePreview_Call struct {
763+ *mock.Call
764+}
765+
766+// SubscribePreview is a helper method to define mock.On call
767+// - request ports.BrokerPreviewRequest
768+func (_e *MockBrokerObservation_Expecter) SubscribePreview(request any) *MockBrokerObservation_SubscribePreview_Call {
769+ return &MockBrokerObservation_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
770+}
771+
772+func (_c *MockBrokerObservation_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerObservation_SubscribePreview_Call {
773+ _c.Call.Run(func(args mock.Arguments) {
774+ var arg0 ports.BrokerPreviewRequest
775+ if args[0] != nil {
776+ arg0 = args[0].(ports.BrokerPreviewRequest)
777+ }
778+ run(
779+ arg0,
780+ )
781+ })
782+ return _c
783+}
784+
785+func (_c *MockBrokerObservation_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerObservation_SubscribePreview_Call {
786+ _c.Call.Return(brokerPreviewSubscription, err)
787+ return _c
788+}
789+
790+func (_c *MockBrokerObservation_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerObservation_SubscribePreview_Call {
791+ _c.Call.Return(run)
792+ return _c
793+}
794+
795+// NewMockBrokerHostMembership creates a new instance of MockBrokerHostMembership. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
796+// The first argument is typically a *testing.T value.
797+func NewMockBrokerHostMembership(t interface {
798+ mock.TestingT
799+ Cleanup(func())
800+}) *MockBrokerHostMembership {
801+ if helper, ok := t.(interface{ Helper() }); ok {
802+ helper.Helper()
803+ }
804+
805+ mock := &MockBrokerHostMembership{}
806+ mock.Mock.Test(t)
807+
808+ t.Cleanup(func() {
809+ if helper, ok := t.(interface{ Helper() }); ok {
810+ helper.Helper()
811+ }
812+ mock.AssertExpectations(t)
813+ })
814+
815+ return mock
816+}
817+
818+// MockBrokerHostMembership is an autogenerated mock type for the BrokerHostMembership type
819+type MockBrokerHostMembership struct {
820+ mock.Mock
821+}
822+
823+type MockBrokerHostMembership_Expecter struct {
824+ mock *mock.Mock
825+}
826+
827+func (_m *MockBrokerHostMembership) EXPECT() *MockBrokerHostMembership_Expecter {
828+ return &MockBrokerHostMembership_Expecter{mock: &_m.Mock}
829+}
830+
831+// AddHost provides a mock function for the type MockBrokerHostMembership
832+func (_mock *MockBrokerHostMembership) AddHost(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
833+ ret := _mock.Called(ctx, endpoint, policy)
834+
835+ if len(ret) == 0 {
836+ panic("no return value specified for AddHost")
837+ }
838+
839+ var r0 domain.RemoteRegistration
840+ var r1 error
841+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
842+ return returnFunc(ctx, endpoint, policy)
843+ }
844+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) domain.RemoteRegistration); ok {
845+ r0 = returnFunc(ctx, endpoint, policy)
846+ } else {
847+ r0 = ret.Get(0).(domain.RemoteRegistration)
848+ }
849+ if returnFunc, ok := ret.Get(1).(func(context.Context, string, ports.BrokerPolicy) error); ok {
850+ r1 = returnFunc(ctx, endpoint, policy)
851+ } else {
852+ r1 = ret.Error(1)
853+ }
854+ return r0, r1
855+}
856+
857+// MockBrokerHostMembership_AddHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHost'
858+type MockBrokerHostMembership_AddHost_Call struct {
859+ *mock.Call
860+}
861+
862+// AddHost is a helper method to define mock.On call
863+// - ctx context.Context
864+// - endpoint string
865+// - policy ports.BrokerPolicy
866+func (_e *MockBrokerHostMembership_Expecter) AddHost(ctx any, endpoint any, policy any) *MockBrokerHostMembership_AddHost_Call {
867+ return &MockBrokerHostMembership_AddHost_Call{Call: _e.mock.On("AddHost", ctx, endpoint, policy)}
868+}
869+
870+func (_c *MockBrokerHostMembership_AddHost_Call) Run(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy)) *MockBrokerHostMembership_AddHost_Call {
871+ _c.Call.Run(func(args mock.Arguments) {
872+ var arg0 context.Context
873+ if args[0] != nil {
874+ arg0 = args[0].(context.Context)
875+ }
876+ var arg1 string
877+ if args[1] != nil {
878+ arg1 = args[1].(string)
879+ }
880+ var arg2 ports.BrokerPolicy
881+ if args[2] != nil {
882+ arg2 = args[2].(ports.BrokerPolicy)
883+ }
884+ run(
885+ arg0,
886+ arg1,
887+ arg2,
888+ )
889+ })
890+ return _c
891+}
892+
893+func (_c *MockBrokerHostMembership_AddHost_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerHostMembership_AddHost_Call {
894+ _c.Call.Return(remoteRegistration, err)
895+ return _c
896+}
897+
898+func (_c *MockBrokerHostMembership_AddHost_Call) RunAndReturn(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerHostMembership_AddHost_Call {
899+ _c.Call.Return(run)
900+ return _c
901+}
902+
903+// RemoveHost provides a mock function for the type MockBrokerHostMembership
904+func (_mock *MockBrokerHostMembership) RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error) {
905+ ret := _mock.Called(ctx, expected)
906+
907+ if len(ret) == 0 {
908+ panic("no return value specified for RemoveHost")
909+ }
910+
911+ var r0 bool
912+ var r1 error
913+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) (bool, error)); ok {
914+ return returnFunc(ctx, expected)
915+ }
916+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) bool); ok {
917+ r0 = returnFunc(ctx, expected)
918+ } else {
919+ r0 = ret.Get(0).(bool)
920+ }
921+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration) error); ok {
922+ r1 = returnFunc(ctx, expected)
923+ } else {
924+ r1 = ret.Error(1)
925+ }
926+ return r0, r1
927+}
928+
929+// MockBrokerHostMembership_RemoveHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveHost'
930+type MockBrokerHostMembership_RemoveHost_Call struct {
931+ *mock.Call
932+}
933+
934+// RemoveHost is a helper method to define mock.On call
935+// - ctx context.Context
936+// - expected domain.RemoteRegistration
937+func (_e *MockBrokerHostMembership_Expecter) RemoveHost(ctx any, expected any) *MockBrokerHostMembership_RemoveHost_Call {
938+ return &MockBrokerHostMembership_RemoveHost_Call{Call: _e.mock.On("RemoveHost", ctx, expected)}
939+}
940+
941+func (_c *MockBrokerHostMembership_RemoveHost_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration)) *MockBrokerHostMembership_RemoveHost_Call {
942+ _c.Call.Run(func(args mock.Arguments) {
943+ var arg0 context.Context
944+ if args[0] != nil {
945+ arg0 = args[0].(context.Context)
946+ }
947+ var arg1 domain.RemoteRegistration
948+ if args[1] != nil {
949+ arg1 = args[1].(domain.RemoteRegistration)
950+ }
951+ run(
952+ arg0,
953+ arg1,
954+ )
955+ })
956+ return _c
957+}
958+
959+func (_c *MockBrokerHostMembership_RemoveHost_Call) Return(b bool, err error) *MockBrokerHostMembership_RemoveHost_Call {
960+ _c.Call.Return(b, err)
961+ return _c
962+}
963+
964+func (_c *MockBrokerHostMembership_RemoveHost_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration) (bool, error)) *MockBrokerHostMembership_RemoveHost_Call {
965+ _c.Call.Return(run)
966+ return _c
967+}
968+
969+// UpdateHostPolicy provides a mock function for the type MockBrokerHostMembership
970+func (_mock *MockBrokerHostMembership) UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
971+ ret := _mock.Called(ctx, expected, policy)
972+
973+ if len(ret) == 0 {
974+ panic("no return value specified for UpdateHostPolicy")
975+ }
976+
977+ var r0 domain.RemoteRegistration
978+ var r1 error
979+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
980+ return returnFunc(ctx, expected, policy)
981+ }
982+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) domain.RemoteRegistration); ok {
983+ r0 = returnFunc(ctx, expected, policy)
984+ } else {
985+ r0 = ret.Get(0).(domain.RemoteRegistration)
986+ }
987+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) error); ok {
988+ r1 = returnFunc(ctx, expected, policy)
989+ } else {
990+ r1 = ret.Error(1)
991+ }
992+ return r0, r1
993+}
994+
995+// MockBrokerHostMembership_UpdateHostPolicy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHostPolicy'
996+type MockBrokerHostMembership_UpdateHostPolicy_Call struct {
997+ *mock.Call
998+}
999+
1000+// UpdateHostPolicy is a helper method to define mock.On call
1001+// - ctx context.Context
1002+// - expected domain.RemoteRegistration
1003+// - policy ports.BrokerPolicy
1004+func (_e *MockBrokerHostMembership_Expecter) UpdateHostPolicy(ctx any, expected any, policy any) *MockBrokerHostMembership_UpdateHostPolicy_Call {
1005+ return &MockBrokerHostMembership_UpdateHostPolicy_Call{Call: _e.mock.On("UpdateHostPolicy", ctx, expected, policy)}
1006+}
1007+
1008+func (_c *MockBrokerHostMembership_UpdateHostPolicy_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy)) *MockBrokerHostMembership_UpdateHostPolicy_Call {
1009+ _c.Call.Run(func(args mock.Arguments) {
1010+ var arg0 context.Context
1011+ if args[0] != nil {
1012+ arg0 = args[0].(context.Context)
1013+ }
1014+ var arg1 domain.RemoteRegistration
1015+ if args[1] != nil {
1016+ arg1 = args[1].(domain.RemoteRegistration)
1017+ }
1018+ var arg2 ports.BrokerPolicy
1019+ if args[2] != nil {
1020+ arg2 = args[2].(ports.BrokerPolicy)
1021+ }
1022+ run(
1023+ arg0,
1024+ arg1,
1025+ arg2,
1026+ )
1027+ })
1028+ return _c
1029+}
1030+
1031+func (_c *MockBrokerHostMembership_UpdateHostPolicy_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerHostMembership_UpdateHostPolicy_Call {
1032+ _c.Call.Return(remoteRegistration, err)
1033+ return _c
1034+}
1035+
1036+func (_c *MockBrokerHostMembership_UpdateHostPolicy_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerHostMembership_UpdateHostPolicy_Call {
1037+ _c.Call.Return(run)
1038+ return _c
1039+}
1040+
1041+// NewMockBrokerSession creates a new instance of MockBrokerSession. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1042+// The first argument is typically a *testing.T value.
1043+func NewMockBrokerSession(t interface {
1044+ mock.TestingT
1045+ Cleanup(func())
1046+}) *MockBrokerSession {
1047+ if helper, ok := t.(interface{ Helper() }); ok {
1048+ helper.Helper()
1049+ }
1050+
1051+ mock := &MockBrokerSession{}
1052+ mock.Mock.Test(t)
1053+
1054+ t.Cleanup(func() {
1055+ if helper, ok := t.(interface{ Helper() }); ok {
1056+ helper.Helper()
1057+ }
1058+ mock.AssertExpectations(t)
1059+ })
1060+
1061+ return mock
1062+}
1063+
1064+// MockBrokerSession is an autogenerated mock type for the BrokerSession type
1065+type MockBrokerSession struct {
1066+ mock.Mock
1067+}
1068+
1069+type MockBrokerSession_Expecter struct {
1070+ mock *mock.Mock
1071+}
1072+
1073+func (_m *MockBrokerSession) EXPECT() *MockBrokerSession_Expecter {
1074+ return &MockBrokerSession_Expecter{mock: &_m.Mock}
1075+}
1076+
1077+// AddHost provides a mock function for the type MockBrokerSession
1078+func (_mock *MockBrokerSession) AddHost(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
1079+ ret := _mock.Called(ctx, endpoint, policy)
1080+
1081+ if len(ret) == 0 {
1082+ panic("no return value specified for AddHost")
1083+ }
1084+
1085+ var r0 domain.RemoteRegistration
1086+ var r1 error
1087+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
1088+ return returnFunc(ctx, endpoint, policy)
1089+ }
1090+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) domain.RemoteRegistration); ok {
1091+ r0 = returnFunc(ctx, endpoint, policy)
1092+ } else {
1093+ r0 = ret.Get(0).(domain.RemoteRegistration)
1094+ }
1095+ if returnFunc, ok := ret.Get(1).(func(context.Context, string, ports.BrokerPolicy) error); ok {
1096+ r1 = returnFunc(ctx, endpoint, policy)
1097+ } else {
1098+ r1 = ret.Error(1)
1099+ }
1100+ return r0, r1
1101+}
1102+
1103+// MockBrokerSession_AddHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHost'
1104+type MockBrokerSession_AddHost_Call struct {
1105+ *mock.Call
1106+}
1107+
1108+// AddHost is a helper method to define mock.On call
1109+// - ctx context.Context
1110+// - endpoint string
1111+// - policy ports.BrokerPolicy
1112+func (_e *MockBrokerSession_Expecter) AddHost(ctx any, endpoint any, policy any) *MockBrokerSession_AddHost_Call {
1113+ return &MockBrokerSession_AddHost_Call{Call: _e.mock.On("AddHost", ctx, endpoint, policy)}
1114+}
1115+
1116+func (_c *MockBrokerSession_AddHost_Call) Run(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy)) *MockBrokerSession_AddHost_Call {
1117+ _c.Call.Run(func(args mock.Arguments) {
1118+ var arg0 context.Context
1119+ if args[0] != nil {
1120+ arg0 = args[0].(context.Context)
1121+ }
1122+ var arg1 string
1123+ if args[1] != nil {
1124+ arg1 = args[1].(string)
1125+ }
1126+ var arg2 ports.BrokerPolicy
1127+ if args[2] != nil {
1128+ arg2 = args[2].(ports.BrokerPolicy)
1129+ }
1130+ run(
1131+ arg0,
1132+ arg1,
1133+ arg2,
1134+ )
1135+ })
1136+ return _c
1137+}
1138+
1139+func (_c *MockBrokerSession_AddHost_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerSession_AddHost_Call {
1140+ _c.Call.Return(remoteRegistration, err)
1141+ return _c
1142+}
1143+
1144+func (_c *MockBrokerSession_AddHost_Call) RunAndReturn(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerSession_AddHost_Call {
1145+ _c.Call.Return(run)
1146+ return _c
1147+}
1148+
1149+// Close provides a mock function for the type MockBrokerSession
1150+func (_mock *MockBrokerSession) Close() error {
1151+ ret := _mock.Called()
1152+
1153+ if len(ret) == 0 {
1154+ panic("no return value specified for Close")
1155+ }
1156+
1157+ var r0 error
1158+ if returnFunc, ok := ret.Get(0).(func() error); ok {
1159+ r0 = returnFunc()
1160+ } else {
1161+ r0 = ret.Error(0)
1162+ }
1163+ return r0
1164+}
1165+
1166+// MockBrokerSession_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
1167+type MockBrokerSession_Close_Call struct {
1168+ *mock.Call
1169+}
1170+
1171+// Close is a helper method to define mock.On call
1172+func (_e *MockBrokerSession_Expecter) Close() *MockBrokerSession_Close_Call {
1173+ return &MockBrokerSession_Close_Call{Call: _e.mock.On("Close")}
1174+}
1175+
1176+func (_c *MockBrokerSession_Close_Call) Run(run func()) *MockBrokerSession_Close_Call {
1177+ _c.Call.Run(func(args mock.Arguments) {
1178+ run()
1179+ })
1180+ return _c
1181+}
1182+
1183+func (_c *MockBrokerSession_Close_Call) Return(err error) *MockBrokerSession_Close_Call {
1184+ _c.Call.Return(err)
1185+ return _c
1186+}
1187+
1188+func (_c *MockBrokerSession_Close_Call) RunAndReturn(run func() error) *MockBrokerSession_Close_Call {
1189+ _c.Call.Return(run)
1190+ return _c
1191+}
1192+
1193+// CloseStream provides a mock function for the type MockBrokerSession
1194+func (_mock *MockBrokerSession) CloseStream(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error {
1195+ ret := _mock.Called(connection, stream)
1196+
1197+ if len(ret) == 0 {
1198+ panic("no return value specified for CloseStream")
1199+ }
1200+
1201+ var r0 error
1202+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerConnectionID, ports.BrokerStreamID) error); ok {
1203+ r0 = returnFunc(connection, stream)
1204+ } else {
1205+ r0 = ret.Error(0)
1206+ }
1207+ return r0
1208+}
1209+
1210+// MockBrokerSession_CloseStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseStream'
1211+type MockBrokerSession_CloseStream_Call struct {
1212+ *mock.Call
1213+}
1214+
1215+// CloseStream is a helper method to define mock.On call
1216+// - connection ports.BrokerConnectionID
1217+// - stream ports.BrokerStreamID
1218+func (_e *MockBrokerSession_Expecter) CloseStream(connection any, stream any) *MockBrokerSession_CloseStream_Call {
1219+ return &MockBrokerSession_CloseStream_Call{Call: _e.mock.On("CloseStream", connection, stream)}
1220+}
1221+
1222+func (_c *MockBrokerSession_CloseStream_Call) Run(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID)) *MockBrokerSession_CloseStream_Call {
1223+ _c.Call.Run(func(args mock.Arguments) {
1224+ var arg0 ports.BrokerConnectionID
1225+ if args[0] != nil {
1226+ arg0 = args[0].(ports.BrokerConnectionID)
1227+ }
1228+ var arg1 ports.BrokerStreamID
1229+ if args[1] != nil {
1230+ arg1 = args[1].(ports.BrokerStreamID)
1231+ }
1232+ run(
1233+ arg0,
1234+ arg1,
1235+ )
1236+ })
1237+ return _c
1238+}
1239+
1240+func (_c *MockBrokerSession_CloseStream_Call) Return(err error) *MockBrokerSession_CloseStream_Call {
1241+ _c.Call.Return(err)
1242+ return _c
1243+}
1244+
1245+func (_c *MockBrokerSession_CloseStream_Call) RunAndReturn(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error) *MockBrokerSession_CloseStream_Call {
1246+ _c.Call.Return(run)
1247+ return _c
1248+}
1249+
1250+// ConnectionID provides a mock function for the type MockBrokerSession
1251+func (_mock *MockBrokerSession) ConnectionID() ports.BrokerConnectionID {
1252+ ret := _mock.Called()
1253+
1254+ if len(ret) == 0 {
1255+ panic("no return value specified for ConnectionID")
1256+ }
1257+
1258+ var r0 ports.BrokerConnectionID
1259+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerConnectionID); ok {
1260+ r0 = returnFunc()
1261+ } else {
1262+ if ret.Get(0) != nil {
1263+ r0 = ret.Get(0).(ports.BrokerConnectionID)
1264+ }
1265+ }
1266+ return r0
1267+}
1268+
1269+// MockBrokerSession_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
1270+type MockBrokerSession_ConnectionID_Call struct {
1271+ *mock.Call
1272+}
1273+
1274+// ConnectionID is a helper method to define mock.On call
1275+func (_e *MockBrokerSession_Expecter) ConnectionID() *MockBrokerSession_ConnectionID_Call {
1276+ return &MockBrokerSession_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
1277+}
1278+
1279+func (_c *MockBrokerSession_ConnectionID_Call) Run(run func()) *MockBrokerSession_ConnectionID_Call {
1280+ _c.Call.Run(func(args mock.Arguments) {
1281+ run()
1282+ })
1283+ return _c
1284+}
1285+
1286+func (_c *MockBrokerSession_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerSession_ConnectionID_Call {
1287+ _c.Call.Return(brokerConnectionID)
1288+ return _c
1289+}
1290+
1291+func (_c *MockBrokerSession_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerSession_ConnectionID_Call {
1292+ _c.Call.Return(run)
1293+ return _c
1294+}
1295+
1296+// Done provides a mock function for the type MockBrokerSession
1297+func (_mock *MockBrokerSession) Done() <-chan struct{} {
1298+ ret := _mock.Called()
1299+
1300+ if len(ret) == 0 {
1301+ panic("no return value specified for Done")
1302+ }
1303+
1304+ var r0 <-chan struct{}
1305+ if returnFunc, ok := ret.Get(0).(func() <-chan struct{}); ok {
1306+ r0 = returnFunc()
1307+ } else {
1308+ if ret.Get(0) != nil {
1309+ r0 = ret.Get(0).(<-chan struct{})
1310+ }
1311+ }
1312+ return r0
1313+}
1314+
1315+// MockBrokerSession_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
1316+type MockBrokerSession_Done_Call struct {
1317+ *mock.Call
1318+}
1319+
1320+// Done is a helper method to define mock.On call
1321+func (_e *MockBrokerSession_Expecter) Done() *MockBrokerSession_Done_Call {
1322+ return &MockBrokerSession_Done_Call{Call: _e.mock.On("Done")}
1323+}
1324+
1325+func (_c *MockBrokerSession_Done_Call) Run(run func()) *MockBrokerSession_Done_Call {
1326+ _c.Call.Run(func(args mock.Arguments) {
1327+ run()
1328+ })
1329+ return _c
1330+}
1331+
1332+func (_c *MockBrokerSession_Done_Call) Return(valCh <-chan struct{}) *MockBrokerSession_Done_Call {
1333+ _c.Call.Return(valCh)
1334+ return _c
1335+}
1336+
1337+func (_c *MockBrokerSession_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerSession_Done_Call {
1338+ _c.Call.Return(run)
1339+ return _c
1340+}
1341+
1342+// Err provides a mock function for the type MockBrokerSession
1343+func (_mock *MockBrokerSession) Err() error {
1344+ ret := _mock.Called()
1345+
1346+ if len(ret) == 0 {
1347+ panic("no return value specified for Err")
1348+ }
1349+
1350+ var r0 error
1351+ if returnFunc, ok := ret.Get(0).(func() error); ok {
1352+ r0 = returnFunc()
1353+ } else {
1354+ r0 = ret.Error(0)
1355+ }
1356+ return r0
1357+}
1358+
1359+// MockBrokerSession_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
1360+type MockBrokerSession_Err_Call struct {
1361+ *mock.Call
1362+}
1363+
1364+// Err is a helper method to define mock.On call
1365+func (_e *MockBrokerSession_Expecter) Err() *MockBrokerSession_Err_Call {
1366+ return &MockBrokerSession_Err_Call{Call: _e.mock.On("Err")}
1367+}
1368+
1369+func (_c *MockBrokerSession_Err_Call) Run(run func()) *MockBrokerSession_Err_Call {
1370+ _c.Call.Run(func(args mock.Arguments) {
1371+ run()
1372+ })
1373+ return _c
1374+}
1375+
1376+func (_c *MockBrokerSession_Err_Call) Return(err error) *MockBrokerSession_Err_Call {
1377+ _c.Call.Return(err)
1378+ return _c
1379+}
1380+
1381+func (_c *MockBrokerSession_Err_Call) RunAndReturn(run func() error) *MockBrokerSession_Err_Call {
1382+ _c.Call.Return(run)
1383+ return _c
1384+}
1385+
1386+// NextStreamID provides a mock function for the type MockBrokerSession
1387+func (_mock *MockBrokerSession) NextStreamID() (ports.BrokerStreamID, error) {
1388+ ret := _mock.Called()
1389+
1390+ if len(ret) == 0 {
1391+ panic("no return value specified for NextStreamID")
1392+ }
1393+
1394+ var r0 ports.BrokerStreamID
1395+ var r1 error
1396+ if returnFunc, ok := ret.Get(0).(func() (ports.BrokerStreamID, error)); ok {
1397+ return returnFunc()
1398+ }
1399+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerStreamID); ok {
1400+ r0 = returnFunc()
1401+ } else {
1402+ r0 = ret.Get(0).(ports.BrokerStreamID)
1403+ }
1404+ if returnFunc, ok := ret.Get(1).(func() error); ok {
1405+ r1 = returnFunc()
1406+ } else {
1407+ r1 = ret.Error(1)
1408+ }
1409+ return r0, r1
1410+}
1411+
1412+// MockBrokerSession_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
1413+type MockBrokerSession_NextStreamID_Call struct {
1414+ *mock.Call
1415+}
1416+
1417+// NextStreamID is a helper method to define mock.On call
1418+func (_e *MockBrokerSession_Expecter) NextStreamID() *MockBrokerSession_NextStreamID_Call {
1419+ return &MockBrokerSession_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
1420+}
1421+
1422+func (_c *MockBrokerSession_NextStreamID_Call) Run(run func()) *MockBrokerSession_NextStreamID_Call {
1423+ _c.Call.Run(func(args mock.Arguments) {
1424+ run()
1425+ })
1426+ return _c
1427+}
1428+
1429+func (_c *MockBrokerSession_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerSession_NextStreamID_Call {
1430+ _c.Call.Return(brokerStreamID, err)
1431+ return _c
1432+}
1433+
1434+func (_c *MockBrokerSession_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerSession_NextStreamID_Call {
1435+ _c.Call.Return(run)
1436+ return _c
1437+}
1438+
1439+// RemoveHost provides a mock function for the type MockBrokerSession
1440+func (_mock *MockBrokerSession) RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error) {
1441+ ret := _mock.Called(ctx, expected)
1442+
1443+ if len(ret) == 0 {
1444+ panic("no return value specified for RemoveHost")
1445+ }
1446+
1447+ var r0 bool
1448+ var r1 error
1449+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) (bool, error)); ok {
1450+ return returnFunc(ctx, expected)
1451+ }
1452+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) bool); ok {
1453+ r0 = returnFunc(ctx, expected)
1454+ } else {
1455+ r0 = ret.Get(0).(bool)
1456+ }
1457+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration) error); ok {
1458+ r1 = returnFunc(ctx, expected)
1459+ } else {
1460+ r1 = ret.Error(1)
1461+ }
1462+ return r0, r1
1463+}
1464+
1465+// MockBrokerSession_RemoveHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveHost'
1466+type MockBrokerSession_RemoveHost_Call struct {
1467+ *mock.Call
1468+}
1469+
1470+// RemoveHost is a helper method to define mock.On call
1471+// - ctx context.Context
1472+// - expected domain.RemoteRegistration
1473+func (_e *MockBrokerSession_Expecter) RemoveHost(ctx any, expected any) *MockBrokerSession_RemoveHost_Call {
1474+ return &MockBrokerSession_RemoveHost_Call{Call: _e.mock.On("RemoveHost", ctx, expected)}
1475+}
1476+
1477+func (_c *MockBrokerSession_RemoveHost_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration)) *MockBrokerSession_RemoveHost_Call {
1478+ _c.Call.Run(func(args mock.Arguments) {
1479+ var arg0 context.Context
1480+ if args[0] != nil {
1481+ arg0 = args[0].(context.Context)
1482+ }
1483+ var arg1 domain.RemoteRegistration
1484+ if args[1] != nil {
1485+ arg1 = args[1].(domain.RemoteRegistration)
1486+ }
1487+ run(
1488+ arg0,
1489+ arg1,
1490+ )
1491+ })
1492+ return _c
1493+}
1494+
1495+func (_c *MockBrokerSession_RemoveHost_Call) Return(b bool, err error) *MockBrokerSession_RemoveHost_Call {
1496+ _c.Call.Return(b, err)
1497+ return _c
1498+}
1499+
1500+func (_c *MockBrokerSession_RemoveHost_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration) (bool, error)) *MockBrokerSession_RemoveHost_Call {
1501+ _c.Call.Return(run)
1502+ return _c
1503+}
1504+
1505+// RequestReconcile provides a mock function for the type MockBrokerSession
1506+func (_mock *MockBrokerSession) RequestReconcile(endpoint string) {
1507+ _mock.Called(endpoint)
1508+ return
1509+}
1510+
1511+// MockBrokerSession_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
1512+type MockBrokerSession_RequestReconcile_Call struct {
1513+ *mock.Call
1514+}
1515+
1516+// RequestReconcile is a helper method to define mock.On call
1517+// - endpoint string
1518+func (_e *MockBrokerSession_Expecter) RequestReconcile(endpoint any) *MockBrokerSession_RequestReconcile_Call {
1519+ return &MockBrokerSession_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
1520+}
1521+
1522+func (_c *MockBrokerSession_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerSession_RequestReconcile_Call {
1523+ _c.Call.Run(func(args mock.Arguments) {
1524+ var arg0 string
1525+ if args[0] != nil {
1526+ arg0 = args[0].(string)
1527+ }
1528+ run(
1529+ arg0,
1530+ )
1531+ })
1532+ return _c
1533+}
1534+
1535+func (_c *MockBrokerSession_RequestReconcile_Call) Return() *MockBrokerSession_RequestReconcile_Call {
1536+ _c.Call.Return()
1537+ return _c
1538+}
1539+
1540+func (_c *MockBrokerSession_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerSession_RequestReconcile_Call {
1541+ _c.Run(run)
1542+ return _c
1543+}
1544+
1545+// Snapshot provides a mock function for the type MockBrokerSession
1546+func (_mock *MockBrokerSession) Snapshot() ports.BrokerSnapshot {
1547+ ret := _mock.Called()
1548+
1549+ if len(ret) == 0 {
1550+ panic("no return value specified for Snapshot")
1551+ }
1552+
1553+ var r0 ports.BrokerSnapshot
1554+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerSnapshot); ok {
1555+ r0 = returnFunc()
1556+ } else {
1557+ r0 = ret.Get(0).(ports.BrokerSnapshot)
1558+ }
1559+ return r0
1560+}
1561+
1562+// MockBrokerSession_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
1563+type MockBrokerSession_Snapshot_Call struct {
1564+ *mock.Call
1565+}
1566+
1567+// Snapshot is a helper method to define mock.On call
1568+func (_e *MockBrokerSession_Expecter) Snapshot() *MockBrokerSession_Snapshot_Call {
1569+ return &MockBrokerSession_Snapshot_Call{Call: _e.mock.On("Snapshot")}
1570+}
1571+
1572+func (_c *MockBrokerSession_Snapshot_Call) Run(run func()) *MockBrokerSession_Snapshot_Call {
1573+ _c.Call.Run(func(args mock.Arguments) {
1574+ run()
1575+ })
1576+ return _c
1577+}
1578+
1579+func (_c *MockBrokerSession_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerSession_Snapshot_Call {
1580+ _c.Call.Return(brokerSnapshot)
1581+ return _c
1582+}
1583+
1584+func (_c *MockBrokerSession_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerSession_Snapshot_Call {
1585+ _c.Call.Return(run)
1586+ return _c
1587+}
1588+
1589+// Subscribe provides a mock function for the type MockBrokerSession
1590+func (_mock *MockBrokerSession) Subscribe() (ports.BrokerSubscription, error) {
1591+ ret := _mock.Called()
1592+
1593+ if len(ret) == 0 {
1594+ panic("no return value specified for Subscribe")
1595+ }
1596+
1597+ var r0 ports.BrokerSubscription
1598+ var r1 error
1599+ if returnFunc, ok := ret.Get(0).(func() (ports.BrokerSubscription, error)); ok {
1600+ return returnFunc()
1601+ }
1602+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerSubscription); ok {
1603+ r0 = returnFunc()
1604+ } else {
1605+ if ret.Get(0) != nil {
1606+ r0 = ret.Get(0).(ports.BrokerSubscription)
1607+ }
1608+ }
1609+ if returnFunc, ok := ret.Get(1).(func() error); ok {
1610+ r1 = returnFunc()
1611+ } else {
1612+ r1 = ret.Error(1)
1613+ }
1614+ return r0, r1
1615+}
1616+
1617+// MockBrokerSession_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
1618+type MockBrokerSession_Subscribe_Call struct {
1619+ *mock.Call
1620+}
1621+
1622+// Subscribe is a helper method to define mock.On call
1623+func (_e *MockBrokerSession_Expecter) Subscribe() *MockBrokerSession_Subscribe_Call {
1624+ return &MockBrokerSession_Subscribe_Call{Call: _e.mock.On("Subscribe")}
1625+}
1626+
1627+func (_c *MockBrokerSession_Subscribe_Call) Run(run func()) *MockBrokerSession_Subscribe_Call {
1628+ _c.Call.Run(func(args mock.Arguments) {
1629+ run()
1630+ })
1631+ return _c
1632+}
1633+
1634+func (_c *MockBrokerSession_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerSession_Subscribe_Call {
1635+ _c.Call.Return(brokerSubscription, err)
1636+ return _c
1637+}
1638+
1639+func (_c *MockBrokerSession_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerSession_Subscribe_Call {
1640+ _c.Call.Return(run)
1641+ return _c
1642+}
1643+
1644+// SubscribePreview provides a mock function for the type MockBrokerSession
1645+func (_mock *MockBrokerSession) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
1646+ ret := _mock.Called(request)
1647+
1648+ if len(ret) == 0 {
1649+ panic("no return value specified for SubscribePreview")
1650+ }
1651+
1652+ var r0 ports.BrokerPreviewSubscription
1653+ var r1 error
1654+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)); ok {
1655+ return returnFunc(request)
1656+ }
1657+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerPreviewRequest) ports.BrokerPreviewSubscription); ok {
1658+ r0 = returnFunc(request)
1659+ } else {
1660+ if ret.Get(0) != nil {
1661+ r0 = ret.Get(0).(ports.BrokerPreviewSubscription)
1662+ }
1663+ }
1664+ if returnFunc, ok := ret.Get(1).(func(ports.BrokerPreviewRequest) error); ok {
1665+ r1 = returnFunc(request)
1666+ } else {
1667+ r1 = ret.Error(1)
1668+ }
1669+ return r0, r1
1670+}
1671+
1672+// MockBrokerSession_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
1673+type MockBrokerSession_SubscribePreview_Call struct {
1674+ *mock.Call
1675+}
1676+
1677+// SubscribePreview is a helper method to define mock.On call
1678+// - request ports.BrokerPreviewRequest
1679+func (_e *MockBrokerSession_Expecter) SubscribePreview(request any) *MockBrokerSession_SubscribePreview_Call {
1680+ return &MockBrokerSession_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
1681+}
1682+
1683+func (_c *MockBrokerSession_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerSession_SubscribePreview_Call {
1684+ _c.Call.Run(func(args mock.Arguments) {
1685+ var arg0 ports.BrokerPreviewRequest
1686+ if args[0] != nil {
1687+ arg0 = args[0].(ports.BrokerPreviewRequest)
1688+ }
1689+ run(
1690+ arg0,
1691+ )
1692+ })
1693+ return _c
1694+}
1695+
1696+func (_c *MockBrokerSession_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerSession_SubscribePreview_Call {
1697+ _c.Call.Return(brokerPreviewSubscription, err)
1698+ return _c
1699+}
1700+
1701+func (_c *MockBrokerSession_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerSession_SubscribePreview_Call {
1702+ _c.Call.Return(run)
1703+ return _c
1704+}
1705+
1706+// UpdateHostPolicy provides a mock function for the type MockBrokerSession
1707+func (_mock *MockBrokerSession) UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
1708+ ret := _mock.Called(ctx, expected, policy)
1709+
1710+ if len(ret) == 0 {
1711+ panic("no return value specified for UpdateHostPolicy")
1712+ }
1713+
1714+ var r0 domain.RemoteRegistration
1715+ var r1 error
1716+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
1717+ return returnFunc(ctx, expected, policy)
1718+ }
1719+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) domain.RemoteRegistration); ok {
1720+ r0 = returnFunc(ctx, expected, policy)
1721+ } else {
1722+ r0 = ret.Get(0).(domain.RemoteRegistration)
1723+ }
1724+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) error); ok {
1725+ r1 = returnFunc(ctx, expected, policy)
1726+ } else {
1727+ r1 = ret.Error(1)
1728+ }
1729+ return r0, r1
1730+}
1731+
1732+// MockBrokerSession_UpdateHostPolicy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHostPolicy'
1733+type MockBrokerSession_UpdateHostPolicy_Call struct {
1734+ *mock.Call
1735+}
1736+
1737+// UpdateHostPolicy is a helper method to define mock.On call
1738+// - ctx context.Context
1739+// - expected domain.RemoteRegistration
1740+// - policy ports.BrokerPolicy
1741+func (_e *MockBrokerSession_Expecter) UpdateHostPolicy(ctx any, expected any, policy any) *MockBrokerSession_UpdateHostPolicy_Call {
1742+ return &MockBrokerSession_UpdateHostPolicy_Call{Call: _e.mock.On("UpdateHostPolicy", ctx, expected, policy)}
1743+}
1744+
1745+func (_c *MockBrokerSession_UpdateHostPolicy_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy)) *MockBrokerSession_UpdateHostPolicy_Call {
1746+ _c.Call.Run(func(args mock.Arguments) {
1747+ var arg0 context.Context
1748+ if args[0] != nil {
1749+ arg0 = args[0].(context.Context)
1750+ }
1751+ var arg1 domain.RemoteRegistration
1752+ if args[1] != nil {
1753+ arg1 = args[1].(domain.RemoteRegistration)
1754+ }
1755+ var arg2 ports.BrokerPolicy
1756+ if args[2] != nil {
1757+ arg2 = args[2].(ports.BrokerPolicy)
1758+ }
1759+ run(
1760+ arg0,
1761+ arg1,
1762+ arg2,
1763+ )
1764+ })
1765+ return _c
1766+}
1767+
1768+func (_c *MockBrokerSession_UpdateHostPolicy_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerSession_UpdateHostPolicy_Call {
1769+ _c.Call.Return(remoteRegistration, err)
1770+ return _c
1771+}
1772+
1773+func (_c *MockBrokerSession_UpdateHostPolicy_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerSession_UpdateHostPolicy_Call {
1774+ _c.Call.Return(run)
1775+ return _c
1776+}
1777+
1778+// NewMockBrokerService creates a new instance of MockBrokerService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1779+// The first argument is typically a *testing.T value.
1780+func NewMockBrokerService(t interface {
1781+ mock.TestingT
1782+ Cleanup(func())
1783+}) *MockBrokerService {
1784+ if helper, ok := t.(interface{ Helper() }); ok {
1785+ helper.Helper()
1786+ }
1787+
1788+ mock := &MockBrokerService{}
1789+ mock.Mock.Test(t)
1790+
1791+ t.Cleanup(func() {
1792+ if helper, ok := t.(interface{ Helper() }); ok {
1793+ helper.Helper()
1794+ }
1795+ mock.AssertExpectations(t)
1796+ })
1797+
1798+ return mock
1799+}
1800+
1801+// MockBrokerService is an autogenerated mock type for the BrokerService type
1802+type MockBrokerService struct {
1803+ mock.Mock
1804+}
1805+
1806+type MockBrokerService_Expecter struct {
1807+ mock *mock.Mock
1808+}
1809+
1810+func (_m *MockBrokerService) EXPECT() *MockBrokerService_Expecter {
1811+ return &MockBrokerService_Expecter{mock: &_m.Mock}
1812+}
1813+
1814+// AddHost provides a mock function for the type MockBrokerService
1815+func (_mock *MockBrokerService) AddHost(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
1816+ ret := _mock.Called(ctx, endpoint, policy)
1817+
1818+ if len(ret) == 0 {
1819+ panic("no return value specified for AddHost")
1820+ }
1821+
1822+ var r0 domain.RemoteRegistration
1823+ var r1 error
1824+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
1825+ return returnFunc(ctx, endpoint, policy)
1826+ }
1827+ if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) domain.RemoteRegistration); ok {
1828+ r0 = returnFunc(ctx, endpoint, policy)
1829+ } else {
1830+ r0 = ret.Get(0).(domain.RemoteRegistration)
1831+ }
1832+ if returnFunc, ok := ret.Get(1).(func(context.Context, string, ports.BrokerPolicy) error); ok {
1833+ r1 = returnFunc(ctx, endpoint, policy)
1834+ } else {
1835+ r1 = ret.Error(1)
1836+ }
1837+ return r0, r1
1838+}
1839+
1840+// MockBrokerService_AddHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHost'
1841+type MockBrokerService_AddHost_Call struct {
1842+ *mock.Call
1843+}
1844+
1845+// AddHost is a helper method to define mock.On call
1846+// - ctx context.Context
1847+// - endpoint string
1848+// - policy ports.BrokerPolicy
1849+func (_e *MockBrokerService_Expecter) AddHost(ctx any, endpoint any, policy any) *MockBrokerService_AddHost_Call {
1850+ return &MockBrokerService_AddHost_Call{Call: _e.mock.On("AddHost", ctx, endpoint, policy)}
1851+}
1852+
1853+func (_c *MockBrokerService_AddHost_Call) Run(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy)) *MockBrokerService_AddHost_Call {
1854+ _c.Call.Run(func(args mock.Arguments) {
1855+ var arg0 context.Context
1856+ if args[0] != nil {
1857+ arg0 = args[0].(context.Context)
1858+ }
1859+ var arg1 string
1860+ if args[1] != nil {
1861+ arg1 = args[1].(string)
1862+ }
1863+ var arg2 ports.BrokerPolicy
1864+ if args[2] != nil {
1865+ arg2 = args[2].(ports.BrokerPolicy)
1866+ }
1867+ run(
1868+ arg0,
1869+ arg1,
1870+ arg2,
1871+ )
1872+ })
1873+ return _c
1874+}
1875+
1876+func (_c *MockBrokerService_AddHost_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerService_AddHost_Call {
1877+ _c.Call.Return(remoteRegistration, err)
1878+ return _c
1879+}
1880+
1881+func (_c *MockBrokerService_AddHost_Call) RunAndReturn(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerService_AddHost_Call {
1882+ _c.Call.Return(run)
1883+ return _c
1884+}
1885+
1886+// Close provides a mock function for the type MockBrokerService
1887+func (_mock *MockBrokerService) Close() error {
1888+ ret := _mock.Called()
1889+
1890+ if len(ret) == 0 {
1891+ panic("no return value specified for Close")
1892+ }
1893+
1894+ var r0 error
1895+ if returnFunc, ok := ret.Get(0).(func() error); ok {
1896+ r0 = returnFunc()
1897+ } else {
1898+ r0 = ret.Error(0)
1899+ }
1900+ return r0
1901+}
1902+
1903+// MockBrokerService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
1904+type MockBrokerService_Close_Call struct {
1905+ *mock.Call
1906+}
1907+
1908+// Close is a helper method to define mock.On call
1909+func (_e *MockBrokerService_Expecter) Close() *MockBrokerService_Close_Call {
1910+ return &MockBrokerService_Close_Call{Call: _e.mock.On("Close")}
1911+}
1912+
1913+func (_c *MockBrokerService_Close_Call) Run(run func()) *MockBrokerService_Close_Call {
1914+ _c.Call.Run(func(args mock.Arguments) {
1915+ run()
1916+ })
1917+ return _c
1918+}
1919+
1920+func (_c *MockBrokerService_Close_Call) Return(err error) *MockBrokerService_Close_Call {
1921+ _c.Call.Return(err)
1922+ return _c
1923+}
1924+
1925+func (_c *MockBrokerService_Close_Call) RunAndReturn(run func() error) *MockBrokerService_Close_Call {
1926+ _c.Call.Return(run)
1927+ return _c
1928+}
1929+
1930+// CloseStream provides a mock function for the type MockBrokerService
1931+func (_mock *MockBrokerService) CloseStream(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error {
1932+ ret := _mock.Called(connection, stream)
1933+
1934+ if len(ret) == 0 {
1935+ panic("no return value specified for CloseStream")
1936+ }
1937+
1938+ var r0 error
1939+ if returnFunc, ok := ret.Get(0).(func(ports.BrokerConnectionID, ports.BrokerStreamID) error); ok {
1940+ r0 = returnFunc(connection, stream)
1941+ } else {
1942+ r0 = ret.Error(0)
1943+ }
1944+ return r0
1945+}
1946+
1947+// MockBrokerService_CloseStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseStream'
1948+type MockBrokerService_CloseStream_Call struct {
1949+ *mock.Call
1950+}
1951+
1952+// CloseStream is a helper method to define mock.On call
1953+// - connection ports.BrokerConnectionID
1954+// - stream ports.BrokerStreamID
1955+func (_e *MockBrokerService_Expecter) CloseStream(connection any, stream any) *MockBrokerService_CloseStream_Call {
1956+ return &MockBrokerService_CloseStream_Call{Call: _e.mock.On("CloseStream", connection, stream)}
1957+}
1958+
1959+func (_c *MockBrokerService_CloseStream_Call) Run(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID)) *MockBrokerService_CloseStream_Call {
1960+ _c.Call.Run(func(args mock.Arguments) {
1961+ var arg0 ports.BrokerConnectionID
1962+ if args[0] != nil {
1963+ arg0 = args[0].(ports.BrokerConnectionID)
1964+ }
1965+ var arg1 ports.BrokerStreamID
1966+ if args[1] != nil {
1967+ arg1 = args[1].(ports.BrokerStreamID)
1968+ }
1969+ run(
1970+ arg0,
1971+ arg1,
1972+ )
1973+ })
1974+ return _c
1975+}
1976+
1977+func (_c *MockBrokerService_CloseStream_Call) Return(err error) *MockBrokerService_CloseStream_Call {
1978+ _c.Call.Return(err)
1979+ return _c
1980+}
1981+
1982+func (_c *MockBrokerService_CloseStream_Call) RunAndReturn(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error) *MockBrokerService_CloseStream_Call {
1983+ _c.Call.Return(run)
1984+ return _c
1985+}
1986+
1987+// ConnectionID provides a mock function for the type MockBrokerService
1988+func (_mock *MockBrokerService) ConnectionID() ports.BrokerConnectionID {
1989+ ret := _mock.Called()
1990+
1991+ if len(ret) == 0 {
1992+ panic("no return value specified for ConnectionID")
1993+ }
1994+
1995+ var r0 ports.BrokerConnectionID
1996+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerConnectionID); ok {
1997+ r0 = returnFunc()
1998+ } else {
1999+ if ret.Get(0) != nil {
2000+ r0 = ret.Get(0).(ports.BrokerConnectionID)
2001+ }
2002+ }
2003+ return r0
2004+}
2005+
2006+// MockBrokerService_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
2007+type MockBrokerService_ConnectionID_Call struct {
2008+ *mock.Call
2009+}
2010+
2011+// ConnectionID is a helper method to define mock.On call
2012+func (_e *MockBrokerService_Expecter) ConnectionID() *MockBrokerService_ConnectionID_Call {
2013+ return &MockBrokerService_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
2014+}
2015+
2016+func (_c *MockBrokerService_ConnectionID_Call) Run(run func()) *MockBrokerService_ConnectionID_Call {
2017+ _c.Call.Run(func(args mock.Arguments) {
2018+ run()
2019+ })
2020+ return _c
2021+}
2022+
2023+func (_c *MockBrokerService_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerService_ConnectionID_Call {
2024+ _c.Call.Return(brokerConnectionID)
2025+ return _c
2026+}
2027+
2028+func (_c *MockBrokerService_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerService_ConnectionID_Call {
2029+ _c.Call.Return(run)
2030+ return _c
2031+}
2032+
2033+// Done provides a mock function for the type MockBrokerService
2034+func (_mock *MockBrokerService) Done() <-chan struct{} {
2035+ ret := _mock.Called()
2036+
2037+ if len(ret) == 0 {
2038+ panic("no return value specified for Done")
2039+ }
2040+
2041+ var r0 <-chan struct{}
2042+ if returnFunc, ok := ret.Get(0).(func() <-chan struct{}); ok {
2043+ r0 = returnFunc()
2044+ } else {
2045+ if ret.Get(0) != nil {
2046+ r0 = ret.Get(0).(<-chan struct{})
2047+ }
2048+ }
2049+ return r0
2050+}
2051+
2052+// MockBrokerService_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
2053+type MockBrokerService_Done_Call struct {
2054+ *mock.Call
2055+}
2056+
2057+// Done is a helper method to define mock.On call
2058+func (_e *MockBrokerService_Expecter) Done() *MockBrokerService_Done_Call {
2059+ return &MockBrokerService_Done_Call{Call: _e.mock.On("Done")}
2060+}
2061+
2062+func (_c *MockBrokerService_Done_Call) Run(run func()) *MockBrokerService_Done_Call {
2063+ _c.Call.Run(func(args mock.Arguments) {
2064+ run()
2065+ })
2066+ return _c
2067+}
2068+
2069+func (_c *MockBrokerService_Done_Call) Return(valCh <-chan struct{}) *MockBrokerService_Done_Call {
2070+ _c.Call.Return(valCh)
2071+ return _c
2072+}
2073+
2074+func (_c *MockBrokerService_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerService_Done_Call {
2075+ _c.Call.Return(run)
2076+ return _c
2077+}
2078+
2079+// Err provides a mock function for the type MockBrokerService
2080+func (_mock *MockBrokerService) Err() error {
2081+ ret := _mock.Called()
2082+
2083+ if len(ret) == 0 {
2084+ panic("no return value specified for Err")
2085+ }
2086+
2087+ var r0 error
2088+ if returnFunc, ok := ret.Get(0).(func() error); ok {
2089+ r0 = returnFunc()
2090+ } else {
2091+ r0 = ret.Error(0)
2092+ }
2093+ return r0
2094+}
2095+
2096+// MockBrokerService_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
2097+type MockBrokerService_Err_Call struct {
2098+ *mock.Call
2099+}
2100+
2101+// Err is a helper method to define mock.On call
2102+func (_e *MockBrokerService_Expecter) Err() *MockBrokerService_Err_Call {
2103+ return &MockBrokerService_Err_Call{Call: _e.mock.On("Err")}
2104+}
2105+
2106+func (_c *MockBrokerService_Err_Call) Run(run func()) *MockBrokerService_Err_Call {
2107+ _c.Call.Run(func(args mock.Arguments) {
2108+ run()
2109+ })
2110+ return _c
2111+}
2112+
2113+func (_c *MockBrokerService_Err_Call) Return(err error) *MockBrokerService_Err_Call {
2114+ _c.Call.Return(err)
2115+ return _c
2116+}
2117+
2118+func (_c *MockBrokerService_Err_Call) RunAndReturn(run func() error) *MockBrokerService_Err_Call {
2119+ _c.Call.Return(run)
2120+ return _c
2121+}
2122+
2123+// NextStreamID provides a mock function for the type MockBrokerService
2124+func (_mock *MockBrokerService) NextStreamID() (ports.BrokerStreamID, error) {
2125+ ret := _mock.Called()
2126+
2127+ if len(ret) == 0 {
2128+ panic("no return value specified for NextStreamID")
2129+ }
2130+
2131+ var r0 ports.BrokerStreamID
2132+ var r1 error
2133+ if returnFunc, ok := ret.Get(0).(func() (ports.BrokerStreamID, error)); ok {
2134+ return returnFunc()
2135+ }
2136+ if returnFunc, ok := ret.Get(0).(func() ports.BrokerStreamID); ok {
2137+ r0 = returnFunc()
2138+ } else {
2139+ r0 = ret.Get(0).(ports.BrokerStreamID)
2140+ }
2141+ if returnFunc, ok := ret.Get(1).(func() error); ok {
2142+ r1 = returnFunc()
2143+ } else {
2144+ r1 = ret.Error(1)
2145+ }
2146+ return r0, r1
2147+}
2148+
2149+// MockBrokerService_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
2150+type MockBrokerService_NextStreamID_Call struct {
2151+ *mock.Call
2152+}
2153+
2154+// NextStreamID is a helper method to define mock.On call
2155+func (_e *MockBrokerService_Expecter) NextStreamID() *MockBrokerService_NextStreamID_Call {
2156+ return &MockBrokerService_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
2157+}
2158+
2159+func (_c *MockBrokerService_NextStreamID_Call) Run(run func()) *MockBrokerService_NextStreamID_Call {
2160+ _c.Call.Run(func(args mock.Arguments) {
2161+ run()
2162+ })
2163+ return _c
2164+}
2165+
2166+func (_c *MockBrokerService_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerService_NextStreamID_Call {
2167+ _c.Call.Return(brokerStreamID, err)
2168+ return _c
2169+}
2170+
2171+func (_c *MockBrokerService_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerService_NextStreamID_Call {
2172+ _c.Call.Return(run)
2173+ return _c
2174+}
2175+
2176+// OpenStream provides a mock function for the type MockBrokerService
2177+func (_mock *MockBrokerService) OpenStream(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
2178+ ret := _mock.Called(ctx, request)
2179+
2180+ if len(ret) == 0 {
2181+ panic("no return value specified for OpenStream")
2182+ }
2183+
2184+ var r0 ports.BrokerLogicalConnection
2185+ var r1 error
2186+ if returnFunc, ok := ret.Get(0).(func(context.Context, ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error)); ok {
2187+ return returnFunc(ctx, request)
2188+ }
2189+ if returnFunc, ok := ret.Get(0).(func(context.Context, ports.BrokerOpenStreamRequest) ports.BrokerLogicalConnection); ok {
2190+ r0 = returnFunc(ctx, request)
2191+ } else {
2192+ if ret.Get(0) != nil {
2193+ r0 = ret.Get(0).(ports.BrokerLogicalConnection)
2194+ }
2195+ }
2196+ if returnFunc, ok := ret.Get(1).(func(context.Context, ports.BrokerOpenStreamRequest) error); ok {
2197+ r1 = returnFunc(ctx, request)
2198+ } else {
2199+ r1 = ret.Error(1)
2200+ }
2201+ return r0, r1
2202+}
2203+
2204+// MockBrokerService_OpenStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenStream'
2205+type MockBrokerService_OpenStream_Call struct {
2206+ *mock.Call
2207+}
2208+
2209+// OpenStream is a helper method to define mock.On call
2210+// - ctx context.Context
2211+// - request ports.BrokerOpenStreamRequest
2212+func (_e *MockBrokerService_Expecter) OpenStream(ctx any, request any) *MockBrokerService_OpenStream_Call {
2213+ return &MockBrokerService_OpenStream_Call{Call: _e.mock.On("OpenStream", ctx, request)}
2214+}
2215+
2216+func (_c *MockBrokerService_OpenStream_Call) Run(run func(ctx context.Context, request ports.BrokerOpenStreamRequest)) *MockBrokerService_OpenStream_Call {
2217+ _c.Call.Run(func(args mock.Arguments) {
2218+ var arg0 context.Context
2219+ if args[0] != nil {
2220+ arg0 = args[0].(context.Context)
2221+ }
2222+ var arg1 ports.BrokerOpenStreamRequest
2223+ if args[1] != nil {
2224+ arg1 = args[1].(ports.BrokerOpenStreamRequest)
2225+ }
2226+ run(
2227+ arg0,
2228+ arg1,
2229+ )
2230+ })
2231+ return _c
2232+}
2233+
2234+func (_c *MockBrokerService_OpenStream_Call) Return(brokerLogicalConnection ports.BrokerLogicalConnection, err error) *MockBrokerService_OpenStream_Call {
2235+ _c.Call.Return(brokerLogicalConnection, err)
2236+ return _c
2237+}
2238+
2239+func (_c *MockBrokerService_OpenStream_Call) RunAndReturn(run func(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error)) *MockBrokerService_OpenStream_Call {
2240+ _c.Call.Return(run)
2241+ return _c
2242+}
2243+
2244+// RemoveHost provides a mock function for the type MockBrokerService
2245+func (_mock *MockBrokerService) RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error) {
2246+ ret := _mock.Called(ctx, expected)
2247+
2248+ if len(ret) == 0 {
2249+ panic("no return value specified for RemoveHost")
2250+ }
2251+
2252+ var r0 bool
2253+ var r1 error
2254+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) (bool, error)); ok {
2255+ return returnFunc(ctx, expected)
2256+ }
2257+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) bool); ok {
2258+ r0 = returnFunc(ctx, expected)
2259+ } else {
2260+ r0 = ret.Get(0).(bool)
2261+ }
2262+ if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration) error); ok {
2263+ r1 = returnFunc(ctx, expected)
2264+ } else {
2265+ r1 = ret.Error(1)
2266+ }
2267+ return r0, r1
2268+}
2269+
2270+// MockBrokerService_RemoveHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveHost'
2271+type MockBrokerService_RemoveHost_Call struct {
2272+ *mock.Call
2273+}
2274+
2275+// RemoveHost is a helper method to define mock.On call
2276+// - ctx context.Context
2277+// - expected domain.RemoteRegistration
2278+func (_e *MockBrokerService_Expecter) RemoveHost(ctx any, expected any) *MockBrokerService_RemoveHost_Call {
2279+ return &MockBrokerService_RemoveHost_Call{Call: _e.mock.On("RemoveHost", ctx, expected)}
2280+}
2281+
2282+func (_c *MockBrokerService_RemoveHost_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration)) *MockBrokerService_RemoveHost_Call {
2283+ _c.Call.Run(func(args mock.Arguments) {
2284+ var arg0 context.Context
2285+ if args[0] != nil {
2286+ arg0 = args[0].(context.Context)
2287+ }
2288+ var arg1 domain.RemoteRegistration
2289+ if args[1] != nil {
2290+ arg1 = args[1].(domain.RemoteRegistration)
7072291 }
7082292 run(
7092293 arg0,
@@ -713,34 +2297,34 @@ func (_c *MockBrokerSession_RemoveHost_Call) Run(run func(ctx context.Context, e
7132297 return _c
7142298 }
7152299
716-func (_c *MockBrokerSession_RemoveHost_Call) Return(b bool, err error) *MockBrokerSession_RemoveHost_Call {
2300+func (_c *MockBrokerService_RemoveHost_Call) Return(b bool, err error) *MockBrokerService_RemoveHost_Call {
7172301 _c.Call.Return(b, err)
7182302 return _c
7192303 }
7202304
721-func (_c *MockBrokerSession_RemoveHost_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration) (bool, error)) *MockBrokerSession_RemoveHost_Call {
2305+func (_c *MockBrokerService_RemoveHost_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration) (bool, error)) *MockBrokerService_RemoveHost_Call {
7222306 _c.Call.Return(run)
7232307 return _c
7242308 }
7252309
726-// RequestReconcile provides a mock function for the type MockBrokerSession
727-func (_mock *MockBrokerSession) RequestReconcile(endpoint string) {
2310+// RequestReconcile provides a mock function for the type MockBrokerService
2311+func (_mock *MockBrokerService) RequestReconcile(endpoint string) {
7282312 _mock.Called(endpoint)
7292313 return
7302314 }
7312315
732-// MockBrokerSession_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
733-type MockBrokerSession_RequestReconcile_Call struct {
2316+// MockBrokerService_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
2317+type MockBrokerService_RequestReconcile_Call struct {
7342318 *mock.Call
7352319 }
7362320
7372321 // RequestReconcile is a helper method to define mock.On call
7382322 // - endpoint string
739-func (_e *MockBrokerSession_Expecter) RequestReconcile(endpoint any) *MockBrokerSession_RequestReconcile_Call {
740- return &MockBrokerSession_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
2323+func (_e *MockBrokerService_Expecter) RequestReconcile(endpoint any) *MockBrokerService_RequestReconcile_Call {
2324+ return &MockBrokerService_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
7412325 }
7422326
743-func (_c *MockBrokerSession_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerSession_RequestReconcile_Call {
2327+func (_c *MockBrokerService_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerService_RequestReconcile_Call {
7442328 _c.Call.Run(func(args mock.Arguments) {
7452329 var arg0 string
7462330 if args[0] != nil {
@@ -753,18 +2337,18 @@ func (_c *MockBrokerSession_RequestReconcile_Call) Run(run func(endpoint string)
7532337 return _c
7542338 }
7552339
756-func (_c *MockBrokerSession_RequestReconcile_Call) Return() *MockBrokerSession_RequestReconcile_Call {
2340+func (_c *MockBrokerService_RequestReconcile_Call) Return() *MockBrokerService_RequestReconcile_Call {
7572341 _c.Call.Return()
7582342 return _c
7592343 }
7602344
761-func (_c *MockBrokerSession_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerSession_RequestReconcile_Call {
2345+func (_c *MockBrokerService_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerService_RequestReconcile_Call {
7622346 _c.Run(run)
7632347 return _c
7642348 }
7652349
766-// Snapshot provides a mock function for the type MockBrokerSession
767-func (_mock *MockBrokerSession) Snapshot() ports.BrokerSnapshot {
2350+// Snapshot provides a mock function for the type MockBrokerService
2351+func (_mock *MockBrokerService) Snapshot() ports.BrokerSnapshot {
7682352 ret := _mock.Called()
7692353
7702354 if len(ret) == 0 {
@@ -780,35 +2364,35 @@ func (_mock *MockBrokerSession) Snapshot() ports.BrokerSnapshot {
7802364 return r0
7812365 }
7822366
783-// MockBrokerSession_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
784-type MockBrokerSession_Snapshot_Call struct {
2367+// MockBrokerService_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
2368+type MockBrokerService_Snapshot_Call struct {
7852369 *mock.Call
7862370 }
7872371
7882372 // Snapshot is a helper method to define mock.On call
789-func (_e *MockBrokerSession_Expecter) Snapshot() *MockBrokerSession_Snapshot_Call {
790- return &MockBrokerSession_Snapshot_Call{Call: _e.mock.On("Snapshot")}
2373+func (_e *MockBrokerService_Expecter) Snapshot() *MockBrokerService_Snapshot_Call {
2374+ return &MockBrokerService_Snapshot_Call{Call: _e.mock.On("Snapshot")}
7912375 }
7922376
793-func (_c *MockBrokerSession_Snapshot_Call) Run(run func()) *MockBrokerSession_Snapshot_Call {
2377+func (_c *MockBrokerService_Snapshot_Call) Run(run func()) *MockBrokerService_Snapshot_Call {
7942378 _c.Call.Run(func(args mock.Arguments) {
7952379 run()
7962380 })
7972381 return _c
7982382 }
7992383
800-func (_c *MockBrokerSession_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerSession_Snapshot_Call {
2384+func (_c *MockBrokerService_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerService_Snapshot_Call {
8012385 _c.Call.Return(brokerSnapshot)
8022386 return _c
8032387 }
8042388
805-func (_c *MockBrokerSession_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerSession_Snapshot_Call {
2389+func (_c *MockBrokerService_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerService_Snapshot_Call {
8062390 _c.Call.Return(run)
8072391 return _c
8082392 }
8092393
810-// Subscribe provides a mock function for the type MockBrokerSession
811-func (_mock *MockBrokerSession) Subscribe() (ports.BrokerSubscription, error) {
2394+// Subscribe provides a mock function for the type MockBrokerService
2395+func (_mock *MockBrokerService) Subscribe() (ports.BrokerSubscription, error) {
8122396 ret := _mock.Called()
8132397
8142398 if len(ret) == 0 {
@@ -835,35 +2419,35 @@ func (_mock *MockBrokerSession) Subscribe() (ports.BrokerSubscription, error) {
8352419 return r0, r1
8362420 }
8372421
838-// MockBrokerSession_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
839-type MockBrokerSession_Subscribe_Call struct {
2422+// MockBrokerService_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
2423+type MockBrokerService_Subscribe_Call struct {
8402424 *mock.Call
8412425 }
8422426
8432427 // Subscribe is a helper method to define mock.On call
844-func (_e *MockBrokerSession_Expecter) Subscribe() *MockBrokerSession_Subscribe_Call {
845- return &MockBrokerSession_Subscribe_Call{Call: _e.mock.On("Subscribe")}
2428+func (_e *MockBrokerService_Expecter) Subscribe() *MockBrokerService_Subscribe_Call {
2429+ return &MockBrokerService_Subscribe_Call{Call: _e.mock.On("Subscribe")}
8462430 }
8472431
848-func (_c *MockBrokerSession_Subscribe_Call) Run(run func()) *MockBrokerSession_Subscribe_Call {
2432+func (_c *MockBrokerService_Subscribe_Call) Run(run func()) *MockBrokerService_Subscribe_Call {
8492433 _c.Call.Run(func(args mock.Arguments) {
8502434 run()
8512435 })
8522436 return _c
8532437 }
8542438
855-func (_c *MockBrokerSession_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerSession_Subscribe_Call {
2439+func (_c *MockBrokerService_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerService_Subscribe_Call {
8562440 _c.Call.Return(brokerSubscription, err)
8572441 return _c
8582442 }
8592443
860-func (_c *MockBrokerSession_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerSession_Subscribe_Call {
2444+func (_c *MockBrokerService_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerService_Subscribe_Call {
8612445 _c.Call.Return(run)
8622446 return _c
8632447 }
8642448
865-// SubscribePreview provides a mock function for the type MockBrokerSession
866-func (_mock *MockBrokerSession) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
2449+// SubscribePreview provides a mock function for the type MockBrokerService
2450+func (_mock *MockBrokerService) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
8672451 ret := _mock.Called(request)
8682452
8692453 if len(ret) == 0 {
@@ -890,18 +2474,18 @@ func (_mock *MockBrokerSession) SubscribePreview(request ports.BrokerPreviewRequ
8902474 return r0, r1
8912475 }
8922476
893-// MockBrokerSession_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
894-type MockBrokerSession_SubscribePreview_Call struct {
2477+// MockBrokerService_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
2478+type MockBrokerService_SubscribePreview_Call struct {
8952479 *mock.Call
8962480 }
8972481
8982482 // SubscribePreview is a helper method to define mock.On call
8992483 // - request ports.BrokerPreviewRequest
900-func (_e *MockBrokerSession_Expecter) SubscribePreview(request any) *MockBrokerSession_SubscribePreview_Call {
901- return &MockBrokerSession_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
2484+func (_e *MockBrokerService_Expecter) SubscribePreview(request any) *MockBrokerService_SubscribePreview_Call {
2485+ return &MockBrokerService_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
9022486 }
9032487
904-func (_c *MockBrokerSession_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerSession_SubscribePreview_Call {
2488+func (_c *MockBrokerService_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerService_SubscribePreview_Call {
9052489 _c.Call.Run(func(args mock.Arguments) {
9062490 var arg0 ports.BrokerPreviewRequest
9072491 if args[0] != nil {
@@ -914,18 +2498,18 @@ func (_c *MockBrokerSession_SubscribePreview_Call) Run(run func(request ports.Br
9142498 return _c
9152499 }
9162500
917-func (_c *MockBrokerSession_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerSession_SubscribePreview_Call {
2501+func (_c *MockBrokerService_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerService_SubscribePreview_Call {
9182502 _c.Call.Return(brokerPreviewSubscription, err)
9192503 return _c
9202504 }
9212505
922-func (_c *MockBrokerSession_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerSession_SubscribePreview_Call {
2506+func (_c *MockBrokerService_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerService_SubscribePreview_Call {
9232507 _c.Call.Return(run)
9242508 return _c
9252509 }
9262510
927-// UpdateHostPolicy provides a mock function for the type MockBrokerSession
928-func (_mock *MockBrokerSession) UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
2511+// UpdateHostPolicy provides a mock function for the type MockBrokerService
2512+func (_mock *MockBrokerService) UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
9292513 ret := _mock.Called(ctx, expected, policy)
9302514
9312515 if len(ret) == 0 {
@@ -950,8 +2534,8 @@ func (_mock *MockBrokerSession) UpdateHostPolicy(ctx context.Context, expected d
9502534 return r0, r1
9512535 }
9522536
953-// MockBrokerSession_UpdateHostPolicy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHostPolicy'
954-type MockBrokerSession_UpdateHostPolicy_Call struct {
2537+// MockBrokerService_UpdateHostPolicy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHostPolicy'
2538+type MockBrokerService_UpdateHostPolicy_Call struct {
9552539 *mock.Call
9562540 }
9572541
@@ -959,11 +2543,11 @@ type MockBrokerSession_UpdateHostPolicy_Call struct {
9592543 // - ctx context.Context
9602544 // - expected domain.RemoteRegistration
9612545 // - policy ports.BrokerPolicy
962-func (_e *MockBrokerSession_Expecter) UpdateHostPolicy(ctx any, expected any, policy any) *MockBrokerSession_UpdateHostPolicy_Call {
963- return &MockBrokerSession_UpdateHostPolicy_Call{Call: _e.mock.On("UpdateHostPolicy", ctx, expected, policy)}
2546+func (_e *MockBrokerService_Expecter) UpdateHostPolicy(ctx any, expected any, policy any) *MockBrokerService_UpdateHostPolicy_Call {
2547+ return &MockBrokerService_UpdateHostPolicy_Call{Call: _e.mock.On("UpdateHostPolicy", ctx, expected, policy)}
9642548 }
9652549
966-func (_c *MockBrokerSession_UpdateHostPolicy_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy)) *MockBrokerSession_UpdateHostPolicy_Call {
2550+func (_c *MockBrokerService_UpdateHostPolicy_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy)) *MockBrokerService_UpdateHostPolicy_Call {
9672551 _c.Call.Run(func(args mock.Arguments) {
9682552 var arg0 context.Context
9692553 if args[0] != nil {
@@ -986,117 +2570,54 @@ func (_c *MockBrokerSession_UpdateHostPolicy_Call) Run(run func(ctx context.Cont
9862570 return _c
9872571 }
9882572
989-func (_c *MockBrokerSession_UpdateHostPolicy_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerSession_UpdateHostPolicy_Call {
2573+func (_c *MockBrokerService_UpdateHostPolicy_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerService_UpdateHostPolicy_Call {
9902574 _c.Call.Return(remoteRegistration, err)
9912575 return _c
9922576 }
9932577
994-func (_c *MockBrokerSession_UpdateHostPolicy_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerSession_UpdateHostPolicy_Call {
2578+func (_c *MockBrokerService_UpdateHostPolicy_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerService_UpdateHostPolicy_Call {
9952579 _c.Call.Return(run)
9962580 return _c
9972581 }
9982582
999-// NewMockBrokerService creates a new instance of MockBrokerService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
2583+// NewMockBrokerNavigator creates a new instance of MockBrokerNavigator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
10002584 // The first argument is typically a *testing.T value.
1001-func NewMockBrokerService(t interface {
2585+func NewMockBrokerNavigator(t interface {
10022586 mock.TestingT
10032587 Cleanup(func())
1004-}) *MockBrokerService {
1005- mock := &MockBrokerService{}
2588+}) *MockBrokerNavigator {
2589+ if helper, ok := t.(interface{ Helper() }); ok {
2590+ helper.Helper()
2591+ }
2592+
2593+ mock := &MockBrokerNavigator{}
10062594 mock.Mock.Test(t)
10072595
1008- t.Cleanup(func() { mock.AssertExpectations(t) })
2596+ t.Cleanup(func() {
2597+ if helper, ok := t.(interface{ Helper() }); ok {
2598+ helper.Helper()
2599+ }
2600+ mock.AssertExpectations(t)
2601+ })
10092602
10102603 return mock
10112604 }
10122605
1013-// MockBrokerService is an autogenerated mock type for the BrokerService type
1014-type MockBrokerService struct {
2606+// MockBrokerNavigator is an autogenerated mock type for the BrokerNavigator type
2607+type MockBrokerNavigator struct {
10152608 mock.Mock
10162609 }
10172610
1018-type MockBrokerService_Expecter struct {
2611+type MockBrokerNavigator_Expecter struct {
10192612 mock *mock.Mock
10202613 }
10212614
1022-func (_m *MockBrokerService) EXPECT() *MockBrokerService_Expecter {
1023- return &MockBrokerService_Expecter{mock: &_m.Mock}
1024-}
1025-
1026-// AddHost provides a mock function for the type MockBrokerService
1027-func (_mock *MockBrokerService) AddHost(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
1028- ret := _mock.Called(ctx, endpoint, policy)
1029-
1030- if len(ret) == 0 {
1031- panic("no return value specified for AddHost")
1032- }
1033-
1034- var r0 domain.RemoteRegistration
1035- var r1 error
1036- if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
1037- return returnFunc(ctx, endpoint, policy)
1038- }
1039- if returnFunc, ok := ret.Get(0).(func(context.Context, string, ports.BrokerPolicy) domain.RemoteRegistration); ok {
1040- r0 = returnFunc(ctx, endpoint, policy)
1041- } else {
1042- r0 = ret.Get(0).(domain.RemoteRegistration)
1043- }
1044- if returnFunc, ok := ret.Get(1).(func(context.Context, string, ports.BrokerPolicy) error); ok {
1045- r1 = returnFunc(ctx, endpoint, policy)
1046- } else {
1047- r1 = ret.Error(1)
1048- }
1049- return r0, r1
1050-}
1051-
1052-// MockBrokerService_AddHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHost'
1053-type MockBrokerService_AddHost_Call struct {
1054- *mock.Call
1055-}
1056-
1057-// AddHost is a helper method to define mock.On call
1058-// - ctx context.Context
1059-// - endpoint string
1060-// - policy ports.BrokerPolicy
1061-func (_e *MockBrokerService_Expecter) AddHost(ctx any, endpoint any, policy any) *MockBrokerService_AddHost_Call {
1062- return &MockBrokerService_AddHost_Call{Call: _e.mock.On("AddHost", ctx, endpoint, policy)}
1063-}
1064-
1065-func (_c *MockBrokerService_AddHost_Call) Run(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy)) *MockBrokerService_AddHost_Call {
1066- _c.Call.Run(func(args mock.Arguments) {
1067- var arg0 context.Context
1068- if args[0] != nil {
1069- arg0 = args[0].(context.Context)
1070- }
1071- var arg1 string
1072- if args[1] != nil {
1073- arg1 = args[1].(string)
1074- }
1075- var arg2 ports.BrokerPolicy
1076- if args[2] != nil {
1077- arg2 = args[2].(ports.BrokerPolicy)
1078- }
1079- run(
1080- arg0,
1081- arg1,
1082- arg2,
1083- )
1084- })
1085- return _c
1086-}
1087-
1088-func (_c *MockBrokerService_AddHost_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerService_AddHost_Call {
1089- _c.Call.Return(remoteRegistration, err)
1090- return _c
1091-}
1092-
1093-func (_c *MockBrokerService_AddHost_Call) RunAndReturn(run func(ctx context.Context, endpoint string, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerService_AddHost_Call {
1094- _c.Call.Return(run)
1095- return _c
2615+func (_m *MockBrokerNavigator) EXPECT() *MockBrokerNavigator_Expecter {
2616+ return &MockBrokerNavigator_Expecter{mock: &_m.Mock}
10962617 }
10972618
1098-// Close provides a mock function for the type MockBrokerService
1099-func (_mock *MockBrokerService) Close() error {
2619+// Close provides a mock function for the type MockBrokerNavigator
2620+func (_mock *MockBrokerNavigator) Close() error {
11002621 ret := _mock.Called()
11012622
11022623 if len(ret) == 0 {
@@ -1112,92 +2633,35 @@ func (_mock *MockBrokerService) Close() error {
11122633 return r0
11132634 }
11142635
1115-// MockBrokerService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
1116-type MockBrokerService_Close_Call struct {
2636+// MockBrokerNavigator_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
2637+type MockBrokerNavigator_Close_Call struct {
11172638 *mock.Call
11182639 }
11192640
11202641 // Close is a helper method to define mock.On call
1121-func (_e *MockBrokerService_Expecter) Close() *MockBrokerService_Close_Call {
1122- return &MockBrokerService_Close_Call{Call: _e.mock.On("Close")}
2642+func (_e *MockBrokerNavigator_Expecter) Close() *MockBrokerNavigator_Close_Call {
2643+ return &MockBrokerNavigator_Close_Call{Call: _e.mock.On("Close")}
11232644 }
11242645
1125-func (_c *MockBrokerService_Close_Call) Run(run func()) *MockBrokerService_Close_Call {
2646+func (_c *MockBrokerNavigator_Close_Call) Run(run func()) *MockBrokerNavigator_Close_Call {
11262647 _c.Call.Run(func(args mock.Arguments) {
11272648 run()
11282649 })
11292650 return _c
11302651 }
11312652
1132-func (_c *MockBrokerService_Close_Call) Return(err error) *MockBrokerService_Close_Call {
1133- _c.Call.Return(err)
1134- return _c
1135-}
1136-
1137-func (_c *MockBrokerService_Close_Call) RunAndReturn(run func() error) *MockBrokerService_Close_Call {
1138- _c.Call.Return(run)
1139- return _c
1140-}
1141-
1142-// CloseStream provides a mock function for the type MockBrokerService
1143-func (_mock *MockBrokerService) CloseStream(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error {
1144- ret := _mock.Called(connection, stream)
1145-
1146- if len(ret) == 0 {
1147- panic("no return value specified for CloseStream")
1148- }
1149-
1150- var r0 error
1151- if returnFunc, ok := ret.Get(0).(func(ports.BrokerConnectionID, ports.BrokerStreamID) error); ok {
1152- r0 = returnFunc(connection, stream)
1153- } else {
1154- r0 = ret.Error(0)
1155- }
1156- return r0
1157-}
1158-
1159-// MockBrokerService_CloseStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseStream'
1160-type MockBrokerService_CloseStream_Call struct {
1161- *mock.Call
1162-}
1163-
1164-// CloseStream is a helper method to define mock.On call
1165-// - connection ports.BrokerConnectionID
1166-// - stream ports.BrokerStreamID
1167-func (_e *MockBrokerService_Expecter) CloseStream(connection any, stream any) *MockBrokerService_CloseStream_Call {
1168- return &MockBrokerService_CloseStream_Call{Call: _e.mock.On("CloseStream", connection, stream)}
1169-}
1170-
1171-func (_c *MockBrokerService_CloseStream_Call) Run(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID)) *MockBrokerService_CloseStream_Call {
1172- _c.Call.Run(func(args mock.Arguments) {
1173- var arg0 ports.BrokerConnectionID
1174- if args[0] != nil {
1175- arg0 = args[0].(ports.BrokerConnectionID)
1176- }
1177- var arg1 ports.BrokerStreamID
1178- if args[1] != nil {
1179- arg1 = args[1].(ports.BrokerStreamID)
1180- }
1181- run(
1182- arg0,
1183- arg1,
1184- )
1185- })
1186- return _c
1187-}
1188-
1189-func (_c *MockBrokerService_CloseStream_Call) Return(err error) *MockBrokerService_CloseStream_Call {
2653+func (_c *MockBrokerNavigator_Close_Call) Return(err error) *MockBrokerNavigator_Close_Call {
11902654 _c.Call.Return(err)
11912655 return _c
11922656 }
11932657
1194-func (_c *MockBrokerService_CloseStream_Call) RunAndReturn(run func(connection ports.BrokerConnectionID, stream ports.BrokerStreamID) error) *MockBrokerService_CloseStream_Call {
2658+func (_c *MockBrokerNavigator_Close_Call) RunAndReturn(run func() error) *MockBrokerNavigator_Close_Call {
11952659 _c.Call.Return(run)
11962660 return _c
11972661 }
11982662
1199-// ConnectionID provides a mock function for the type MockBrokerService
1200-func (_mock *MockBrokerService) ConnectionID() ports.BrokerConnectionID {
2663+// ConnectionID provides a mock function for the type MockBrokerNavigator
2664+func (_mock *MockBrokerNavigator) ConnectionID() ports.BrokerConnectionID {
12012665 ret := _mock.Called()
12022666
12032667 if len(ret) == 0 {
@@ -1214,36 +2678,36 @@ func (_mock *MockBrokerService) ConnectionID() ports.BrokerConnectionID {
12142678 }
12152679 return r0
12162680 }
1217-
1218-// MockBrokerService_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
1219-type MockBrokerService_ConnectionID_Call struct {
2681+
2682+// MockBrokerNavigator_ConnectionID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectionID'
2683+type MockBrokerNavigator_ConnectionID_Call struct {
12202684 *mock.Call
12212685 }
12222686
12232687 // ConnectionID is a helper method to define mock.On call
1224-func (_e *MockBrokerService_Expecter) ConnectionID() *MockBrokerService_ConnectionID_Call {
1225- return &MockBrokerService_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
2688+func (_e *MockBrokerNavigator_Expecter) ConnectionID() *MockBrokerNavigator_ConnectionID_Call {
2689+ return &MockBrokerNavigator_ConnectionID_Call{Call: _e.mock.On("ConnectionID")}
12262690 }
12272691
1228-func (_c *MockBrokerService_ConnectionID_Call) Run(run func()) *MockBrokerService_ConnectionID_Call {
2692+func (_c *MockBrokerNavigator_ConnectionID_Call) Run(run func()) *MockBrokerNavigator_ConnectionID_Call {
12292693 _c.Call.Run(func(args mock.Arguments) {
12302694 run()
12312695 })
12322696 return _c
12332697 }
12342698
1235-func (_c *MockBrokerService_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerService_ConnectionID_Call {
2699+func (_c *MockBrokerNavigator_ConnectionID_Call) Return(brokerConnectionID ports.BrokerConnectionID) *MockBrokerNavigator_ConnectionID_Call {
12362700 _c.Call.Return(brokerConnectionID)
12372701 return _c
12382702 }
12392703
1240-func (_c *MockBrokerService_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerService_ConnectionID_Call {
2704+func (_c *MockBrokerNavigator_ConnectionID_Call) RunAndReturn(run func() ports.BrokerConnectionID) *MockBrokerNavigator_ConnectionID_Call {
12412705 _c.Call.Return(run)
12422706 return _c
12432707 }
12442708
1245-// Done provides a mock function for the type MockBrokerService
1246-func (_mock *MockBrokerService) Done() <-chan struct{} {
2709+// Done provides a mock function for the type MockBrokerNavigator
2710+func (_mock *MockBrokerNavigator) Done() <-chan struct{} {
12472711 ret := _mock.Called()
12482712
12492713 if len(ret) == 0 {
@@ -1261,35 +2725,35 @@ func (_mock *MockBrokerService) Done() <-chan struct{} {
12612725 return r0
12622726 }
12632727
1264-// MockBrokerService_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
1265-type MockBrokerService_Done_Call struct {
2728+// MockBrokerNavigator_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
2729+type MockBrokerNavigator_Done_Call struct {
12662730 *mock.Call
12672731 }
12682732
12692733 // Done is a helper method to define mock.On call
1270-func (_e *MockBrokerService_Expecter) Done() *MockBrokerService_Done_Call {
1271- return &MockBrokerService_Done_Call{Call: _e.mock.On("Done")}
2734+func (_e *MockBrokerNavigator_Expecter) Done() *MockBrokerNavigator_Done_Call {
2735+ return &MockBrokerNavigator_Done_Call{Call: _e.mock.On("Done")}
12722736 }
12732737
1274-func (_c *MockBrokerService_Done_Call) Run(run func()) *MockBrokerService_Done_Call {
2738+func (_c *MockBrokerNavigator_Done_Call) Run(run func()) *MockBrokerNavigator_Done_Call {
12752739 _c.Call.Run(func(args mock.Arguments) {
12762740 run()
12772741 })
12782742 return _c
12792743 }
12802744
1281-func (_c *MockBrokerService_Done_Call) Return(valCh <-chan struct{}) *MockBrokerService_Done_Call {
2745+func (_c *MockBrokerNavigator_Done_Call) Return(valCh <-chan struct{}) *MockBrokerNavigator_Done_Call {
12822746 _c.Call.Return(valCh)
12832747 return _c
12842748 }
12852749
1286-func (_c *MockBrokerService_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerService_Done_Call {
2750+func (_c *MockBrokerNavigator_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockBrokerNavigator_Done_Call {
12872751 _c.Call.Return(run)
12882752 return _c
12892753 }
12902754
1291-// Err provides a mock function for the type MockBrokerService
1292-func (_mock *MockBrokerService) Err() error {
2755+// Err provides a mock function for the type MockBrokerNavigator
2756+func (_mock *MockBrokerNavigator) Err() error {
12932757 ret := _mock.Called()
12942758
12952759 if len(ret) == 0 {
@@ -1305,35 +2769,35 @@ func (_mock *MockBrokerService) Err() error {
13052769 return r0
13062770 }
13072771
1308-// MockBrokerService_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
1309-type MockBrokerService_Err_Call struct {
2772+// MockBrokerNavigator_Err_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Err'
2773+type MockBrokerNavigator_Err_Call struct {
13102774 *mock.Call
13112775 }
13122776
13132777 // Err is a helper method to define mock.On call
1314-func (_e *MockBrokerService_Expecter) Err() *MockBrokerService_Err_Call {
1315- return &MockBrokerService_Err_Call{Call: _e.mock.On("Err")}
2778+func (_e *MockBrokerNavigator_Expecter) Err() *MockBrokerNavigator_Err_Call {
2779+ return &MockBrokerNavigator_Err_Call{Call: _e.mock.On("Err")}
13162780 }
13172781
1318-func (_c *MockBrokerService_Err_Call) Run(run func()) *MockBrokerService_Err_Call {
2782+func (_c *MockBrokerNavigator_Err_Call) Run(run func()) *MockBrokerNavigator_Err_Call {
13192783 _c.Call.Run(func(args mock.Arguments) {
13202784 run()
13212785 })
13222786 return _c
13232787 }
13242788
1325-func (_c *MockBrokerService_Err_Call) Return(err error) *MockBrokerService_Err_Call {
2789+func (_c *MockBrokerNavigator_Err_Call) Return(err error) *MockBrokerNavigator_Err_Call {
13262790 _c.Call.Return(err)
13272791 return _c
13282792 }
13292793
1330-func (_c *MockBrokerService_Err_Call) RunAndReturn(run func() error) *MockBrokerService_Err_Call {
2794+func (_c *MockBrokerNavigator_Err_Call) RunAndReturn(run func() error) *MockBrokerNavigator_Err_Call {
13312795 _c.Call.Return(run)
13322796 return _c
13332797 }
13342798
1335-// NextStreamID provides a mock function for the type MockBrokerService
1336-func (_mock *MockBrokerService) NextStreamID() (ports.BrokerStreamID, error) {
2799+// NextStreamID provides a mock function for the type MockBrokerNavigator
2800+func (_mock *MockBrokerNavigator) NextStreamID() (ports.BrokerStreamID, error) {
13372801 ret := _mock.Called()
13382802
13392803 if len(ret) == 0 {
@@ -1358,35 +2822,35 @@ func (_mock *MockBrokerService) NextStreamID() (ports.BrokerStreamID, error) {
13582822 return r0, r1
13592823 }
13602824
1361-// MockBrokerService_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
1362-type MockBrokerService_NextStreamID_Call struct {
2825+// MockBrokerNavigator_NextStreamID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextStreamID'
2826+type MockBrokerNavigator_NextStreamID_Call struct {
13632827 *mock.Call
13642828 }
13652829
13662830 // NextStreamID is a helper method to define mock.On call
1367-func (_e *MockBrokerService_Expecter) NextStreamID() *MockBrokerService_NextStreamID_Call {
1368- return &MockBrokerService_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
2831+func (_e *MockBrokerNavigator_Expecter) NextStreamID() *MockBrokerNavigator_NextStreamID_Call {
2832+ return &MockBrokerNavigator_NextStreamID_Call{Call: _e.mock.On("NextStreamID")}
13692833 }
13702834
1371-func (_c *MockBrokerService_NextStreamID_Call) Run(run func()) *MockBrokerService_NextStreamID_Call {
2835+func (_c *MockBrokerNavigator_NextStreamID_Call) Run(run func()) *MockBrokerNavigator_NextStreamID_Call {
13722836 _c.Call.Run(func(args mock.Arguments) {
13732837 run()
13742838 })
13752839 return _c
13762840 }
13772841
1378-func (_c *MockBrokerService_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerService_NextStreamID_Call {
2842+func (_c *MockBrokerNavigator_NextStreamID_Call) Return(brokerStreamID ports.BrokerStreamID, err error) *MockBrokerNavigator_NextStreamID_Call {
13792843 _c.Call.Return(brokerStreamID, err)
13802844 return _c
13812845 }
13822846
1383-func (_c *MockBrokerService_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerService_NextStreamID_Call {
2847+func (_c *MockBrokerNavigator_NextStreamID_Call) RunAndReturn(run func() (ports.BrokerStreamID, error)) *MockBrokerNavigator_NextStreamID_Call {
13842848 _c.Call.Return(run)
13852849 return _c
13862850 }
13872851
1388-// OpenStream provides a mock function for the type MockBrokerService
1389-func (_mock *MockBrokerService) OpenStream(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
2852+// OpenStream provides a mock function for the type MockBrokerNavigator
2853+func (_mock *MockBrokerNavigator) OpenStream(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
13902854 ret := _mock.Called(ctx, request)
13912855
13922856 if len(ret) == 0 {
@@ -1413,19 +2877,19 @@ func (_mock *MockBrokerService) OpenStream(ctx context.Context, request ports.Br
14132877 return r0, r1
14142878 }
14152879
1416-// MockBrokerService_OpenStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenStream'
1417-type MockBrokerService_OpenStream_Call struct {
2880+// MockBrokerNavigator_OpenStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenStream'
2881+type MockBrokerNavigator_OpenStream_Call struct {
14182882 *mock.Call
14192883 }
14202884
14212885 // OpenStream is a helper method to define mock.On call
14222886 // - ctx context.Context
14232887 // - request ports.BrokerOpenStreamRequest
1424-func (_e *MockBrokerService_Expecter) OpenStream(ctx any, request any) *MockBrokerService_OpenStream_Call {
1425- return &MockBrokerService_OpenStream_Call{Call: _e.mock.On("OpenStream", ctx, request)}
2888+func (_e *MockBrokerNavigator_Expecter) OpenStream(ctx any, request any) *MockBrokerNavigator_OpenStream_Call {
2889+ return &MockBrokerNavigator_OpenStream_Call{Call: _e.mock.On("OpenStream", ctx, request)}
14262890 }
14272891
1428-func (_c *MockBrokerService_OpenStream_Call) Run(run func(ctx context.Context, request ports.BrokerOpenStreamRequest)) *MockBrokerService_OpenStream_Call {
2892+func (_c *MockBrokerNavigator_OpenStream_Call) Run(run func(ctx context.Context, request ports.BrokerOpenStreamRequest)) *MockBrokerNavigator_OpenStream_Call {
14292893 _c.Call.Run(func(args mock.Arguments) {
14302894 var arg0 context.Context
14312895 if args[0] != nil {
@@ -1443,100 +2907,34 @@ func (_c *MockBrokerService_OpenStream_Call) Run(run func(ctx context.Context, r
14432907 return _c
14442908 }
14452909
1446-func (_c *MockBrokerService_OpenStream_Call) Return(brokerLogicalConnection ports.BrokerLogicalConnection, err error) *MockBrokerService_OpenStream_Call {
2910+func (_c *MockBrokerNavigator_OpenStream_Call) Return(brokerLogicalConnection ports.BrokerLogicalConnection, err error) *MockBrokerNavigator_OpenStream_Call {
14472911 _c.Call.Return(brokerLogicalConnection, err)
14482912 return _c
14492913 }
14502914
1451-func (_c *MockBrokerService_OpenStream_Call) RunAndReturn(run func(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error)) *MockBrokerService_OpenStream_Call {
1452- _c.Call.Return(run)
1453- return _c
1454-}
1455-
1456-// RemoveHost provides a mock function for the type MockBrokerService
1457-func (_mock *MockBrokerService) RemoveHost(ctx context.Context, expected domain.RemoteRegistration) (bool, error) {
1458- ret := _mock.Called(ctx, expected)
1459-
1460- if len(ret) == 0 {
1461- panic("no return value specified for RemoveHost")
1462- }
1463-
1464- var r0 bool
1465- var r1 error
1466- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) (bool, error)); ok {
1467- return returnFunc(ctx, expected)
1468- }
1469- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration) bool); ok {
1470- r0 = returnFunc(ctx, expected)
1471- } else {
1472- r0 = ret.Get(0).(bool)
1473- }
1474- if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration) error); ok {
1475- r1 = returnFunc(ctx, expected)
1476- } else {
1477- r1 = ret.Error(1)
1478- }
1479- return r0, r1
1480-}
1481-
1482-// MockBrokerService_RemoveHost_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveHost'
1483-type MockBrokerService_RemoveHost_Call struct {
1484- *mock.Call
1485-}
1486-
1487-// RemoveHost is a helper method to define mock.On call
1488-// - ctx context.Context
1489-// - expected domain.RemoteRegistration
1490-func (_e *MockBrokerService_Expecter) RemoveHost(ctx any, expected any) *MockBrokerService_RemoveHost_Call {
1491- return &MockBrokerService_RemoveHost_Call{Call: _e.mock.On("RemoveHost", ctx, expected)}
1492-}
1493-
1494-func (_c *MockBrokerService_RemoveHost_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration)) *MockBrokerService_RemoveHost_Call {
1495- _c.Call.Run(func(args mock.Arguments) {
1496- var arg0 context.Context
1497- if args[0] != nil {
1498- arg0 = args[0].(context.Context)
1499- }
1500- var arg1 domain.RemoteRegistration
1501- if args[1] != nil {
1502- arg1 = args[1].(domain.RemoteRegistration)
1503- }
1504- run(
1505- arg0,
1506- arg1,
1507- )
1508- })
1509- return _c
1510-}
1511-
1512-func (_c *MockBrokerService_RemoveHost_Call) Return(b bool, err error) *MockBrokerService_RemoveHost_Call {
1513- _c.Call.Return(b, err)
1514- return _c
1515-}
1516-
1517-func (_c *MockBrokerService_RemoveHost_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration) (bool, error)) *MockBrokerService_RemoveHost_Call {
2915+func (_c *MockBrokerNavigator_OpenStream_Call) RunAndReturn(run func(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error)) *MockBrokerNavigator_OpenStream_Call {
15182916 _c.Call.Return(run)
15192917 return _c
15202918 }
15212919
1522-// RequestReconcile provides a mock function for the type MockBrokerService
1523-func (_mock *MockBrokerService) RequestReconcile(endpoint string) {
2920+// RequestReconcile provides a mock function for the type MockBrokerNavigator
2921+func (_mock *MockBrokerNavigator) RequestReconcile(endpoint string) {
15242922 _mock.Called(endpoint)
15252923 return
15262924 }
15272925
1528-// MockBrokerService_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
1529-type MockBrokerService_RequestReconcile_Call struct {
2926+// MockBrokerNavigator_RequestReconcile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestReconcile'
2927+type MockBrokerNavigator_RequestReconcile_Call struct {
15302928 *mock.Call
15312929 }
15322930
15332931 // RequestReconcile is a helper method to define mock.On call
15342932 // - endpoint string
1535-func (_e *MockBrokerService_Expecter) RequestReconcile(endpoint any) *MockBrokerService_RequestReconcile_Call {
1536- return &MockBrokerService_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
2933+func (_e *MockBrokerNavigator_Expecter) RequestReconcile(endpoint any) *MockBrokerNavigator_RequestReconcile_Call {
2934+ return &MockBrokerNavigator_RequestReconcile_Call{Call: _e.mock.On("RequestReconcile", endpoint)}
15372935 }
15382936
1539-func (_c *MockBrokerService_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerService_RequestReconcile_Call {
2937+func (_c *MockBrokerNavigator_RequestReconcile_Call) Run(run func(endpoint string)) *MockBrokerNavigator_RequestReconcile_Call {
15402938 _c.Call.Run(func(args mock.Arguments) {
15412939 var arg0 string
15422940 if args[0] != nil {
@@ -1549,18 +2947,18 @@ func (_c *MockBrokerService_RequestReconcile_Call) Run(run func(endpoint string)
15492947 return _c
15502948 }
15512949
1552-func (_c *MockBrokerService_RequestReconcile_Call) Return() *MockBrokerService_RequestReconcile_Call {
2950+func (_c *MockBrokerNavigator_RequestReconcile_Call) Return() *MockBrokerNavigator_RequestReconcile_Call {
15532951 _c.Call.Return()
15542952 return _c
15552953 }
15562954
1557-func (_c *MockBrokerService_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerService_RequestReconcile_Call {
2955+func (_c *MockBrokerNavigator_RequestReconcile_Call) RunAndReturn(run func(endpoint string)) *MockBrokerNavigator_RequestReconcile_Call {
15582956 _c.Run(run)
15592957 return _c
15602958 }
15612959
1562-// Snapshot provides a mock function for the type MockBrokerService
1563-func (_mock *MockBrokerService) Snapshot() ports.BrokerSnapshot {
2960+// Snapshot provides a mock function for the type MockBrokerNavigator
2961+func (_mock *MockBrokerNavigator) Snapshot() ports.BrokerSnapshot {
15642962 ret := _mock.Called()
15652963
15662964 if len(ret) == 0 {
@@ -1576,35 +2974,35 @@ func (_mock *MockBrokerService) Snapshot() ports.BrokerSnapshot {
15762974 return r0
15772975 }
15782976
1579-// MockBrokerService_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
1580-type MockBrokerService_Snapshot_Call struct {
2977+// MockBrokerNavigator_Snapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Snapshot'
2978+type MockBrokerNavigator_Snapshot_Call struct {
15812979 *mock.Call
15822980 }
15832981
15842982 // Snapshot is a helper method to define mock.On call
1585-func (_e *MockBrokerService_Expecter) Snapshot() *MockBrokerService_Snapshot_Call {
1586- return &MockBrokerService_Snapshot_Call{Call: _e.mock.On("Snapshot")}
2983+func (_e *MockBrokerNavigator_Expecter) Snapshot() *MockBrokerNavigator_Snapshot_Call {
2984+ return &MockBrokerNavigator_Snapshot_Call{Call: _e.mock.On("Snapshot")}
15872985 }
15882986
1589-func (_c *MockBrokerService_Snapshot_Call) Run(run func()) *MockBrokerService_Snapshot_Call {
2987+func (_c *MockBrokerNavigator_Snapshot_Call) Run(run func()) *MockBrokerNavigator_Snapshot_Call {
15902988 _c.Call.Run(func(args mock.Arguments) {
15912989 run()
15922990 })
15932991 return _c
15942992 }
15952993
1596-func (_c *MockBrokerService_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerService_Snapshot_Call {
2994+func (_c *MockBrokerNavigator_Snapshot_Call) Return(brokerSnapshot ports.BrokerSnapshot) *MockBrokerNavigator_Snapshot_Call {
15972995 _c.Call.Return(brokerSnapshot)
15982996 return _c
15992997 }
16002998
1601-func (_c *MockBrokerService_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerService_Snapshot_Call {
2999+func (_c *MockBrokerNavigator_Snapshot_Call) RunAndReturn(run func() ports.BrokerSnapshot) *MockBrokerNavigator_Snapshot_Call {
16023000 _c.Call.Return(run)
16033001 return _c
16043002 }
16053003
1606-// Subscribe provides a mock function for the type MockBrokerService
1607-func (_mock *MockBrokerService) Subscribe() (ports.BrokerSubscription, error) {
3004+// Subscribe provides a mock function for the type MockBrokerNavigator
3005+func (_mock *MockBrokerNavigator) Subscribe() (ports.BrokerSubscription, error) {
16083006 ret := _mock.Called()
16093007
16103008 if len(ret) == 0 {
@@ -1631,35 +3029,35 @@ func (_mock *MockBrokerService) Subscribe() (ports.BrokerSubscription, error) {
16313029 return r0, r1
16323030 }
16333031
1634-// MockBrokerService_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
1635-type MockBrokerService_Subscribe_Call struct {
3032+// MockBrokerNavigator_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
3033+type MockBrokerNavigator_Subscribe_Call struct {
16363034 *mock.Call
16373035 }
16383036
16393037 // Subscribe is a helper method to define mock.On call
1640-func (_e *MockBrokerService_Expecter) Subscribe() *MockBrokerService_Subscribe_Call {
1641- return &MockBrokerService_Subscribe_Call{Call: _e.mock.On("Subscribe")}
3038+func (_e *MockBrokerNavigator_Expecter) Subscribe() *MockBrokerNavigator_Subscribe_Call {
3039+ return &MockBrokerNavigator_Subscribe_Call{Call: _e.mock.On("Subscribe")}
16423040 }
16433041
1644-func (_c *MockBrokerService_Subscribe_Call) Run(run func()) *MockBrokerService_Subscribe_Call {
3042+func (_c *MockBrokerNavigator_Subscribe_Call) Run(run func()) *MockBrokerNavigator_Subscribe_Call {
16453043 _c.Call.Run(func(args mock.Arguments) {
16463044 run()
16473045 })
16483046 return _c
16493047 }
16503048
1651-func (_c *MockBrokerService_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerService_Subscribe_Call {
3049+func (_c *MockBrokerNavigator_Subscribe_Call) Return(brokerSubscription ports.BrokerSubscription, err error) *MockBrokerNavigator_Subscribe_Call {
16523050 _c.Call.Return(brokerSubscription, err)
16533051 return _c
16543052 }
16553053
1656-func (_c *MockBrokerService_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerService_Subscribe_Call {
3054+func (_c *MockBrokerNavigator_Subscribe_Call) RunAndReturn(run func() (ports.BrokerSubscription, error)) *MockBrokerNavigator_Subscribe_Call {
16573055 _c.Call.Return(run)
16583056 return _c
16593057 }
16603058
1661-// SubscribePreview provides a mock function for the type MockBrokerService
1662-func (_mock *MockBrokerService) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
3059+// SubscribePreview provides a mock function for the type MockBrokerNavigator
3060+func (_mock *MockBrokerNavigator) SubscribePreview(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error) {
16633061 ret := _mock.Called(request)
16643062
16653063 if len(ret) == 0 {
@@ -1686,18 +3084,18 @@ func (_mock *MockBrokerService) SubscribePreview(request ports.BrokerPreviewRequ
16863084 return r0, r1
16873085 }
16883086
1689-// MockBrokerService_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
1690-type MockBrokerService_SubscribePreview_Call struct {
3087+// MockBrokerNavigator_SubscribePreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribePreview'
3088+type MockBrokerNavigator_SubscribePreview_Call struct {
16913089 *mock.Call
16923090 }
16933091
16943092 // SubscribePreview is a helper method to define mock.On call
16953093 // - request ports.BrokerPreviewRequest
1696-func (_e *MockBrokerService_Expecter) SubscribePreview(request any) *MockBrokerService_SubscribePreview_Call {
1697- return &MockBrokerService_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
3094+func (_e *MockBrokerNavigator_Expecter) SubscribePreview(request any) *MockBrokerNavigator_SubscribePreview_Call {
3095+ return &MockBrokerNavigator_SubscribePreview_Call{Call: _e.mock.On("SubscribePreview", request)}
16983096 }
16993097
1700-func (_c *MockBrokerService_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerService_SubscribePreview_Call {
3098+func (_c *MockBrokerNavigator_SubscribePreview_Call) Run(run func(request ports.BrokerPreviewRequest)) *MockBrokerNavigator_SubscribePreview_Call {
17013099 _c.Call.Run(func(args mock.Arguments) {
17023100 var arg0 ports.BrokerPreviewRequest
17033101 if args[0] != nil {
@@ -1710,84 +3108,12 @@ func (_c *MockBrokerService_SubscribePreview_Call) Run(run func(request ports.Br
17103108 return _c
17113109 }
17123110
1713-func (_c *MockBrokerService_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerService_SubscribePreview_Call {
3111+func (_c *MockBrokerNavigator_SubscribePreview_Call) Return(brokerPreviewSubscription ports.BrokerPreviewSubscription, err error) *MockBrokerNavigator_SubscribePreview_Call {
17143112 _c.Call.Return(brokerPreviewSubscription, err)
17153113 return _c
17163114 }
17173115
1718-func (_c *MockBrokerService_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerService_SubscribePreview_Call {
1719- _c.Call.Return(run)
1720- return _c
1721-}
1722-
1723-// UpdateHostPolicy provides a mock function for the type MockBrokerService
1724-func (_mock *MockBrokerService) UpdateHostPolicy(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error) {
1725- ret := _mock.Called(ctx, expected, policy)
1726-
1727- if len(ret) == 0 {
1728- panic("no return value specified for UpdateHostPolicy")
1729- }
1730-
1731- var r0 domain.RemoteRegistration
1732- var r1 error
1733- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) (domain.RemoteRegistration, error)); ok {
1734- return returnFunc(ctx, expected, policy)
1735- }
1736- if returnFunc, ok := ret.Get(0).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) domain.RemoteRegistration); ok {
1737- r0 = returnFunc(ctx, expected, policy)
1738- } else {
1739- r0 = ret.Get(0).(domain.RemoteRegistration)
1740- }
1741- if returnFunc, ok := ret.Get(1).(func(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) error); ok {
1742- r1 = returnFunc(ctx, expected, policy)
1743- } else {
1744- r1 = ret.Error(1)
1745- }
1746- return r0, r1
1747-}
1748-
1749-// MockBrokerService_UpdateHostPolicy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHostPolicy'
1750-type MockBrokerService_UpdateHostPolicy_Call struct {
1751- *mock.Call
1752-}
1753-
1754-// UpdateHostPolicy is a helper method to define mock.On call
1755-// - ctx context.Context
1756-// - expected domain.RemoteRegistration
1757-// - policy ports.BrokerPolicy
1758-func (_e *MockBrokerService_Expecter) UpdateHostPolicy(ctx any, expected any, policy any) *MockBrokerService_UpdateHostPolicy_Call {
1759- return &MockBrokerService_UpdateHostPolicy_Call{Call: _e.mock.On("UpdateHostPolicy", ctx, expected, policy)}
1760-}
1761-
1762-func (_c *MockBrokerService_UpdateHostPolicy_Call) Run(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy)) *MockBrokerService_UpdateHostPolicy_Call {
1763- _c.Call.Run(func(args mock.Arguments) {
1764- var arg0 context.Context
1765- if args[0] != nil {
1766- arg0 = args[0].(context.Context)
1767- }
1768- var arg1 domain.RemoteRegistration
1769- if args[1] != nil {
1770- arg1 = args[1].(domain.RemoteRegistration)
1771- }
1772- var arg2 ports.BrokerPolicy
1773- if args[2] != nil {
1774- arg2 = args[2].(ports.BrokerPolicy)
1775- }
1776- run(
1777- arg0,
1778- arg1,
1779- arg2,
1780- )
1781- })
1782- return _c
1783-}
1784-
1785-func (_c *MockBrokerService_UpdateHostPolicy_Call) Return(remoteRegistration domain.RemoteRegistration, err error) *MockBrokerService_UpdateHostPolicy_Call {
1786- _c.Call.Return(remoteRegistration, err)
1787- return _c
1788-}
1789-
1790-func (_c *MockBrokerService_UpdateHostPolicy_Call) RunAndReturn(run func(ctx context.Context, expected domain.RemoteRegistration, policy ports.BrokerPolicy) (domain.RemoteRegistration, error)) *MockBrokerService_UpdateHostPolicy_Call {
3116+func (_c *MockBrokerNavigator_SubscribePreview_Call) RunAndReturn(run func(request ports.BrokerPreviewRequest) (ports.BrokerPreviewSubscription, error)) *MockBrokerNavigator_SubscribePreview_Call {
17913117 _c.Call.Return(run)
17923118 return _c
17933119 }
@@ -1798,10 +3124,19 @@ func NewMockBrokerEnvelopeStream(t interface {
17983124 mock.TestingT
17993125 Cleanup(func())
18003126 }) *MockBrokerEnvelopeStream {
3127+ if helper, ok := t.(interface{ Helper() }); ok {
3128+ helper.Helper()
3129+ }
3130+
18013131 mock := &MockBrokerEnvelopeStream{}
18023132 mock.Mock.Test(t)
18033133
1804- t.Cleanup(func() { mock.AssertExpectations(t) })
3134+ t.Cleanup(func() {
3135+ if helper, ok := t.(interface{ Helper() }); ok {
3136+ helper.Helper()
3137+ }
3138+ mock.AssertExpectations(t)
3139+ })
18053140
18063141 return mock
18073142 }
@@ -2065,10 +3400,19 @@ func NewMockBrokerCoreService(t interface {
20653400 mock.TestingT
20663401 Cleanup(func())
20673402 }) *MockBrokerCoreService {
3403+ if helper, ok := t.(interface{ Helper() }); ok {
3404+ helper.Helper()
3405+ }
3406+
20683407 mock := &MockBrokerCoreService{}
20693408 mock.Mock.Test(t)
20703409
2071- t.Cleanup(func() { mock.AssertExpectations(t) })
3410+ t.Cleanup(func() {
3411+ if helper, ok := t.(interface{ Helper() }); ok {
3412+ helper.Helper()
3413+ }
3414+ mock.AssertExpectations(t)
3415+ })
20723416
20733417 return mock
20743418 }
@@ -2861,10 +4205,19 @@ func NewMockSessionCodec(t interface {
28614205 mock.TestingT
28624206 Cleanup(func())
28634207 }) *MockSessionCodec {
4208+ if helper, ok := t.(interface{ Helper() }); ok {
4209+ helper.Helper()
4210+ }
4211+
28644212 mock := &MockSessionCodec{}
28654213 mock.Mock.Test(t)
28664214
2867- t.Cleanup(func() { mock.AssertExpectations(t) })
4215+ t.Cleanup(func() {
4216+ if helper, ok := t.(interface{ Helper() }); ok {
4217+ helper.Helper()
4218+ }
4219+ mock.AssertExpectations(t)
4220+ })
28684221
28694222 return mock
28704223 }
@@ -2941,10 +4294,19 @@ func NewMockBrokerSnapshotStore(t interface {
29414294 mock.TestingT
29424295 Cleanup(func())
29434296 }) *MockBrokerSnapshotStore {
4297+ if helper, ok := t.(interface{ Helper() }); ok {
4298+ helper.Helper()
4299+ }
4300+
29444301 mock := &MockBrokerSnapshotStore{}
29454302 mock.Mock.Test(t)
29464303
2947- t.Cleanup(func() { mock.AssertExpectations(t) })
4304+ t.Cleanup(func() {
4305+ if helper, ok := t.(interface{ Helper() }); ok {
4306+ helper.Helper()
4307+ }
4308+ mock.AssertExpectations(t)
4309+ })
29484310
29494311 return mock
29504312 }
@@ -3072,10 +4434,19 @@ func NewMockBrokerHostProbe(t interface {
30724434 mock.TestingT
30734435 Cleanup(func())
30744436 }) *MockBrokerHostProbe {
4437+ if helper, ok := t.(interface{ Helper() }); ok {
4438+ helper.Helper()
4439+ }
4440+
30754441 mock := &MockBrokerHostProbe{}
30764442 mock.Mock.Test(t)
30774443
3078- t.Cleanup(func() { mock.AssertExpectations(t) })
4444+ t.Cleanup(func() {
4445+ if helper, ok := t.(interface{ Helper() }); ok {
4446+ helper.Helper()
4447+ }
4448+ mock.AssertExpectations(t)
4449+ })
30794450
30804451 return mock
30814452 }
@@ -3165,10 +4536,19 @@ func NewMockBrokerPhysicalConnection(t interface {
31654536 mock.TestingT
31664537 Cleanup(func())
31674538 }) *MockBrokerPhysicalConnection {
4539+ if helper, ok := t.(interface{ Helper() }); ok {
4540+ helper.Helper()
4541+ }
4542+
31684543 mock := &MockBrokerPhysicalConnection{}
31694544 mock.Mock.Test(t)
31704545
3171- t.Cleanup(func() { mock.AssertExpectations(t) })
4546+ t.Cleanup(func() {
4547+ if helper, ok := t.(interface{ Helper() }); ok {
4548+ helper.Helper()
4549+ }
4550+ mock.AssertExpectations(t)
4551+ })
31724552
31734553 return mock
31744554 }
@@ -3572,10 +4952,19 @@ func NewMockBrokerEndpointConnector(t interface {
35724952 mock.TestingT
35734953 Cleanup(func())
35744954 }) *MockBrokerEndpointConnector {
4955+ if helper, ok := t.(interface{ Helper() }); ok {
4956+ helper.Helper()
4957+ }
4958+
35754959 mock := &MockBrokerEndpointConnector{}
35764960 mock.Mock.Test(t)
35774961
3578- t.Cleanup(func() { mock.AssertExpectations(t) })
4962+ t.Cleanup(func() {
4963+ if helper, ok := t.(interface{ Helper() }); ok {
4964+ helper.Helper()
4965+ }
4966+ mock.AssertExpectations(t)
4967+ })
35794968
35804969 return mock
35814970 }
@@ -3667,10 +5056,19 @@ func NewMockBrokerConnector(t interface {
36675056 mock.TestingT
36685057 Cleanup(func())
36695058 }) *MockBrokerConnector {
5059+ if helper, ok := t.(interface{ Helper() }); ok {
5060+ helper.Helper()
5061+ }
5062+
36705063 mock := &MockBrokerConnector{}
36715064 mock.Mock.Test(t)
36725065
3673- t.Cleanup(func() { mock.AssertExpectations(t) })
5066+ t.Cleanup(func() {
5067+ if helper, ok := t.(interface{ Helper() }); ok {
5068+ helper.Helper()
5069+ }
5070+ mock.AssertExpectations(t)
5071+ })
36745072
36755073 return mock
36765074 }
@@ -3689,23 +5087,23 @@ func (_m *MockBrokerConnector) EXPECT() *MockBrokerConnector_Expecter {
36895087 }
36905088
36915089 // Connect provides a mock function for the type MockBrokerConnector
3692-func (_mock *MockBrokerConnector) Connect(ctx context.Context) (ports.BrokerService, error) {
5090+func (_mock *MockBrokerConnector) Connect(ctx context.Context) (ports.BrokerNavigator, error) {
36935091 ret := _mock.Called(ctx)
36945092
36955093 if len(ret) == 0 {
36965094 panic("no return value specified for Connect")
36975095 }
36985096
3699- var r0 ports.BrokerService
5097+ var r0 ports.BrokerNavigator
37005098 var r1 error
3701- if returnFunc, ok := ret.Get(0).(func(context.Context) (ports.BrokerService, error)); ok {
5099+ if returnFunc, ok := ret.Get(0).(func(context.Context) (ports.BrokerNavigator, error)); ok {
37025100 return returnFunc(ctx)
37035101 }
3704- if returnFunc, ok := ret.Get(0).(func(context.Context) ports.BrokerService); ok {
5102+ if returnFunc, ok := ret.Get(0).(func(context.Context) ports.BrokerNavigator); ok {
37055103 r0 = returnFunc(ctx)
37065104 } else {
37075105 if ret.Get(0) != nil {
3708- r0 = ret.Get(0).(ports.BrokerService)
5106+ r0 = ret.Get(0).(ports.BrokerNavigator)
37095107 }
37105108 }
37115109 if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
@@ -3740,12 +5138,12 @@ func (_c *MockBrokerConnector_Connect_Call) Run(run func(ctx context.Context)) *
37405138 return _c
37415139 }
37425140
3743-func (_c *MockBrokerConnector_Connect_Call) Return(brokerService ports.BrokerService, err error) *MockBrokerConnector_Connect_Call {
3744- _c.Call.Return(brokerService, err)
5141+func (_c *MockBrokerConnector_Connect_Call) Return(brokerNavigator ports.BrokerNavigator, err error) *MockBrokerConnector_Connect_Call {
5142+ _c.Call.Return(brokerNavigator, err)
37455143 return _c
37465144 }
37475145
3748-func (_c *MockBrokerConnector_Connect_Call) RunAndReturn(run func(ctx context.Context) (ports.BrokerService, error)) *MockBrokerConnector_Connect_Call {
5146+func (_c *MockBrokerConnector_Connect_Call) RunAndReturn(run func(ctx context.Context) (ports.BrokerNavigator, error)) *MockBrokerConnector_Connect_Call {
37495147 _c.Call.Return(run)
37505148 return _c
37515149 }
@@ -3756,10 +5154,19 @@ func NewMockBrokerAuthority(t interface {
37565154 mock.TestingT
37575155 Cleanup(func())
37585156 }) *MockBrokerAuthority {
5157+ if helper, ok := t.(interface{ Helper() }); ok {
5158+ helper.Helper()
5159+ }
5160+
37595161 mock := &MockBrokerAuthority{}
37605162 mock.Mock.Test(t)
37615163
3762- t.Cleanup(func() { mock.AssertExpectations(t) })
5164+ t.Cleanup(func() {
5165+ if helper, ok := t.(interface{ Helper() }); ok {
5166+ helper.Helper()
5167+ }
5168+ mock.AssertExpectations(t)
5169+ })
37635170
37645171 return mock
37655172 }
@@ -3845,10 +5252,19 @@ func NewMockBrokerListener(t interface {
38455252 mock.TestingT
38465253 Cleanup(func())
38475254 }) *MockBrokerListener {
5255+ if helper, ok := t.(interface{ Helper() }); ok {
5256+ helper.Helper()
5257+ }
5258+
38485259 mock := &MockBrokerListener{}
38495260 mock.Mock.Test(t)
38505261
3851- t.Cleanup(func() { mock.AssertExpectations(t) })
5262+ t.Cleanup(func() {
5263+ if helper, ok := t.(interface{ Helper() }); ok {
5264+ helper.Helper()
5265+ }
5266+ mock.AssertExpectations(t)
5267+ })
38525268
38535269 return mock
38545270 }
M internal/ports/mocks/broker_pool_mock.go +10 -1
@@ -16,10 +16,19 @@ func NewMockBrokerLogicalConnection(t interface {
1616 mock.TestingT
1717 Cleanup(func())
1818 }) *MockBrokerLogicalConnection {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
1923 mock := &MockBrokerLogicalConnection{}
2024 mock.Mock.Test(t)
2125
22- t.Cleanup(func() { mock.AssertExpectations(t) })
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
2332
2433 return mock
2534 }
M internal/ports/mocks/broker_store_mock.go +20 -2
@@ -17,10 +17,19 @@ func NewMockBrokerHostAuthorityReader(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockBrokerHostAuthorityReader {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockBrokerHostAuthorityReader{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
@@ -116,10 +125,19 @@ func NewMockBrokerHostStore(t interface {
116125 mock.TestingT
117126 Cleanup(func())
118127 }) *MockBrokerHostStore {
128+ if helper, ok := t.(interface{ Helper() }); ok {
129+ helper.Helper()
130+ }
131+
119132 mock := &MockBrokerHostStore{}
120133 mock.Mock.Test(t)
121134
122- t.Cleanup(func() { mock.AssertExpectations(t) })
135+ t.Cleanup(func() {
136+ if helper, ok := t.(interface{ Helper() }); ok {
137+ helper.Helper()
138+ }
139+ mock.AssertExpectations(t)
140+ })
123141
124142 return mock
125143 }
M internal/ports/mocks/clipboard_mock.go +10 -1
@@ -16,10 +16,19 @@ func NewMockClipboardReader(t interface {
1616 mock.TestingT
1717 Cleanup(func())
1818 }) *MockClipboardReader {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
1923 mock := &MockClipboardReader{}
2024 mock.Mock.Test(t)
2125
22- t.Cleanup(func() { mock.AssertExpectations(t) })
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
2332
2433 return mock
2534 }
M internal/ports/mocks/clock_mock.go +20 -2
@@ -17,10 +17,19 @@ func NewMockClock(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockClock {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockClock{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
@@ -141,10 +150,19 @@ func NewMockTimer(t interface {
141150 mock.TestingT
142151 Cleanup(func())
143152 }) *MockTimer {
153+ if helper, ok := t.(interface{ Helper() }); ok {
154+ helper.Helper()
155+ }
156+
144157 mock := &MockTimer{}
145158 mock.Mock.Test(t)
146159
147- t.Cleanup(func() { mock.AssertExpectations(t) })
160+ t.Cleanup(func() {
161+ if helper, ok := t.(interface{ Helper() }); ok {
162+ helper.Helper()
163+ }
164+ mock.AssertExpectations(t)
165+ })
148166
149167 return mock
150168 }
M internal/ports/mocks/link_mock.go +10 -1
@@ -15,10 +15,19 @@ func NewMockLinkStateReporter(t interface {
1515 mock.TestingT
1616 Cleanup(func())
1717 }) *MockLinkStateReporter {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
1822 mock := &MockLinkStateReporter{}
1923 mock.Mock.Test(t)
2024
21- t.Cleanup(func() { mock.AssertExpectations(t) })
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
2231
2332 return mock
2433 }
M internal/ports/mocks/notice_mock.go +10 -1
@@ -15,10 +15,19 @@ func NewMockNoticeStore(t interface {
1515 mock.TestingT
1616 Cleanup(func())
1717 }) *MockNoticeStore {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
1822 mock := &MockNoticeStore{}
1923 mock.Mock.Test(t)
2024
21- t.Cleanup(func() { mock.AssertExpectations(t) })
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
2231
2332 return mock
2433 }
M internal/ports/mocks/process_mock.go +10 -1
@@ -14,10 +14,19 @@ func NewMockProcessInspector(t interface {
1414 mock.TestingT
1515 Cleanup(func())
1616 }) *MockProcessInspector {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
1721 mock := &MockProcessInspector{}
1822 mock.Mock.Test(t)
1923
20- t.Cleanup(func() { mock.AssertExpectations(t) })
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
2130
2231 return mock
2332 }
M internal/ports/mocks/pty_mock.go +20 -2
@@ -18,10 +18,19 @@ func NewMockPTY(t interface {
1818 mock.TestingT
1919 Cleanup(func())
2020 }) *MockPTY {
21+ if helper, ok := t.(interface{ Helper() }); ok {
22+ helper.Helper()
23+ }
24+
2125 mock := &MockPTY{}
2226 mock.Mock.Test(t)
2327
24- t.Cleanup(func() { mock.AssertExpectations(t) })
28+ t.Cleanup(func() {
29+ if helper, ok := t.(interface{ Helper() }); ok {
30+ helper.Helper()
31+ }
32+ mock.AssertExpectations(t)
33+ })
2534
2635 return mock
2736 }
@@ -357,10 +366,19 @@ func NewMockPTYFactory(t interface {
357366 mock.TestingT
358367 Cleanup(func())
359368 }) *MockPTYFactory {
369+ if helper, ok := t.(interface{ Helper() }); ok {
370+ helper.Helper()
371+ }
372+
360373 mock := &MockPTYFactory{}
361374 mock.Mock.Test(t)
362375
363- t.Cleanup(func() { mock.AssertExpectations(t) })
376+ t.Cleanup(func() {
377+ if helper, ok := t.(interface{ Helper() }); ok {
378+ helper.Helper()
379+ }
380+ mock.AssertExpectations(t)
381+ })
364382
365383 return mock
366384 }
M internal/ports/mocks/recovery_mock.go +20 -2
@@ -18,10 +18,19 @@ func NewMockCatalogue(t interface {
1818 mock.TestingT
1919 Cleanup(func())
2020 }) *MockCatalogue {
21+ if helper, ok := t.(interface{ Helper() }); ok {
22+ helper.Helper()
23+ }
24+
2125 mock := &MockCatalogue{}
2226 mock.Mock.Test(t)
2327
24- t.Cleanup(func() { mock.AssertExpectations(t) })
28+ t.Cleanup(func() {
29+ if helper, ok := t.(interface{ Helper() }); ok {
30+ helper.Helper()
31+ }
32+ mock.AssertExpectations(t)
33+ })
2534
2635 return mock
2736 }
@@ -521,10 +530,19 @@ func NewMockSnapshotRepository(t interface {
521530 mock.TestingT
522531 Cleanup(func())
523532 }) *MockSnapshotRepository {
533+ if helper, ok := t.(interface{ Helper() }); ok {
534+ helper.Helper()
535+ }
536+
524537 mock := &MockSnapshotRepository{}
525538 mock.Mock.Test(t)
526539
527- t.Cleanup(func() { mock.AssertExpectations(t) })
540+ t.Cleanup(func() {
541+ if helper, ok := t.(interface{ Helper() }); ok {
542+ helper.Helper()
543+ }
544+ mock.AssertExpectations(t)
545+ })
528546
529547 return mock
530548 }
M internal/ports/mocks/remote_mock.go +50 -5
@@ -19,10 +19,19 @@ func NewMockRemoteHostStore(t interface {
1919 mock.TestingT
2020 Cleanup(func())
2121 }) *MockRemoteHostStore {
22+ if helper, ok := t.(interface{ Helper() }); ok {
23+ helper.Helper()
24+ }
25+
2226 mock := &MockRemoteHostStore{}
2327 mock.Mock.Test(t)
2428
25- t.Cleanup(func() { mock.AssertExpectations(t) })
29+ t.Cleanup(func() {
30+ if helper, ok := t.(interface{ Helper() }); ok {
31+ helper.Helper()
32+ }
33+ mock.AssertExpectations(t)
34+ })
2635
2736 return mock
2837 }
@@ -373,10 +382,19 @@ func NewMockRemoteCatalogClient(t interface {
373382 mock.TestingT
374383 Cleanup(func())
375384 }) *MockRemoteCatalogClient {
385+ if helper, ok := t.(interface{ Helper() }); ok {
386+ helper.Helper()
387+ }
388+
376389 mock := &MockRemoteCatalogClient{}
377390 mock.Mock.Test(t)
378391
379- t.Cleanup(func() { mock.AssertExpectations(t) })
392+ t.Cleanup(func() {
393+ if helper, ok := t.(interface{ Helper() }); ok {
394+ helper.Helper()
395+ }
396+ mock.AssertExpectations(t)
397+ })
380398
381399 return mock
382400 }
@@ -466,10 +484,19 @@ func NewMockRemoteCatalogCache(t interface {
466484 mock.TestingT
467485 Cleanup(func())
468486 }) *MockRemoteCatalogCache {
487+ if helper, ok := t.(interface{ Helper() }); ok {
488+ helper.Helper()
489+ }
490+
469491 mock := &MockRemoteCatalogCache{}
470492 mock.Mock.Test(t)
471493
472- t.Cleanup(func() { mock.AssertExpectations(t) })
494+ t.Cleanup(func() {
495+ if helper, ok := t.(interface{ Helper() }); ok {
496+ helper.Helper()
497+ }
498+ mock.AssertExpectations(t)
499+ })
473500
474501 return mock
475502 }
@@ -599,10 +626,19 @@ func NewMockRemoteEndpointFactory(t interface {
599626 mock.TestingT
600627 Cleanup(func())
601628 }) *MockRemoteEndpointFactory {
629+ if helper, ok := t.(interface{ Helper() }); ok {
630+ helper.Helper()
631+ }
632+
602633 mock := &MockRemoteEndpointFactory{}
603634 mock.Mock.Test(t)
604635
605- t.Cleanup(func() { mock.AssertExpectations(t) })
636+ t.Cleanup(func() {
637+ if helper, ok := t.(interface{ Helper() }); ok {
638+ helper.Helper()
639+ }
640+ mock.AssertExpectations(t)
641+ })
606642
607643 return mock
608644 }
@@ -692,10 +728,19 @@ func NewMockClientHostRegistry(t interface {
692728 mock.TestingT
693729 Cleanup(func())
694730 }) *MockClientHostRegistry {
731+ if helper, ok := t.(interface{ Helper() }); ok {
732+ helper.Helper()
733+ }
734+
695735 mock := &MockClientHostRegistry{}
696736 mock.Mock.Test(t)
697737
698- t.Cleanup(func() { mock.AssertExpectations(t) })
738+ t.Cleanup(func() {
739+ if helper, ok := t.(interface{ Helper() }); ok {
740+ helper.Helper()
741+ }
742+ mock.AssertExpectations(t)
743+ })
699744
700745 return mock
701746 }
M internal/ports/mocks/remote_runtime_mock.go +10 -1
@@ -17,10 +17,19 @@ func NewMockRemoteRuntime(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockRemoteRuntime {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockRemoteRuntime{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
M internal/ports/mocks/runtime_observer_mock.go +20 -2
@@ -15,10 +15,19 @@ func NewMockRuntimeObserver(t interface {
1515 mock.TestingT
1616 Cleanup(func())
1717 }) *MockRuntimeObserver {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
1822 mock := &MockRuntimeObserver{}
1923 mock.Mock.Test(t)
2024
21- t.Cleanup(func() { mock.AssertExpectations(t) })
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
2231
2332 return mock
2433 }
@@ -82,10 +91,19 @@ func NewMockSerializedRuntimeObserver(t interface {
8291 mock.TestingT
8392 Cleanup(func())
8493 }) *MockSerializedRuntimeObserver {
94+ if helper, ok := t.(interface{ Helper() }); ok {
95+ helper.Helper()
96+ }
97+
8598 mock := &MockSerializedRuntimeObserver{}
8699 mock.Mock.Test(t)
87100
88- t.Cleanup(func() { mock.AssertExpectations(t) })
101+ t.Cleanup(func() {
102+ if helper, ok := t.(interface{ Helper() }); ok {
103+ helper.Helper()
104+ }
105+ mock.AssertExpectations(t)
106+ })
89107
90108 return mock
91109 }
M internal/ports/mocks/session_admission_mock.go +10 -1
@@ -15,10 +15,19 @@ func NewMockSessionAdmissionProvider(t interface {
1515 mock.TestingT
1616 Cleanup(func())
1717 }) *MockSessionAdmissionProvider {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
1822 mock := &MockSessionAdmissionProvider{}
1923 mock.Mock.Test(t)
2024
21- t.Cleanup(func() { mock.AssertExpectations(t) })
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
2231
2332 return mock
2433 }
M internal/ports/mocks/session_mock.go +50 -5
@@ -19,10 +19,19 @@ func NewMockClientConnection(t interface {
1919 mock.TestingT
2020 Cleanup(func())
2121 }) *MockClientConnection {
22+ if helper, ok := t.(interface{ Helper() }); ok {
23+ helper.Helper()
24+ }
25+
2226 mock := &MockClientConnection{}
2327 mock.Mock.Test(t)
2428
25- t.Cleanup(func() { mock.AssertExpectations(t) })
29+ t.Cleanup(func() {
30+ if helper, ok := t.(interface{ Helper() }); ok {
31+ helper.Helper()
32+ }
33+ mock.AssertExpectations(t)
34+ })
2635
2736 return mock
2837 }
@@ -330,10 +339,19 @@ func NewMockClientDialer(t interface {
330339 mock.TestingT
331340 Cleanup(func())
332341 }) *MockClientDialer {
342+ if helper, ok := t.(interface{ Helper() }); ok {
343+ helper.Helper()
344+ }
345+
333346 mock := &MockClientDialer{}
334347 mock.Mock.Test(t)
335348
336- t.Cleanup(func() { mock.AssertExpectations(t) })
349+ t.Cleanup(func() {
350+ if helper, ok := t.(interface{ Helper() }); ok {
351+ helper.Helper()
352+ }
353+ mock.AssertExpectations(t)
354+ })
337355
338356 return mock
339357 }
@@ -419,10 +437,19 @@ func NewMockServerConnection(t interface {
419437 mock.TestingT
420438 Cleanup(func())
421439 }) *MockServerConnection {
440+ if helper, ok := t.(interface{ Helper() }); ok {
441+ helper.Helper()
442+ }
443+
422444 mock := &MockServerConnection{}
423445 mock.Mock.Test(t)
424446
425- t.Cleanup(func() { mock.AssertExpectations(t) })
447+ t.Cleanup(func() {
448+ if helper, ok := t.(interface{ Helper() }); ok {
449+ helper.Helper()
450+ }
451+ mock.AssertExpectations(t)
452+ })
426453
427454 return mock
428455 }
@@ -985,10 +1012,19 @@ func NewMockHandshakeDeadlineProvider(t interface {
9851012 mock.TestingT
9861013 Cleanup(func())
9871014 }) *MockHandshakeDeadlineProvider {
1015+ if helper, ok := t.(interface{ Helper() }); ok {
1016+ helper.Helper()
1017+ }
1018+
9881019 mock := &MockHandshakeDeadlineProvider{}
9891020 mock.Mock.Test(t)
9901021
991- t.Cleanup(func() { mock.AssertExpectations(t) })
1022+ t.Cleanup(func() {
1023+ if helper, ok := t.(interface{ Helper() }); ok {
1024+ helper.Helper()
1025+ }
1026+ mock.AssertExpectations(t)
1027+ })
9921028
9931029 return mock
9941030 }
@@ -1056,10 +1092,19 @@ func NewMockServerListener(t interface {
10561092 mock.TestingT
10571093 Cleanup(func())
10581094 }) *MockServerListener {
1095+ if helper, ok := t.(interface{ Helper() }); ok {
1096+ helper.Helper()
1097+ }
1098+
10591099 mock := &MockServerListener{}
10601100 mock.Mock.Test(t)
10611101
1062- t.Cleanup(func() { mock.AssertExpectations(t) })
1102+ t.Cleanup(func() {
1103+ if helper, ok := t.(interface{ Helper() }); ok {
1104+ helper.Helper()
1105+ }
1106+ mock.AssertExpectations(t)
1107+ })
10631108
10641109 return mock
10651110 }
M internal/ports/mocks/shell_mock.go +10 -1
@@ -17,10 +17,19 @@ func NewMockShellCommandRunner(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockShellCommandRunner {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockShellCommandRunner{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
M internal/ports/mocks/store_mock.go +10 -1
@@ -14,10 +14,19 @@ func NewMockStore(t interface {
1414 mock.TestingT
1515 Cleanup(func())
1616 }) *MockStore {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
1721 mock := &MockStore{}
1822 mock.Mock.Test(t)
1923
20- t.Cleanup(func() { mock.AssertExpectations(t) })
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
2130
2231 return mock
2332 }
M internal/ports/mocks/terminal_mock.go +10 -1
@@ -17,10 +17,19 @@ func NewMockTerminal(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockTerminal {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockTerminal{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
M internal/ports/mocks/ui_mock.go +40 -4
@@ -18,10 +18,19 @@ func NewMockUIService(t interface {
1818 mock.TestingT
1919 Cleanup(func())
2020 }) *MockUIService {
21+ if helper, ok := t.(interface{ Helper() }); ok {
22+ helper.Helper()
23+ }
24+
2125 mock := &MockUIService{}
2226 mock.Mock.Test(t)
2327
24- t.Cleanup(func() { mock.AssertExpectations(t) })
28+ t.Cleanup(func() {
29+ if helper, ok := t.(interface{ Helper() }); ok {
30+ helper.Helper()
31+ }
32+ mock.AssertExpectations(t)
33+ })
2534
2635 return mock
2736 }
@@ -237,10 +246,19 @@ func NewMockUIObservationSink(t interface {
237246 mock.TestingT
238247 Cleanup(func())
239248 }) *MockUIObservationSink {
249+ if helper, ok := t.(interface{ Helper() }); ok {
250+ helper.Helper()
251+ }
252+
240253 mock := &MockUIObservationSink{}
241254 mock.Mock.Test(t)
242255
243- t.Cleanup(func() { mock.AssertExpectations(t) })
256+ t.Cleanup(func() {
257+ if helper, ok := t.(interface{ Helper() }); ok {
258+ helper.Helper()
259+ }
260+ mock.AssertExpectations(t)
261+ })
244262
245263 return mock
246264 }
@@ -410,10 +428,19 @@ func NewMockUIOutputTransaction(t interface {
410428 mock.TestingT
411429 Cleanup(func())
412430 }) *MockUIOutputTransaction {
431+ if helper, ok := t.(interface{ Helper() }); ok {
432+ helper.Helper()
433+ }
434+
413435 mock := &MockUIOutputTransaction{}
414436 mock.Mock.Test(t)
415437
416- t.Cleanup(func() { mock.AssertExpectations(t) })
438+ t.Cleanup(func() {
439+ if helper, ok := t.(interface{ Helper() }); ok {
440+ helper.Helper()
441+ }
442+ mock.AssertExpectations(t)
443+ })
417444
418445 return mock
419446 }
@@ -568,10 +595,19 @@ func NewMockUIState(t interface {
568595 mock.TestingT
569596 Cleanup(func())
570597 }) *MockUIState {
598+ if helper, ok := t.(interface{ Helper() }); ok {
599+ helper.Helper()
600+ }
601+
571602 mock := &MockUIState{}
572603 mock.Mock.Test(t)
573604
574- t.Cleanup(func() { mock.AssertExpectations(t) })
605+ t.Cleanup(func() {
606+ if helper, ok := t.(interface{ Helper() }); ok {
607+ helper.Helper()
608+ }
609+ mock.AssertExpectations(t)
610+ })
575611
576612 return mock
577613 }
M internal/protocol/wire/mocks/transport_mock.go +60 -6
@@ -17,10 +17,19 @@ func NewMockTransport(t interface {
1717 mock.TestingT
1818 Cleanup(func())
1919 }) *MockTransport {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
2024 mock := &MockTransport{}
2125 mock.Mock.Test(t)
2226
23- t.Cleanup(func() { mock.AssertExpectations(t) })
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
2433
2534 return mock
2635 }
@@ -192,10 +201,19 @@ func NewMockDatagramTransport(t interface {
192201 mock.TestingT
193202 Cleanup(func())
194203 }) *MockDatagramTransport {
204+ if helper, ok := t.(interface{ Helper() }); ok {
205+ helper.Helper()
206+ }
207+
195208 mock := &MockDatagramTransport{}
196209 mock.Mock.Test(t)
197210
198- t.Cleanup(func() { mock.AssertExpectations(t) })
211+ t.Cleanup(func() {
212+ if helper, ok := t.(interface{ Helper() }); ok {
213+ helper.Helper()
214+ }
215+ mock.AssertExpectations(t)
216+ })
199217
200218 return mock
201219 }
@@ -400,10 +418,19 @@ func NewMockAsyncTransport(t interface {
400418 mock.TestingT
401419 Cleanup(func())
402420 }) *MockAsyncTransport {
421+ if helper, ok := t.(interface{ Helper() }); ok {
422+ helper.Helper()
423+ }
424+
403425 mock := &MockAsyncTransport{}
404426 mock.Mock.Test(t)
405427
406- t.Cleanup(func() { mock.AssertExpectations(t) })
428+ t.Cleanup(func() {
429+ if helper, ok := t.(interface{ Helper() }); ok {
430+ helper.Helper()
431+ }
432+ mock.AssertExpectations(t)
433+ })
407434
408435 return mock
409436 }
@@ -478,10 +505,19 @@ func NewMockOwnedSynchronousTransport(t interface {
478505 mock.TestingT
479506 Cleanup(func())
480507 }) *MockOwnedSynchronousTransport {
508+ if helper, ok := t.(interface{ Helper() }); ok {
509+ helper.Helper()
510+ }
511+
481512 mock := &MockOwnedSynchronousTransport{}
482513 mock.Mock.Test(t)
483514
484- t.Cleanup(func() { mock.AssertExpectations(t) })
515+ t.Cleanup(func() {
516+ if helper, ok := t.(interface{ Helper() }); ok {
517+ helper.Helper()
518+ }
519+ mock.AssertExpectations(t)
520+ })
485521
486522 return mock
487523 }
@@ -556,10 +592,19 @@ func NewMockDialer(t interface {
556592 mock.TestingT
557593 Cleanup(func())
558594 }) *MockDialer {
595+ if helper, ok := t.(interface{ Helper() }); ok {
596+ helper.Helper()
597+ }
598+
559599 mock := &MockDialer{}
560600 mock.Mock.Test(t)
561601
562- t.Cleanup(func() { mock.AssertExpectations(t) })
602+ t.Cleanup(func() {
603+ if helper, ok := t.(interface{ Helper() }); ok {
604+ helper.Helper()
605+ }
606+ mock.AssertExpectations(t)
607+ })
563608
564609 return mock
565610 }
@@ -645,10 +690,19 @@ func NewMockListener(t interface {
645690 mock.TestingT
646691 Cleanup(func())
647692 }) *MockListener {
693+ if helper, ok := t.(interface{ Helper() }); ok {
694+ helper.Helper()
695+ }
696+
648697 mock := &MockListener{}
649698 mock.Mock.Test(t)
650699
651- t.Cleanup(func() { mock.AssertExpectations(t) })
700+ t.Cleanup(func() {
701+ if helper, ok := t.(interface{ Helper() }); ok {
702+ helper.Helper()
703+ }
704+ mock.AssertExpectations(t)
705+ })
652706
653707 return mock
654708 }
A internal/usecase/broker/daemon_start.go +75 -0
@@ -0,0 +1,75 @@
1+package broker
2+
3+import (
4+ "errors"
5+ "fmt"
6+
7+ "github.com/bnema/vev/internal/ports"
8+)
9+
10+// DaemonLaunchAuthority is the policy launch token that explicitly authorizes
11+// starting a stopped target daemon. Ports carry it opaquely; the broker is the
12+// component that interprets it. Any other token, including every
13+// sandbox-private one, fails closed and never starts a daemon.
14+const DaemonLaunchAuthority = "explicit"
15+
16+// RequireLocalDaemonTarget refuses a target that is not the broker-owned local
17+// daemon. Only that authority names a daemon this process can start, so a
18+// registered host is never started by mistake, even on a local carriage.
19+func RequireLocalDaemonTarget(target ports.BrokerDialTarget) error {
20+ if !target.Fence.Local {
21+ return daemonStartRefused("the target is not the broker-owned local daemon")
22+ }
23+ return nil
24+}
25+
26+// ClassifyDaemonDialFailure decides whether a failed carriage dial may lead to
27+// a start at all. absent reports whether the transport proved the daemon is
28+// simply not there; that classification belongs to the carriage adapter and
29+// must fail closed.
30+//
31+// It returns nil only when the daemon is absent under a mode other than
32+// ExistingOnly. Otherwise it returns the error to report, and no lock,
33+// election, or process may be touched:
34+//
35+// - ExistingOnly never starts: absence becomes BrokerErrorNoDaemon and every
36+// other failure is reported unchanged.
37+// - A failure that is not absence (cancellation, a rejected peer, a foreign
38+// path, a permission error) is never repaired by starting another daemon.
39+func ClassifyDaemonDialFailure(target ports.BrokerDialTarget, dialErr error, absent bool) error {
40+ if dialErr == nil {
41+ return errors.New("broker: a running daemon is never started again")
42+ }
43+ if target.StartMode == ports.BrokerDaemonExistingOnly {
44+ if absent {
45+ return ports.BrokerError{Code: ports.BrokerErrorNoDaemon, Cause: dialErr}
46+ }
47+ return dialErr
48+ }
49+ if !absent {
50+ return dialErr
51+ }
52+ return nil
53+}
54+
55+// AuthorizeDaemonLaunch is the final start decision for an absent daemon. The
56+// start mode is an authorization, never an obligation, and it can only narrow
57+// the policy: the resolved policy must also name DaemonLaunchAuthority.
58+func AuthorizeDaemonLaunch(target ports.BrokerDialTarget) error {
59+ if target.StartMode != ports.BrokerDaemonStartIfNeeded {
60+ return daemonStartRefused("the acquisition does not authorize starting a daemon")
61+ }
62+ if target.Policy.Launch != DaemonLaunchAuthority {
63+ return daemonStartRefused("the resolved policy does not authorize launching")
64+ }
65+ return nil
66+}
67+
68+// daemonStartRefused reports a refused start as a typed policy conflict. The
69+// reason is local diagnostic text, never a message the daemon produced.
70+func daemonStartRefused(reason string) error {
71+ return ports.BrokerError{
72+ Code: ports.BrokerErrorConflictingPolicy,
73+ Cause: fmt.Errorf("vev: refusing to start the daemon: %s", reason),
74+ }
75+}
A internal/usecase/broker/daemon_start_test.go +82 -0
@@ -0,0 +1,82 @@
1+package broker
2+
3+import (
4+ "errors"
5+ "testing"
6+
7+ "github.com/stretchr/testify/require"
8+
9+ "github.com/bnema/vev/internal/ports"
10+)
11+
12+func daemonStartTarget(mode ports.BrokerDaemonStartMode, launch string) ports.BrokerDialTarget {
13+ return ports.BrokerDialTarget{StartMode: mode, Policy: ports.BrokerPolicy{Launch: launch}}
14+}
15+
16+func requireBrokerCode(t *testing.T, err error, code ports.BrokerErrorCode) {
17+ t.Helper()
18+ var typed ports.BrokerError
19+ require.ErrorAs(t, err, &typed)
20+ require.Equal(t, code, typed.Code)
21+}
22+
23+func TestClassifyDaemonDialFailure(t *testing.T) {
24+ dialErr := errors.New("dial failed")
25+ tests := []struct {
26+ name string
27+ mode ports.BrokerDaemonStartMode
28+ dialErr error
29+ absent bool
30+ wantCode ports.BrokerErrorCode
31+ wantSame bool // the dial error is reported unchanged
32+ wantOK bool
33+ }{
34+ {name: "running daemon is never started", mode: ports.BrokerDaemonStartIfNeeded},
35+ {name: "existing-only absence is no daemon", mode: ports.BrokerDaemonExistingOnly, dialErr: dialErr, absent: true, wantCode: ports.BrokerErrorNoDaemon},
36+ {name: "existing-only other failure is unchanged", mode: ports.BrokerDaemonExistingOnly, dialErr: dialErr, wantSame: true},
37+ {name: "start-if-needed non-absence is never repaired", mode: ports.BrokerDaemonStartIfNeeded, dialErr: dialErr, wantSame: true},
38+ {name: "start-if-needed absence may continue", mode: ports.BrokerDaemonStartIfNeeded, dialErr: dialErr, absent: true, wantOK: true},
39+ }
40+ for _, tt := range tests {
41+ t.Run(tt.name, func(t *testing.T) {
42+ err := ClassifyDaemonDialFailure(daemonStartTarget(tt.mode, DaemonLaunchAuthority), tt.dialErr, tt.absent)
43+ switch {
44+ case tt.wantOK:
45+ require.NoError(t, err)
46+ case tt.wantSame:
47+ require.Same(t, tt.dialErr, err)
48+ case tt.wantCode != 0:
49+ requireBrokerCode(t, err, tt.wantCode)
50+ default:
51+ require.Error(t, err)
52+ }
53+ })
54+ }
55+}
56+
57+func TestAuthorizeDaemonLaunch(t *testing.T) {
58+ tests := []struct {
59+ name string
60+ target ports.BrokerDialTarget
61+ wantOK bool
62+ }{
63+ {name: "start-if-needed with launch authority", target: daemonStartTarget(ports.BrokerDaemonStartIfNeeded, DaemonLaunchAuthority), wantOK: true},
64+ {name: "policy without launch authority refuses", target: daemonStartTarget(ports.BrokerDaemonStartIfNeeded, "sandbox-private")},
65+ {name: "unknown mode refuses", target: daemonStartTarget(ports.BrokerDaemonStartMode(99), DaemonLaunchAuthority)},
66+ }
67+ for _, tt := range tests {
68+ t.Run(tt.name, func(t *testing.T) {
69+ err := AuthorizeDaemonLaunch(tt.target)
70+ if tt.wantOK {
71+ require.NoError(t, err)
72+ return
73+ }
74+ requireBrokerCode(t, err, ports.BrokerErrorConflictingPolicy)
75+ })
76+ }
77+}
78+
79+func TestRequireLocalDaemonTarget(t *testing.T) {
80+ require.NoError(t, RequireLocalDaemonTarget(ports.BrokerDialTarget{Fence: ports.BrokerEndpointFence{Local: true}}))
81+ requireBrokerCode(t, RequireLocalDaemonTarget(ports.BrokerDialTarget{}), ports.BrokerErrorConflictingPolicy)
82+}
M internal/usecase/broker/registry.go +5 -29
@@ -1398,36 +1398,12 @@ func (r *Registry) publishLocked(persist bool) {
13981398 }
13991399
14001400 // durable returns the persistable copy of a publication, rendered by the
1401-// writer goroutine. Checking is transient in-flight state and never reaches
1402-// the durable snapshot. Retirement tombstones are process-local fencing state:
1403-// they retire registrations only for this process lifetime and a restart never
1404-// adopts them, so persisting them would leak stale authority into durable
1405-// state. Removed is therefore cleared before persistence.
1406-//
1407-// Policy is membership authority, not observation state, so the durable format
1408-// deliberately omits it: membership is the single policy authority, and the
1409-// loader re-stamps every restored observation from the matching
1410-// ports.BrokerHostRecord (see stampHostAuthority). Persisting it would create a
1411-// second, stale authority that a later membership change could contradict.
1412-//
1413-// Only remote observations are durable: a local daemon observation is
1414-// process-local state and is dropped here (the store also rejects one), so a
1415-// future local producer can never break durable persistence.
1401+// writer goroutine with the shared rule (ports.BrokerSnapshot.DurableProjection).
1402+// The registry may publish the process-local daemon, which is never durable,
1403+// so it is dropped first; the store would refuse it otherwise. Restored
1404+// observations regain policy from membership (see stampHostAuthority).
14161405 func durable(snapshot ports.BrokerSnapshot) ports.BrokerSnapshot {
1417- out := snapshot.Clone()
1418- out.Removed = nil
1419- daemons := out.Daemons[:0]
1420- for _, daemon := range out.Daemons {
1421- if daemon.Local {
1422- continue
1423- }
1424- daemon.Checking = false
1425- daemon.LastFailure.Err = nil
1426- daemon.Policy = ports.BrokerPolicy{}
1427- daemons = append(daemons, daemon)
1428- }
1429- out.Daemons = daemons
1430- return out
1406+ return snapshot.WithoutLocal().DurableProjection()
14311407 }
14321408
14331409 // snapshotWriter serializes durable snapshot writes off the registry lock.
M internal/usecase/client/broker_operations.go +2 -2
@@ -99,14 +99,14 @@ func (r BrokerOperationRoute) Validate() error {
9999 // closes the borrowed service, and exposes no way to open or retarget a
100100 // session.
101101 type BrokerOperations struct {
102- service ports.BrokerService
102+ service ports.BrokerNavigator
103103 clock ports.Clock
104104 }
105105
106106 // NewBrokerOperations builds the executor over a borrowed broker service. It
107107 // refuses a nil or typed-nil service or clock so no operation can panic on a
108108 // missing dependency; the caller keeps ownership of the service lifetime.
109-func NewBrokerOperations(service ports.BrokerService, clock ports.Clock) (*BrokerOperations, error) {
109+func NewBrokerOperations(service ports.BrokerNavigator, clock ports.Clock) (*BrokerOperations, error) {
110110 if supervisorNil(service) {
111111 return nil, errors.New("vev: broker operations require a broker service")
112112 }
M internal/usecase/client/broker_operations_test.go +2 -19
@@ -10,7 +10,6 @@ import (
1010
1111 "github.com/stretchr/testify/require"
1212
13- "github.com/bnema/vev/internal/domain"
1413 "github.com/bnema/vev/internal/ports"
1514 "github.com/bnema/vev/internal/protocol"
1615 )
@@ -210,22 +209,6 @@ func (s *brokerOpsTestService) closeCount() int {
210209 return s.closes
211210 }
212211
213-func (s *brokerOpsTestService) CloseStream(ports.BrokerConnectionID, ports.BrokerStreamID) error {
214- return nil
215-}
216-
217-func (s *brokerOpsTestService) AddHost(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error) {
218- return domain.RemoteRegistration{}, nil
219-}
220-
221-func (s *brokerOpsTestService) RemoveHost(context.Context, domain.RemoteRegistration) (bool, error) {
222- return false, nil
223-}
224-
225-func (s *brokerOpsTestService) UpdateHostPolicy(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) (domain.RemoteRegistration, error) {
226- return domain.RemoteRegistration{}, nil
227-}
228-
229212 func (s *brokerOpsTestService) RequestReconcile(endpoint string) {
230213 s.mu.Lock()
231214 s.reconciles = append(s.reconciles, endpoint)
@@ -239,7 +222,7 @@ func (s *brokerOpsTestService) Close() error {
239222 return nil
240223 }
241224
242-var _ ports.BrokerService = (*brokerOpsTestService)(nil)
225+var _ ports.BrokerNavigator = (*brokerOpsTestService)(nil)
243226
244227 func brokerOpsTestLocalSnapshot() ports.BrokerSnapshot {
245228 now := time.Unix(1000, 0)
@@ -297,7 +280,7 @@ func TestBrokerOperationsConstructorRefusesMissingDependencies(t *testing.T) {
297280
298281 tests := []struct {
299282 name string
300- service ports.BrokerService
283+ service ports.BrokerNavigator
301284 clock ports.Clock
302285 wantErr bool
303286 }{
M internal/usecase/client/initial_navigation_test.go +5 -5
@@ -344,7 +344,7 @@ func TestInitialNavigationResolverIsConsultedAtMostOnce(t *testing.T) {
344344 first.setOpenStream(func(context.Context, ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
345345 return stream, nil
346346 })
347- connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerService, error) {
347+ connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerNavigator, error) {
348348 if call == 1 {
349349 return first, nil
350350 }
@@ -438,7 +438,7 @@ func TestNewSupervisorRefusesContradictoryInitialConfiguration(t *testing.T) {
438438 reader := newSupervisorTestReader()
439439 t.Cleanup(reader.unblock)
440440 terminal := newSupervisorTestTerminal(reader)
441- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
441+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
442442 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable}
443443 })
444444
@@ -484,7 +484,7 @@ func TestInitialNavigationResolverFailureIsSelectionUnavailable(t *testing.T) {
484484 var calls atomic.Int64
485485 resolverErr := errors.New("no such target")
486486 sup := mustSupervisor(t, SupervisorConfig{
487- Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) { return service, nil }),
487+ Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil }),
488488 Terminal: terminal, Clock: clock, Jitter: func() float64 { return 0 }, Picker: picker,
489489 NotifyLifecycle: func(notice LifecycleNotice) { notices <- notice },
490490 ResolveInitialNavigation: func(ports.BrokerSnapshot) (InitialNavigation, error) {
@@ -538,7 +538,7 @@ func TestInitialNavigationWaitsForTargetObservation(t *testing.T) {
538538 notices := make(chan LifecycleNotice, 4)
539539 var calls atomic.Int64
540540 sup := mustSupervisor(t, SupervisorConfig{
541- Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) { return service, nil }),
541+ Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil }),
542542 Terminal: terminal, Clock: clock, Jitter: func() float64 { return 0 }, Picker: picker,
543543 NotifyLifecycle: func(notice LifecycleNotice) { notices <- notice },
544544 ResolveInitialNavigation: func(snapshot ports.BrokerSnapshot) (InitialNavigation, error) {
@@ -625,7 +625,7 @@ func TestInitialNavigationDropsDecisionsTakenWhileHidden(t *testing.T) {
625625 service.setOpenStream(func(context.Context, ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
626626 return stream, nil
627627 })
628- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) { return service, nil })
628+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil })
629629 // A keystroke typed during the cold start: the hidden picker recorded a
630630 // commit before the broker published anything.
631631 picker.recordOp(pickerOp{commit: true}, "row", ports.BrokerOpenStreamRequest{})
M internal/usecase/client/lifecycle_p54a_test.go +3 -3
@@ -136,7 +136,7 @@ func TestP54InitialNavigationCreatesEphemeralThroughBroker(t *testing.T) {
136136 service.setOpenStream(func(context.Context, ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
137137 return stream, nil
138138 })
139- sup := mustSupervisor(t, SupervisorConfig{Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) { return service, nil }), Terminal: terminal, Clock: clock, Jitter: func() float64 { return 0 }, Picker: picker, InitialNavigation: navigation})
139+ sup := mustSupervisor(t, SupervisorConfig{Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil }), Terminal: terminal, Clock: clock, Jitter: func() float64 { return 0 }, Picker: picker, InitialNavigation: navigation})
140140 done := make(chan error, 1)
141141 go func() { done <- sup.Run(ctx) }()
142142 require.Eventually(t, func() bool { return len(service.openedRequests()) == 1 }, 5*time.Second, time.Millisecond)
@@ -165,7 +165,7 @@ func TestP54InitialNavigationIsNotReplayedAfterReconnect(t *testing.T) {
165165 first.setOpenStream(func(context.Context, ports.BrokerOpenStreamRequest) (ports.BrokerLogicalConnection, error) {
166166 return stream, nil
167167 })
168- connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerService, error) {
168+ connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerNavigator, error) {
169169 if call == 1 {
170170 return first, nil
171171 }
@@ -229,7 +229,7 @@ func TestP54BrokerRestartDoesNotReattachOrReplayUnknownMutation(t *testing.T) {
229229 first := newSupervisorTestService(ports.BrokerConnectionID{1})
230230 first.publish(1, 1)
231231 second := newSupervisorTestService(ports.BrokerConnectionID{2})
232- connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerService, error) {
232+ connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerNavigator, error) {
233233 if call == 1 {
234234 return first, nil
235235 }
M internal/usecase/client/picker_catalogue.go +9 -2
@@ -394,8 +394,10 @@ func (c *pickerCatalogue) Resolve(key string, base pickerResolveBase) (ports.Bro
394394 return c.resolveRefLocked(ref, base)
395395 }
396396
397-// ResolveTarget is Resolve plus the exact tab the row names, both revalidated
398-// under one lock against the same publication.
397+// ResolveTarget is the commit resolution of one published row: the row's
398+// selection kind, the exact broker stream request, and the tab it names, all
399+// revalidated under one lock against the same publication. Only a session,
400+// tab, or create row is a destination; any other kind is refused.
399401 func (c *pickerCatalogue) ResolveTarget(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
400402 if c == nil {
401403 return ports.BrokerOpenStreamRequest{}, attachmentTab{}, pickerCatalogueError{Code: pickerCatalogueUnknown, Text: "no catalogue"}
@@ -409,6 +411,11 @@ func (c *pickerCatalogue) ResolveTarget(key string, base pickerResolveBase) (por
409411 if !ok {
410412 return ports.BrokerOpenStreamRequest{}, attachmentTab{}, pickerCatalogueError{Code: pickerCatalogueUnknown, Text: "picker row is not in the catalogue"}
411413 }
414+ switch ref.kind {
415+ case pickerSelectionExact, pickerSelectionCreateNamed, pickerSelectionCreateEphemeral:
416+ default:
417+ return ports.BrokerOpenStreamRequest{}, attachmentTab{}, pickerCatalogueError{Code: pickerCatalogueUnavailable, Text: "this picker row is not a session destination"}
418+ }
412419 return resolvePickerTarget(c.snapshot.Epoch, c.authorityForRefLocked(ref), ref, base, true)
413420 }
414421
A internal/usecase/client/picker_commit_test.go +125 -0
@@ -0,0 +1,125 @@
1+package client
2+
3+import (
4+ "fmt"
5+ "testing"
6+ "time"
7+
8+ "github.com/stretchr/testify/require"
9+
10+ "github.com/bnema/vev/internal/domain"
11+ "github.com/bnema/vev/internal/ports"
12+ "github.com/bnema/vev/internal/protocol/catalogue"
13+)
14+
15+// TestPickerCommitResolvesTheCommittedRow drives the whole picker commit path
16+// through the real controller and catalogue: a keypress records the commit
17+// decision with its row key, TakeOp hands the key over, and ResolveCommit
18+// revalidates it against the latest publication into the exact broker stream
19+// request and tab. A publication between commit and resolution must never
20+// retarget the commit.
21+func TestPickerCommitResolvesTheCommittedRow(t *testing.T) {
22+ now := time.Unix(1000, 0)
23+ // tabbed publishes session "work" at revision with tabs t1, t2, ... named
24+ // in order. A session with tabs is a header; only its tab rows commit.
25+ tabbed := func(revision ports.BrokerRevision, names ...string) ports.BrokerSnapshot {
26+ tabs := make([]catalogue.RemoteCatalogTab, 0, len(names))
27+ for i, name := range names {
28+ tabs = append(tabs, pickerTestTab(fmt.Sprintf("t%d", i+1), name, "", false))
29+ }
30+ return ports.BrokerSnapshot{Epoch: 3, Revision: revision, Daemons: []ports.BrokerDaemonObservation{
31+ pickerTestLocalObservation(now, pickerTestTabbed("work", 3, catalogue_Up, 1, "t1", tabs...)),
32+ }}
33+ }
34+ tests := []struct {
35+ name string
36+ // row is the label of the tab row the cursor commits.
37+ row string
38+ republished *ports.BrokerSnapshot
39+ wantTab domain.TabStableID
40+ wantErr pickerCatalogueErrorCode
41+ }{
42+ {name: "first tab commits its tab", row: "shell", wantTab: "t1"},
43+ {name: "second tab commits its tab", row: "build", wantTab: "t2"},
44+ {name: "unrelated republication keeps the commit", row: "build", republished: ptr(tabbed(2, "shell", "build", "logs")), wantTab: "t2"},
45+ {name: "tab closed after commit is refused", row: "build", republished: ptr(tabbed(2, "shell")), wantErr: pickerCatalogueGone},
46+ }
47+ for _, tt := range tests {
48+ t.Run(tt.name, func(t *testing.T) {
49+ controller, _ := pickerTestController(t)
50+ controller.ApplySnapshot(tabbed(1, "shell", "build"))
51+ key := pickerTabKey(t, controller.Catalogue().RecentLines(), "work", tt.row)
52+ for i := 0; i < 16; i++ {
53+ if current, ok := controller.CursorKey(); ok && current == key {
54+ break
55+ }
56+ require.True(t, controller.ConsumeTerminalRead([]byte("j")))
57+ }
58+ require.True(t, controller.ConsumeTerminalRead([]byte("\r")))
59+ op, committed := controller.TakeOp()
60+ require.True(t, op.commit)
61+ require.Equal(t, key, committed, "the commit captures the row under the cursor")
62+
63+ if tt.republished != nil {
64+ controller.ApplySnapshot(*tt.republished)
65+ }
66+ request, tab, err := controller.ResolveCommit(committed, pickerTestBase())
67+
68+ if tt.wantErr != 0 {
69+ require.True(t, pickerCatalogueErrorIs(err, tt.wantErr), "want %v, got %v", tt.wantErr, err)
70+ return
71+ }
72+ require.NoError(t, err)
73+ require.Equal(t, ports.BrokerAdmissionExact, request.Admission)
74+ require.Equal(t, "work", request.Target.SessionName)
75+ require.Equal(t, pickerTestBase().Stream, request.Stream)
76+ require.Equal(t, tt.wantTab, tab.preferred)
77+ })
78+ }
79+}
80+
81+// TestPickerCatalogueResolveTargetKinds covers every selection kind a commit
82+// key can carry: destinations resolve to their admission, while a CLI-only
83+// attach-by-name identity is refused as a picker commit.
84+func TestPickerCatalogueResolveTargetKinds(t *testing.T) {
85+ observation := pickerTestLocalObservation(time.Unix(1000, 0), pickerTestSession("alpha", 1, catalogue_Up))
86+ tests := []struct {
87+ name string
88+ ref pickerSelectionRef
89+ wantAdmission ports.BrokerStreamAdmission
90+ wantErr pickerCatalogueErrorCode
91+ }{
92+ {name: "exact session", ref: pickerSelectionRef{kind: pickerSelectionExact, lifecycle: pickerTestLifecycle(1), name: "alpha"}, wantAdmission: ports.BrokerAdmissionExact},
93+ {name: "create named", ref: pickerSelectionRef{kind: pickerSelectionCreateNamed, createName: "fresh"}, wantAdmission: ports.BrokerAdmissionCreateNamed},
94+ {name: "create named with invalid name", ref: pickerSelectionRef{kind: pickerSelectionCreateNamed, createName: "bad name/"}, wantErr: pickerCatalogueInvalidName},
95+ {name: "create ephemeral", ref: pickerSelectionRef{kind: pickerSelectionCreateEphemeral}, wantAdmission: ports.BrokerAdmissionCreateEphemeral},
96+ {name: "attach named is not a picker destination", ref: pickerSelectionRef{kind: pickerSelectionAttachNamed, name: "alpha"}, wantErr: pickerCatalogueUnavailable},
97+ {name: "unknown key", wantErr: pickerCatalogueUnknown},
98+ }
99+ for _, tt := range tests {
100+ t.Run(tt.name, func(t *testing.T) {
101+ catalogue, _ := pickerTestCatalogue(t)
102+ require.True(t, catalogue.Apply(ports.BrokerSnapshot{Epoch: 3, Revision: 1, Daemons: []ports.BrokerDaemonObservation{observation}}))
103+ key := "missing"
104+ if tt.ref.kind != 0 {
105+ key = "injected"
106+ tt.ref.epoch = 3
107+ tt.ref.local = true
108+ catalogue.mu.Lock()
109+ catalogue.refs[key] = tt.ref
110+ catalogue.mu.Unlock()
111+ }
112+
113+ request, _, err := catalogue.ResolveTarget(key, pickerTestBase())
114+
115+ if tt.wantErr != 0 {
116+ require.True(t, pickerCatalogueErrorIs(err, tt.wantErr), "want %v, got %v", tt.wantErr, err)
117+ return
118+ }
119+ require.NoError(t, err)
120+ require.Equal(t, tt.wantAdmission, request.Admission)
121+ })
122+ }
123+}
124+
125+func ptr[T any](v T) *T { return &v }
M internal/usecase/client/picker_composition.go +4 -12
@@ -72,20 +72,12 @@ func (p *Picker) TakeOp() (pickerOp, string) {
7272 return p.controller.TakeOp()
7373 }
7474
75-// ResolveKey resolves a committed catalogue key for the supervisor.
76-func (p *Picker) ResolveKey(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, error) {
75+// ResolveCommit resolves a committed key plus the exact tab it names.
76+func (p *Picker) ResolveCommit(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
7777 if p == nil || p.controller == nil {
78- return (*pickerController)(nil).ResolveKey(key, base)
78+ return (*pickerController)(nil).ResolveCommit(key, base)
7979 }
80- return p.controller.ResolveKey(key, base)
81-}
82-
83-// ResolveKeyTarget resolves a committed key plus the exact tab it names.
84-func (p *Picker) ResolveKeyTarget(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
85- if p == nil || p.controller == nil {
86- return (*pickerController)(nil).ResolveKeyTarget(key, base)
87- }
88- return p.controller.ResolveKeyTarget(key, base)
80+ return p.controller.ResolveCommit(key, base)
8981 }
9082
9183 // ResolveKill revalidates one kill key for the supervisor.
M internal/usecase/client/picker_controller.go +15 -40
@@ -45,7 +45,7 @@ import (
4545 // The commit seam is what lets the supervisor turn a user
4646 // commit into one exact broker stream without ever reading the presentation
4747 // model itself: the picker records the decision and the key it committed
48-// atomically, the supervisor wakes on OpsReady, and ResolveKey revalidates
48+// atomically, the supervisor wakes on OpsReady, and ResolveCommit revalidates
4949 // exactly that key. The picker never opens a stream, and the supervisor never
5050 // reconstructs a selection from a display label.
5151 type pickerHost interface {
@@ -56,9 +56,9 @@ type pickerHost interface {
5656 // TakeOp returns and clears the accumulated presentation decision together
5757 // with the catalogue key captured with a commit decision.
5858 TakeOp() (pickerOp, string)
59- // ResolveKey revalidates exactly one committed catalogue key into the
60- // exact broker stream request the user committed.
61- ResolveKey(string, pickerResolveBase) (ports.BrokerOpenStreamRequest, error)
59+ // ResolveCommit revalidates exactly one committed catalogue key into the
60+ // exact broker stream request and tab the user committed.
61+ ResolveCommit(string, pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error)
6262 // SetOwnsInput releases or re-acquires picker input ownership at an attach
6363 // boundary, so exactly one owner consumes the shared terminal reader.
6464 SetOwnsInput(bool)
@@ -580,7 +580,7 @@ func (p *pickerController) CursorKey() (string, bool) {
580580 // Resolve reads the mutable presentation model, so a concurrent ApplySnapshot
581581 // can move the cursor between the caller's commit decision and this call. A
582582 // driver that is committing a specific row must capture that row's key with
583-// the decision (TakeOp) and resolve it with ResolveKey instead.
583+// the decision (TakeOp) and resolve it with ResolveCommit instead.
584584 func (p *pickerController) Resolve(base pickerResolveBase) (ports.BrokerOpenStreamRequest, error) {
585585 if p == nil {
586586 return ports.BrokerOpenStreamRequest{}, pickerCatalogueError{Code: pickerCatalogueNoSelection, Text: "picker is not available"}
@@ -591,28 +591,18 @@ func (p *pickerController) Resolve(base pickerResolveBase) (ports.BrokerOpenStre
591591 p.Notify(pickerRefusalNotice(err))
592592 return ports.BrokerOpenStreamRequest{}, err
593593 }
594- return p.ResolveKey(key, base)
595-}
596-
597-// ResolveKey revalidates exactly the supplied catalogue key against the latest
598-// applied snapshot and returns the exact broker stream request. It is the
599-// commit path: the key captured atomically with the commit decision (see
600-// TakeOp) resolves the row the user committed even if the cursor has since
601-// moved. A refusal is bounded and is also surfaced as a notice.
602-func (p *pickerController) ResolveKey(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, error) {
603- if p == nil || p.catalogue == nil {
604- err := pickerCatalogueError{Code: pickerCatalogueNoSelection, Text: "picker is not available"}
605- if p != nil {
606- p.Notify(pickerRefusalNotice(err))
607- }
608- return ports.BrokerOpenStreamRequest{}, err
609- }
610- request, _, err := p.ResolveKeyTarget(key, base)
594+ request, _, err := p.ResolveCommit(key, base)
611595 return request, err
612596 }
613597
614-// ResolveKeyTarget is ResolveKey plus the exact tab the committed row names.
615-func (p *pickerController) ResolveKeyTarget(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
598+// ResolveCommit is the single commit path from a published row to an
599+// attachment target. It revalidates exactly the supplied catalogue key
600+// against the latest applied snapshot, in one catalogue transaction, and
601+// returns the exact broker stream request plus the tab the row names. The key
602+// captured atomically with the commit decision (see TakeOp) resolves the row
603+// the user committed even if the cursor has since moved. A refusal is bounded
604+// and is also surfaced as a notice.
605+func (p *pickerController) ResolveCommit(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
616606 if p == nil || p.catalogue == nil {
617607 err := pickerCatalogueError{Code: pickerCatalogueNoSelection, Text: "picker is not available"}
618608 if p != nil {
@@ -620,22 +610,7 @@ func (p *pickerController) ResolveKeyTarget(key string, base pickerResolveBase)
620610 }
621611 return ports.BrokerOpenStreamRequest{}, attachmentTab{}, err
622612 }
623- ref, ok := p.catalogue.Ref(key)
624- if !ok {
625- err := pickerCatalogueError{Code: pickerCatalogueUnknown, Text: "picker row is not in the catalogue"}
626- p.Notify(pickerRefusalNotice(err))
627- return ports.BrokerOpenStreamRequest{}, attachmentTab{}, err
628- }
629- var request ports.BrokerOpenStreamRequest
630- var tab attachmentTab
631- var err error
632- if ref.kind == pickerSelectionCreateNamed || ref.kind == pickerSelectionCreateEphemeral {
633- request, err = p.catalogue.Resolve(key, base)
634- } else if ref.kind == pickerSelectionExact {
635- request, tab, err = p.catalogue.ResolveTarget(key, base)
636- } else {
637- err = pickerCatalogueError{Code: pickerCatalogueUnavailable, Text: "this picker row is not a session destination"}
638- }
613+ request, tab, err := p.catalogue.ResolveTarget(key, base)
639614 if err != nil {
640615 p.Notify(pickerRefusalNotice(err))
641616 return ports.BrokerOpenStreamRequest{}, attachmentTab{}, err
M internal/usecase/client/picker_controller_test.go +4 -4
@@ -422,7 +422,7 @@ func TestSupervisorPickerFoldsPublicationsAndInput(t *testing.T) {
422422 reader := newPickerChunkReader()
423423 t.Cleanup(reader.close)
424424 terminal := &pickerRecordingTerminal{in: reader}
425- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
425+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
426426 service := newSupervisorTestService(ports.BrokerConnectionID{1})
427427 service.hub.publish(pickerTestSnapshot(3, 1, clock.Now(), "alpha", "beta"))
428428 return service, nil
@@ -468,7 +468,7 @@ func TestSupervisorPickerFoldsLaterPublication(t *testing.T) {
468468 terminal := &pickerRecordingTerminal{in: reader}
469469
470470 service := newSupervisorTestService(ports.BrokerConnectionID{1})
471- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
471+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
472472 service.hub.publish(pickerTestSnapshot(3, 1, clock.Now(), "alpha"))
473473 return service, nil
474474 })
@@ -518,7 +518,7 @@ func TestPickerControllerResolveKeyUsesCommittedRow(t *testing.T) {
518518 require.Equal(t, "beta", displayed.Target.SessionName)
519519
520520 // ...while the captured key resolves exactly the committed row.
521- committed, err := controller.ResolveKey(committedKey, pickerTestBase())
521+ committed, _, err := controller.ResolveCommit(committedKey, pickerTestBase())
522522 require.NoError(t, err)
523523 require.Equal(t, "alpha", committed.Target.SessionName)
524524 }
@@ -554,7 +554,7 @@ func TestPickerControllerCommittedKeySurvivesConcurrentApply(t *testing.T) {
554554 if !op.commit || key == "" {
555555 continue
556556 }
557- request, err := controller.ResolveKey(key, pickerTestBase())
557+ request, _, err := controller.ResolveCommit(key, pickerTestBase())
558558 if err != nil {
559559 continue
560560 }
M internal/usecase/client/picker_parity_test.go +1 -1
@@ -612,7 +612,7 @@ func TestPickerControllerRefusesFailingRemoteInstantly(t *testing.T) {
612612 controller.notices = ui.NewToastQueue[ui.Toast](ui.ToastQueueOptions{MaxVisible: pickerNoticeVisible})
613613 controller.mu.Unlock()
614614
615- _, _, err := controller.ResolveKeyTarget(pickerRowKeyByLabel(t, controller, "remote-a"), pickerTestBase())
615+ _, _, err := controller.ResolveCommit(pickerRowKeyByLabel(t, controller, "remote-a"), pickerTestBase())
616616 if tt.wantNotice == "" {
617617 require.NoError(t, err)
618618 return
M internal/usecase/client/preview_manager.go +3 -3
@@ -103,7 +103,7 @@ type previewManager struct {
103103 // previewDebounce is one armed selection. Its goroutine only forwards the
104104 // clock timer to wake and exits on fire or cancellation.
105105 type previewDebounce struct {
106- service ports.BrokerService
106+ service ports.BrokerNavigator
107107 route ports.BrokerPreviewRoute
108108 preview protocol.RemotePreviewRequest
109109 wake chan struct{}
@@ -112,7 +112,7 @@ type previewDebounce struct {
112112
113113 func (d *previewDebounce) cancel() { close(d.stop) }
114114
115-func (m *previewManager) armDebounce(service ports.BrokerService, route ports.BrokerPreviewRoute, preview protocol.RemotePreviewRequest) {
115+func (m *previewManager) armDebounce(service ports.BrokerNavigator, route ports.BrokerPreviewRoute, preview protocol.RemotePreviewRequest) {
116116 pending := &previewDebounce{service: service, route: route, preview: preview, wake: make(chan struct{}, 1), stop: make(chan struct{})}
117117 m.pending = pending
118118 if supervisorNil(m.clock) {
@@ -163,7 +163,7 @@ func (m *previewManager) selected(route ports.BrokerPreviewRoute, preview protoc
163163 // refresh follows the picker's selected row. A new selection shows its cached
164164 // frame (stale) or a loading placeholder at once, then subscribes after the
165165 // cursor rests for the debounce.
166-func (m *previewManager) refresh(service ports.BrokerService, host pickerHost, size domain.Size) {
166+func (m *previewManager) refresh(service ports.BrokerNavigator, host pickerHost, size domain.Size) {
167167 picker, ok := host.(pickerPreviewHost)
168168 if supervisorNil(service) || !ok {
169169 m.close(host)
M internal/usecase/client/resize_presentation_test.go +6 -6
@@ -228,7 +228,7 @@ type resizeHarnessOptions struct {
228228 // closeResizes hands the supervisor an already closed ResizeEvents channel.
229229 closeResizes bool
230230 // connect scripts the broker attempts; nil returns the harness service.
231- connect func(ctx context.Context, call int) (ports.BrokerService, error)
231+ connect func(ctx context.Context, call int) (ports.BrokerNavigator, error)
232232 }
233233
234234 // startResizeHarness builds and runs one supervisor over the resize-aware
@@ -250,7 +250,7 @@ func startResizeHarness(t *testing.T, options resizeHarnessOptions) *resizeSuper
250250 service.publish(3, 1)
251251 connect := options.connect
252252 if connect == nil {
253- connect = func(context.Context, int) (ports.BrokerService, error) { return service, nil }
253+ connect = func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil }
254254 }
255255 connector := newSupervisorTestConnector(connect)
256256 recorder := newResizeRenderRecorder(terminal)
@@ -442,7 +442,7 @@ func TestSupervisorResizeRepaintsConnectingRetryAndNonRetryableWaiting(t *testin
442442 name: "broker connect in flight",
443443 start: func(t *testing.T) (*resizeSupervisorHarness, State) {
444444 harness := startResizeHarness(t, resizeHarnessOptions{
445- connect: func(ctx context.Context, _ int) (ports.BrokerService, error) {
445+ connect: func(ctx context.Context, _ int) (ports.BrokerNavigator, error) {
446446 <-ctx.Done()
447447 return nil, ctx.Err()
448448 },
@@ -455,7 +455,7 @@ func TestSupervisorResizeRepaintsConnectingRetryAndNonRetryableWaiting(t *testin
455455 name: "retry cadence wait",
456456 start: func(t *testing.T) (*resizeSupervisorHarness, State) {
457457 harness := startResizeHarness(t, resizeHarnessOptions{
458- connect: func(context.Context, int) (ports.BrokerService, error) { return nil, unavailable },
458+ connect: func(context.Context, int) (ports.BrokerNavigator, error) { return nil, unavailable },
459459 })
460460 harness.clock.awaitTimer(t)
461461 // The cadence exists because the first attempt already failed, so its
@@ -470,7 +470,7 @@ func TestSupervisorResizeRepaintsConnectingRetryAndNonRetryableWaiting(t *testin
470470 name: "non-retryable picker wait",
471471 start: func(t *testing.T) (*resizeSupervisorHarness, State) {
472472 harness := startResizeHarness(t, resizeHarnessOptions{
473- connect: func(context.Context, int) (ports.BrokerService, error) { return nil, incompatible },
473+ connect: func(context.Context, int) (ports.BrokerNavigator, error) { return nil, incompatible },
474474 })
475475 require.Eventually(t, func() bool {
476476 state := harness.sup.State()
@@ -842,7 +842,7 @@ func TestResizeCollectorAndSupervisorJoinOnClosedEventsAndCancellation(t *testin
842842 t.Run("supervisor run joins on closed ResizeEvents and cancellation", func(t *testing.T) {
843843 harness := startResizeHarness(t, resizeHarnessOptions{
844844 closeResizes: true,
845- connect: func(context.Context, int) (ports.BrokerService, error) {
845+ connect: func(context.Context, int) (ports.BrokerNavigator, error) {
846846 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "down"}
847847 },
848848 })
M internal/usecase/client/supervisor.go +4 -4
@@ -576,7 +576,7 @@ func (s *Supervisor) Run(ctx context.Context) (retErr error) {
576576 // The active connection is owned across loop iterations. retire is
577577 // idempotent so every exit path closes exactly the connection it adopted.
578578 var (
579- service ports.BrokerService
579+ service ports.BrokerNavigator
580580 sub ports.BrokerSubscription
581581 )
582582 retire := func() {
@@ -725,7 +725,7 @@ func (s *Supervisor) Run(ctx context.Context) (retErr error) {
725725 // that produced it (see adoptAttempt's generation fence).
726726 type supervisorAttempt struct {
727727 generation uint64
728- service ports.BrokerService
728+ service ports.BrokerNavigator
729729 sub ports.BrokerSubscription
730730 err error
731731 }
@@ -886,7 +886,7 @@ type readyOutcome struct {
886886 // folded into the picker as they arrive; a commit decision wakes the loop so
887887 // the supervisor can admit exactly the row the user committed. It opens no
888888 // stream and starts no terminal work itself.
889-func (s *Supervisor) awaitReady(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, sub ports.BrokerSubscription) readyOutcome {
889+func (s *Supervisor) awaitReady(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, sub ports.BrokerSubscription) readyOutcome {
890890 if key := s.pendingPickerKey; key != "" {
891891 s.pendingPickerKey = ""
892892 return readyOutcome{commitKey: key}
@@ -957,7 +957,7 @@ func (s *Supervisor) awaitReady(ctx context.Context, input *terminalInputLifetim
957957 }
958958 }
959959
960-func (s *Supervisor) refreshPreview(service ports.BrokerService) {
960+func (s *Supervisor) refreshPreview(service ports.BrokerNavigator) {
961961 if s == nil || s.cfg.Picker == nil {
962962 return
963963 }
M internal/usecase/client/supervisor_attach.go +66 -60
@@ -277,7 +277,7 @@ func attachmentTerminatedOutcome(err error) attachmentOutcome {
277277 // allocated by the broker service — the single allocator on its own connection
278278 // — and is consumed even when resolution refuses, matching the never-reused
279279 // contract.
280-func (s *Supervisor) resolveInitialStreamRequest(service ports.BrokerService, snapshot ports.BrokerSnapshot, navigation InitialNavigation) (ports.BrokerOpenStreamRequest, error) {
280+func (s *Supervisor) resolveInitialStreamRequest(service ports.BrokerNavigator, snapshot ports.BrokerSnapshot, navigation InitialNavigation) (ports.BrokerOpenStreamRequest, error) {
281281 // The intent is resolved against the very snapshot the resolver saw, so the
282282 // authority the resolver translated its target into and the authority the
283283 // request is resolved from can never diverge.
@@ -310,26 +310,15 @@ func classifyInitialNavigationFailure(err error) error {
310310 return pickerCatalogueError{Code: pickerCatalogueNoSelection, Text: "initial navigation could not be resolved"}
311311 }
312312
313-func (s *Supervisor) resolveCommittedStreamRequest(service ports.BrokerService, key string) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
313+func (s *Supervisor) resolveCommittedStreamRequest(service ports.BrokerNavigator, key string) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
314314 stream, err := service.NextStreamID()
315315 if err != nil {
316316 return ports.BrokerOpenStreamRequest{}, attachmentTab{}, err
317317 }
318- base := pickerResolveBase{
318+ return s.cfg.Picker.ResolveCommit(key, pickerResolveBase{
319319 Connection: service.ConnectionID(),
320320 Stream: stream,
321- }
322- if resolver, ok := s.cfg.Picker.(pickerTargetResolver); ok {
323- return resolver.ResolveKeyTarget(key, base)
324- }
325- request, err := s.cfg.Picker.ResolveKey(key, base)
326- return request, attachmentTab{}, err
327-}
328-
329-// pickerTargetResolver is the optional tab-aware resolution of the real
330-// picker; a scripted picker may resolve sessions only.
331-type pickerTargetResolver interface {
332- ResolveKeyTarget(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error)
321+ })
333322 }
334323
335324 // pickerAttachmentTarget is one resolved attachment: the exact broker stream
@@ -474,7 +463,7 @@ type initialNavigationTake struct {
474463 // expires (the resolver's fallback, or a bounded refusal without one), or the
475464 // run ends. The returned snapshot is the publication the decision was made on,
476465 // so the stream request resolves against the same authority.
477-func (s *Supervisor) awaitInitialNavigationObservation(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, pending InitialNavigationNotObserved) initialNavigationTake {
466+func (s *Supervisor) awaitInitialNavigationObservation(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, pending InitialNavigationNotObserved) initialNavigationTake {
478467 timer := s.cfg.Clock.NewTimer(initialNavigationObservationBudget)
479468 defer timer.Stop()
480469 for {
@@ -513,7 +502,7 @@ func (s *Supervisor) awaitInitialNavigationObservation(ctx context.Context, inpu
513502 // the picker. It reports terminated=true only when the run itself must end
514503 // (process cancellation or terminal EOF); every attachment outcome returns to
515504 // the picker in the same process.
516-func (s *Supervisor) runInitialNavigation(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService) (bool, error) {
505+func (s *Supervisor) runInitialNavigation(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator) (bool, error) {
517506 // The intent is consumed against the first committed publication of the
518507 // adopted connection; the resolver and the request resolution share that one
519508 // read.
@@ -557,7 +546,7 @@ func (s *Supervisor) runInitialNavigation(ctx context.Context, input *terminalIn
557546 return s.runResolvedAttachment(ctx, input, service, pickerAttachmentTarget{request: request}, SessionEnvironmentLocalCLI)
558547 }
559548
560-func (s *Supervisor) runCommittedAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, key string) (bool, error) {
549+func (s *Supervisor) runCommittedAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, key string) (bool, error) {
561550 if s.cfg.Picker == nil {
562551 return false, nil
563552 }
@@ -571,7 +560,7 @@ func (s *Supervisor) runCommittedAttachment(ctx context.Context, input *terminal
571560 return s.runResolvedAttachment(ctx, input, service, pickerAttachmentTarget{request: request, tab: tab}, SessionEnvironmentLocalPicker)
572561 }
573562
574-func (s *Supervisor) runResolvedAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, target pickerAttachmentTarget, localProvenance SessionEnvironmentProvenance) (bool, error) {
563+func (s *Supervisor) runResolvedAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, target pickerAttachmentTarget, localProvenance SessionEnvironmentProvenance) (bool, error) {
575564 picker := s.cfg.Picker
576565 if picker == nil {
577566 return false, nil
@@ -590,14 +579,13 @@ func (s *Supervisor) runResolvedAttachment(ctx context.Context, input *terminalI
590579 picker.SetOwnsInput(true)
591580 input.acquirePicker()
592581 }()
593- // resuming is true while the loop reconnects a lost attachment: attempts
594- // then return transport-class failures as attachmentRetry instead of
595- // presenting them, so a retry stays on Connecting.
596- resuming := false
597- resumes := 0
582+ // budget.resuming is true while the loop reconnects a lost attachment:
583+ // attempts then return transport-class failures as attachmentRetry instead
584+ // of presenting them, so a retry stays on Connecting.
585+ var budget attachmentResumeBudget
598586 for {
599587 attemptStart := s.cfg.Clock.Now()
600- outcome := s.attachResolved(ctx, input, service, target, localProvenance, resuming)
588+ outcome := s.attachResolved(ctx, input, service, target, localProvenance, budget.resuming)
601589 switch outcome.kind {
602590 case attachmentTerminated:
603591 return true, outcome.cause
@@ -606,57 +594,75 @@ func (s *Supervisor) runResolvedAttachment(ctx context.Context, input *terminalI
606594 // ended, refused).
607595 return false, nil
608596 case attachmentSwap:
609- resumes = 0
610- resuming = false
611597 // A commit from the picker overlay to another target: the previous
612598 // attachment detached cleanly, and the swap goes through Connecting
613- // exactly like any committed selection. The stream identity is
614- // allocated now, not at commit: streams opened while the source was
615- // live (route publications) may have moved the connection's
616- // anti-replay window past an identity reserved earlier.
617- stream, err := service.NextStreamID()
618- if err != nil {
619- s.reportAttachmentFailure(err)
599+ // exactly like any committed selection.
600+ budget = attachmentResumeBudget{}
601+ next, ok := s.withFreshStream(service, outcome.target)
602+ if !ok {
620603 return false, nil
621604 }
622- target, localProvenance = outcome.target, SessionEnvironmentLocalPicker
623- target.request.Stream = stream
605+ target, localProvenance = next, SessionEnvironmentLocalPicker
624606 continue
625- case attachmentResume:
626- // A live attachment was lost. One that stayed up long enough
627- // starts a fresh resume budget; one that drops right after
628- // attaching keeps counting, so a flapping session gives up.
629- if s.cfg.Clock.Now().Sub(attemptStart) >= resumeStableAttachment {
630- resumes = 0
631- }
632607 case attachmentRetry:
633608 // A resume attempt hit a transport-class failure before
634609 // attaching (the route or destination is still down): try the
635610 // same target again.
636611 outcome.target = target
637612 }
638- resume, lastErr := outcome.target, outcome.cause
639- resumes++
640- if resumes > maxAttachmentResumes {
641- s.logger.Warn("client_attachment_resume_exhausted", "endpoint", resume.request.Endpoint, "session", resume.request.Target.SessionName, "attempts", resumes-1, "error", lastErr)
642- s.transition(supervisorEvent{kind: supervisorAttachEnded, err: lastErr})
613+ attempt, ok := budget.spend(outcome.kind, s.cfg.Clock.Now().Sub(attemptStart))
614+ if !ok {
615+ s.logger.Warn("client_attachment_resume_exhausted", "endpoint", outcome.target.request.Endpoint, "session", outcome.target.request.Target.SessionName, "attempts", attempt-1, "error", outcome.cause)
616+ s.transition(supervisorEvent{kind: supervisorAttachEnded, err: outcome.cause})
643617 s.notifyLifecycle(LifecycleNoticeDestinationFailed)
644- s.notifyAttachment(lastErr)
618+ s.notifyAttachment(outcome.cause)
645619 return false, nil
646620 }
647- resuming = true
648- if terminated, termErr, brokerLost := s.waitResume(ctx, input, service, resumes); terminated || brokerLost {
621+ if terminated, termErr, brokerLost := s.waitResume(ctx, input, service, attempt); terminated || brokerLost {
649622 return terminated, termErr
650623 }
651- stream, err := service.NextStreamID()
652- if err != nil {
653- s.reportAttachmentFailure(err)
624+ next, ok := s.withFreshStream(service, outcome.target)
625+ if !ok {
654626 return false, nil
655627 }
656- resume.request.Stream = stream
657- s.logger.Info("client_attachment_resume", "endpoint", resume.request.Endpoint, "session", resume.request.Target.SessionName, "attempt", resumes)
658- target = resume
628+ s.logger.Info("client_attachment_resume", "endpoint", next.request.Endpoint, "session", next.request.Target.SessionName, "attempt", attempt)
629+ target = next
630+ }
631+}
632+
633+// attachmentResumeBudget bounds how often one lost attachment reconnects.
634+type attachmentResumeBudget struct {
635+ used int
636+ resuming bool
637+}
638+
639+// spend records one resume after an attempt of the given kind that ran for
640+// up. A live attachment that stayed up for resumeStableAttachment starts a
641+// fresh budget; one that drops right after attaching keeps counting, so a
642+// flapping session gives up.
643+// It returns the 1-based resume attempt, and false once the budget is
644+// exhausted.
645+func (b *attachmentResumeBudget) spend(kind attachmentOutcomeKind, up time.Duration) (int, bool) {
646+ if kind == attachmentResume && up >= resumeStableAttachment {
647+ b.used = 0
648+ }
649+ b.used++
650+ b.resuming = true
651+ return b.used, b.used <= maxAttachmentResumes
652+}
653+
654+// withFreshStream gives target a newly allocated stream identity. It is
655+// allocated right before the open, never earlier: streams opened meanwhile
656+// (route publications) may have moved the connection's anti-replay window past
657+// an identity reserved at commit. A refusal is presented.
658+func (s *Supervisor) withFreshStream(service ports.BrokerNavigator, target pickerAttachmentTarget) (pickerAttachmentTarget, bool) {
659+ stream, err := service.NextStreamID()
660+ if err != nil {
661+ s.reportAttachmentFailure(err)
662+ return pickerAttachmentTarget{}, false
659663 }
664+ target.request.Stream = stream
665+ return target, true
660666 }
661667
662668 // attachResolved runs one resolved attachment attempt end to end: open the
@@ -664,7 +670,7 @@ func (s *Supervisor) runResolvedAttachment(ctx context.Context, input *terminalI
664670 // foreground grant, settle it, and classify the result. resuming marks an
665671 // attempt of the resume loop, whose transport-class failures are returned as
666672 // attachmentRetry instead of presented.
667-func (s *Supervisor) attachResolved(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, target pickerAttachmentTarget, localProvenance SessionEnvironmentProvenance, resuming bool) attachmentOutcome {
673+func (s *Supervisor) attachResolved(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, target pickerAttachmentTarget, localProvenance SessionEnvironmentProvenance, resuming bool) attachmentOutcome {
668674 request := target.request
669675 s.transition(supervisorEvent{kind: supervisorAttachBegin})
670676 deadline := startAttachmentDeadline(ctx, s.cfg.Clock)
@@ -734,7 +740,7 @@ func (s *Supervisor) attachResolved(ctx context.Context, input *terminalInputLif
734740 // context, terminal EOF, and broker-connection loss. The deadline is the only
735741 // other stop: when it fires before the worker settled, the attachment ends as
736742 // a typed timeout without claiming attachment.
737-func (s *Supervisor) settleAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, deadline *attachmentDeadline, run *attachmentRun, request ports.BrokerOpenStreamRequest, resuming bool) attachmentOutcome {
743+func (s *Supervisor) settleAttachment(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, deadline *attachmentDeadline, run *attachmentRun, request ports.BrokerOpenStreamRequest, resuming bool) attachmentOutcome {
738744 settled := make(chan attachmentSettlement, 1)
739745 go func() {
740746 event, adopted := run.Wait(deadline.Context())
@@ -905,7 +911,7 @@ func resumeTarget(request ports.BrokerOpenStreamRequest, fg *attachmentForegroun
905911 // next resume attempt. It settles early on cancellation or terminal EOF
906912 // (terminated), or on broker loss, which ends the resume and leaves the ready
907913 // loop to observe and retire the connection.
908-func (s *Supervisor) waitResume(ctx context.Context, input *terminalInputLifetime, service ports.BrokerService, attempt int) (terminated bool, termErr error, brokerLost bool) {
914+func (s *Supervisor) waitResume(ctx context.Context, input *terminalInputLifetime, service ports.BrokerNavigator, attempt int) (terminated bool, termErr error, brokerLost bool) {
909915 s.transition(supervisorEvent{kind: supervisorAttachBegin})
910916 delay := supervisorBackoffDelay(uint64(attempt), s.cfg.Jitter)
911917 timer := s.cfg.Clock.NewTimer(delay)
M internal/usecase/client/supervisor_attach_test.go +57 -6
@@ -266,7 +266,7 @@ type attachTestPicker struct {
266266 consumed int
267267 op pickerOp
268268 key string
269- // resolveErr makes ResolveKey refuse locally, which is how a test reaches
269+ // resolveErr makes ResolveCommit refuse locally, which is how a test reaches
270270 // the local-refusal classification without dialing anything.
271271 resolveErr error
272272 request ports.BrokerOpenStreamRequest
@@ -277,6 +277,8 @@ type attachTestPicker struct {
277277 consumeRequest ports.BrokerOpenStreamRequest
278278 // resolvedStream is the stream identity the last resolution reserved.
279279 resolvedStream ports.BrokerStreamID
280+ // tab is the tab every resolution names.
281+ tab attachmentTab
280282 }
281283
282284 func newAttachTestPicker() *attachTestPicker {
@@ -318,18 +320,18 @@ func (p *attachTestPicker) TakeOp() (pickerOp, string) {
318320 return op, key
319321 }
320322
321-func (p *attachTestPicker) ResolveKey(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, error) {
323+func (p *attachTestPicker) ResolveCommit(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
322324 p.mu.Lock()
323325 defer p.mu.Unlock()
324326 p.resolved++
325327 if p.resolveErr != nil {
326- return ports.BrokerOpenStreamRequest{}, p.resolveErr
328+ return ports.BrokerOpenStreamRequest{}, attachmentTab{}, p.resolveErr
327329 }
328330 request := p.request
329331 request.Connection = base.Connection
330332 request.Stream = base.Stream
331333 p.resolvedStream = base.Stream
332- return request, nil
334+ return request, p.tab, nil
333335 }
334336
335337 func (p *attachTestPicker) SetOwnsInput(owns bool) {
@@ -407,7 +409,7 @@ func startAttachHarnessConfig(t *testing.T, picker pickerHost, configure func(*S
407409 service := newSupervisorTestService(ports.BrokerConnectionID{1})
408410 service.publish(3, 1)
409411
410- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
412+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
411413 return service, nil
412414 })
413415 cfg := SupervisorConfig{
@@ -1315,6 +1317,55 @@ func fireResumeTimer(t *testing.T, clock *supervisorTestClock, attempt int) {
13151317 }
13161318 }
13171319
1320+func TestAttachmentResumeBudget(t *testing.T) {
1321+ brief := time.Second
1322+ tests := []struct {
1323+ name string
1324+ steps []attachmentOutcomeKind
1325+ ups []time.Duration
1326+ want []bool
1327+ }{
1328+ {name: "flapping resumes exhaust", steps: repeatKinds(attachmentResume, maxAttachmentResumes+1), ups: repeatDurations(brief, maxAttachmentResumes+1), want: append(repeatBools(true, maxAttachmentResumes), false)},
1329+ {name: "stable attachment restores the budget", steps: repeatKinds(attachmentResume, maxAttachmentResumes+2), ups: repeatDurations(resumeStableAttachment, maxAttachmentResumes+2), want: repeatBools(true, maxAttachmentResumes+2)},
1330+ {name: "retries never restore the budget", steps: repeatKinds(attachmentRetry, maxAttachmentResumes+1), ups: repeatDurations(resumeStableAttachment, maxAttachmentResumes+1), want: append(repeatBools(true, maxAttachmentResumes), false)},
1331+ }
1332+ for _, tt := range tests {
1333+ t.Run(tt.name, func(t *testing.T) {
1334+ var budget attachmentResumeBudget
1335+ require.False(t, budget.resuming)
1336+ for i, kind := range tt.steps {
1337+ _, ok := budget.spend(kind, tt.ups[i])
1338+ require.Equal(t, tt.want[i], ok, "step %d", i)
1339+ require.True(t, budget.resuming)
1340+ }
1341+ })
1342+ }
1343+}
1344+
1345+func repeatKinds(k attachmentOutcomeKind, n int) []attachmentOutcomeKind {
1346+ out := make([]attachmentOutcomeKind, n)
1347+ for i := range out {
1348+ out[i] = k
1349+ }
1350+ return out
1351+}
1352+
1353+func repeatDurations(d time.Duration, n int) []time.Duration {
1354+ out := make([]time.Duration, n)
1355+ for i := range out {
1356+ out[i] = d
1357+ }
1358+ return out
1359+}
1360+
1361+func repeatBools(b bool, n int) []bool {
1362+ out := make([]bool, n)
1363+ for i := range out {
1364+ out[i] = b
1365+ }
1366+ return out
1367+}
1368+
13181369 // TestSupervisorAttachmentLossResumesSameSession is the regression for a
13191370 // remote attachment that died with attachment_lost and left the client stuck:
13201371 // a stream lost after attachment reconnects to the exact session it was
@@ -1584,7 +1635,7 @@ func TestSupervisorAttachmentReachableFromRealPicker(t *testing.T) {
15841635 })
15851636
15861637 controller := newPickerController(clock, pickerTestFreshness, true)
1587- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) { return service, nil })
1638+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) { return service, nil })
15881639 sup := mustSupervisor(t, SupervisorConfig{
15891640 Connector: connector,
15901641 Terminal: terminal,
M internal/usecase/client/supervisor_integration_test.go +1 -1
@@ -167,7 +167,7 @@ func integrationSupervisor(t *testing.T, path string) (*Supervisor, *supervisorT
167167 t.Cleanup(reader.unblock)
168168 terminal := newSupervisorTestTerminal(reader)
169169 sup := mustSupervisor(t, SupervisorConfig{
170- Connector: brokeripc.NewConnector(path, brokeripc.Config{}),
170+ Connector: brokeripc.NewConnector(path, brokeripc.Config{}).Navigator(),
171171 Terminal: terminal,
172172 Clock: clock,
173173 Jitter: func() float64 { return 0 },
M internal/usecase/client/supervisor_overlay.go +1 -1
@@ -29,7 +29,7 @@ import (
2929 type attachmentPickerOverlay struct {
3030 sup *Supervisor
3131 run *attachmentRun
32- service ports.BrokerService
32+ service ports.BrokerNavigator
3333 request ports.BrokerOpenStreamRequest
3434 active bool
3535 // swapping is set once a commit elsewhere asked the live attachment to
M internal/usecase/client/supervisor_picker_kill.go +2 -2
@@ -64,7 +64,7 @@ func (s *Supervisor) setPickerCurrent(current pickerCurrent) {
6464 // startPickerKill resolves one kill key against the latest catalogue and runs
6565 // the kill. A refusal is already a picker notice; a second `x` while one kill
6666 // runs is refused rather than queued.
67-func (s *Supervisor) startPickerKill(service ports.BrokerService, key string) {
67+func (s *Supervisor) startPickerKill(service ports.BrokerNavigator, key string) {
6868 resolver, ok := s.cfg.Picker.(pickerKillResolver)
6969 if !ok || key == "" || supervisorNil(service) {
7070 return
@@ -98,7 +98,7 @@ func (s *Supervisor) startPickerKill(service ports.BrokerService, key string) {
9898
9999 // finishPickerKill reports one settled kill and asks the broker to re-observe
100100 // the local daemon, so the killed row leaves the catalogue promptly.
101-func (s *Supervisor) finishPickerKill(service ports.BrokerService, outcome pickerKillOutcome) {
101+func (s *Supervisor) finishPickerKill(service ports.BrokerNavigator, outcome pickerKillOutcome) {
102102 s.settlePickerKill()
103103 s.notifyPicker(pickerKillNotice(outcome))
104104 if !supervisorNil(service) {
M internal/usecase/client/supervisor_picker_parity_test.go +2 -10
@@ -20,11 +20,10 @@ import (
2020 // They drive the real supervisor, host, foreground, and worker with bounded
2121 // waits and no sleeps.
2222
23-// parityTestPicker adds the optional tab, kill, and notice seams of the real
24-// picker to the scripted picker. The fields are guarded by attachTestPicker.mu.
23+// parityTestPicker adds the optional kill and notice seams of the real picker
24+// to the scripted picker. The fields are guarded by attachTestPicker.mu.
2525 type parityTestPicker struct {
2626 *attachTestPicker
27- tab attachmentTab
2827 kill pickerKillTarget
2928 notices []string
3029 }
@@ -33,13 +32,6 @@ func newParityTestPicker() *parityTestPicker {
3332 return &parityTestPicker{attachTestPicker: newAttachTestPicker()}
3433 }
3534
36-func (p *parityTestPicker) ResolveKeyTarget(key string, base pickerResolveBase) (ports.BrokerOpenStreamRequest, attachmentTab, error) {
37- request, err := p.ResolveKey(key, base)
38- p.mu.Lock()
39- defer p.mu.Unlock()
40- return request, p.tab, err
41-}
42-
4335 func (p *parityTestPicker) ResolveKill(string) (pickerKillTarget, error) {
4436 p.mu.Lock()
4537 defer p.mu.Unlock()
M internal/usecase/client/supervisor_routes.go +6 -6
@@ -41,7 +41,7 @@ func (s *Supervisor) brokerChanged() <-chan struct{} {
4141
4242 // publishRoutes rebuilds the ledger over the live attachment and hands a
4343 // changed snapshot, or the first one of this attachment, to its worker.
44-func (s *Supervisor) publishRoutes(service ports.BrokerService, run *attachmentRun, request ports.BrokerOpenStreamRequest) {
44+func (s *Supervisor) publishRoutes(service ports.BrokerNavigator, run *attachmentRun, request ports.BrokerOpenStreamRequest) {
4545 target, _, known := s.attachments.committedView()
4646 if !known {
4747 return
@@ -67,7 +67,7 @@ func requestAuthority(request ports.BrokerOpenStreamRequest) routeAuthority {
6767
6868 // settleDaemonNavigation carries out one daemon navigation request over the
6969 // live attachment.
70-func (s *Supervisor) settleDaemonNavigation(service ports.BrokerService, overlay *attachmentPickerOverlay, message protocol.ServerMessage) {
70+func (s *Supervisor) settleDaemonNavigation(service ports.BrokerNavigator, overlay *attachmentPickerOverlay, message protocol.ServerMessage) {
7171 target, ok := s.resolveDaemonNavigation(service, overlay.run.token, overlay.request, message)
7272 if !ok {
7373 return
@@ -106,7 +106,7 @@ func navigationCauseActionID(message protocol.ServerMessage) uint64 {
106106 // takeSettledNavigation adopts a navigation request the worker handed over
107107 // just before its attachment ended, such as a close-and-dial handoff whose
108108 // daemon detached the source right after sending it.
109-func (s *Supervisor) takeSettledNavigation(service ports.BrokerService, token AttachmentToken, request ports.BrokerOpenStreamRequest) {
109+func (s *Supervisor) takeSettledNavigation(service ports.BrokerNavigator, token AttachmentToken, request ports.BrokerOpenStreamRequest) {
110110 message, ok := s.attachments.takeNavigation()
111111 if !ok || s.pendingSwap != nil {
112112 return
@@ -121,7 +121,7 @@ func (s *Supervisor) takeSettledNavigation(service ports.BrokerService, token At
121121
122122 // resolveDaemonNavigation turns one daemon request into an exact attachment
123123 // target. A refusal is answered on the attachment with the typed failure.
124-func (s *Supervisor) resolveDaemonNavigation(service ports.BrokerService, token AttachmentToken, request ports.BrokerOpenStreamRequest, message protocol.ServerMessage) (pickerAttachmentTarget, bool) {
124+func (s *Supervisor) resolveDaemonNavigation(service ports.BrokerNavigator, token AttachmentToken, request ports.BrokerOpenStreamRequest, message protocol.ServerMessage) (pickerAttachmentTarget, bool) {
125125 switch typed := message.(type) {
126126 case protocol.RouteNavigationAction:
127127 fail := func(code protocol.RouteFailureCode) (pickerAttachmentTarget, bool) {
@@ -168,7 +168,7 @@ func (s *Supervisor) resolveDaemonNavigation(service ports.BrokerService, token
168168 // daemon itself named one of its own lifecycles, so the attachment's own
169169 // authority is kept and only the exact target and tab change. The daemon
170170 // revalidates the exact identity on Hello.
171-func (s *Supervisor) resolveServingHandoff(service ports.BrokerService, request ports.BrokerOpenStreamRequest, handoff protocol.AttachTarget) (pickerAttachmentTarget, bool) {
171+func (s *Supervisor) resolveServingHandoff(service ports.BrokerNavigator, request ports.BrokerOpenStreamRequest, handoff protocol.AttachTarget) (pickerAttachmentTarget, bool) {
172172 if handoff.Endpoint != "" || handoff.SessionTarget != nil || handoff.ExactTarget == nil || handoff.Intent != protocol.IntentAttach {
173173 s.notifyPicker(domain.Notification{Code: domain.NoticeSessionUnavailable, Scope: "handoff", Severity: domain.NoticeWarn, Message: "the daemon asked for a destination this client cannot open"})
174174 return pickerAttachmentTarget{}, false
@@ -200,7 +200,7 @@ func (s *Supervisor) resolveRoute(ref protocol.RouteRef) (routeLedgerTarget, boo
200200
201201 // resolveRouteSelection resolves one route through the same catalogue rules
202202 // as a picker commit, against the latest broker publication.
203-func (s *Supervisor) resolveRouteSelection(service ports.BrokerService, selection pickerSelectionRef) (pickerAttachmentTarget, error) {
203+func (s *Supervisor) resolveRouteSelection(service ports.BrokerNavigator, selection pickerSelectionRef) (pickerAttachmentTarget, error) {
204204 stream, err := service.NextStreamID()
205205 if err != nil {
206206 return pickerAttachmentTarget{}, err
M internal/usecase/client/supervisor_test.go +18 -34
@@ -175,7 +175,7 @@ func (t *supervisorTestTerminal) restoreCount() int {
175175 // supervisorTestConnector scripts connection attempts and records concurrency,
176176 // so a test can prove attempts never overlap.
177177 type supervisorTestConnector struct {
178- connect func(ctx context.Context, call int) (ports.BrokerService, error)
178+ connect func(ctx context.Context, call int) (ports.BrokerNavigator, error)
179179
180180 mu sync.Mutex
181181 calls int
@@ -184,11 +184,11 @@ type supervisorTestConnector struct {
184184 started chan int
185185 }
186186
187-func newSupervisorTestConnector(connect func(ctx context.Context, call int) (ports.BrokerService, error)) *supervisorTestConnector {
187+func newSupervisorTestConnector(connect func(ctx context.Context, call int) (ports.BrokerNavigator, error)) *supervisorTestConnector {
188188 return &supervisorTestConnector{connect: connect, started: make(chan int, 32)}
189189 }
190190
191-func (c *supervisorTestConnector) Connect(ctx context.Context) (ports.BrokerService, error) {
191+func (c *supervisorTestConnector) Connect(ctx context.Context) (ports.BrokerNavigator, error) {
192192 c.mu.Lock()
193193 c.calls++
194194 call := c.calls
@@ -403,22 +403,6 @@ func (s *supervisorTestService) openedRequests() []ports.BrokerOpenStreamRequest
403403 return append([]ports.BrokerOpenStreamRequest(nil), s.openCalls...)
404404 }
405405
406-func (s *supervisorTestService) CloseStream(ports.BrokerConnectionID, ports.BrokerStreamID) error {
407- return nil
408-}
409-
410-func (s *supervisorTestService) AddHost(context.Context, string, ports.BrokerPolicy) (domain.RemoteRegistration, error) {
411- return domain.RemoteRegistration{}, nil
412-}
413-
414-func (s *supervisorTestService) RemoveHost(context.Context, domain.RemoteRegistration) (bool, error) {
415- return false, nil
416-}
417-
418-func (s *supervisorTestService) UpdateHostPolicy(context.Context, domain.RemoteRegistration, ports.BrokerPolicy) (domain.RemoteRegistration, error) {
419- return domain.RemoteRegistration{}, nil
420-}
421-
422406 func (s *supervisorTestService) RequestReconcile(endpoint string) {
423407 s.mu.Lock()
424408 s.reconciles = append(s.reconciles, endpoint)
@@ -664,7 +648,7 @@ func TestSupervisorPickerWithoutBroker(t *testing.T) {
664648 reader := newSupervisorTestReader()
665649 t.Cleanup(reader.unblock)
666650 terminal := newSupervisorTestTerminal(reader)
667- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
651+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
668652 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "broker down"}
669653 })
670654
@@ -726,7 +710,7 @@ func TestSupervisorPickerPublicationRequestsRepaint(t *testing.T) {
726710 renders := make(chan State, 16)
727711
728712 sup := mustSupervisor(t, SupervisorConfig{
729- Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
713+ Connector: newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
730714 return service, nil
731715 }),
732716 Terminal: newSupervisorTestTerminal(reader),
@@ -775,7 +759,7 @@ func TestSupervisorBrokerLossReconnectsWithFreshGeneration(t *testing.T) {
775759 first.publish(1, 1)
776760 second := newSupervisorTestService(ports.BrokerConnectionID{2})
777761
778- connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerService, error) {
762+ connector := newSupervisorTestConnector(func(_ context.Context, call int) (ports.BrokerNavigator, error) {
779763 switch call {
780764 case 1:
781765 return first, nil
@@ -856,7 +840,7 @@ func TestSupervisorCancellationClosesLateConnection(t *testing.T) {
856840 release := make(chan struct{})
857841 late := newSupervisorTestService(ports.BrokerConnectionID{9})
858842 late.publish(1, 1)
859- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
843+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
860844 <-release
861845 return late, nil
862846 })
@@ -897,7 +881,7 @@ func TestSupervisorIncompatibleStopsReconnecting(t *testing.T) {
897881 terminal := newSupervisorTestTerminal(reader)
898882
899883 incompatible := ports.BrokerError{Code: ports.BrokerErrorIncompatible, Text: "protocol"}
900- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
884+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
901885 return nil, incompatible
902886 })
903887 notified := make(chan error, 4)
@@ -933,7 +917,7 @@ func TestSupervisorIncompatibleStopsReconnecting(t *testing.T) {
933917 func TestSupervisorTerminalEOFRestoresRawOnce(t *testing.T) {
934918 clock := newSupervisorTestClock()
935919 terminal := newSupervisorTestTerminal(strings.NewReader(""))
936- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
920+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
937921 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "down"}
938922 })
939923
@@ -956,7 +940,7 @@ func TestSupervisorRawModePrecedesBroker(t *testing.T) {
956940 terminal := newSupervisorTestTerminal(reader)
957941
958942 enteredAfterRaw := make(chan bool, 1)
959- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
943+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
960944 enteredAfterRaw <- terminal.restoreCount() == 0
961945 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "down"}
962946 })
@@ -984,7 +968,7 @@ func TestSupervisorSingleAttemptAndTimer(t *testing.T) {
984968 reader := newSupervisorTestReader()
985969 t.Cleanup(reader.unblock)
986970 terminal := newSupervisorTestTerminal(reader)
987- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
971+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
988972 return nil, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "down"}
989973 })
990974
@@ -1065,7 +1049,7 @@ func TestSupervisorCancellationRacingSettlementIsTerminal(t *testing.T) {
10651049 for round := 0; round < supervisorCancellationRaceRounds; round++ {
10661050 release := make(chan struct{})
10671051 var raced *supervisorTestService
1068- race := startCancellationRace(t, func(context.Context, int) (ports.BrokerService, error) {
1052+ race := startCancellationRace(t, func(context.Context, int) (ports.BrokerNavigator, error) {
10691053 <-release
10701054 service, err := tc.attempt()
10711055 raced = service
@@ -1103,7 +1087,7 @@ func TestSupervisorCancellationRacingSettlementIsTerminal(t *testing.T) {
11031087 losing := newSupervisorTestService(ports.BrokerConnectionID{4})
11041088 losing.publish(1, 1)
11051089 losing.holdClose()
1106- race := startCancellationRace(t, func(context.Context, int) (ports.BrokerService, error) {
1090+ race := startCancellationRace(t, func(context.Context, int) (ports.BrokerNavigator, error) {
11071091 return losing, nil
11081092 })
11091093 require.Equal(t, 1, race.connector.awaitStart(t), "round %d", round)
@@ -1148,7 +1132,7 @@ type cancellationRace struct {
11481132 // startCancellationRace starts one supervisor run over a scripted connector. The
11491133 // reader is shared and never unblocked until the test ends, so the run can only
11501134 // end through cancellation.
1151-func startCancellationRace(t *testing.T, connect func(ctx context.Context, call int) (ports.BrokerService, error)) *cancellationRace {
1135+func startCancellationRace(t *testing.T, connect func(ctx context.Context, call int) (ports.BrokerNavigator, error)) *cancellationRace {
11521136 t.Helper()
11531137 ctx, cancel := context.WithCancel(context.Background())
11541138 reader := newSupervisorTestReader()
@@ -1315,7 +1299,7 @@ func TestSupervisorNormalizesUntypedConnectFailure(t *testing.T) {
13151299 terminal := newSupervisorTestTerminal(reader)
13161300
13171301 cause := errors.New("dial: connection refused")
1318- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
1302+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
13191303 return nil, cause
13201304 })
13211305 notified := make(chan error, 4)
@@ -1364,7 +1348,7 @@ func TestSupervisorNormalizesUntypedLoss(t *testing.T) {
13641348
13651349 service := newSupervisorTestService(ports.BrokerConnectionID{1})
13661350 service.publish(1, 1)
1367- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
1351+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
13681352 return service, nil
13691353 })
13701354 sup := mustSupervisor(t, SupervisorConfig{
@@ -1415,7 +1399,7 @@ func TestSupervisorNilSubscriptionIsTypedUnavailable(t *testing.T) {
14151399
14161400 base := newSupervisorTestService(ports.BrokerConnectionID{7})
14171401 svc := &supervisorNilSubService{supervisorTestService: base, sub: tc.sub}
1418- connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerService, error) {
1402+ connector := newSupervisorTestConnector(func(context.Context, int) (ports.BrokerNavigator, error) {
14191403 return svc, nil
14201404 })
14211405 sup := mustSupervisor(t, SupervisorConfig{
@@ -1496,7 +1480,7 @@ func TestSupervisorPickerCloseWhileOffline(t *testing.T) {
14961480 terminal := newSupervisorTestTerminal(reader)
14971481 clock := newSupervisorTestClock()
14981482 reached := make(chan struct{}, 1)
1499- connector := newSupervisorTestConnector(func(ctx context.Context, _ int) (ports.BrokerService, error) {
1483+ connector := newSupervisorTestConnector(func(ctx context.Context, _ int) (ports.BrokerNavigator, error) {
15001484 if phase == "connecting" {
15011485 reached <- struct{}{}
15021486 <-ctx.Done()
M internal/usecase/command/context_mock_test.go +10 -1
@@ -14,10 +14,19 @@ func NewMockContext(t interface {
1414 mock.TestingT
1515 Cleanup(func())
1616 }) *MockContext {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
1721 mock := &MockContext{}
1822 mock.Mock.Test(t)
1923
20- t.Cleanup(func() { mock.AssertExpectations(t) })
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
2130
2231 return mock
2332 }
A internal/usecase/daemon/action_runner_mock_test.go +96 -0
@@ -0,0 +1,96 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package daemon
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockdaemonActionRunner creates a new instance of mockdaemonActionRunner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockdaemonActionRunner(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockdaemonActionRunner {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockdaemonActionRunner{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockdaemonActionRunner is an autogenerated mock type for the daemonActionRunner type
35+type mockdaemonActionRunner struct {
36+ mock.Mock
37+}
38+
39+type mockdaemonActionRunner_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockdaemonActionRunner) EXPECT() *mockdaemonActionRunner_Expecter {
44+ return &mockdaemonActionRunner_Expecter{mock: &_m.Mock}
45+}
46+
47+// Run provides a mock function for the type mockdaemonActionRunner
48+func (_mock *mockdaemonActionRunner) Run(daemonActionRequestMoqParam daemonActionRequest) error {
49+ ret := _mock.Called(daemonActionRequestMoqParam)
50+
51+ if len(ret) == 0 {
52+ panic("no return value specified for Run")
53+ }
54+
55+ var r0 error
56+ if returnFunc, ok := ret.Get(0).(func(daemonActionRequest) error); ok {
57+ r0 = returnFunc(daemonActionRequestMoqParam)
58+ } else {
59+ r0 = ret.Error(0)
60+ }
61+ return r0
62+}
63+
64+// mockdaemonActionRunner_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
65+type mockdaemonActionRunner_Run_Call struct {
66+ *mock.Call
67+}
68+
69+// Run is a helper method to define mock.On call
70+// - daemonActionRequestMoqParam daemonActionRequest
71+func (_e *mockdaemonActionRunner_Expecter) Run(daemonActionRequestMoqParam any) *mockdaemonActionRunner_Run_Call {
72+ return &mockdaemonActionRunner_Run_Call{Call: _e.mock.On("Run", daemonActionRequestMoqParam)}
73+}
74+
75+func (_c *mockdaemonActionRunner_Run_Call) Run(run func(daemonActionRequestMoqParam daemonActionRequest)) *mockdaemonActionRunner_Run_Call {
76+ _c.Call.Run(func(args mock.Arguments) {
77+ var arg0 daemonActionRequest
78+ if args[0] != nil {
79+ arg0 = args[0].(daemonActionRequest)
80+ }
81+ run(
82+ arg0,
83+ )
84+ })
85+ return _c
86+}
87+
88+func (_c *mockdaemonActionRunner_Run_Call) Return(err error) *mockdaemonActionRunner_Run_Call {
89+ _c.Call.Return(err)
90+ return _c
91+}
92+
93+func (_c *mockdaemonActionRunner_Run_Call) RunAndReturn(run func(daemonActionRequestMoqParam daemonActionRequest) error) *mockdaemonActionRunner_Run_Call {
94+ _c.Call.Return(run)
95+ return _c
96+}
A internal/usecase/daemon/attachment_resize.go +285 -0
@@ -0,0 +1,285 @@
1+package daemon
2+
3+import (
4+ "github.com/bnema/vev/internal/domain"
5+ "github.com/bnema/vev/internal/ports"
6+)
7+
8+// requestResize reports reset invalidation completion for immediate
9+// attached requests, and coordinator schedule acceptance for async requests.
10+// Headless requests have no reset invalidation and report geometry completion.
11+func (g *sharedPTYGeometry) requestResize(d *Daemon, sess *session, ac *attachedClient, size domain.Size, immediate bool) bool {
12+ if ac == nil {
13+ return g.requestResizeForLease(d, sess, nil, nil, size, immediate)
14+ }
15+ rc := d.attachCoordinator(sess, nil, ac, true)
16+ return g.requestResizeForLease(d, sess, ac, rc.attachmentLease(ac), size, immediate)
17+}
18+
19+// requestResizeForLease carries the Connection's captured lease
20+// through the full resize transaction and every delayed retry callback.
21+func (g *sharedPTYGeometry) requestResizeForLease(d *Daemon, sess *session, ac *attachedClient, lease *attachmentLease, size domain.Size, immediate bool) bool {
22+ valid := sess != nil && size.Valid()
23+ d.observeRuntime(ports.RuntimeResizeRequested, 0, valid)
24+ if !valid {
25+ return false
26+ }
27+ if ac == nil {
28+ // Headless geometry has no coordinator/transport to coalesce, but keeps
29+ // the same prepare/apply/commit ordering.
30+ _, ok := g.applySessionLayout(d, sess, size, nil, nil)
31+ return ok
32+ }
33+ rc := sess.renderCoordinator()
34+ if rc == nil || !rc.leaseCurrent(lease, true) {
35+ return false
36+ }
37+ geometryClaim, claimed := g.claimSize(sess, ac, size)
38+ if !claimed {
39+ return false
40+ }
41+ resize := attachmentResize{d: d, sess: sess, ac: ac, lease: lease}
42+ if immediate {
43+ resize.epoch = rc.recordResizeRequestForLeaseWithClaim(size, ac, lease, geometryClaim)
44+ if resize.epoch == 0 {
45+ g.release(sess, geometryClaim)
46+ return false
47+ }
48+ return resize.run()
49+ }
50+ epoch := rc.scheduleResizeForLeaseWithClaim(size, ac, lease, geometryClaim, func(epoch uint64) {
51+ accepted := resize
52+ accepted.epoch = epoch
53+ accepted.run()
54+ })
55+ if epoch == 0 {
56+ g.release(sess, geometryClaim)
57+ }
58+ return epoch != 0
59+}
60+
61+// attachmentResize is one accepted resize of an attachment's session
62+// geometry. It owns the complete lifecycle after the coordinator admits an
63+// epoch: the session layout transaction (applySessionLayout), attachment size
64+// publication, bounded background retries for members whose PTY resize
65+// failed, and the single reset frame. The coordinator keeps scheduling and
66+// epoch fencing; this type keeps what an accepted epoch does.
67+type attachmentResize struct {
68+ d *Daemon
69+ sess *session
70+ ac *attachedClient
71+ lease *attachmentLease
72+ epoch uint64
73+}
74+
75+func (r attachmentResize) retryCurrent(rc *renderCoordinator) bool {
76+ return rc.retryCurrentForLease(r.epoch, r.ac, r.lease)
77+}
78+
79+func (r attachmentResize) scheduleRetry(rc *renderCoordinator, failed []resizeMember) {
80+ rc.scheduleResizeRetryForLease(r.epoch, r.ac, r.lease, func() { r.retry(failed) })
81+}
82+
83+// run is the accepted attachment resize: claim shared geometry, apply the
84+// session layout transaction, publish the attachment size, schedule retries
85+// for failed members, and emit exactly one reset frame. Every step is fenced
86+// by the attachment effect, the geometry claim, and the resize epoch.
87+func (r attachmentResize) run() bool {
88+ d, sess, ac, lease, epoch := r.d, r.sess, r.ac, r.lease, r.epoch
89+ g := &sess.geometry
90+ rc := sess.renderCoordinator()
91+ if rc == nil {
92+ return false
93+ }
94+ snap := rc.resizeSnapshot()
95+ geometryClaim := snap.geometryClaim
96+ if geometryClaim == nil {
97+ var claimed bool
98+ geometryClaim, claimed = g.claimSize(sess, ac, snap.size)
99+ if !claimed {
100+ return false
101+ }
102+ }
103+ effect, admitted := beginAttachmentLeaseEffect(sess, ac, lease)
104+ if !admitted {
105+ return false
106+ }
107+ defer effect.End()
108+ current := func() bool {
109+ return effect.current() && sess.geometry.current(geometryClaim) &&
110+ rc.resizeCurrentForLease(epoch, ac, lease, false)
111+ }
112+ if !current() {
113+ return false
114+ }
115+ d.exitCopyMode(ac)
116+ failed, ok := g.applySessionLayout(d, sess, snap.size, current, func() bool {
117+ return rc.resizeCurrentForLease(epoch, ac, lease, true)
118+ })
119+ if !ok {
120+ return false
121+ }
122+ // Revalidate while holding the attachment output boundary. A lease can be
123+ // retired after the layout commit but before this attachment-local size is
124+ // published; stale generations must not publish any remaining effects.
125+ d.observeBeforeResizeOwnerPostEffect(resizeOwnerPostCommitPublication)
126+ ac.sendMu.Lock()
127+ if !current() {
128+ ac.sendMu.Unlock()
129+ return false
130+ }
131+ ac.setSize(snap.size)
132+ ac.sendMu.Unlock()
133+ if !current() {
134+ return false
135+ }
136+ if len(failed) != 0 && rc.resizeRetryAvailableForLease(r.epoch, r.ac, r.lease) {
137+ r.scheduleRetry(rc, failed)
138+ }
139+ if !current() {
140+ return false
141+ }
142+ d.refreshBarScriptsIfDue(sess, d.clock.Now(), true)
143+ // A successful transaction publishes exactly one full S2 frame. The
144+ // coordinator is the only emission route and stale epochs never reach it.
145+ if !current() || !rc.invalidateForLeaseAtResizeEpoch(ac, lease, epoch, renderInvalidation{class: invalidateUrgent, reset: true, producer: "attachment_resize.go"}) {
146+ return false
147+ }
148+ // The resize debounce has already elapsed. Consume this sticky reset now;
149+ // fire preserves ACK and synchronized-output gates rather than scheduling a
150+ // second urgent deadline.
151+ if !current() {
152+ return false
153+ }
154+ rc.fireCurrent(false)
155+ return true
156+}
157+
158+// retryResizeMembers retries failed committed members through a freshly
159+// prepared tab transaction. The captured members identify retry candidates
160+// only: their rectangles must never cross this delayed boundary, because any
161+// later layout mutation may have changed their geometry or removed them.
162+func (r attachmentResize) retry(members []resizeMember) {
163+ d, sess := r.d, r.sess
164+ g := &sess.geometry
165+ rc := sess.renderCoordinator()
166+ if rc == nil || !r.retryCurrent(rc) {
167+ return
168+ }
169+
170+ // Retain tab order for deterministic external PTY ordering while collapsing
171+ // several failed members from the same tab into one canonical transaction.
172+ tabs := make([]*tab, 0, len(members))
173+ seen := make(map[*tab]struct{}, len(members))
174+ for _, member := range members {
175+ if member.tab == nil || member.isFloating || !resizeMemberOwnerCurrent(&member) {
176+ continue
177+ }
178+ if _, ok := seen[member.tab]; ok {
179+ continue
180+ }
181+ seen[member.tab] = struct{}{}
182+ tabs = append(tabs, member.tab)
183+ }
184+
185+ failed := make([]resizeMember, 0, len(members))
186+ succeeded := false
187+ for _, tb := range tabs {
188+ if !r.retryCurrent(rc) {
189+ return
190+ }
191+ // A later accepted layout transaction clears resizeRetry. In that case
192+ // this delayed callback has no remaining work and, importantly, must not
193+ // replay the obsolete rectangle it captured before the mutation.
194+ retryPending := false
195+ tb.mu.Lock()
196+ for _, member := range members {
197+ if member.tab != tb || member.pane == nil || tb.panes[member.pane.id] != member.pane {
198+ continue
199+ }
200+ member.pane.mu.Lock()
201+ retryPending = retryPending || member.pane.resizeRetry
202+ member.pane.mu.Unlock()
203+ }
204+ tb.mu.Unlock()
205+ if !retryPending {
206+ continue
207+ }
208+
209+ // applyTabLayoutTransaction captures the current generation, pane
210+ // pointers, and solved rectangles, and validates them again before any
211+ // VT/rectangle publication. It also preserves the resize gate and
212+ // degradation notice behavior for another failed external attempt.
213+ freshFailed, ok := g.applyTabLayoutTransaction(d, sess, tb, func() bool {
214+ return r.retryCurrent(rc)
215+ })
216+ if !ok || !r.retryCurrent(rc) {
217+ return
218+ }
219+ failed = append(failed, freshFailed...)
220+ // A retry success is a formerly failed, still-current target whose
221+ // canonical apply cleared its retry bit. A collapsed or removed target
222+ // is neither a retry completion nor a reason to publish a reset.
223+ tb.mu.Lock()
224+ for _, member := range members {
225+ if member.tab != tb || member.pane == nil || tb.panes[member.pane.id] != member.pane {
226+ continue
227+ }
228+ member.pane.mu.Lock()
229+ succeeded = succeeded || !member.pane.resizeRetry
230+ member.pane.mu.Unlock()
231+ }
232+ tb.mu.Unlock()
233+ }
234+ for _, member := range members {
235+ if !member.isFloating || member.tab == nil || member.pane == nil {
236+ continue
237+ }
238+ if !r.retryCurrent(rc) {
239+ return
240+ }
241+ // Floating panes are outside tb.panes. Validate the exact accepted slot
242+ // before preparing a fresh geometry; applyVisibleFloatingLayout repeats
243+ // the same pointer/generation check around external PTY.Resize.
244+ member.tab.mu.Lock()
245+ currentSlot := member.tab.floating.state == floatingVisible &&
246+ member.tab.floating.generation == member.floatingGeneration &&
247+ member.tab.floating.pane == member.pane && resizeMemberOwnerCurrent(&member)
248+ retryPending := false
249+ if currentSlot {
250+ member.pane.mu.Lock()
251+ retryPending = member.pane.resizeRetry
252+ member.pane.mu.Unlock()
253+ }
254+ member.tab.mu.Unlock()
255+ if !currentSlot || !retryPending {
256+ continue
257+ }
258+ freshFailed, ok := g.applyVisibleFloatingLayoutForMember(d, sess, member.tab, func() bool {
259+ return r.retryCurrent(rc)
260+ }, &member)
261+ if !ok || !r.retryCurrent(rc) {
262+ return
263+ }
264+ failed = append(failed, freshFailed...)
265+ member.tab.mu.Lock()
266+ stillCurrent := member.tab.floating.state == floatingVisible &&
267+ member.tab.floating.generation == member.floatingGeneration &&
268+ member.tab.floating.pane == member.pane && resizeMemberOwnerCurrent(&member)
269+ member.tab.mu.Unlock()
270+ if stillCurrent && len(freshFailed) == 0 {
271+ member.pane.mu.Lock()
272+ succeeded = succeeded || !member.pane.resizeRetry
273+ member.pane.mu.Unlock()
274+ }
275+ }
276+ if len(failed) != 0 && rc.resizeRetryAvailableForLease(r.epoch, r.ac, r.lease) {
277+ r.scheduleRetry(rc, failed)
278+ }
279+ if succeeded {
280+ // Retry completion changes VT state after the original layout commit.
281+ // Keep a named session's eventual snapshot generation aligned with it.
282+ markSnapshotDirty(sess)
283+ rc.invalidateForLease(r.ac, r.lease, renderInvalidation{class: invalidateUrgent, reset: true, producer: "attachment_resize.go"})
284+ }
285+}
M internal/usecase/daemon/control.go +50 -9
@@ -465,25 +465,66 @@ func (e controlExec) runAction(request daemonActionRequest) error {
465465 if request.target.session == nil {
466466 request.target = e.target
467467 }
468- runner := e.actions
468+ _, err := e.d.dispatchAction(daemonActionDispatch{runner: e.actions, request: request, producer: "control.go"})
469+ return err
470+}
471+
472+// daemonActionDispatch describes one action started by any initiating path
473+// (palette, control command, key binding, or resize mode).
474+type daemonActionDispatch struct {
475+ // runner performs the mutation; nil selects the daemon's own actions.
476+ runner daemonActionRunner
477+ request daemonActionRequest
478+ // serialize, when non-nil, runs target resolution and the mutation under
479+ // that session's dispatch boundary. Callers already inside it leave it nil.
480+ serialize *session
481+ // resolveFrom and attachment resolve an unset target from the attachment's
482+ // current view; attachment also receives the follow-up render.
483+ resolveFrom *session
484+ attachment *attachedClient
485+ producer string
486+}
487+
488+// dispatchAction runs one daemon action through its whole lifecycle: target
489+// resolution, the mutation, no-change normalization, and the attached
490+// client's follow-up render. With serialize set, the render runs after the
491+// dispatch boundary is released; otherwise it runs inside the caller's
492+// boundary (palette and control paths). It reports whether the action
493+// changed anything; errDaemonActionNoChange is never returned.
494+func (d *Daemon) dispatchAction(x daemonActionDispatch) (bool, error) {
495+ runner := x.runner
469496 if runner == nil {
470- runner = daemonActions{d: e.d}
497+ runner = daemonActions{d: d}
498+ }
499+ request := x.request
500+ run := func() error {
501+ if request.target.session == nil && x.resolveFrom != nil {
502+ request.target = resolveDaemonActionTargetForAttachment(x.resolveFrom, x.attachment)
503+ }
504+ return runner.Run(request)
505+ }
506+ var err error
507+ if x.serialize != nil {
508+ err = x.serialize.runMutation(run)
509+ } else {
510+ err = run()
471511 }
472- err := runner.Run(request)
473512 if errors.Is(err, errDaemonActionNoChange) {
474- return nil
513+ return false, nil
475514 }
476515 if err != nil {
477- return err
516+ return false, err
478517 }
479- if e.actions == nil {
480- finishDaemonActionForClient(e.d, request, request.target.attachment, "control.go")
518+ ac := x.attachment
519+ if ac == nil {
520+ ac = request.target.attachment
481521 }
482- return nil
522+ finishDaemonActionForClient(d, request, ac, x.producer)
523+ return true, nil
483524 }
484525
485526 func finishDaemonActionForClient(d *Daemon, request daemonActionRequest, ac *attachedClient, producer string) {
486- if ac == nil {
527+ if d == nil || ac == nil {
487528 return
488529 }
489530 if request.kind == daemonActionFocusPane && request.target.tab != nil && request.target.pane != nil {
M internal/usecase/daemon/control_test.go +84 -11
@@ -21,6 +21,7 @@ import (
2121 "github.com/bnema/vev/internal/protocol/wire"
2222 "github.com/bnema/vev/internal/usecase/command"
2323 "github.com/bnema/vev/internal/usecase/layout"
24+ "github.com/stretchr/testify/mock"
2425 "github.com/stretchr/testify/require"
2526 )
2627
@@ -45,14 +46,15 @@ func TestPaletteAndControlShareExplicitDaemonActionTarget(t *testing.T) {
4546 tb.mu.Lock()
4647 pane := tb.focusedPane()
4748 tb.mu.Unlock()
48- spy := &actionRunnerSpy{}
49+ spy := newMockdaemonActionRunner(t)
50+ requests := recordActionRuns(spy, nil)
4951 target := daemonActionTarget{session: sess, tab: tb, pane: pane}
5052
5153 require.NoError(t, tt.palette(paletteExec{d: d, sess: sess, actions: spy}))
5254 require.NoError(t, tt.control(controlExec{d: d, sess: sess, tab: tb, actions: spy, target: target}))
5355
54- require.Len(t, spy.requests, 2)
55- for _, request := range spy.requests {
56+ require.Len(t, *requests, 2)
57+ for _, request := range *requests {
5658 require.Equal(t, tt.kind, request.kind)
5759 require.Same(t, sess, request.target.session)
5860 require.Same(t, tb, request.target.tab)
@@ -118,14 +120,14 @@ func TestConsumeOrExpelControlEdgeNoopReturnsOKAndPreservesFocus(t *testing.T) {
118120 requireNoInvalidation(t, invalidations)
119121 }
120122
121-type actionRunnerSpy struct {
122- requests []daemonActionRequest
123- err error
124-}
125-
126-func (s *actionRunnerSpy) Run(request daemonActionRequest) error {
127- s.requests = append(s.requests, request)
128- return s.err
123+// recordActionRuns makes runner return err and records every request it runs.
124+func recordActionRuns(runner *mockdaemonActionRunner, err error) *[]daemonActionRequest {
125+ var requests []daemonActionRequest
126+ runner.EXPECT().Run(mock.Anything).RunAndReturn(func(request daemonActionRequest) error {
127+ requests = append(requests, request)
128+ return err
129+ })
130+ return &requests
129131 }
130132
131133 func TestHandleCommandTimesOutWithRequestGeneration(t *testing.T) {
@@ -1528,3 +1530,74 @@ func TestCloseTabParticipantsChangedReportsRetryable(t *testing.T) {
15281530 require.Equal(t, 1, tabs, "an aborted last-tab close must retain the tab")
15291531 require.Equal(t, 1, sessionCount(d), "an aborted last-tab close must retain the session")
15301532 }
1533+
1534+func TestDispatchActionLifecycle(t *testing.T) {
1535+ boom := errors.New("boom")
1536+ tests := []struct {
1537+ name string
1538+ runErr error
1539+ serialize bool
1540+ // callerHolds enters dispatchAction already inside the dispatch
1541+ // boundary, as the palette and control paths do.
1542+ callerHolds bool
1543+ wantChanged bool
1544+ wantErr error
1545+ wantRender bool
1546+ }{
1547+ {name: "change renders the attachment", wantChanged: true, wantRender: true},
1548+ {name: "no change is success without render", runErr: errDaemonActionNoChange},
1549+ {name: "failure skips render", runErr: boom, wantErr: boom},
1550+ {name: "serialized change holds dispatch boundary", serialize: true, wantChanged: true, wantRender: true},
1551+ {name: "caller-held boundary is reused and still renders", callerHolds: true, wantChanged: true, wantRender: true},
1552+ }
1553+ for _, tt := range tests {
1554+ t.Run(tt.name, func(t *testing.T) {
1555+ d := newTestDaemon(t, nil, stubClock{})
1556+ sess := addControlSession(d, "work", "t_work", "p_work")
1557+ ac := &attachedClient{}
1558+ ac.setSession(sess)
1559+ sess.mu.Lock()
1560+ sess.registerAttachmentLocked(ac)
1561+ sess.mu.Unlock()
1562+ invalidations := make(chan renderInvalidation, 2)
1563+ rc := newRenderCoordinator(renderCoordinatorOptions{onInvalidate: func(inv renderInvalidation) { invalidations <- inv }})
1564+ rc.attach(ac)
1565+ sess.installRenderCoordinator(rc)
1566+
1567+ runner := newMockdaemonActionRunner(t)
1568+ runner.EXPECT().Run(mock.Anything).RunAndReturn(func(request daemonActionRequest) error {
1569+ require.Same(t, sess, request.target.session, "unset target resolves from the attachment")
1570+ require.Same(t, ac, request.target.attachment)
1571+ held := !sess.dispatchMu.TryLock()
1572+ if !held {
1573+ sess.dispatchMu.Unlock()
1574+ }
1575+ require.Equal(t, tt.serialize || tt.callerHolds, held, "dispatch boundary ownership")
1576+ return tt.runErr
1577+ }).Once()
1578+ x := daemonActionDispatch{runner: runner, request: daemonActionRequest{kind: daemonActionEqualizePanes}, resolveFrom: sess, attachment: ac, producer: "test"}
1579+ if tt.serialize {
1580+ x.serialize = sess
1581+ }
1582+
1583+ if tt.callerHolds {
1584+ sess.dispatchMu.Lock()
1585+ }
1586+ changed, err := d.dispatchAction(x)
1587+ if tt.callerHolds {
1588+ sess.dispatchMu.Unlock()
1589+ }
1590+
1591+ require.ErrorIs(t, err, tt.wantErr)
1592+ require.NotErrorIs(t, err, errDaemonActionNoChange)
1593+ require.Equal(t, tt.wantChanged, changed)
1594+ require.True(t, sess.dispatchMu.TryLock(), "dispatchAction must not leave the boundary held")
1595+ sess.dispatchMu.Unlock()
1596+ if tt.wantRender {
1597+ require.Equal(t, "test", awaitInvalidation(t, invalidations).producer)
1598+ } else {
1599+ requireNoInvalidation(t, invalidations)
1600+ }
1601+ })
1602+ }
1603+}
M internal/usecase/daemon/input.go +7 -14
@@ -483,26 +483,19 @@ func (h daemonKeyHandler) Action(action keys.Action, _ []byte) {
483483 }
484484 runAction := func(request daemonActionRequest) {
485485 request.effect = effect
486- runner := h.actions
487- if runner == nil {
488- runner = daemonActions{d: h.d}
489- }
490- if err := sess.runMutation(func() error {
491- request.target = resolveDaemonActionTargetForAttachment(sess, h.ac)
492- return runner.Run(request)
486+ if _, err := h.d.dispatchAction(daemonActionDispatch{
487+ runner: h.actions,
488+ request: request,
489+ serialize: sess,
490+ resolveFrom: sess,
491+ attachment: h.ac,
492+ producer: "input.go",
493493 }); err != nil {
494- if errors.Is(err, errDaemonActionNoChange) {
495- return
496- }
497494 var userErr *domain.UserError
498495 if !errors.As(err, &userErr) {
499496 err = resizeUserError(err)
500497 }
501498 h.d.reportError(sess, err)
502- return
503- }
504- if h.actions == nil {
505- finishDaemonActionForClient(h.d, request, h.ac, "input.go")
506499 }
507500 }
508501 switch action {
M internal/usecase/daemon/input_test.go +12 -19
@@ -28,22 +28,6 @@ import (
2828
2929 // --- test doubles -----------------------------------------------------------
3030
31-type blockingInputActionRunner struct {
32- admitted chan<- struct{}
33- release <-chan struct{}
34- mu *sync.Mutex
35- order *[]string
36-}
37-
38-func (r *blockingInputActionRunner) Run(daemonActionRequest) error {
39- close(r.admitted)
40- <-r.release
41- r.mu.Lock()
42- *r.order = append(*r.order, "keyboard")
43- r.mu.Unlock()
44- return nil
45-}
46-
4731 func TestAttachedKeyboardMutationSharesDispatchBoundaryWithCommand(t *testing.T) {
4832 d := newTestDaemon(t, nil, stubClock{})
4933 sess := addControlSession(d, "work", "t_work", "p_work")
@@ -54,7 +38,15 @@ func TestAttachedKeyboardMutationSharesDispatchBoundaryWithCommand(t *testing.T)
5438 var order []string
5539 admitted := make(chan struct{})
5640 release := make(chan struct{})
57- runner := &blockingInputActionRunner{admitted: admitted, release: release, mu: &orderMu, order: &order}
41+ runner := newMockdaemonActionRunner(t)
42+ runner.EXPECT().Run(mock.Anything).RunAndReturn(func(daemonActionRequest) error {
43+ close(admitted)
44+ <-release
45+ orderMu.Lock()
46+ order = append(order, "keyboard")
47+ orderMu.Unlock()
48+ return nil
49+ }).Once()
5850 handler := daemonKeyHandler{d: d, ac: ac, actions: runner}
5951 keyboardDone := make(chan struct{})
6052 go func() {
@@ -166,11 +158,12 @@ func TestConsumeOrExpelKeyActionPreservesRearrangementWarning(t *testing.T) {
166158 sess := addControlSession(d, "work", "t_work", "p_work")
167159 ac := &attachedClient{}
168160 ac.setSession(sess)
169- runner := &actionRunnerSpy{err: domain.UserWarn(
161+ runner := newMockdaemonActionRunner(t)
162+ runner.EXPECT().Run(mock.Anything).Return(domain.UserWarn(
170163 domain.NoticeLayoutTooSmall,
171164 "not enough space to rearrange pane",
172165 layout.ErrTooSmall,
173- )}
166+ )).Once()
174167
175168 daemonKeyHandler{d: d, ac: ac, actions: runner}.Action(tt.action, nil)
176169
M internal/usecase/daemon/palette.go +11 -20
@@ -758,27 +758,18 @@ type paletteExec struct {
758758
759759 func (e paletteExec) runAction(request daemonActionRequest) error {
760760 request.effect = e.effect
761- if request.target.session == nil {
762- request.target = resolveDaemonActionTargetForAttachment(e.sess, e.ac)
763- }
764- runner := e.actions
765- if runner == nil {
766- runner = daemonActions{d: e.d}
767- }
768- err := runner.Run(request)
769- if errors.Is(err, errDaemonActionNoChange) {
770- if e.redrawClosedPalette {
771- e.d.invalidateRender(e.sess, e.ac, true, "palette.go")
772- }
773- return nil
774- }
775- if err != nil {
776- return err
777- }
778- if e.actions == nil {
779- finishDaemonActionForClient(e.d, request, e.ac, "palette.go")
761+ changed, err := e.d.dispatchAction(daemonActionDispatch{
762+ runner: e.actions,
763+ request: request,
764+ resolveFrom: e.sess,
765+ attachment: e.ac,
766+ producer: "palette.go",
767+ })
768+ if err == nil && !changed && e.redrawClosedPalette && e.d != nil {
769+ // The palette closed before a no-op action; repaint what it covered.
770+ e.d.invalidateRender(e.sess, e.ac, true, "palette.go")
780771 }
781- return nil
772+ return err
782773 }
783774
784775 func (e paletteExec) CreateTab() error {
M internal/usecase/daemon/performance_benchmark_test.go +1 -1
@@ -1305,7 +1305,7 @@ func (f *performanceFixture) retryLatest() {
13051305 members = append(members, plan.members...)
13061306 }
13071307 failuresBefore, callsBefore := f.pty.metrics()
1308- f.sess.geometry.retryResizeMembers(f.d, f.sess, f.ac, f.sess.renderCoordinator().attachmentLease(f.ac), epoch, members)
1308+ attachmentResize{d: f.d, sess: f.sess, ac: f.ac, lease: f.sess.renderCoordinator().attachmentLease(f.ac), epoch: epoch}.retry(members)
13091309 failuresAfter, callsAfter := f.pty.metrics()
13101310 f.ptyFailures += failuresAfter - failuresBefore
13111311 if callsAfter > callsBefore {
A internal/usecase/daemon/render_publication_attempt_test.go +110 -0
@@ -0,0 +1,110 @@
1+package daemon
2+
3+import (
4+ "errors"
5+ "testing"
6+
7+ "github.com/stretchr/testify/mock"
8+ "github.com/stretchr/testify/require"
9+
10+ "github.com/bnema/vev/internal/protocol/wire"
11+)
12+
13+// TestPaintPublicationAttempt drives one complete publication attempt through
14+// paint (capture, compose, publish, settle) and asserts its observable
15+// outcome: what reached the transport, which VT damage was acknowledged,
16+// whether the attachment stayed owned, and that settlement never ran under the
17+// attachment's send lock.
18+func TestPaintPublicationAttempt(t *testing.T) {
19+ tests := []struct {
20+ name string
21+ sendErr error
22+ unown bool
23+ wantResult paintResult
24+ wantSent bool
25+ wantDamage bool
26+ wantAttached bool
27+ }{
28+ {name: "success emits and commits damage", wantResult: paintEmitted, wantSent: true, wantAttached: true},
29+ {name: "send failure retains damage and detaches", sendErr: errors.New("link lost"), wantResult: paintEmitted, wantDamage: true},
30+ {name: "unowned attachment is rejected before capture", unown: true, wantResult: paintRejected, wantDamage: true},
31+ }
32+ for _, tt := range tests {
33+ t.Run(tt.name, func(t *testing.T) {
34+ d, sess, ac, sends := newManualSessionWithPTYs(t, newQuietPTY())
35+ healthy := ac.transport()
36+ d.paint(sess, ac, true, nil)
37+ <-sends
38+
39+ p := sess.tabs[0].focusedPane()
40+ p.mu.Lock()
41+ p.screen.Write([]byte("\x1b[1;1Hchanged"))
42+ p.mu.Unlock()
43+
44+ tr := newMockServerConnection(t)
45+ var sendLockHeld []bool
46+ tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Envelope) error {
47+ if tt.sendErr != nil {
48+ return tt.sendErr
49+ }
50+ sends <- f
51+ return nil
52+ }).Maybe()
53+ tr.EXPECT().Close().RunAndReturn(func() error {
54+ // Send-error cleanup belongs to settlement, after sendMu is released.
55+ locked := !ac.sendMu.TryLock()
56+ if !locked {
57+ ac.sendMu.Unlock()
58+ }
59+ sendLockHeld = append(sendLockHeld, locked)
60+ return nil
61+ }).Maybe()
62+ ac.replaceTransport(tr)
63+ if tt.unown {
64+ sess.mu.Lock()
65+ delete(sess.attachments, ac)
66+ sess.mu.Unlock()
67+ }
68+
69+ result := d.paint(sess, ac, false, nil)
70+ d.attachmentCleanupWg.Wait()
71+
72+ require.Equal(t, tt.wantResult, result)
73+ if tt.sendErr != nil {
74+ require.NotEmpty(t, sendLockHeld, "send failure must close the failed link")
75+ }
76+ require.NotContains(t, sendLockHeld, true, "settlement ran under sendMu")
77+ if tt.wantSent {
78+ out := unmarshalTestOutput(t, (<-sends).Payload)
79+ require.Contains(t, string(out.Data), "changed")
80+ } else {
81+ select {
82+ case f := <-sends:
83+ t.Fatalf("unexpected frame %s", envelopeMessageName(t, f.Payload))
84+ default:
85+ }
86+ }
87+ p.mu.Lock()
88+ require.Equal(t, tt.wantDamage, len(p.screen.Damage()) != 0, "damage is acknowledged only after emission")
89+ p.mu.Unlock()
90+ sess.mu.Lock()
91+ _, attached := sess.attachments[ac]
92+ sess.mu.Unlock()
93+ require.Equal(t, tt.wantAttached, attached)
94+ require.True(t, ac.sendMu.TryLock(), "paint must release sendMu")
95+ ac.sendMu.Unlock()
96+
97+ if tt.wantDamage && !tt.unown {
98+ // A retry on a healthy link emits the retained change.
99+ sess.mu.Lock()
100+ sess.registerAttachmentLocked(ac)
101+ sess.mu.Unlock()
102+ ac.setSession(sess)
103+ ac.replaceTransport(healthy)
104+ require.Equal(t, paintEmitted, d.paint(sess, ac, false, nil))
105+ out := unmarshalTestOutput(t, (<-sends).Payload)
106+ require.Contains(t, string(out.Data), "changed")
107+ }
108+ })
109+ }
110+}
M internal/usecase/daemon/resize_mode.go +6 -5
@@ -131,14 +131,15 @@ func (d *Daemon) handleResizeInput(ac *attachedClient, data []byte) {
131131 return
132132 }
133133 for _, request := range requests {
134- if err := sess.runMutation(func() error {
135- request.target = resolveDaemonActionTargetForAttachment(sess, ac)
136- return (daemonActions{d: d}).Run(request)
134+ if _, err := d.dispatchAction(daemonActionDispatch{
135+ request: request,
136+ serialize: sess,
137+ resolveFrom: sess,
138+ attachment: ac,
139+ producer: "resize_mode.go",
137140 }); err != nil {
138141 d.reportError(sess, resizeUserError(err))
139- continue
140142 }
141- finishDaemonActionForClient(d, request, ac, "resize_mode.go")
142143 }
143144 if exit {
144145 d.invalidateRender(sess, ac, true, "resize_mode.go")
M internal/usecase/daemon/resize_mode_test.go +13 -10
@@ -27,27 +27,30 @@ func TestPaletteAndControlShareResizeAction(t *testing.T) {
2727 }
2828 for _, tt := range tests {
2929 t.Run(tt.name, func(t *testing.T) {
30- p := &actionRunnerSpy{}
31- c := &actionRunnerSpy{}
30+ p := newMockdaemonActionRunner(t)
31+ c := newMockdaemonActionRunner(t)
32+ paletteRequests := recordActionRuns(p, nil)
33+ controlRequests := recordActionRuns(c, nil)
3234 require.NoError(t, tt.palette(paletteExec{actions: p}))
3335 require.NoError(t, tt.control(controlExec{actions: c}))
34- require.Len(t, p.requests, 1)
35- require.Equal(t, p.requests, c.requests)
36- require.Equal(t, tt.kind, p.requests[0].kind)
37- require.Equal(t, tt.axis, p.requests[0].axis)
38- require.Equal(t, tt.delta, p.requests[0].delta)
36+ require.Len(t, *paletteRequests, 1)
37+ require.Equal(t, *paletteRequests, *controlRequests)
38+ require.Equal(t, tt.kind, (*paletteRequests)[0].kind)
39+ require.Equal(t, tt.axis, (*paletteRequests)[0].axis)
40+ require.Equal(t, tt.delta, (*paletteRequests)[0].delta)
3941 })
4042 }
4143 }
4244
4345 func TestControlEqualizeMapsResizeErrors(t *testing.T) {
44- runner := &actionRunnerSpy{err: layout.ErrTooSmall}
46+ runner := newMockdaemonActionRunner(t)
47+ requests := recordActionRuns(runner, layout.ErrTooSmall)
4548 err := (controlExec{actions: runner}).EqualizePanes()
4649 require.ErrorIs(t, err, layout.ErrTooSmall)
4750 var userErr *domain.UserError
4851 require.ErrorAs(t, err, &userErr)
49- require.Len(t, runner.requests, 1)
50- require.Equal(t, daemonActionEqualizePanes, runner.requests[0].kind)
52+ require.Len(t, *requests, 1)
53+ require.Equal(t, daemonActionEqualizePanes, (*requests)[0].kind)
5154 }
5255
5356 func TestResizeControlHeadlessAndErrors(t *testing.T) {
M internal/usecase/daemon/transactional_resize.go +0 -244
@@ -688,247 +688,3 @@ func (g *sharedPTYGeometry) applySessionLayout(d *Daemon, sess *session, size do
688688 return failed, true
689689 }
690690 }
691-
692-func (g *sharedPTYGeometry) runResizeTransaction(d *Daemon, sess *session, ac *attachedClient, lease *attachmentLease, epoch uint64) bool {
693- rc := sess.renderCoordinator()
694- if rc == nil {
695- return false
696- }
697- snap := rc.resizeSnapshot()
698- geometryClaim := snap.geometryClaim
699- if geometryClaim == nil {
700- var claimed bool
701- geometryClaim, claimed = g.claimSize(sess, ac, snap.size)
702- if !claimed {
703- return false
704- }
705- }
706- effect, admitted := beginAttachmentLeaseEffect(sess, ac, lease)
707- if !admitted {
708- return false
709- }
710- defer effect.End()
711- current := func() bool {
712- return effect.current() && sess.geometry.current(geometryClaim) &&
713- rc.resizeCurrentForLease(epoch, ac, lease, false)
714- }
715- if !current() {
716- return false
717- }
718- d.exitCopyMode(ac)
719- failed, ok := g.applySessionLayout(d, sess, snap.size, current, func() bool {
720- return rc.resizeCurrentForLease(epoch, ac, lease, true)
721- })
722- if !ok {
723- return false
724- }
725- // Revalidate while holding the attachment output boundary. A lease can be
726- // retired after the layout commit but before this attachment-local size is
727- // published; stale generations must not publish any remaining effects.
728- d.observeBeforeResizeOwnerPostEffect(resizeOwnerPostCommitPublication)
729- ac.sendMu.Lock()
730- if !current() {
731- ac.sendMu.Unlock()
732- return false
733- }
734- ac.setSize(snap.size)
735- ac.sendMu.Unlock()
736- if !current() {
737- return false
738- }
739- if len(failed) != 0 && rc.resizeRetryAvailableForLease(epoch, ac, lease) {
740- rc.scheduleResizeRetryForLease(epoch, ac, lease, func() { g.retryResizeMembers(d, sess, ac, lease, epoch, failed) })
741- }
742- if !current() {
743- return false
744- }
745- d.refreshBarScriptsIfDue(sess, d.clock.Now(), true)
746- // A successful transaction publishes exactly one full S2 frame. The
747- // coordinator is the only emission route and stale epochs never reach it.
748- if !current() || !rc.invalidateForLeaseAtResizeEpoch(ac, lease, epoch, renderInvalidation{class: invalidateUrgent, reset: true, producer: "transactional_resize.go"}) {
749- return false
750- }
751- // The resize debounce has already elapsed. Consume this sticky reset now;
752- // fire preserves ACK and synchronized-output gates rather than scheduling a
753- // second urgent deadline.
754- if !current() {
755- return false
756- }
757- rc.fireCurrent(false)
758- return true
759-}
760-
761-// retryResizeMembers retries failed committed members through a freshly
762-// prepared tab transaction. The captured members identify retry candidates
763-// only: their rectangles must never cross this delayed boundary, because any
764-// later layout mutation may have changed their geometry or removed them.
765-func (g *sharedPTYGeometry) retryResizeMembers(d *Daemon, sess *session, ac *attachedClient, lease *attachmentLease, epoch uint64, members []resizeMember) {
766- rc := sess.renderCoordinator()
767- if rc == nil || !rc.retryCurrentForLease(epoch, ac, lease) {
768- return
769- }
770-
771- // Retain tab order for deterministic external PTY ordering while collapsing
772- // several failed members from the same tab into one canonical transaction.
773- tabs := make([]*tab, 0, len(members))
774- seen := make(map[*tab]struct{}, len(members))
775- for _, member := range members {
776- if member.tab == nil || member.isFloating || !resizeMemberOwnerCurrent(&member) {
777- continue
778- }
779- if _, ok := seen[member.tab]; ok {
780- continue
781- }
782- seen[member.tab] = struct{}{}
783- tabs = append(tabs, member.tab)
784- }
785-
786- failed := make([]resizeMember, 0, len(members))
787- succeeded := false
788- for _, tb := range tabs {
789- if !rc.retryCurrentForLease(epoch, ac, lease) {
790- return
791- }
792- // A later accepted layout transaction clears resizeRetry. In that case
793- // this delayed callback has no remaining work and, importantly, must not
794- // replay the obsolete rectangle it captured before the mutation.
795- retryPending := false
796- tb.mu.Lock()
797- for _, member := range members {
798- if member.tab != tb || member.pane == nil || tb.panes[member.pane.id] != member.pane {
799- continue
800- }
801- member.pane.mu.Lock()
802- retryPending = retryPending || member.pane.resizeRetry
803- member.pane.mu.Unlock()
804- }
805- tb.mu.Unlock()
806- if !retryPending {
807- continue
808- }
809-
810- // applyTabLayoutTransaction captures the current generation, pane
811- // pointers, and solved rectangles, and validates them again before any
812- // VT/rectangle publication. It also preserves the resize gate and
813- // degradation notice behavior for another failed external attempt.
814- freshFailed, ok := g.applyTabLayoutTransaction(d, sess, tb, func() bool {
815- return rc.retryCurrentForLease(epoch, ac, lease)
816- })
817- if !ok || !rc.retryCurrentForLease(epoch, ac, lease) {
818- return
819- }
820- failed = append(failed, freshFailed...)
821- // A retry success is a formerly failed, still-current target whose
822- // canonical apply cleared its retry bit. A collapsed or removed target
823- // is neither a retry completion nor a reason to publish a reset.
824- tb.mu.Lock()
825- for _, member := range members {
826- if member.tab != tb || member.pane == nil || tb.panes[member.pane.id] != member.pane {
827- continue
828- }
829- member.pane.mu.Lock()
830- succeeded = succeeded || !member.pane.resizeRetry
831- member.pane.mu.Unlock()
832- }
833- tb.mu.Unlock()
834- }
835- for _, member := range members {
836- if !member.isFloating || member.tab == nil || member.pane == nil {
837- continue
838- }
839- if !rc.retryCurrentForLease(epoch, ac, lease) {
840- return
841- }
842- // Floating panes are outside tb.panes. Validate the exact accepted slot
843- // before preparing a fresh geometry; applyVisibleFloatingLayout repeats
844- // the same pointer/generation check around external PTY.Resize.
845- member.tab.mu.Lock()
846- currentSlot := member.tab.floating.state == floatingVisible &&
847- member.tab.floating.generation == member.floatingGeneration &&
848- member.tab.floating.pane == member.pane && resizeMemberOwnerCurrent(&member)
849- retryPending := false
850- if currentSlot {
851- member.pane.mu.Lock()
852- retryPending = member.pane.resizeRetry
853- member.pane.mu.Unlock()
854- }
855- member.tab.mu.Unlock()
856- if !currentSlot || !retryPending {
857- continue
858- }
859- freshFailed, ok := g.applyVisibleFloatingLayoutForMember(d, sess, member.tab, func() bool {
860- return rc.retryCurrentForLease(epoch, ac, lease)
861- }, &member)
862- if !ok || !rc.retryCurrentForLease(epoch, ac, lease) {
863- return
864- }
865- failed = append(failed, freshFailed...)
866- member.tab.mu.Lock()
867- stillCurrent := member.tab.floating.state == floatingVisible &&
868- member.tab.floating.generation == member.floatingGeneration &&
869- member.tab.floating.pane == member.pane && resizeMemberOwnerCurrent(&member)
870- member.tab.mu.Unlock()
871- if stillCurrent && len(freshFailed) == 0 {
872- member.pane.mu.Lock()
873- succeeded = succeeded || !member.pane.resizeRetry
874- member.pane.mu.Unlock()
875- }
876- }
877- if len(failed) != 0 && rc.resizeRetryAvailableForLease(epoch, ac, lease) {
878- rc.scheduleResizeRetryForLease(epoch, ac, lease, func() { g.retryResizeMembers(d, sess, ac, lease, epoch, failed) })
879- }
880- if succeeded {
881- // Retry completion changes VT state after the original layout commit.
882- // Keep a named session's eventual snapshot generation aligned with it.
883- markSnapshotDirty(sess)
884- rc.invalidateForLease(ac, lease, renderInvalidation{class: invalidateUrgent, reset: true, producer: "transactional_resize.go"})
885- }
886-}
887-
888-// requestResize reports reset invalidation completion for immediate
889-// attached requests, and coordinator schedule acceptance for async requests.
890-// Headless requests have no reset invalidation and report geometry completion.
891-func (g *sharedPTYGeometry) requestResize(d *Daemon, sess *session, ac *attachedClient, size domain.Size, immediate bool) bool {
892- if ac == nil {
893- return g.requestResizeForLease(d, sess, nil, nil, size, immediate)
894- }
895- rc := d.attachCoordinator(sess, nil, ac, true)
896- return g.requestResizeForLease(d, sess, ac, rc.attachmentLease(ac), size, immediate)
897-}
898-
899-// requestResizeForLease carries the Connection's captured lease
900-// through the full resize transaction and every delayed retry callback.
901-func (g *sharedPTYGeometry) requestResizeForLease(d *Daemon, sess *session, ac *attachedClient, lease *attachmentLease, size domain.Size, immediate bool) bool {
902- valid := sess != nil && size.Valid()
903- d.observeRuntime(ports.RuntimeResizeRequested, 0, valid)
904- if !valid {
905- return false
906- }
907- if ac == nil {
908- // Headless geometry has no coordinator/transport to coalesce, but keeps
909- // the same prepare/apply/commit ordering.
910- _, ok := g.applySessionLayout(d, sess, size, nil, nil)
911- return ok
912- }
913- rc := sess.renderCoordinator()
914- if rc == nil || !rc.leaseCurrent(lease, true) {
915- return false
916- }
917- geometryClaim, claimed := g.claimSize(sess, ac, size)
918- if !claimed {
919- return false
920- }
921- if immediate {
922- epoch := rc.recordResizeRequestForLeaseWithClaim(size, ac, lease, geometryClaim)
923- if epoch == 0 {
924- g.release(sess, geometryClaim)
925- return false
926- }
927- return g.runResizeTransaction(d, sess, ac, lease, epoch)
928- }
929- epoch := rc.scheduleResizeForLeaseWithClaim(size, ac, lease, geometryClaim, func(epoch uint64) { g.runResizeTransaction(d, sess, ac, lease, epoch) })
930- if epoch == 0 {
931- g.release(sess, geometryClaim)
932- }
933- return epoch != 0
934-}
M internal/usecase/daemon/transactional_resize_test.go +8 -8
@@ -336,7 +336,7 @@ func TestTransactionalResizeRetryMarksNamedSnapshotDirtyOnlyOnSuccess(t *testing
336336 require.True(t, sess.geometry.requestResize(d, sess, ac, domain.Size{Cols: 100, Rows: 30}, true))
337337 rc := sess.renderCoordinator()
338338 snapshot := rc.resizeSnapshot()
339- sess.geometry.retryResizeMembers(d, sess, ac, rc.attachmentLease(ac), snapshot.epoch, []resizeMember{{session: sess, tab: tb, pane: p, rect: p.rect}})
339+ attachmentResize{d: d, sess: sess, ac: ac, lease: rc.attachmentLease(ac), epoch: snapshot.epoch}.retry([]resizeMember{{session: sess, tab: tb, pane: p, rect: p.rect}})
340340
341341 sess.snapshotMu.Lock()
342342 generation := sess.snapshotGeneration
@@ -441,7 +441,7 @@ func TestTransactionalResizeRejectsNewerEpochBeforeSessionPublication(t *testing
441441 require.Equal(t, domain.Size{Cols: 80, Rows: 23}, domain.Size{Cols: p.screen.Columns(), Rows: p.screen.Rows()}, "rejected epoch published a VT size")
442442 }
443443
444- require.True(t, sess.geometry.runResizeTransaction(d, sess, ac, lease, newer))
444+ require.True(t, attachmentResize{d: d, sess: sess, ac: ac, lease: lease, epoch: newer}.run())
445445 for _, tb := range sess.tabs {
446446 require.Equal(t, domain.Size{Cols: 120, Rows: 32}, tb.size)
447447 p := tb.focusedPane()
@@ -486,7 +486,7 @@ func TestTransactionalResizeRechecksLeaseAtAttachmentPublication(t *testing.T) {
486486 <-release
487487 }
488488 done := make(chan bool, 1)
489- go func() { done <- sess.geometry.runResizeTransaction(d, sess, ac, lease, epoch) }()
489+ go func() { done <- attachmentResize{d: d, sess: sess, ac: ac, lease: lease, epoch: epoch}.run() }()
490490 <-entered
491491 newer := rc.recordResizeRequestForLease(domain.Size{Cols: 120, Rows: 34}, ac, lease)
492492 require.NotZero(t, newer)
@@ -557,7 +557,7 @@ func TestRetryOwnerCannotPublishFloatingGeometryAfterMove(t *testing.T) {
557557 rc := d.attachCoordinator(source, nil, ac, true)
558558 lease := rc.attachmentLease(ac)
559559 epoch := rc.recordResizeRequestForLease(domain.Size{Cols: 80, Rows: 24}, ac, lease)
560- require.True(t, source.geometry.runResizeTransaction(d, source, ac, lease, epoch))
560+ require.True(t, attachmentResize{d: d, sess: source, ac: ac, lease: lease, epoch: epoch}.run())
561561
562562 destination := &session{sessionCore: sessionCore{id: "destination", name: "destination"}, ctx: source.ctx, tabs: []*tab{tb}}
563563 publishPaneOwner(popup, destination, tb, 7)
@@ -571,7 +571,7 @@ func TestRetryOwnerCannotPublishFloatingGeometryAfterMove(t *testing.T) {
571571 source.snapshotMu.Unlock()
572572 requested := popupPTY.requested()
573573
574- source.geometry.retryResizeMembers(d, source, ac, lease, epoch, []resizeMember{{session: source, tab: tb, pane: popup, owner: owner, isFloating: true, floatingGeneration: 7}})
574+ attachmentResize{d: d, sess: source, ac: ac, lease: lease, epoch: epoch}.retry([]resizeMember{{session: source, tab: tb, pane: popup, owner: owner, isFloating: true, floatingGeneration: 7}})
575575
576576 require.Equal(t, requested, popupPTY.requested(), "stale floating retry reached the moved PTY")
577577 popup.mu.Lock()
@@ -787,11 +787,11 @@ func TestTransactionalResizeRetriesAcceptedFloatingSlotByIdentity(t *testing.T)
787787 lease := rc.attachmentLease(ac)
788788 epoch := rc.recordResizeRequestForLease(domain.Size{Cols: 80, Rows: 24}, ac, lease)
789789 require.NotZero(t, epoch)
790- require.True(t, sess.geometry.runResizeTransaction(d, sess, ac, lease, epoch))
790+ require.True(t, attachmentResize{d: d, sess: sess, ac: ac, lease: lease, epoch: epoch}.run())
791791 first := popupPTY.requested()
792792 require.Len(t, first, 1)
793793
794- sess.geometry.retryResizeMembers(d, sess, ac, lease, epoch, []resizeMember{{session: sess, tab: tb, pane: popup, isFloating: true, floatingGeneration: 7}})
794+ attachmentResize{d: d, sess: sess, ac: ac, lease: lease, epoch: epoch}.retry([]resizeMember{{session: sess, tab: tb, pane: popup, isFloating: true, floatingGeneration: 7}})
795795 retried := popupPTY.requested()
796796 require.Len(t, retried, 2)
797797 require.Equal(t, first[0], retried[1], "retry must use the current validated floating slot geometry")
@@ -805,7 +805,7 @@ func TestTransactionalResizeRetriesAcceptedFloatingSlotByIdentity(t *testing.T)
805805 tb.mu.Lock()
806806 tb.floating = floatingSlot{state: floatingVisible, pane: replacement, generation: 8}
807807 tb.mu.Unlock()
808- sess.geometry.retryResizeMembers(d, sess, ac, lease, epoch, []resizeMember{{session: sess, tab: tb, pane: popup, isFloating: true, floatingGeneration: 7}})
808+ attachmentResize{d: d, sess: sess, ac: ac, lease: lease, epoch: epoch}.retry([]resizeMember{{session: sess, tab: tb, pane: popup, isFloating: true, floatingGeneration: 7}})
809809 require.Empty(t, replacementPTY.requested(), "a replaced floating slot must not inherit an old retry")
810810 }
811811

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close