package main import ( "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/capacity" ) // fakeCapacityEmitter captures the capacity_awaken broadcast args so the // composition-root test can assert the wire forwards the transition to the sink. type fakeCapacityEmitter struct { callCount int sessionID string fromState string toState string tool string } func (f *fakeCapacityEmitter) BroadcastCapacityAwaken(sessionID, fromState, toState, tool string) { f.callCount++ f.sessionID = sessionID f.fromState = fromState f.toState = toState f.tool = tool } // TestOnCapacityBroadcastsAwaken exercises the audit-gap fix (#6): a capacity // state transition received by the loop's OnCapacity sink is forwarded to the // gateway as a capacity_awaken broadcast carrying the originating session and the // frontend AwakenPayload fields (fromState, toState, tool). func TestOnCapacityBroadcastsAwaken(t *testing.T) { fake := &fakeCapacityEmitter{} a := &app{log: testLog(), capacitySink: fake} a.onCapacity(capacity.Event{ Type: capacity.EventAwaken, FromState: capacity.StateQuiet, ToState: capacity.StateAwake, Tool: "web_search", SessionID: "web", }) if fake.callCount != 1 { t.Fatalf("broadcast call count = %d, want 1", fake.callCount) } if fake.sessionID != "web" || fake.fromState != "quiet" || fake.toState != "awake" || fake.tool != "web_search" { t.Fatalf("broadcast args = {sessionID:%q from:%q to:%q tool:%q}, want {web,quiet,awake,web_search}", fake.sessionID, fake.fromState, fake.toState, fake.tool) } } // TestOnCapacityNilSinkNoPanic locks the guard: a boot/degraded path where the // gateway is not yet wired must not panic — the sink is optional. func TestOnCapacityNilSinkNoPanic(t *testing.T) { a := &app{log: testLog()} a.onCapacity(capacity.Event{ Type: capacity.EventAwaken, FromState: capacity.StateQuiet, ToState: capacity.StateFull, Tool: "code", SessionID: "web", }) }