package streamgate

import (
	"context"
	"errors"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

// testNow is a deterministic timestamp used in tests.
var testNow = time.Date(2026, 7, 24, 12, 0, 0, 0, time.UTC)

// testSink is a configurable test-only ReleaseSink that records calls and
// can be programmed to fail specific calls.
type testSink struct {
	mu                 sync.Mutex
	responseStarts     []ResponseStart
	releases           []ReleaseEvent
	terminals          []TerminalResult
	state              CommitState
	failAfterSuccesses int  // >0: fail after N successes; 0: no failure
	failAll            bool // if true, all releases fail
	successCount       int  // how many successful releases have occurred (only tracked when failAfterSuccesses > 0)
	onRelease          func(ReleaseEvent)
	onTerminal         func(TerminalResult)
}

func (s *testSink) CommitResponseStart(ctx context.Context, rs ResponseStart) (CommitState, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.responseStarts = append(s.responseStarts, rs)
	s.state = CommitStateStreamOpen
	return CommitStateStreamOpen, nil
}

func (s *testSink) Release(ctx context.Context, ev ReleaseEvent) (CommitState, error) {
	s.mu.Lock()
	if s.onRelease != nil {
		fn := s.onRelease
		s.mu.Unlock()
		fn(ev)
		s.mu.Lock()
	}
	defer s.mu.Unlock()
	if s.failAll {
		return "", errors.New("test: forced release failure")
	}
	if s.failAfterSuccesses > 0 {
		s.successCount++
		if s.successCount > s.failAfterSuccesses {
			return "", errors.New("test: forced release failure")
		}
	}
	s.releases = append(s.releases, ev)
	return s.state, nil
}

func (s *testSink) CommitTerminal(ctx context.Context, tr TerminalResult) (CommitState, error) {
	s.mu.Lock()
	if s.onTerminal != nil {
		fn := s.onTerminal
		s.mu.Unlock()
		fn(tr)
		s.mu.Lock()
	}
	defer s.mu.Unlock()
	s.terminals = append(s.terminals, tr)
	s.state = CommitStateTerminalCommitted
	return CommitStateTerminalCommitted, nil
}

// ---------------------------------------------------------------------------
// REVIEW_API-1: Request-scope staging and monotonic sink state
// ---------------------------------------------------------------------------

// TestCommitBoundaryStagesUntilFirstSafeRelease verifies that stage calls
// produce zero sink invocations and the first release commits start→event
// order with a single start.
func TestCommitBoundaryStagesUntilFirstSafeRelease(t *testing.T) {
	ctx := context.Background()
	sink := &testSink{}
	b, err := NewCommitBoundary(sink)
	if err != nil {
		t.Fatalf("NewCommitBoundary: %v", err)
	}

	rs, _ := NewResponseStart("ch", 200, map[string]string{"x-test": "v"}, testNow)

	if err := b.BeginAttempt("a1"); err != nil {
		t.Fatalf("BeginAttempt: %v", err)
	}

	if err := b.StageResponseStart("a1", rs); err != nil {
		t.Fatalf("StageResponseStart: %v", err)
	}

	if got := b.State(); got != CommitStateTransportUncommitted {
		t.Errorf("state before release = %q, want %q", got, CommitStateTransportUncommitted)
	}

	ev1, _ := NewReleaseTextDeltaEvent("ch", "hello ", testNow)
	ev2, _ := NewReleaseTextDeltaEvent("ch", "world", testNow)

	prog, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev1, ev2})
	if err != nil {
		t.Fatalf("ReleaseSafe: %v", err)
	}

	if len(sink.responseStarts) != 1 {
		t.Errorf("responseStarts = %d, want 1", len(sink.responseStarts))
	}
	if len(sink.releases) != 2 {
		t.Errorf("releases = %d, want 2", len(sink.releases))
	}
	if prog.ReleasedEvents() != 2 {
		t.Errorf("ReleasedEvents = %d, want 2", prog.ReleasedEvents())
	}

	if got := b.State(); got != CommitStateStreamOpen {
		t.Errorf("state after release = %q, want %q", got, CommitStateStreamOpen)
	}

	// Second release still works (start already consumed).
	_, err = b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev1})
	if err != nil {
		t.Fatalf("second ReleaseSafe: %v", err)
	}
	if len(sink.releases) != 3 {
		t.Errorf("total releases after second call = %d, want 3", len(sink.releases))
	}
	if len(sink.responseStarts) != 1 {
		t.Errorf("total responseStarts = %d, want 1", len(sink.responseStarts))
	}
}

// TestCommitBoundaryPreservesProgressAndMonotonicState verifies the state
// transition table for start/body/error and that successful event count is
// preserved across failures.
func TestCommitBoundaryPreservesProgressAndMonotonicState(t *testing.T) {
	ctx := context.Background()

	t.Run("success_steps_preserve_count", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		evs := make([]ReleaseEvent, 5)
		for i := range evs {
			e, _ := NewReleaseTextDeltaEvent("ch", "chunk", testNow)
			evs[i] = e
		}

		prog, err := b.ReleaseSafe(ctx, "a1", evs)
		if err != nil {
			t.Fatalf("ReleaseSafe: %v", err)
		}
		if prog.ReleasedEvents() != 5 {
			t.Errorf("ReleasedEvents = %d, want 5", prog.ReleasedEvents())
		}
		if len(sink.releases) != 5 {
			t.Errorf("releases = %d, want 5", len(sink.releases))
		}
		if got := b.State(); got != CommitStateStreamOpen {
			t.Errorf("state = %q, want stream_open", got)
		}
	})

	t.Run("sink_error_preserves_progress", func(t *testing.T) {
		sink := &testSink{failAfterSuccesses: 1}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		evs := make([]ReleaseEvent, 3)
		for i := range evs {
			e, _ := NewReleaseTextDeltaEvent("ch", "chunk", testNow)
			evs[i] = e
		}

		prog, err := b.ReleaseSafe(ctx, "a1", evs)
		if err == nil {
			t.Error("expected error from ReleaseSafe")
		}
		// First event succeeded before the forced failure.
		if prog.ReleasedEvents() != 1 {
			t.Errorf("ReleasedEvents = %d, want 1", prog.ReleasedEvents())
		}
		if len(sink.releases) != 1 {
			t.Errorf("releases = %d, want 1", len(sink.releases))
		}
		if got := b.State(); got != CommitStateStreamOpen {
			t.Errorf("state = %q, want stream_open (preserved)", got)
		}
	})

	t.Run("begin_after_stream_open_rejected", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})

		err := b.BeginAttempt("a2")
		if err != ErrBoundaryUncommitted {
			t.Errorf("BeginAttempt error = %v, want ErrBoundaryUncommitted", err)
		}
	})

	t.Run("zero_release_events_rejected", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")

		_, err := b.ReleaseSafe(ctx, "a1", nil)
		if err == nil {
			t.Error("expected error for empty events")
		}
	})
}

// TestCommitBoundaryCommitsEmptySuccessAndTerminalOnce verifies that success
// terminal without body commits start first, terminal exactly once, and
// State() does not deadlock during callbacks.
func TestCommitBoundaryCommitsEmptySuccessAndTerminalOnce(t *testing.T) {
	ctx := context.Background()

	t.Run("success_terminal_no_body", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		tr, _ := NewSuccessTerminalResult("ch", testNow)
		if err := b.CommitTerminal(ctx, "a1", tr); err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}

		if len(sink.responseStarts) != 1 {
			t.Errorf("responseStarts = %d, want 1", len(sink.responseStarts))
		}
		if len(sink.terminals) != 1 {
			t.Errorf("terminals = %d, want 1", len(sink.terminals))
		}
		if got := b.State(); got != CommitStateTerminalCommitted {
			t.Errorf("state = %q, want terminal_committed", got)
		}
	})

	t.Run("second_terminal_rejected", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)
		b.CommitTerminal(ctx, "a1", tr)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err != ErrBoundaryAlreadyTerminal {
			t.Errorf("second CommitTerminal error = %v, want ErrBoundaryAlreadyTerminal", err)
		}
	})

	t.Run("state_no_deadlock_during_callback", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		done := make(chan struct{})
		go func() {
			defer close(done)
			for i := 0; i < 100; i++ {
				_ = b.State()
			}
		}()

		evs := make([]ReleaseEvent, 50)
		for i := range evs {
			e, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
			evs[i] = e
		}
		_, err := b.ReleaseSafe(ctx, "a1", evs)
		if err != nil {
			t.Fatalf("ReleaseSafe: %v", err)
		}

		<-done
	})

	t.Run("error_terminal_discards_staged_start", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		desc, _ := NewExternalDescriptor("generic", "internal_error", "error", "")
		causes, _ := NewFailureCauseChain([]FailureCause{})
		tr, _ := NewErrorTerminalResult("ch", desc, causes, testNow)

		if err := b.CommitTerminal(ctx, "a1", tr); err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}

		if len(sink.responseStarts) != 0 {
			t.Errorf("responseStarts = %d, want 0 (error discards start)", len(sink.responseStarts))
		}
		if len(sink.terminals) != 1 {
			t.Errorf("terminals = %d, want 1", len(sink.terminals))
		}
	})
}

// ---------------------------------------------------------------------------
// REVIEW_API-3: Attempt replacement and recovery strategy matrix
// ---------------------------------------------------------------------------

// TestCommitBoundaryReplacesOnlyUncommittedAttempt verifies that replacement
// discards the old attempt and staged start, allowing a new attempt to begin.
func TestCommitBoundaryReplacesOnlyUncommittedAttempt(t *testing.T) {
	ctx := context.Background()

	t.Run("replacement_discards_old_and_allows_new", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)

		// First attempt with staged start.
		b.BeginAttempt("old")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("old", rs)

		// Replace.
		if err := b.ReplaceUncommittedAttempt("old", "new"); err != nil {
			t.Fatalf("ReplaceUncommittedAttempt: %v", err)
		}

		// Old attempt should not work (no current attempt).
		err := b.StageResponseStart("old", rs)
		if err == nil {
			// Actually after replace, there's no current attempt, so
			// StageResponseStart should work since state is still uncommitted.
			// But the old attempt ID is not special anymore.
		}

		// New attempt should work.
		b.BeginAttempt("new")
		rs2, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("new", rs2)

		ev, _ := NewReleaseTextDeltaEvent("ch", "data", testNow)
		_, err = b.ReleaseSafe(ctx, "new", []ReleaseEvent{ev})
		if err != nil {
			t.Fatalf("ReleaseSafe: %v", err)
		}

		// Exactly one start from new attempt.
		if len(sink.responseStarts) != 1 {
			t.Errorf("responseStarts = %d, want 1 (only new attempt)", len(sink.responseStarts))
		}
	})

	t.Run("post_open_replacement_rejected", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})

		// After stream_open, we cannot begin a new attempt.
		err := b.BeginAttempt("a2")
		if err != ErrBoundaryUncommitted {
			t.Errorf("BeginAttempt after open error = %v, want ErrBoundaryUncommitted", err)
		}
	})
}

// TestCommitBoundaryCommitStrategyMatrix verifies the allowed strategy table
// for each commit state.
func TestCommitBoundaryCommitStrategyMatrix(t *testing.T) {
	ctx := context.Background()
	strategies := []RecoveryStrategy{
		RecoveryStrategyExactReplay,
		RecoveryStrategyContinuationRepair,
		RecoveryStrategySchemaRepair,
		RecoveryStrategyManagedContinuation,
	}

	t.Run("transport_uncommitted", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")

		expectations := map[RecoveryStrategy]bool{
			RecoveryStrategyExactReplay:         true,
			RecoveryStrategySchemaRepair:        true,
			RecoveryStrategyContinuationRepair:  false,
			RecoveryStrategyManagedContinuation: false,
		}
		for _, s := range strategies {
			got := b.CommitAllowsStrategy(s)
			want := expectations[s]
			if got != want {
				t.Errorf("CommitAllowsStrategy(%s) = %v, want %v", s, got, want)
			}
		}
	})

	t.Run("stream_open", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		b.StageResponseStart("a1", rs)
		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})

		expectations := map[RecoveryStrategy]bool{
			RecoveryStrategyExactReplay:         false,
			RecoveryStrategySchemaRepair:        false,
			RecoveryStrategyContinuationRepair:  true,
			RecoveryStrategyManagedContinuation: true,
		}
		for _, s := range strategies {
			got := b.CommitAllowsStrategy(s)
			want := expectations[s]
			if got != want {
				t.Errorf("CommitAllowsStrategy(%s) = %v, want %v", s, got, want)
			}
		}
	})

	t.Run("terminal_committed", func(t *testing.T) {
		sink := &testSink{}
		b, _ := NewCommitBoundary(sink)
		b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)
		b.CommitTerminal(ctx, "a1", tr)

		for _, s := range strategies {
			got := b.CommitAllowsStrategy(s)
			if got {
				t.Errorf("CommitAllowsStrategy(%s) = true, want false after terminal", s)
			}
		}
	})
}

func TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors(t *testing.T) {
	ctx := context.Background()

	t.Run("sink_error_with_forward_state_preserved", func(t *testing.T) {
		sink := &testSink{failAfterSuccesses: 1}
		b, _ := NewCommitBoundary(sink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		evs := make([]ReleaseEvent, 3)
		for i := range evs {
			e, _ := NewReleaseTextDeltaEvent("ch", "chunk", testNow)
			evs[i] = e
		}

		prog, err := b.ReleaseSafe(ctx, "a1", evs)
		if err == nil {
			t.Fatal("expected sink error")
		}
		if prog.ReleasedEvents() != 1 {
			t.Fatalf("ReleasedEvents = %d, want 1", prog.ReleasedEvents())
		}
		if b.State() != CommitStateStreamOpen {
			t.Fatalf("state = %v, want stream_open", b.State())
		}
	})

	t.Run("empty_returned_state_on_success_rejected", func(t *testing.T) {
		customSink := &customStateSink{
			startState: "",
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition for empty state on success, got %v", err)
		}
	})

	t.Run("invalid_state_regression_rejected", func(t *testing.T) {
		customSink := &customStateSink{
			startState:   CommitStateStreamOpen,
			releaseState: CommitStateTransportUncommitted, // invalid transition stream_open -> uncommitted
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition for state regression, got %v", err)
		}
	})

	t.Run("terminal_returns_non_terminal_state_rejected", func(t *testing.T) {
		customSink := &customStateSink{
			terminalState: CommitStateStreamOpen, // wrong: terminal should return terminal_committed
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)
		err := b.CommitTerminal(ctx, "a1", tr)
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition for terminal returning %q, got %v", CommitStateStreamOpen, err)
		}
		// Role mismatch does not prevent advancing to a valid forward state.
		// The callback returned stream_open which is a valid forward transition
		// from transport_uncommitted, so the state is preserved.
		if b.State() != CommitStateStreamOpen {
			t.Fatalf("state = %v, want stream_open (forward state preserved despite role mismatch)", b.State())
		}
	})

	t.Run("response_start_returns_non_stream_open_rejected", func(t *testing.T) {
		customSink := &customStateSink{
			startState: CommitStateTerminalCommitted, // wrong: response-start should return stream_open
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition for response-start returning %q, got %v", CommitStateTerminalCommitted, err)
		}
		// Role mismatch does not prevent advancing to a valid forward state.
		// The callback returned terminal_committed which is a valid forward
		// transition from transport_uncommitted, so the state is preserved.
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (forward state preserved despite role mismatch)", b.State())
		}
	})

	t.Run("release_returns_non_stream_open_rejected", func(t *testing.T) {
		customSink := &customStateSink{
			startState:   CommitStateStreamOpen,
			releaseState: CommitStateTerminalCommitted, // wrong: release should return stream_open
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition for release returning %q, got %v", CommitStateTerminalCommitted, err)
		}
		// Role mismatch does not prevent advancing to a valid forward state.
		// Response-start advanced to stream_open, and release returned
		// terminal_committed which is a valid forward transition, so state
		// is preserved at terminal_committed.
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (forward state preserved despite role mismatch)", b.State())
		}
	})

	t.Run("response_start_error_short_circuits_release", func(t *testing.T) {
		customSink := &customStateSink{
			startErr: errors.New("test: start failed"),
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if err == nil {
			t.Fatal("expected error from response-start short-circuit")
		}
	})

	t.Run("terminal_success_with_terminal_committed_allows_no_reentry", func(t *testing.T) {
		customSink := &customStateSink{
			terminalState: CommitStateTerminalCommitted,
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		if err := b.CommitTerminal(ctx, "a1", tr); err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed", b.State())
		}

		// Re-entry must be rejected.
		err := b.CommitTerminal(ctx, "a1", tr)
		if !errors.Is(err, ErrBoundaryAlreadyTerminal) {
			t.Fatalf("re-entry error = %v, want ErrBoundaryAlreadyTerminal", err)
		}
	})

	t.Run("terminal_error_with_terminal_committed_preserves_state", func(t *testing.T) {
		customSink := &customStateSink{
			terminalState: CommitStateTerminalCommitted,
			terminalErr:   errors.New("test: terminal network error"),
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err == nil {
			t.Fatal("expected error from terminal with error + terminal_committed")
		}
		// State should still be terminal_committed.
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (preserved)", b.State())
		}
		// Re-entry must still be rejected.
		err2 := b.CommitTerminal(ctx, "a1", tr)
		if !errors.Is(err2, ErrBoundaryAlreadyTerminal) {
			t.Fatalf("re-entry error = %v, want ErrBoundaryAlreadyTerminal", err2)
		}
	})

	t.Run("callback_exact_count", func(t *testing.T) {
		var callCounts struct {
			starts, releases, terminals int
		}
		customSink := &countingTestSink{
			inner:      &testSink{},
			onStart:    func() { callCounts.starts++ },
			onRelease:  func() { callCounts.releases++ },
			onTerminal: func() { callCounts.terminals++ },
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		evs := make([]ReleaseEvent, 2)
		for i := range evs {
			e, _ := NewReleaseTextDeltaEvent("ch", "chunk", testNow)
			evs[i] = e
		}

		_, err := b.ReleaseSafe(ctx, "a1", evs)
		if err != nil {
			t.Fatalf("ReleaseSafe: %v", err)
		}

		if callCounts.starts != 1 {
			t.Errorf("starts = %d, want 1", callCounts.starts)
		}
		if callCounts.releases != 2 {
			t.Errorf("releases = %d, want 2", callCounts.releases)
		}

		tr, _ := NewSuccessTerminalResult("ch", testNow)
		if err := b.CommitTerminal(ctx, "a1", tr); err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}

		if callCounts.terminals != 1 {
			t.Errorf("terminals = %d, want 1", callCounts.terminals)
		}

		// Second terminal should be rejected without calling sink.
		_ = b.CommitTerminal(ctx, "a1", tr)
		if callCounts.terminals != 1 {
			t.Errorf("terminals after re-entry = %d, want 1", callCounts.terminals)
		}
	})

	t.Run("attempt_mismatch_rejected_with_identity_error", func(t *testing.T) {
		// Defense-in-depth: verify that applySinkOutcomeLockedWithOpLocked
		// rejects a callback when res.attemptID != b.attemptID.
		// We trigger this by using a custom sink that, during a release
		// callback, changes b.attemptID via ReplaceUncommittedAttempt.
		// Since ReplaceUncommittedAttempt returns ErrBoundarySerializerConflict
		// when an active reservation exists, we instead directly verify the
		// identity check by calling applySinkOutcomeLockedWithOpLocked with
		// a reservation whose attemptID differs from the boundary's.
		b, _ := NewCommitBoundary(&testSink{})
		_ = b.BeginAttempt("a1")

		// Manually create a reservation with a different attemptID.
		b.mu.Lock()
		b.generation++
		fakeRes := &reservation{
			op:         boundaryOpRelease,
			attemptID:  "wrong-attempt",
			generation: b.generation,
		}
		b.activeReservation = fakeRes
		b.mu.Unlock()

		// Call applySinkOutcomeLockedWithOpLocked with the correct op.
		// The attemptID mismatch should produce ErrBoundaryInvalidAttempt.
		applyErr := b.applySinkOutcomeLockedWithOpLocked(
			fakeRes, boundaryOpRelease, CommitStateStreamOpen, nil,
		)
		if !errors.Is(applyErr, ErrBoundaryInvalidAttempt) {
			t.Fatalf("applySinkOutcomeLockedWithOpLocked error = %v, want ErrBoundaryInvalidAttempt", applyErr)
		}
		// State should still be preserved (forward state applied despite identity error).
		if b.State() != CommitStateStreamOpen {
			t.Fatalf("state = %v, want stream_open (forward state preserved)", b.State())
		}
	})

	t.Run("release_reservation_rejects_terminal_callback", func(t *testing.T) {
		// Defense-in-depth: verify that a release reservation rejects a terminal callback.
		b, _ := NewCommitBoundary(&testSink{})
		_ = b.BeginAttempt("a1")

		b.mu.Lock()
		b.generation++
		releaseRes := &reservation{
			op:         boundaryOpRelease,
			attemptID:  "a1",
			generation: b.generation,
		}
		b.activeReservation = releaseRes
		b.mu.Unlock()

		// Call applySinkOutcomeLockedWithOpLocked with terminal op (mismatch).
		applyErr := b.applySinkOutcomeLockedWithOpLocked(
			releaseRes, boundaryOpTerminal, CommitStateTerminalCommitted, nil,
		)
		if !errors.Is(applyErr, ErrBoundaryInvalidCallbackOp) {
			t.Fatalf("applySinkOutcomeLockedWithOpLocked error = %v, want ErrBoundaryInvalidCallbackOp", applyErr)
		}
		// Forward state should still be preserved.
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (forward state preserved)", b.State())
		}
	})

	t.Run("terminal_reservation_rejects_release_callback", func(t *testing.T) {
		// Defense-in-depth: verify that a terminal reservation rejects a release callback.
		b, _ := NewCommitBoundary(&testSink{})
		_ = b.BeginAttempt("a1")

		b.mu.Lock()
		b.generation++
		terminalRes := &reservation{
			op:         boundaryOpTerminal,
			attemptID:  "a1",
			generation: b.generation,
		}
		b.activeReservation = terminalRes
		b.mu.Unlock()

		// Call applySinkOutcomeLockedWithOpLocked with release op (mismatch).
		applyErr := b.applySinkOutcomeLockedWithOpLocked(
			terminalRes, boundaryOpRelease, CommitStateStreamOpen, nil,
		)
		if !errors.Is(applyErr, ErrBoundaryInvalidCallbackOp) {
			t.Fatalf("applySinkOutcomeLockedWithOpLocked error = %v, want ErrBoundaryInvalidCallbackOp", applyErr)
		}
	})

	t.Run("terminal_state_blocks_callback_reentry", func(t *testing.T) {
		// Verify that after terminal, ReleaseSafe and CommitTerminal return
		// ErrBoundaryAlreadyTerminal and sink counts do not increase.
		var startCount, relCount, termCount int
		countingSink := &countingTestSink{
			inner:      &testSink{},
			onStart:    func() { startCount++ },
			onRelease:  func() { relCount++ },
			onTerminal: func() { termCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if err != nil {
			t.Fatalf("ReleaseSafe: %v", err)
		}

		tr, _ := NewSuccessTerminalResult("ch", testNow)
		err = b.CommitTerminal(ctx, "a1", tr)
		if err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed", b.State())
		}

		// Re-entry via ReleaseSafe.
		_, err = b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrBoundaryAlreadyTerminal) {
			t.Fatalf("ReleaseSafe re-entry error = %v, want ErrBoundaryAlreadyTerminal", err)
		}
		if relCount != 1 {
			t.Fatalf("releases after ReleaseSafe re-entry = %d, want 1 (no increase)", relCount)
		}

		// Re-entry via CommitTerminal.
		err = b.CommitTerminal(ctx, "a1", tr)
		if !errors.Is(err, ErrBoundaryAlreadyTerminal) {
			t.Fatalf("CommitTerminal re-entry error = %v, want ErrBoundaryAlreadyTerminal", err)
		}
		if termCount != 1 {
			t.Fatalf("terminals after CommitTerminal re-entry = %d, want 1 (no increase)", termCount)
		}

		// Verify exact counts: 1 start, 1 release, 1 terminal.
		if startCount != 1 {
			t.Errorf("starts = %d, want 1", startCount)
		}
		if relCount != 1 {
			t.Errorf("releases = %d, want 1", relCount)
		}
		if termCount != 1 {
			t.Errorf("terminals = %d, want 1", termCount)
		}
	})
}

type customStateSink struct {
	startState    CommitState
	startErr      error
	releaseState  CommitState
	releaseErr    error
	terminalState CommitState
	terminalErr   error
}

func (s *customStateSink) CommitResponseStart(ctx context.Context, rs ResponseStart) (CommitState, error) {
	return s.startState, s.startErr
}
func (s *customStateSink) Release(ctx context.Context, ev ReleaseEvent) (CommitState, error) {
	st := s.releaseState
	if st == "" {
		st = s.startState
	}
	return st, s.releaseErr
}
func (s *customStateSink) CommitTerminal(ctx context.Context, tr TerminalResult) (CommitState, error) {
	st := s.terminalState
	if st == "" {
		st = CommitStateTerminalCommitted
	}
	return st, s.terminalErr
}

func TestCommitBoundaryRejectsWrongOrMissingAttempt(t *testing.T) {
	ctx := context.Background()
	sink := &testSink{}
	b, _ := NewCommitBoundary(sink)
	ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
	rs, _ := NewResponseStart("ch", 200, nil, testNow)
	tr, _ := NewSuccessTerminalResult("ch", testNow)

	// StageResponseStart checks
	if err := b.StageResponseStart("", rs); err == nil {
		t.Fatal("expected error for empty attempt on stage")
	}
	if err := b.StageResponseStart("a1", rs); err != ErrBoundaryNoCurrentAttempt {
		t.Fatalf("StageResponseStart without current attempt err = %v, want ErrBoundaryNoCurrentAttempt", err)
	}

	_ = b.BeginAttempt("a1")

	if err := b.StageResponseStart("wrong", rs); err != ErrBoundaryInvalidAttempt {
		t.Fatalf("StageResponseStart wrong attempt err = %v, want ErrBoundaryInvalidAttempt", err)
	}

	// ReleaseSafe checks
	_, err := b.ReleaseSafe(ctx, "", []ReleaseEvent{ev})
	if err == nil {
		t.Fatal("expected error for empty attempt on release")
	}

	_, err = b.ReleaseSafe(ctx, "wrong", []ReleaseEvent{ev})
	if err != ErrBoundaryInvalidAttempt {
		t.Fatalf("ReleaseSafe wrong attempt err = %v, want ErrBoundaryInvalidAttempt", err)
	}

	// CommitTerminal checks
	err = b.CommitTerminal(ctx, "", tr)
	if err == nil {
		t.Fatal("expected error for empty attempt on terminal")
	}
	err = b.CommitTerminal(ctx, "wrong", tr)
	if err != ErrBoundaryInvalidAttempt {
		t.Fatalf("CommitTerminal wrong attempt err = %v, want ErrBoundaryInvalidAttempt", err)
	}

	// ReplaceUncommittedAttempt checks
	err = b.ReplaceUncommittedAttempt("", "a2")
	if err != ErrBoundaryInvalidAttempt {
		t.Fatalf("ReplaceUncommittedAttempt empty oldAttemptID err = %v, want ErrBoundaryInvalidAttempt", err)
	}
	err = b.ReplaceUncommittedAttempt("wrong", "a2")
	if err != ErrBoundaryInvalidAttempt {
		t.Fatalf("ReplaceUncommittedAttempt wrong oldAttemptID err = %v, want ErrBoundaryInvalidAttempt", err)
	}
}

func TestCommitBoundarySerializesConcurrentStartAndTerminal(t *testing.T) {
	ctx := context.Background()

	callCounts := &sinkCallCounts{starts: new(int32), releases: new(int32), terminals: new(int32)}
	barrierSink := &barrierTestSink{
		enterBarrier: make(chan struct{}),
		blockChan:    make(chan struct{}),
		callCounts:   callCounts,
	}
	b, _ := NewCommitBoundary(barrierSink)
	_ = b.BeginAttempt("a1")
	rs, _ := NewResponseStart("ch", 200, nil, testNow)
	_ = b.StageResponseStart("a1", rs)

	ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
	tr, _ := NewSuccessTerminalResult("ch", testNow)

	var wg sync.WaitGroup
	var relErr, termErr error
	wg.Add(1)
	go func() {
		defer wg.Done()
		_, relErr = b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
	}()

	// Wait until ReleaseSafe enters sink.Release and holds active reservation
	select {
	case <-barrierSink.enterBarrier:
	case <-time.After(time.Second):
		t.Fatal("timeout waiting for ReleaseSafe sink entry")
	}

	// Concurrent CommitTerminal must fail with ErrBoundarySerializerConflict
	termErr = b.CommitTerminal(ctx, "a1", tr)
	if !errors.Is(termErr, ErrBoundarySerializerConflict) {
		t.Fatalf("concurrent CommitTerminal error = %v, want ErrBoundarySerializerConflict", termErr)
	}

	// Unblock first release
	close(barrierSink.blockChan)
	wg.Wait()

	if relErr != nil {
		t.Fatalf("ReleaseSafe failed: %v", relErr)
	}
	if b.State() != CommitStateStreamOpen {
		t.Fatalf("state = %v, want stream_open", b.State())
	}

	// Verify exact call counts after release.
	if atomic.LoadInt32(callCounts.starts) != 1 {
		t.Errorf("starts after release = %d, want 1", atomic.LoadInt32(callCounts.starts))
	}
	if atomic.LoadInt32(callCounts.releases) != 1 {
		t.Errorf("releases after release = %d, want 1", atomic.LoadInt32(callCounts.releases))
	}
	if atomic.LoadInt32(callCounts.terminals) != 0 {
		t.Errorf("terminals after release = %d, want 0", atomic.LoadInt32(callCounts.terminals))
	}

	// CommitTerminal after release succeeds.
	if err := b.CommitTerminal(ctx, "a1", tr); err != nil {
		t.Fatalf("subsequent CommitTerminal failed: %v", err)
	}
	if b.State() != CommitStateTerminalCommitted {
		t.Fatalf("state = %v, want terminal_committed", b.State())
	}

	// Verify exact call counts after terminal.
	if atomic.LoadInt32(callCounts.starts) != 1 {
		t.Errorf("starts after terminal = %d, want 1", atomic.LoadInt32(callCounts.starts))
	}
	if atomic.LoadInt32(callCounts.releases) != 1 {
		t.Errorf("releases after terminal = %d, want 1", atomic.LoadInt32(callCounts.releases))
	}
	if atomic.LoadInt32(callCounts.terminals) != 1 {
		t.Errorf("terminals after terminal = %d, want 1", atomic.LoadInt32(callCounts.terminals))
	}
}

// countingTestSink wraps a ReleaseSink and counts calls to each method.
// It is used to verify exact callback counts in tests.
type countingTestSink struct {
	inner      ReleaseSink
	onStart    func()
	onRelease  func()
	onTerminal func()
}

func (s *countingTestSink) CommitResponseStart(ctx context.Context, rs ResponseStart) (CommitState, error) {
	if s.onStart != nil {
		s.onStart()
	}
	return s.inner.CommitResponseStart(ctx, rs)
}
func (s *countingTestSink) Release(ctx context.Context, ev ReleaseEvent) (CommitState, error) {
	if s.onRelease != nil {
		s.onRelease()
	}
	return s.inner.Release(ctx, ev)
}
func (s *countingTestSink) CommitTerminal(ctx context.Context, tr TerminalResult) (CommitState, error) {
	if s.onTerminal != nil {
		s.onTerminal()
	}
	return s.inner.CommitTerminal(ctx, tr)
}

// barrierTestSink is a test sink with an enter barrier and block channel
// for testing concurrent reservation conflict.
type barrierTestSink struct {
	enterBarrier chan struct{}
	blockChan    chan struct{}
	mu           sync.Mutex
	starts       int
	releases     int
	terminals    int
	callCounts   *sinkCallCounts
}

type sinkCallCounts struct {
	starts    *int32
	releases  *int32
	terminals *int32
}

func (s *barrierTestSink) CommitResponseStart(ctx context.Context, rs ResponseStart) (CommitState, error) {
	s.mu.Lock()
	s.starts++
	if s.callCounts != nil {
		atomic.AddInt32(s.callCounts.starts, 1)
	}
	s.mu.Unlock()
	return CommitStateStreamOpen, nil
}

func (s *barrierTestSink) Release(ctx context.Context, ev ReleaseEvent) (CommitState, error) {
	s.mu.Lock()
	s.releases++
	if s.callCounts != nil {
		atomic.AddInt32(s.callCounts.releases, 1)
	}
	s.mu.Unlock()
	s.enterBarrier <- struct{}{}
	<-s.blockChan
	return CommitStateStreamOpen, nil
}

func (s *barrierTestSink) CommitTerminal(ctx context.Context, tr TerminalResult) (CommitState, error) {
	s.mu.Lock()
	s.terminals++
	if s.callCounts != nil {
		atomic.AddInt32(s.callCounts.terminals, 1)
	}
	s.mu.Unlock()
	return CommitStateTerminalCommitted, nil
}

// TestCommitBoundaryPreservesTerminalStateOnCallbackError verifies that when
// the terminal callback returns terminal_committed with an error, the state
// is preserved and re-entry is rejected (exactly-once terminal).
func TestCommitBoundaryPreservesTerminalStateOnCallbackError(t *testing.T) {
	ctx := context.Background()

	t.Run("terminal_error_preserves_terminal_state", func(t *testing.T) {
		var termCount int
		countingSink := &countingTestSink{
			inner: &customStateSink{
				terminalState: CommitStateTerminalCommitted,
				terminalErr:   errors.New("test: terminal network error"),
			},
			onTerminal: func() { termCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err == nil {
			t.Fatal("expected error from terminal with network error")
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (preserved despite error)", b.State())
		}

		// Re-entry must be rejected without calling sink.
		err2 := b.CommitTerminal(ctx, "a1", tr)
		if !errors.Is(err2, ErrBoundaryAlreadyTerminal) {
			t.Fatalf("re-entry error = %v, want ErrBoundaryAlreadyTerminal", err2)
		}
		if termCount != 1 {
			t.Fatalf("terminals = %d, want 1 (exactly-once)", termCount)
		}
	})

	t.Run("terminal_error_with_role_mismatch_preserves_state", func(t *testing.T) {
		var termCount int
		countingSink := &countingTestSink{
			inner: &customStateSink{
				terminalState: CommitStateStreamOpen,
				terminalErr:   errors.New("test: terminal partial error"),
			},
			onTerminal: func() { termCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err == nil {
			t.Fatal("expected error from terminal with role mismatch + error")
		}
		// Verify joined error contains both sink and role errors.
		errStr := err.Error()
		if !strings.Contains(errStr, "test: terminal partial error") {
			t.Errorf("expected sink error in joined error, got: %v", err)
		}
		if !strings.Contains(errStr, ErrInvalidStateTransition.Error()) {
			t.Errorf("expected role error in joined error, got: %v", err)
		}
		// State should be preserved at stream_open (valid forward state).
		if b.State() != CommitStateStreamOpen {
			t.Fatalf("state = %v, want stream_open (forward state preserved)", b.State())
		}
		if termCount != 1 {
			t.Fatalf("terminals = %d, want 1", termCount)
		}
	})

	t.Run("response_start_role_mismatch_advances_state", func(t *testing.T) {
		var startCount int
		countingSink := &countingTestSink{
			inner: &customStateSink{
				startState: CommitStateTerminalCommitted,
			},
			onStart: func() { startCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition, got %v", err)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (forward state preserved)", b.State())
		}
		// Staged start should be cleared because state advanced.
		if startCount != 1 {
			t.Fatalf("responseStarts = %d, want 1", startCount)
		}
	})

	t.Run("release_role_mismatch_advances_to_terminal", func(t *testing.T) {
		var relCount int
		countingSink := &countingTestSink{
			inner: &customStateSink{
				startState:   CommitStateStreamOpen,
				releaseState: CommitStateTerminalCommitted,
			},
			onRelease: func() { relCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		rs, _ := NewResponseStart("ch", 200, nil, testNow)
		_ = b.StageResponseStart("a1", rs)

		ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
		_, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{ev})
		if !errors.Is(err, ErrInvalidStateTransition) {
			t.Fatalf("expected ErrInvalidStateTransition, got %v", err)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed (forward state preserved)", b.State())
		}
		// No further releases should be attempted.
		if relCount != 1 {
			t.Fatalf("releases = %d, want 1 (short-circuited after role mismatch)", relCount)
		}
	})

	t.Run("sink_error_with_valid_forward_state_joins_errors", func(t *testing.T) {
		customSink := &customStateSink{
			terminalState: CommitStateTerminalCommitted,
			terminalErr:   errors.New("test: terminal error"),
		}
		b, _ := NewCommitBoundary(customSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err == nil {
			t.Fatal("expected error")
		}
		// Should be a joined error with the sink error.
		if !strings.Contains(err.Error(), "test: terminal error") {
			t.Fatalf("expected error to contain 'test: terminal error', got %v", err)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed", b.State())
		}
	})

	t.Run("exact_callback_count_after_terminal_preservation", func(t *testing.T) {
		var termCount int
		countingSink := &countingTestSink{
			inner: &customStateSink{
				terminalState: CommitStateTerminalCommitted,
				terminalErr:   errors.New("test: terminal failure"),
			},
			onTerminal: func() { termCount++ },
		}
		b, _ := NewCommitBoundary(countingSink)
		_ = b.BeginAttempt("a1")
		tr, _ := NewSuccessTerminalResult("ch", testNow)

		err := b.CommitTerminal(ctx, "a1", tr)
		if err == nil {
			t.Fatal("expected error")
		}

		if termCount != 1 {
			t.Fatalf("terminals = %d, want 1", termCount)
		}

		// Re-entry should be rejected without calling sink.
		_ = b.CommitTerminal(ctx, "a1", tr)
		if termCount != 1 {
			t.Fatalf("terminals after re-entry = %d, want 1 (exactly-once)", termCount)
		}
		if b.State() != CommitStateTerminalCommitted {
			t.Fatalf("state = %v, want terminal_committed", b.State())
		}
	})
}

func TestCommitBoundaryRejectsPostOpenReplacement(t *testing.T) {
	ctx := context.Background()
	sink := &testSink{}
	b, _ := NewCommitBoundary(sink)

	_ = b.BeginAttempt("a1")
	rs, _ := NewResponseStart("ch", 200, nil, testNow)
	_ = b.StageResponseStart("a1", rs)

	// Valid replacement prior to release
	if err := b.ReplaceUncommittedAttempt("a1", "a2"); err != nil {
		t.Fatalf("valid ReplaceUncommittedAttempt failed: %v", err)
	}
	if b.CurrentAttempt() != "a2" {
		t.Fatalf("CurrentAttempt = %q, want a2", b.CurrentAttempt())
	}

	_ = b.StageResponseStart("a2", rs)
	ev, _ := NewReleaseTextDeltaEvent("ch", "x", testNow)
	_, _ = b.ReleaseSafe(ctx, "a2", []ReleaseEvent{ev})

	// After stream_open, replacement is rejected and selected attempt is preserved
	err := b.ReplaceUncommittedAttempt("a2", "a3")
	if err != ErrBoundaryUncommitted {
		t.Fatalf("ReplaceUncommittedAttempt after open err = %v, want ErrBoundaryUncommitted", err)
	}
	if b.CurrentAttempt() != "a2" {
		t.Fatalf("CurrentAttempt = %q, want preserved a2", b.CurrentAttempt())
	}
}

func mustReleaseTextDelta(channel, text string, ts time.Time) ReleaseEvent {
	ev, err := NewReleaseTextDeltaEvent(channel, text, ts)
	if err != nil {
		panic(err)
	}
	return ev
}

func TestCommitBoundaryContinuesOpenAttempt(t *testing.T) {
	ctx := context.Background()

	t.Run("identity_rejections_preserve_open_state", func(t *testing.T) {
		sink := &testSink{}
		b, err := NewCommitBoundary(sink)
		if err != nil {
			t.Fatalf("NewCommitBoundary: %v", err)
		}
		if err := b.BeginAttempt("a1"); err != nil {
			t.Fatalf("BeginAttempt: %v", err)
		}
		if err := b.ContinueOpenAttempt("a1", "a2"); err != ErrBoundaryUncommitted {
			t.Fatalf("ContinueOpenAttempt before open err = %v, want ErrBoundaryUncommitted", err)
		}
		rs, err := NewResponseStart("ch", 200, nil, testNow)
		if err != nil {
			t.Fatalf("NewResponseStart: %v", err)
		}
		if err := b.StageResponseStart("a1", rs); err != nil {
			t.Fatalf("StageResponseStart: %v", err)
		}
		prefix := mustReleaseTextDelta("ch", "prefix", testNow)
		if _, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{prefix}); err != nil {
			t.Fatalf("ReleaseSafe prefix: %v", err)
		}

		beforeGeneration := b.generation
		beforeConfirmed := len(b.confirmed)
		for _, tc := range []struct {
			name  string
			oldID string
			newID string
			want  error
		}{
			{name: "empty_new", oldID: "a1", want: errors.New("non-nil")},
			{name: "empty_old", newID: "a2", want: ErrBoundaryInvalidAttempt},
			{name: "same_id", oldID: "a1", newID: "a1", want: ErrBoundaryDuplicateAttempt},
			{name: "wrong_old", oldID: "wrong", newID: "a2", want: ErrBoundaryInvalidAttempt},
		} {
			t.Run(tc.name, func(t *testing.T) {
				err := b.ContinueOpenAttempt(tc.oldID, tc.newID)
				if tc.name == "empty_new" {
					if err == nil {
						t.Fatal("ContinueOpenAttempt empty new ID succeeded")
					}
				} else if err != tc.want {
					t.Fatalf("ContinueOpenAttempt err = %v, want %v", err, tc.want)
				}
				if b.CurrentAttempt() != "a1" || b.State() != CommitStateStreamOpen {
					t.Fatalf("identity/state changed: attempt=%q state=%q", b.CurrentAttempt(), b.State())
				}
				if b.generation != beforeGeneration || len(b.confirmed) != beforeConfirmed {
					t.Fatalf("generation/confirmed changed: (%d,%d), want (%d,%d)", b.generation, len(b.confirmed), beforeGeneration, beforeConfirmed)
				}
				if len(sink.responseStarts) != 1 || len(sink.releases) != 1 {
					t.Fatalf("sink counts changed: starts=%d releases=%d", len(sink.responseStarts), len(sink.releases))
				}
			})
		}
	})

	t.Run("active_reservation_rejected_without_handoff", func(t *testing.T) {
		sink := &barrierTestSink{enterBarrier: make(chan struct{}), blockChan: make(chan struct{})}
		b, err := NewCommitBoundary(sink)
		if err != nil {
			t.Fatalf("NewCommitBoundary: %v", err)
		}
		if err := b.BeginAttempt("a1"); err != nil {
			t.Fatalf("BeginAttempt: %v", err)
		}
		b.mu.Lock()
		b.state = CommitStateStreamOpen
		b.mu.Unlock()
		releaseDone := make(chan error, 1)
		go func() {
			_, releaseErr := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{mustReleaseTextDelta("ch", "blocked", testNow)})
			releaseDone <- releaseErr
		}()
		<-sink.enterBarrier
		beforeGeneration := b.generation
		if err := b.ContinueOpenAttempt("a1", "a2"); err != ErrBoundarySerializerConflict {
			t.Fatalf("ContinueOpenAttempt reserved err = %v, want ErrBoundarySerializerConflict", err)
		}
		if b.CurrentAttempt() != "a1" || b.generation != beforeGeneration {
			t.Fatalf("reserved handoff mutated identity: attempt=%q generation=%d", b.CurrentAttempt(), b.generation)
		}
		close(sink.blockChan)
		if err := <-releaseDone; err != nil {
			t.Fatalf("blocked ReleaseSafe: %v", err)
		}
	})

	t.Run("successful_handoff_preserves_prefix_and_terminal_once", func(t *testing.T) {
		sink := &testSink{}
		b, err := NewCommitBoundary(sink)
		if err != nil {
			t.Fatalf("NewCommitBoundary: %v", err)
		}
		if err := b.BeginAttempt("a1"); err != nil {
			t.Fatalf("BeginAttempt: %v", err)
		}
		rs, err := NewResponseStart("ch", 200, nil, testNow)
		if err != nil {
			t.Fatalf("NewResponseStart: %v", err)
		}
		if err := b.StageResponseStart("a1", rs); err != nil {
			t.Fatalf("StageResponseStart: %v", err)
		}
		if _, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{mustReleaseTextDelta("ch", "prefix", testNow)}); err != nil {
			t.Fatalf("ReleaseSafe prefix: %v", err)
		}
		beforeGeneration := b.generation
		beforeConfirmed := len(b.confirmed)
		if err := b.ContinueOpenAttempt("a1", "a2"); err != nil {
			t.Fatalf("ContinueOpenAttempt: %v", err)
		}
		if b.CurrentAttempt() != "a2" || b.State() != CommitStateStreamOpen {
			t.Fatalf("handoff state: attempt=%q state=%q", b.CurrentAttempt(), b.State())
		}
		if b.generation != beforeGeneration+1 || len(b.confirmed) != beforeConfirmed {
			t.Fatalf("handoff generation/confirmed = (%d,%d), want (%d,%d)", b.generation, len(b.confirmed), beforeGeneration+1, beforeConfirmed)
		}
		suffix := mustReleaseTextDelta("ch", "suffix", testNow)
		if _, err := b.ReleaseSafe(ctx, "a1", []ReleaseEvent{suffix}); err != ErrBoundaryInvalidAttempt {
			t.Fatalf("old attempt release err = %v, want ErrBoundaryInvalidAttempt", err)
		}
		if _, err := b.ReleaseSafe(ctx, "a2", []ReleaseEvent{suffix}); err != nil {
			t.Fatalf("new attempt release: %v", err)
		}
		terminal, err := NewSuccessTerminalResult("ch", testNow)
		if err != nil {
			t.Fatalf("NewSuccessTerminalResult: %v", err)
		}
		if err := b.CommitTerminal(ctx, "a2", terminal); err != nil {
			t.Fatalf("CommitTerminal: %v", err)
		}
		if len(sink.responseStarts) != 1 || len(sink.releases) != 2 || len(sink.terminals) != 1 {
			t.Fatalf("sink counts starts/releases/terminals = %d/%d/%d, want 1/2/1", len(sink.responseStarts), len(sink.releases), len(sink.terminals))
		}
		prefixText, prefixErr := sink.releases[0].AsTextDelta()
		if prefixErr != nil {
			t.Fatalf("prefix AsTextDelta: %v", prefixErr)
		}
		suffixText, suffixErr := sink.releases[1].AsTextDelta()
		if suffixErr != nil {
			t.Fatalf("suffix AsTextDelta: %v", suffixErr)
		}
		if prefixText != "prefix" || suffixText != "suffix" {
			t.Fatalf("released text = %q,%q, want prefix,suffix", prefixText, suffixText)
		}
		if err := b.ContinueOpenAttempt("a2", "a3"); err != ErrBoundaryAlreadyTerminal {
			t.Fatalf("ContinueOpenAttempt after terminal err = %v, want ErrBoundaryAlreadyTerminal", err)
		}
	})
}
