package openai

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	toki "git.toki-labs.com/toki/proto-socket/go"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/testutil"
	dto "github.com/prometheus/client_model/go"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"go.uber.org/zap/zaptest/observer"
	"google.golang.org/protobuf/proto"

	"iop/apps/edge/internal/authprojection"
	edgenode "iop/apps/edge/internal/node"
	edgeservice "iop/apps/edge/internal/service"
	"iop/packages/go/config"
	iop "iop/proto/gen/iop"
)

const (
	testSingleRequestModel = "virtual-single-request"
	testSingleRequestToken = "single-request-token"
)

type anthropicSingleRequestExecutorFunc func(context.Context, edgeservice.SingleRequestRequest, edgeservice.SingleRequestController) error

func (f anthropicSingleRequestExecutorFunc) ExecuteSingleRequest(
	ctx context.Context,
	req edgeservice.SingleRequestRequest,
	ctrl edgeservice.SingleRequestController,
) error {
	return f(ctx, req, ctrl)
}

// newAdmittedAnthropicSingleRequestService builds the same catalog and ready
// owner preconditions that the public service requires in production. Endpoint
// tests must cross this boundary rather than using a zero-value Service.
func newAdmittedAnthropicSingleRequestService(
	t *testing.T,
	executor edgeservice.SingleRequestExecutor,
	workspaceRef string,
) *edgeservice.Service {
	t.Helper()
	const nodeID = "workspace-node"

	registry := edgenode.NewRegistry()
	registry.Register(&edgenode.NodeEntry{NodeID: nodeID, Alias: "workspace"})
	store := edgenode.NewNodeStore()
	store.Add(&edgenode.NodeRecord{
		ID:    nodeID,
		Alias: "workspace",
		Token: "workspace-node-token",
		Workspaces: []config.WorkspaceDefinition{{
			Ref:          workspaceRef,
			Platform:     "darwin",
			Root:         "/Users/operator/project",
			Operations:   []config.WorkspaceOperation{config.WorkspaceOpRead},
			MaxReadBytes: 4096,
		}},
	})

	svc := edgeservice.New(registry, nil)
	svc.SetNodeStore(store)
	svc.SetSingleRequestExecutor(executor)
	return svc
}

func newAnthropicSingleRequestServer(t *testing.T, svc runService) *Server {
	t.Helper()
	now := time.Date(2026, 8, 6, 12, 0, 0, 0, time.UTC)
	cache := authprojection.NewCache(authprojection.DefaultLimits(), func() time.Time { return now })
	routes := map[string]authprojection.Route{
		"plan": {
			RouteID: "public-plan", PrincipalRef: "principal-1", CredentialSlotRef: "slot-plan",
			ProfileID: "profile-plan", UpstreamModel: "served-plan", ResourceSelector: "default",
		},
		"work": {
			RouteID: "public-work", PrincipalRef: "principal-1", CredentialSlotRef: "slot-work",
			ProfileID: "profile-work", UpstreamModel: "served-work", ResourceSelector: "default",
		},
		"review": {
			RouteID: "public-review", PrincipalRef: "principal-1", CredentialSlotRef: "slot-review",
			ProfileID: "profile-review", UpstreamModel: "served-review", ResourceSelector: "default",
		},
	}
	if err := cache.Apply(makeTestProjection(
		1, now, time.Hour,
		map[string]string{testSingleRequestToken: "principal-1"}, routes,
	)); err != nil {
		t.Fatalf("apply projection: %v", err)
	}

	deterministicCounter := config.TokenCounterConf{Mode: config.TokenCounterDeterministic}
	srv := NewServer(config.EdgeOpenAIConf{}, svc, nil)
	setManagedPrincipalProjection(srv, cache)
	srv.SetExecutionPresets([]config.ExecutionPreset{validSingleRequestPreset()})
	srv.SetModelCatalog([]config.ModelCatalogEntry{
		{ID: testSingleRequestModel, ExecutionPreset: "preset-single-request"},
		{ID: "plan-model", Providers: map[string]string{"provider-plan": "served-plan"}, TokenCounter: &deterministicCounter},
		{ID: "work-model", Providers: map[string]string{"provider-work": "served-work"}},
		{ID: "review-model", Providers: map[string]string{"provider-review": "served-review"}},
	})
	return srv
}

func newAnthropicSingleRequestHTTPReq(t *testing.T, ctx context.Context, target, path, body string) *http.Request {
	t.Helper()
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, target+path, strings.NewReader(body))
	if err != nil {
		t.Fatalf("new request: %v", err)
	}
	req.Header.Set("Authorization", "Bearer "+testSingleRequestToken)
	req.Header.Set(anthropicVersionHeader, anthropicSupportedVersion)
	req.Header.Set("Content-Type", "application/json")
	return req
}

func serveAnthropicSingleRequest(t *testing.T, srv *Server, ctx context.Context, path, body string, w http.ResponseWriter) {
	t.Helper()
	req := newAnthropicSingleRequestHTTPReq(t, ctx, "http://edge.invalid", path, body)
	srv.routes().ServeHTTP(w, req)
}

func TestAnthropicPreIngressRejectionClassificationIsClosed(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name string
		err  string
		want anthropicPreIngressRejectionClass
	}{
		{name: "unsupported beta", err: `unsupported anthropic-beta "SECRET_BETA"`, want: anthropicPreIngressUnsupportedBeta},
		{name: "unknown field", err: `decode Messages request: json: unknown field "SECRET_FIELD"`, want: anthropicPreIngressUnknownField},
		{name: "thinking", err: `thinking.display SECRET_DISPLAY`, want: anthropicPreIngressInvalidThinking},
		{name: "output config", err: `output_config.effort SECRET_EFFORT`, want: anthropicPreIngressInvalidOutput},
		{name: "generic", err: `SECRET_UNCLASSIFIED`, want: anthropicPreIngressInvalidRequest},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()
			if got := classifyAnthropicPreIngressRejection(errors.New(test.err)); got != test.want {
				t.Fatalf("class=%q want=%q", got, test.want)
			}
		})
	}
}

func TestAnthropicPreIngressRejectionLogOmitsArbitraryInput(t *testing.T) {
	t.Parallel()
	service := newAdmittedAnthropicSingleRequestService(t, anthropicSingleRequestExecutorFunc(
		func(context.Context, edgeservice.SingleRequestRequest, edgeservice.SingleRequestController) error {
			return nil
		},
	), "workspace")
	core, logs := observer.New(zap.InfoLevel)
	srv := newAnthropicSingleRequestServer(t, service)
	srv.logger = zap.New(core)

	tests := []struct {
		name   string
		marker string
		body   string
		header string
		want   anthropicPreIngressRejectionClass
	}{
		{
			name: "unknown field", marker: "SECRET_FIELD_MARKER",
			body: `{"model":"` + testSingleRequestModel + `","max_tokens":16,"messages":[{"role":"user","content":"hello"}],"SECRET_FIELD_MARKER":true}`,
			want: anthropicPreIngressUnknownField,
		},
		{
			name: "unsupported beta", marker: "SECRET_BETA_MARKER",
			body:   `{"model":"` + testSingleRequestModel + `","max_tokens":16,"messages":[{"role":"user","content":"hello"}]}`,
			header: "SECRET_BETA_MARKER", want: anthropicPreIngressUnsupportedBeta,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			logs.TakeAll()
			recorder := httptest.NewRecorder()
			request := newAnthropicSingleRequestHTTPReq(t, context.Background(), "http://edge.invalid", "/v1/messages", test.body)
			if test.header != "" {
				request.Header.Set(anthropicBetaHeader, test.header)
			}
			srv.routes().ServeHTTP(recorder, request)
			if recorder.Code != http.StatusBadRequest {
				t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
			}
			entries := logs.FilterMessage(anthropicPreIngressRejectionLogMessage).All()
			if len(entries) != 1 {
				t.Fatalf("log entries=%d want=1", len(entries))
			}
			fields := entries[0].ContextMap()
			if got := fields["rejection_class"]; got != string(test.want) {
				t.Fatalf("rejection_class=%v want=%q", got, test.want)
			}
			if fields["surface"] != "messages" || fields["http_status"] != int64(http.StatusBadRequest) {
				t.Fatalf("log fields=%v", fields)
			}
			if strings.Contains(fmt.Sprint(entries[0].Message, fields), test.marker) {
				t.Fatal("arbitrary input leaked into pre-ingress log")
			}
		})
	}
}

func submitAnthropicSingleRequestLifecycle(
	req edgeservice.SingleRequestRequest,
	ctrl edgeservice.SingleRequestController,
	result string,
) error {
	type step struct {
		stage edgeservice.SingleRequestState
		saved edgeservice.SingleRequestState
	}
	steps := []step{
		{stage: edgeservice.SingleRequestStatePlanning},
		{stage: edgeservice.SingleRequestStateWorking},
		{stage: edgeservice.SingleRequestStateReviewing},
		{stage: edgeservice.SingleRequestStateRepairing},
		{stage: edgeservice.SingleRequestStateFinalizing},
	}
	for index, item := range steps {
		envelope := edgeservice.SingleRequestEnvelope{
			RequestID:  req.RequestID,
			Sequence:   uint64(index + 1),
			Stage:      item.stage,
			SavedStage: item.saved,
			Message:    "PRIVATE_STAGE_SENTINEL",
		}
		if item.stage == edgeservice.SingleRequestStateFinalizing {
			envelope.Result = &edgeservice.SingleRequestResult{Output: result}
		}
		if err := ctrl.SubmitEnvelope(envelope); err != nil {
			return err
		}
	}
	return nil
}

func TestAnthropicSingleRequestUsesOnePost(t *testing.T) {
	const (
		privatePrompt = "PRIVATE_CALLER_PROMPT_SENTINEL"
		finalOutput   = "workspace task completed"
	)
	var calls atomic.Int32
	requestCh := make(chan edgeservice.SingleRequestRequest, 1)
	controllerCh := make(chan edgeservice.SingleRequestController, 1)
	executor := anthropicSingleRequestExecutorFunc(func(
		_ context.Context,
		req edgeservice.SingleRequestRequest,
		ctrl edgeservice.SingleRequestController,
	) error {
		calls.Add(1)
		requestCh <- req
		if err := submitAnthropicSingleRequestLifecycle(req, ctrl, finalOutput); err != nil {
			return err
		}
		controllerCh <- ctrl
		return nil
	})
	svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
	srv := newAnthropicSingleRequestServer(t, svc)
	httpServer := httptest.NewServer(srv.routes())
	defer httpServer.Close()

	before := testutil.ToFloat64(singleRequestIngressTotal)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":128,"messages":[{"role":"user","content":"` + privatePrompt + `"}],"tools":[{"name":"caller_tool","input_schema":{"type":"object"}}]}`
	req := newAnthropicSingleRequestHTTPReq(t, ctx, httpServer.URL, "/v1/messages", body)
	req.Header.Set(anthropicBetaHeader, "advisor-tool-2026-03-01,thinking-token-count-2026-05-13")
	response, err := httpServer.Client().Do(req)
	if err != nil {
		t.Fatalf("POST /v1/messages: %v", err)
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		payload, _ := io.ReadAll(response.Body)
		t.Fatalf("status=%d body=%s", response.StatusCode, payload)
	}
	if got := response.Header.Get("Content-Type"); !strings.HasPrefix(got, "application/json") {
		t.Fatalf("content-type=%q, want buffered application/json terminal", got)
	}

	var terminal anthropicMessageResponse
	decoder := json.NewDecoder(response.Body)
	if err := decoder.Decode(&terminal); err != nil {
		t.Fatalf("decode terminal: %v", err)
	}
	var extra json.RawMessage
	if err := decoder.Decode(&extra); err != io.EOF {
		t.Fatalf("expected exactly one JSON terminal, trailing decode error=%v value=%s", err, extra)
	}
	if terminal.Model != testSingleRequestModel || terminal.Type != "message" || terminal.Role != "assistant" {
		t.Fatalf("public terminal identity mismatch: %+v", terminal)
	}
	if terminal.StopReason == nil || *terminal.StopReason != "end_turn" {
		t.Fatalf("stop_reason=%v, want end_turn", terminal.StopReason)
	}
	if len(terminal.Content) != 1 || terminal.Content[0]["type"] != "text" || terminal.Content[0]["text"] != finalOutput {
		t.Fatalf("terminal content=%+v, want one sanitized text block", terminal.Content)
	}
	encoded, err := json.Marshal(terminal)
	if err != nil {
		t.Fatal(err)
	}
	for _, privateValue := range []string{
		privatePrompt, "PRIVATE_STAGE_SENTINEL", "caller_tool", "tool_use",
		"ws-opaque-ref", "plan-model", "provider-plan", "slot-plan",
	} {
		if strings.Contains(string(encoded), privateValue) {
			t.Fatalf("terminal leaked %q: %s", privateValue, encoded)
		}
	}

	if got := testutil.ToFloat64(singleRequestIngressTotal) - before; got != 1 {
		t.Fatalf("single-request ingress counter delta=%v, want 1", got)
	}
	if got := calls.Load(); got != 1 {
		t.Fatalf("executor calls=%d, want 1", got)
	}
	captured := <-requestCh
	if captured.Binding == nil || captured.Binding.PublicModel != testSingleRequestModel {
		t.Fatalf("captured immutable binding=%+v", captured.Binding)
	}
	if workspace := captured.Binding.Workspace; workspace == nil ||
		workspace.Ref != "ws-opaque-ref" ||
		workspace.NodeID != "workspace-node" ||
		workspace.ConnectionGeneration == 0 ||
		len(workspace.OperationIDs) != 1 || workspace.OperationIDs[0] != string(config.WorkspaceOpRead) {
		t.Fatalf("captured workspace projection=%#v, want frozen ready read capability", workspace)
	}
	if !strings.Contains(captured.Prompt, privatePrompt) {
		t.Fatalf("executor did not receive immutable caller input: %q", captured.Prompt)
	}
	controller := <-controllerCh
	if got := controller.State(); got != edgeservice.SingleRequestStateCompleted {
		t.Fatalf("terminal acknowledgement state=%s, want completed", got)
	}

	families, err := prometheus.DefaultGatherer.Gather()
	if err != nil {
		t.Fatalf("gather metrics: %v", err)
	}
	foundMetric := false
	for _, family := range families {
		if family.GetName() != "iop_anthropic_single_request_ingress_total" {
			continue
		}
		foundMetric = true
		for _, metric := range family.Metric {
			if len(metric.Label) != 0 {
				t.Fatalf("single-request ingress metric has request-derived labels: %+v", metric.Label)
			}
		}
	}
	if !foundMetric {
		t.Fatal("registered single-request ingress metric was not gathered")
	}
}

func TestAnthropicSingleRequestErrorCancelMatrix(t *testing.T) {
	const privatePartial = "PRIVATE_PARTIAL_STAGE_OUTPUT"
	tests := []struct {
		name        string
		disposition edgeservice.SingleRequestTerminalDisposition
		wantStatus  int
		wantStop    string
		wantType    string
		wantMessage string
		silent      bool
	}{
		{name: "end turn", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalEndTurn}, wantStatus: http.StatusOK, wantStop: "end_turn"},
		{name: "length", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalLength}, wantStatus: http.StatusOK, wantStop: "max_tokens"},
		{name: "cancelled", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalCancelled}, silent: true},
		{name: "provider", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorProvider}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
		{name: "validation", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorValidation}, wantStatus: http.StatusBadRequest, wantType: "invalid_request_error", wantMessage: "single-request execution was rejected"},
		{name: "timeout", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorTimeout}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution timed out"},
		{name: "budget", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorBudget}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
		{name: "repetition", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorRepetition}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
		{name: "malformed", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorMalformed}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
		{name: "context", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorContext}, wantStatus: http.StatusBadRequest, wantType: "invalid_request_error", wantMessage: "single-request context limit exceeded"},
		{name: "internal tool", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorInternalTool}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
		{name: "workspace cleanup", disposition: edgeservice.SingleRequestTerminalDisposition{Kind: edgeservice.SingleRequestTerminalError, ErrorClass: edgeservice.SingleRequestTerminalErrorWorkspaceCleanup}, wantStatus: http.StatusBadGateway, wantType: "api_error", wantMessage: "single-request execution failed"},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			executor := anthropicSingleRequestExecutorFunc(func(
				_ context.Context,
				req edgeservice.SingleRequestRequest,
				ctrl edgeservice.SingleRequestController,
			) error {
				if err := ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: 1, Stage: edgeservice.SingleRequestStatePlanning}); err != nil {
					return err
				}
				switch tc.disposition.Kind {
				case edgeservice.SingleRequestTerminalEndTurn, edgeservice.SingleRequestTerminalLength:
					for sequence, stage := range []edgeservice.SingleRequestState{edgeservice.SingleRequestStateWorking, edgeservice.SingleRequestStateReviewing} {
						if err := ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: uint64(sequence + 2), Stage: stage}); err != nil {
							return err
						}
					}
					output := "safe final result"
					if tc.disposition.Kind == edgeservice.SingleRequestTerminalLength {
						output = privatePartial
					}
					return ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{
						RequestID: req.RequestID,
						Sequence:  4,
						Stage:     edgeservice.SingleRequestStateFinalizing,
						Result:    &edgeservice.SingleRequestResult{Output: output, Terminal: tc.disposition},
					})
				case edgeservice.SingleRequestTerminalCancelled:
					return ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: 2, Stage: edgeservice.SingleRequestStateCancelled, Terminal: &tc.disposition})
				default:
					return ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: 2, Stage: edgeservice.SingleRequestStateFailed, Terminal: &tc.disposition, Err: edgeservice.ErrSingleRequestFailed})
				}
			})
			svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
			srv := newAnthropicSingleRequestServer(t, svc)
			core, logs := observer.New(zap.InfoLevel)
			srv.logger = zap.New(core)
			w := httptest.NewRecorder()
			before := testutil.ToFloat64(singleRequestIngressTotal)
			serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages", `{"model":"`+testSingleRequestModel+`","max_tokens":128,"messages":[{"role":"user","content":"run"}]}`, w)

			if got := testutil.ToFloat64(singleRequestIngressTotal) - before; got != 1 {
				t.Fatalf("ingress delta=%v, want 1", got)
			}
			if strings.Contains(w.Body.String(), privatePartial) {
				t.Fatalf("private partial output reached caller: %q", w.Body.String())
			}
			entries := logs.FilterMessage(anthropicSingleRequestTerminalRejectionLogMessage).All()
			if tc.disposition.Kind == edgeservice.SingleRequestTerminalError {
				if len(entries) != 1 {
					t.Fatalf("terminal rejection logs=%d, want 1", len(entries))
				}
				fields := entries[0].ContextMap()
				if fields["surface"] != "messages" || fields["terminal_kind"] != string(tc.disposition.Kind) || fields["terminal_error_class"] != string(tc.disposition.ErrorClass) || fields["http_status"] != int64(tc.wantStatus) {
					t.Fatalf("terminal rejection fields=%v", fields)
				}
				for _, forbidden := range []string{privatePartial, "ws-opaque-ref", "run"} {
					if strings.Contains(fmt.Sprintf("%v", fields), forbidden) {
						t.Fatalf("terminal rejection log leaked %q: %v", forbidden, fields)
					}
				}
			} else if len(entries) != 0 {
				t.Fatalf("terminal rejection logs=%d, want 0", len(entries))
			}
			if tc.silent {
				if w.Body.Len() != 0 {
					t.Fatalf("cancel body=%q, want silent terminal", w.Body.String())
				}
				return
			}
			if w.Code != tc.wantStatus {
				t.Fatalf("status=%d body=%q, want %d", w.Code, w.Body.String(), tc.wantStatus)
			}
			if tc.wantStop != "" {
				var response anthropicMessageResponse
				if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
					t.Fatalf("decode message terminal: %v", err)
				}
				if response.StopReason == nil || *response.StopReason != tc.wantStop {
					t.Fatalf("stop_reason=%v, want %q", response.StopReason, tc.wantStop)
				}
				if tc.disposition.Kind == edgeservice.SingleRequestTerminalLength && len(response.Content) != 0 {
					t.Fatalf("length content=%v, want empty", response.Content)
				}
				return
			}
			var response anthropicErrorResponse
			if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
				t.Fatalf("decode error terminal: %v", err)
			}
			if response.Error.Type != tc.wantType || response.Error.Message != tc.wantMessage {
				t.Fatalf("error=%+v, want %s/%q", response.Error, tc.wantType, tc.wantMessage)
			}
		})
	}
}

func TestAnthropicSingleRequestLiveContextProviderCancellationBuffered(t *testing.T) {
	var providerCalls atomic.Int32
	var providerContextDone atomic.Bool
	runner := &mockService{submit: func(ctx context.Context, _ edgeservice.ProviderPoolDispatchRequest) (*edgeservice.ProviderPoolDispatchResult, error) {
		if ctx.Err() != nil {
			providerContextDone.Store(true)
		}
		providerCalls.Add(1)
		return nil, context.Canceled
	}}
	executor := NewSingleRequestExecutor(runner)
	svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
	srv := newAnthropicSingleRequestServer(t, svc)
	w := httptest.NewRecorder()
	before := testutil.ToFloat64(singleRequestIngressTotal)
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":128,"messages":[{"role":"user","content":"run"}]}`

	serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages", body, w)

	if got := providerCalls.Load(); got != 1 {
		t.Fatalf("provider calls=%d, want 1", got)
	}
	if providerContextDone.Load() {
		t.Fatal("provider context was already done before the provider-owned cancellation")
	}
	if got := testutil.ToFloat64(singleRequestIngressTotal) - before; got != 1 {
		t.Fatalf("ingress delta=%v, want 1", got)
	}
	if w.Code != http.StatusBadGateway {
		t.Fatalf("status=%d body=%q, want 502", w.Code, w.Body.String())
	}
	var response anthropicErrorResponse
	if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
		t.Fatalf("decode error terminal: %v", err)
	}
	if response.Error.Type != "api_error" || response.Error.Message != "single-request execution failed" {
		t.Fatalf("error=%+v, want sanitized provider api_error", response.Error)
	}
	for _, forbidden := range []string{"context canceled", "cancelled", "ws-opaque-ref", "plan-model", "provider-plan"} {
		if strings.Contains(w.Body.String(), forbidden) {
			t.Fatalf("buffered error leaked %q: %s", forbidden, w.Body.String())
		}
	}
}

type anthropicInternalToolExecutor struct {
	results       chan edgeservice.InternalWorkspaceToolResult
	continueCount atomic.Int32
}

func newAnthropicInternalToolExecutor() *anthropicInternalToolExecutor {
	return &anthropicInternalToolExecutor{results: make(chan edgeservice.InternalWorkspaceToolResult, 2)}
}

func (e *anthropicInternalToolExecutor) ExecuteSingleRequest(
	ctx context.Context,
	req edgeservice.SingleRequestRequest,
	ctrl edgeservice.SingleRequestController,
) error {
	sequence := uint64(1)
	if err := ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: sequence, Stage: edgeservice.SingleRequestStatePlanning}); err != nil {
		return err
	}
	calls := []*edgeservice.InternalWorkspaceToolCall{
		{
			RequestID: req.RequestID, StageID: "plan", ToolCallID: "tool-read",
			Name: edgeservice.InternalWorkspaceToolRead, Arguments: json.RawMessage(`{"relative_path":"README.md"}`),
		},
		{
			RequestID: req.RequestID, StageID: "plan", ToolCallID: "tool-write",
			Name:      edgeservice.InternalWorkspaceToolWrite,
			Arguments: json.RawMessage(`{"relative_path":"result.txt","content":"PRIVATE_INTERNAL_ARGUMENT_SENTINEL"}`),
		},
	}
	for _, call := range calls {
		sequence++
		if err := ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{
			RequestID: req.RequestID, Sequence: sequence,
			Stage: edgeservice.SingleRequestStateInternalTool, SavedStage: edgeservice.SingleRequestStatePlanning,
			ToolCall: call,
		}); err != nil {
			return err
		}
		select {
		case result := <-e.results:
			if result.RequestID != req.RequestID || result.StageID != "plan" || result.ToolCallID != call.ToolCallID {
				return errors.New("internal tool result identity mismatch")
			}
		case <-ctx.Done():
			return ctx.Err()
		}
		sequence++
		if err := ctrl.SubmitEnvelope(edgeservice.SingleRequestEnvelope{
			RequestID: req.RequestID, Sequence: sequence,
			Stage: edgeservice.SingleRequestStatePlanning, SavedStage: edgeservice.SingleRequestStatePlanning,
		}); err != nil {
			return err
		}
	}
	for _, stage := range []edgeservice.SingleRequestState{
		edgeservice.SingleRequestStateWorking,
		edgeservice.SingleRequestStateReviewing,
		edgeservice.SingleRequestStateFinalizing,
	} {
		sequence++
		envelope := edgeservice.SingleRequestEnvelope{RequestID: req.RequestID, Sequence: sequence, Stage: stage}
		if stage == edgeservice.SingleRequestStateFinalizing {
			envelope.Result = &edgeservice.SingleRequestResult{Output: "workspace task completed privately"}
		}
		if err := ctrl.SubmitEnvelope(envelope); err != nil {
			return err
		}
	}
	return nil
}

func (e *anthropicInternalToolExecutor) ContinueInternalTool(_ context.Context, result edgeservice.InternalWorkspaceToolResult) error {
	e.continueCount.Add(1)
	e.results <- result.Clone()
	return nil
}

func newAnthropicInternalToolService(
	t *testing.T,
	executor *anthropicInternalToolExecutor,
) (*edgeservice.Service, *toki.TcpClient) {
	t.Helper()
	edgeConn, nodeConn := net.Pipe()
	edgeClient := toki.NewTcpClient(edgeConn, 0, 0, toki.ParserMap{
		toki.TypeNameOf(&iop.WorkspaceOpenResponse{}):    parseAnthropicWorkspaceMessage(&iop.WorkspaceOpenResponse{}),
		toki.TypeNameOf(&iop.WorkspaceToolResponse{}):    parseAnthropicWorkspaceMessage(&iop.WorkspaceToolResponse{}),
		toki.TypeNameOf(&iop.WorkspaceCleanupResponse{}): parseAnthropicWorkspaceMessage(&iop.WorkspaceCleanupResponse{}),
	})
	nodeClient := toki.NewTcpClient(nodeConn, 0, 0, toki.ParserMap{
		toki.TypeNameOf(&iop.WorkspaceOpenRequest{}):    parseAnthropicWorkspaceMessage(&iop.WorkspaceOpenRequest{}),
		toki.TypeNameOf(&iop.WorkspaceToolRequest{}):    parseAnthropicWorkspaceMessage(&iop.WorkspaceToolRequest{}),
		toki.TypeNameOf(&iop.WorkspaceCleanupRequest{}): parseAnthropicWorkspaceMessage(&iop.WorkspaceCleanupRequest{}),
	})
	t.Cleanup(func() {
		_ = edgeClient.Close()
		_ = nodeClient.Close()
	})

	registry := edgenode.NewRegistry()
	registry.Register(&edgenode.NodeEntry{NodeID: "workspace-node", Alias: "workspace", Client: edgeClient})
	store := edgenode.NewNodeStore()
	store.Add(&edgenode.NodeRecord{
		ID: "workspace-node", Alias: "workspace", Token: "workspace-node-token",
		Workspaces: []config.WorkspaceDefinition{{
			Ref: "ws-opaque-ref", Platform: "darwin", Root: "/Users/operator/project",
			Operations:   []config.WorkspaceOperation{config.WorkspaceOpRead, config.WorkspaceOpWrite},
			MaxReadBytes: 4096, MaxWriteBytes: 4096,
		}},
	})
	service := edgeservice.New(registry, nil)
	service.SetNodeStore(store)
	service.SetSingleRequestExecutor(executor)
	return service, nodeClient
}

func parseAnthropicWorkspaceMessage(template proto.Message) func([]byte) (proto.Message, error) {
	return func(payload []byte) (proto.Message, error) {
		message := template.ProtoReflect().Type().New().Interface()
		return message, proto.Unmarshal(payload, message)
	}
}

func TestAnthropicSingleRequestInternalToolsStayPrivate(t *testing.T) {
	executor := newAnthropicInternalToolExecutor()
	service, node := newAnthropicInternalToolService(t, executor)
	var openCount atomic.Int32
	var toolCount atomic.Int32
	toolOrder := make(chan string, 2)
	var cleanupCount atomic.Int32
	toki.AddRequestListenerTyped[*iop.WorkspaceOpenRequest, *iop.WorkspaceOpenResponse](&node.Communicator, func(req *iop.WorkspaceOpenRequest) (*iop.WorkspaceOpenResponse, error) {
		openCount.Add(1)
		return &iop.WorkspaceOpenResponse{RequestId: req.GetRequestId(), WorkspaceRef: req.GetWorkspaceRef(), Status: iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS}, nil
	})
	toki.AddRequestListenerTyped[*iop.WorkspaceToolRequest, *iop.WorkspaceToolResponse](&node.Communicator, func(req *iop.WorkspaceToolRequest) (*iop.WorkspaceToolResponse, error) {
		toolCount.Add(1)
		toolOrder <- req.GetToolCallId()
		response := &iop.WorkspaceToolResponse{
			RequestId: req.GetRequestId(), StageId: req.GetStageId(), ToolCallId: req.GetToolCallId(),
			Status: iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS,
		}
		if req.GetOperation() == iop.WorkspaceOperation_WORKSPACE_OPERATION_READ {
			response.Content = []byte("private read result")
		}
		return response, nil
	})
	toki.AddRequestListenerTyped[*iop.WorkspaceCleanupRequest, *iop.WorkspaceCleanupResponse](&node.Communicator, func(req *iop.WorkspaceCleanupRequest) (*iop.WorkspaceCleanupResponse, error) {
		cleanupCount.Add(1)
		return &iop.WorkspaceCleanupResponse{
			RequestId: req.GetRequestId(),
			Status:    iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS,
		}, nil
	})

	srv := newAnthropicSingleRequestServer(t, service)
	var httpRequests atomic.Int32
	httpServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpRequests.Add(1)
		srv.routes().ServeHTTP(w, r)
	}))
	defer httpServer.Close()

	before := testutil.ToFloat64(singleRequestIngressTotal)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":128,"messages":[{"role":"user","content":"complete the task"}]}`
	request := newAnthropicSingleRequestHTTPReq(t, ctx, httpServer.URL, "/v1/messages", body)
	response, err := httpServer.Client().Do(request)
	if err != nil {
		t.Fatalf("POST /v1/messages: %v", err)
	}
	defer response.Body.Close()
	payload, err := io.ReadAll(response.Body)
	if err != nil {
		t.Fatal(err)
	}
	if response.StatusCode != http.StatusOK {
		t.Fatalf("status=%d body=%s", response.StatusCode, payload)
	}
	var terminal anthropicMessageResponse
	decoder := json.NewDecoder(strings.NewReader(string(payload)))
	if err := decoder.Decode(&terminal); err != nil {
		t.Fatalf("decode terminal: %v", err)
	}
	var extra json.RawMessage
	if err := decoder.Decode(&extra); err != io.EOF {
		t.Fatalf("terminal had trailing output: %v %s", err, extra)
	}
	if len(terminal.Content) != 1 || terminal.Content[0]["text"] != "workspace task completed privately" {
		t.Fatalf("terminal content = %+v", terminal.Content)
	}
	for _, private := range []string{
		"tool_use", "tool_result", edgeservice.InternalWorkspaceToolRead,
		edgeservice.InternalWorkspaceToolWrite, "PRIVATE_INTERNAL_ARGUMENT_SENTINEL", "private read result",
	} {
		if strings.Contains(string(payload), private) {
			t.Fatalf("public terminal leaked %q: %s", private, payload)
		}
	}
	if httpRequests.Load() != 1 || testutil.ToFloat64(singleRequestIngressTotal)-before != 1 {
		t.Fatalf("HTTP requests=%d ingress delta=%v, want 1/1", httpRequests.Load(), testutil.ToFloat64(singleRequestIngressTotal)-before)
	}
	if openCount.Load() != 1 || toolCount.Load() != 2 || cleanupCount.Load() != 1 || executor.continueCount.Load() != 2 {
		t.Fatalf("open=%d tools=%d cleanup=%d continuations=%d, want 1/2/1/2", openCount.Load(), toolCount.Load(), cleanupCount.Load(), executor.continueCount.Load())
	}
	for index, want := range []string{"tool-read", "tool-write"} {
		if got := <-toolOrder; got != want {
			t.Fatalf("tool order[%d]=%q, want %q", index, got, want)
		}
	}
}

type singleRequestMetricKey struct {
	eventClass string
	stage      string
	operation  string
	outcome    string
	errorClass string
}

func singleRequestMetricKeyFromLabels(labels []*dto.LabelPair) (singleRequestMetricKey, error) {
	var key singleRequestMetricKey
	seen := make(map[string]bool)
	for _, lp := range labels {
		name := lp.GetName()
		if seen[name] {
			return singleRequestMetricKey{}, fmt.Errorf("duplicate metric label %q", name)
		}
		seen[name] = true
		switch name {
		case "event_class":
			key.eventClass = lp.GetValue()
		case "stage":
			key.stage = lp.GetValue()
		case "operation":
			key.operation = lp.GetValue()
		case "outcome":
			key.outcome = lp.GetValue()
		case "error_class":
			key.errorClass = lp.GetValue()
		default:
			return singleRequestMetricKey{}, fmt.Errorf("unexpected metric label %q", name)
		}
	}
	expectedLabels := []string{"event_class", "stage", "operation", "outcome", "error_class"}
	for _, expected := range expectedLabels {
		if !seen[expected] {
			return singleRequestMetricKey{}, fmt.Errorf("missing metric label %q", expected)
		}
	}
	return key, nil
}

func isValidSingleRequestCorrelationID(corr string) bool {
	if strings.HasPrefix(corr, "sr-fallback-") {
		rest := corr[len("sr-fallback-"):]
		if len(rest) == 0 || len(rest) > 32 {
			return false
		}
		for _, r := range rest {
			if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'z')) {
				return false
			}
		}
		return true
	}
	if strings.HasPrefix(corr, "sr-") {
		rest := corr[len("sr-"):]
		if len(rest) != 32 {
			return false
		}
		for _, r := range rest {
			if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f')) {
				return false
			}
		}
		return true
	}
	return false
}

func zapFieldTypeName(t zapcore.FieldType) string {
	switch t {
	case zapcore.StringType:
		return "StringType"
	case zapcore.Int64Type:
		return "Int64Type"
	case zapcore.Int32Type:
		return "Int32Type"
	case zapcore.Float64Type:
		return "Float64Type"
	case zapcore.BoolType:
		return "BoolType"
	default:
		return fmt.Sprintf("FieldType(%d)", t)
	}
}

func singleRequestLogKey(fields []zapcore.Field) (singleRequestMetricKey, string, error) {
	if len(fields) != 9 {
		return singleRequestMetricKey{}, "", fmt.Errorf("expected 9 context fields, got %d", len(fields))
	}
	expectedTypes := map[string]zapcore.FieldType{
		"correlation": zapcore.StringType,
		"event_class": zapcore.StringType,
		"stage":       zapcore.StringType,
		"operation":   zapcore.StringType,
		"outcome":     zapcore.StringType,
		"error_class": zapcore.StringType,
		"duration_ms": zapcore.Int64Type,
		"tool_count":  zapcore.Int64Type,
		"has_result":  zapcore.BoolType,
	}

	seen := make(map[string]bool, len(fields))
	stringVals := make(map[string]string)

	for _, f := range fields {
		if seen[f.Key] {
			return singleRequestMetricKey{}, "", fmt.Errorf("duplicate context key %q", f.Key)
		}
		wantType, ok := expectedTypes[f.Key]
		if !ok {
			return singleRequestMetricKey{}, "", fmt.Errorf("unexpected context key %q", f.Key)
		}
		if f.Type != wantType {
			return singleRequestMetricKey{}, "", fmt.Errorf("key %q has Zap type %s, want %s", f.Key, zapFieldTypeName(f.Type), zapFieldTypeName(wantType))
		}
		seen[f.Key] = true
		if wantType == zapcore.StringType {
			stringVals[f.Key] = f.String
		}
	}

	for k := range expectedTypes {
		if !seen[k] {
			return singleRequestMetricKey{}, "", fmt.Errorf("missing context key %q", k)
		}
	}

	corrVal := stringVals["correlation"]
	if !isValidSingleRequestCorrelationID(corrVal) {
		return singleRequestMetricKey{}, "", fmt.Errorf("invalid correlation format %q", corrVal)
	}

	key := singleRequestMetricKey{
		eventClass: stringVals["event_class"],
		stage:      stringVals["stage"],
		operation:  stringVals["operation"],
		outcome:    stringVals["outcome"],
		errorClass: stringVals["error_class"],
	}
	return key, corrVal, nil
}

func snapshotSingleRequestMetrics(gatherer prometheus.Gatherer) (map[singleRequestMetricKey]float64, map[singleRequestMetricKey]uint64, error) {
	var families []*dto.MetricFamily
	var err error
	families, err = gatherer.Gather()
	if err != nil {
		return nil, nil, err
	}
	counters := make(map[singleRequestMetricKey]float64)
	histograms := make(map[singleRequestMetricKey]uint64)
	for _, family := range families {
		switch family.GetName() {
		case "iop_edge_single_request_lifecycle_total":
			for _, m := range family.GetMetric() {
				key, err := singleRequestMetricKeyFromLabels(m.GetLabel())
				if err != nil {
					return nil, nil, fmt.Errorf("family %s metric key error: %w", family.GetName(), err)
				}
				counters[key] = m.GetCounter().GetValue()
			}
		case "iop_edge_single_request_duration_seconds":
			for _, m := range family.GetMetric() {
				key, err := singleRequestMetricKeyFromLabels(m.GetLabel())
				if err != nil {
					return nil, nil, fmt.Errorf("family %s metric key error: %w", family.GetName(), err)
				}
				histograms[key] = m.GetHistogram().GetSampleCount()
			}
		}
	}
	return counters, histograms, nil
}

// TestAnthropicSingleRequestObservation links ingress, request-total, terminal,
// stage/tool/cleanup counts, and raw-free correlation for a real marked POST
// that exercises deterministic internal tools. It asserts the single-request
// lifecycle produces exactly one accepted ingress, one executor call, one
// terminal acknowledgement, the expected stage/tool/cleanup deltas, and a
// public terminal that never carries internal tool protocol or raw values.
// External Claude timing evidence on an approved IOP Node is explicitly deferred to claude-smoke.
func TestAnthropicSingleRequestObservation(t *testing.T) {
	executor := newAnthropicInternalToolExecutor()
	service, node := newAnthropicInternalToolService(t, executor)
	var openCount atomic.Int32
	var toolCount atomic.Int32
	var cleanupCount atomic.Int32
	toki.AddRequestListenerTyped[*iop.WorkspaceOpenRequest, *iop.WorkspaceOpenResponse](&node.Communicator, func(req *iop.WorkspaceOpenRequest) (*iop.WorkspaceOpenResponse, error) {
		openCount.Add(1)
		return &iop.WorkspaceOpenResponse{RequestId: req.GetRequestId(), WorkspaceRef: req.GetWorkspaceRef(), Status: iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS}, nil
	})
	toki.AddRequestListenerTyped[*iop.WorkspaceToolRequest, *iop.WorkspaceToolResponse](&node.Communicator, func(req *iop.WorkspaceToolRequest) (*iop.WorkspaceToolResponse, error) {
		toolCount.Add(1)
		response := &iop.WorkspaceToolResponse{
			RequestId: req.GetRequestId(), StageId: req.GetStageId(), ToolCallId: req.GetToolCallId(),
			Status: iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS,
		}
		return response, nil
	})
	toki.AddRequestListenerTyped[*iop.WorkspaceCleanupRequest, *iop.WorkspaceCleanupResponse](&node.Communicator, func(req *iop.WorkspaceCleanupRequest) (*iop.WorkspaceCleanupResponse, error) {
		cleanupCount.Add(1)
		return &iop.WorkspaceCleanupResponse{
			RequestId: req.GetRequestId(),
			Status:    iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS,
		}, nil
	})

	core, logs := observer.New(zap.InfoLevel)
	obsLogger := zap.New(core)
	lifecycleRegistry := prometheus.NewRegistry()
	service.SetSingleRequestObservationLoggerForTesting(lifecycleRegistry, obsLogger)

	srv := newAnthropicSingleRequestServer(t, service)
	httpServer := httptest.NewServer(srv.routes())
	defer httpServer.Close()

	beforeIngress := testutil.ToFloat64(singleRequestIngressTotal)
	beforeCounters, beforeHistograms, err := snapshotSingleRequestMetrics(lifecycleRegistry)
	if err != nil {
		t.Fatalf("snapshot initial metrics: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":128,"messages":[{"role":"user","content":"complete the task"}]}`
	request := newAnthropicSingleRequestHTTPReq(t, ctx, httpServer.URL, "/v1/messages", body)
	response, err := httpServer.Client().Do(request)
	if err != nil {
		t.Fatalf("POST /v1/messages: %v", err)
	}
	defer response.Body.Close()
	payload, err := io.ReadAll(response.Body)
	if err != nil {
		t.Fatal(err)
	}
	if response.StatusCode != http.StatusOK {
		t.Fatalf("status=%d body=%s", response.StatusCode, payload)
	}
	var terminal anthropicMessageResponse
	decoder := json.NewDecoder(strings.NewReader(string(payload)))
	if err := decoder.Decode(&terminal); err != nil {
		t.Fatalf("decode terminal: %v", err)
	}
	var extra json.RawMessage
	if err := decoder.Decode(&extra); err != io.EOF {
		t.Fatalf("terminal had trailing output: %v %s", err, extra)
	}
	if terminal.Model != testSingleRequestModel || terminal.Type != "message" || terminal.Role != "assistant" {
		t.Fatalf("public terminal identity mismatch: %+v", terminal)
	}
	if terminal.StopReason == nil || *terminal.StopReason != "end_turn" {
		t.Fatalf("stop_reason=%v, want end_turn", terminal.StopReason)
	}
	if len(terminal.Content) != 1 || terminal.Content[0]["type"] != "text" {
		t.Fatalf("terminal content=%+v, want one sanitized text block", terminal.Content)
	}
	encoded, err := json.Marshal(terminal)
	if err != nil {
		t.Fatal(err)
	}
	for _, privateValue := range []string{
		"tool_use", "tool_result", edgeservice.InternalWorkspaceToolRead,
		edgeservice.InternalWorkspaceToolWrite, "PRIVATE_INTERNAL_ARGUMENT_SENTINEL",
		"private read result", "ws-opaque-ref", "plan-model", "provider-plan", "slot-plan",
	} {
		if strings.Contains(string(encoded), privateValue) {
			t.Fatalf("terminal leaked %q: %s", privateValue, encoded)
		}
	}
	if got := testutil.ToFloat64(singleRequestIngressTotal) - beforeIngress; got != 1 {
		t.Fatalf("single-request ingress counter delta=%v, want 1", got)
	}
	if got := executor.continueCount.Load(); got != 2 {
		t.Fatalf("executor continuations=%d, want 2 (one per internal tool)", got)
	}
	if openCount.Load() != 1 {
		t.Fatalf("workspace open count=%d, want 1", openCount.Load())
	}
	if toolCount.Load() != 2 {
		t.Fatalf("internal tool count=%d, want 2", toolCount.Load())
	}
	if cleanupCount.Load() != 1 {
		t.Fatalf("workspace cleanup count=%d, want 1", cleanupCount.Load())
	}

	afterCounters, afterHistograms, err := snapshotSingleRequestMetrics(lifecycleRegistry)
	if err != nil {
		t.Fatalf("snapshot final metrics: %v", err)
	}

	wantDeltas := map[singleRequestMetricKey]float64{
		{eventClass: "request", stage: "none", operation: "total", outcome: "success", errorClass: "none"}:     1,
		{eventClass: "stage", stage: "plan", operation: "plan", outcome: "success", errorClass: "none"}:        1,
		{eventClass: "stage", stage: "work", operation: "work", outcome: "success", errorClass: "none"}:        1,
		{eventClass: "stage", stage: "review", operation: "review", outcome: "success", errorClass: "none"}:    1,
		{eventClass: "tool", stage: "none", operation: "tool", outcome: "success", errorClass: "none"}:         2,
		{eventClass: "cleanup", stage: "none", operation: "cleanup", outcome: "success", errorClass: "none"}:   1,
		{eventClass: "terminal", stage: "none", operation: "terminal", outcome: "success", errorClass: "none"}: 1,
	}

	for key, wantDelta := range wantDeltas {
		gotCounterDelta := afterCounters[key] - beforeCounters[key]
		if gotCounterDelta != wantDelta {
			t.Fatalf("lifecycle metric counter delta for %+v = %v, want %v", key, gotCounterDelta, wantDelta)
		}
		gotHistDelta := afterHistograms[key] - beforeHistograms[key]
		if float64(gotHistDelta) != wantDelta {
			t.Fatalf("lifecycle metric duration delta for %+v = %v, want %v", key, gotHistDelta, wantDelta)
		}
	}

	for key, afterVal := range afterCounters {
		delta := afterVal - beforeCounters[key]
		if delta > 0 {
			if _, expected := wantDeltas[key]; !expected {
				t.Fatalf("unexpected lifecycle metric delta for key %+v: %v", key, delta)
			}
		}
	}

	entries := logs.All()
	if len(entries) != 8 {
		t.Fatalf("captured observation logs count = %d, want 8", len(entries))
	}

	logCounts := make(map[singleRequestMetricKey]float64)
	var requestCorrelation string
	for i, entry := range entries {
		if entry.Message != "edge_single_request_observation" {
			t.Fatalf("log[%d] message = %q, want edge_single_request_observation", i, entry.Message)
		}
		key, corrVal, err := singleRequestLogKey(entry.Context)
		if err != nil {
			t.Fatalf("log[%d] schema: %v", i, err)
		}
		if i == 0 {
			requestCorrelation = corrVal
		} else if corrVal != requestCorrelation {
			t.Fatalf("log[%d] correlation = %q, want shared correlation %q", i, corrVal, requestCorrelation)
		}
		logCounts[key]++

		rawLog := fmt.Sprintf("%+v", entry.ContextMap())
		for _, privateValue := range []string{
			edgeservice.InternalWorkspaceToolRead, edgeservice.InternalWorkspaceToolWrite,
			"README.md", "result.txt", "PRIVATE_INTERNAL_ARGUMENT_SENTINEL",
			"private read result", "ws-opaque-ref", "complete the task",
			"workspace task completed privately",
		} {
			if strings.Contains(rawLog, privateValue) {
				t.Fatalf("log[%d] leaked private content %q: %s", i, privateValue, rawLog)
			}
		}
	}

	if len(logCounts) != len(wantDeltas) {
		t.Fatalf("captured log unique tuple count = %d, want %d", len(logCounts), len(wantDeltas))
	}
	for key, wantCount := range wantDeltas {
		if got := logCounts[key]; got != wantCount {
			t.Fatalf("captured log count for tuple %+v = %v, want %v", key, got, wantCount)
		}
	}

	families, err := prometheus.DefaultGatherer.Gather()
	if err != nil {
		t.Fatalf("gather metrics: %v", err)
	}
	foundMetric := false
	for _, family := range families {
		if family.GetName() != "iop_anthropic_single_request_ingress_total" {
			continue
		}
		foundMetric = true
		for _, metric := range family.Metric {
			if len(metric.Label) != 0 {
				t.Fatalf("single-request ingress metric has request-derived labels: %+v", metric.Label)
			}
		}
	}
	if !foundMetric {
		t.Fatal("registered single-request ingress metric was not gathered")
	}
}

func TestAnthropicSingleRequestUnavailableFailsClosed(t *testing.T) {
	fake := &providerFakeRunService{poolDispatchPath: string(edgeservice.ProviderPoolPathTunnel)}
	srv := newAnthropicSingleRequestServer(t, fake)
	before := testutil.ToFloat64(singleRequestIngressTotal)
	w := httptest.NewRecorder()
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":32,"messages":[{"role":"user","content":"hello"}]}`
	serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages", body, w)
	if w.Code != http.StatusServiceUnavailable {
		t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "single-request execution is unavailable") {
		t.Fatalf("unexpected unavailable body: %s", w.Body.String())
	}
	if got := fake.poolSubmitCountSnapshot(); got != 0 {
		t.Fatalf("marked request fell back to provider pool: submissions=%d", got)
	}
	if got := testutil.ToFloat64(singleRequestIngressTotal) - before; got != 0 {
		t.Fatalf("unavailable capability changed accepted-ingress counter by %v", got)
	}
}

func TestAnthropicSingleRequestExecutorFailureIsSanitized(t *testing.T) {
	const privateFailure = "PRIVATE_PROVIDER_ROUTE_CREDENTIAL_FAILURE"
	executor := anthropicSingleRequestExecutorFunc(func(
		context.Context,
		edgeservice.SingleRequestRequest,
		edgeservice.SingleRequestController,
	) error {
		return errors.New(privateFailure)
	})
	svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
	srv := newAnthropicSingleRequestServer(t, svc)
	w := httptest.NewRecorder()
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":32,"messages":[{"role":"user","content":"hello"}]}`
	serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages", body, w)
	if w.Code != http.StatusBadGateway {
		t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
	}
	if strings.Contains(w.Body.String(), privateFailure) || !strings.Contains(w.Body.String(), "single-request execution failed") {
		t.Fatalf("executor failure was not sanitized: %s", w.Body.String())
	}
}

type singleRequestFailingWriter struct {
	header http.Header
	status int
}

func (w *singleRequestFailingWriter) Header() http.Header {
	if w.header == nil {
		w.header = make(http.Header)
	}
	return w.header
}

func (w *singleRequestFailingWriter) WriteHeader(status int) { w.status = status }

func (w *singleRequestFailingWriter) Write([]byte) (int, error) {
	return 0, errors.New("test response write failure")
}

func TestAnthropicSingleRequestWriteFailureRejectsAcknowledgement(t *testing.T) {
	controllerCh := make(chan edgeservice.SingleRequestController, 1)
	executor := anthropicSingleRequestExecutorFunc(func(
		_ context.Context,
		req edgeservice.SingleRequestRequest,
		ctrl edgeservice.SingleRequestController,
	) error {
		if err := submitAnthropicSingleRequestLifecycle(req, ctrl, "safe final"); err != nil {
			return err
		}
		controllerCh <- ctrl
		return nil
	})
	svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
	srv := newAnthropicSingleRequestServer(t, svc)
	w := &singleRequestFailingWriter{}
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":32,"messages":[{"role":"user","content":"hello"}]}`
	serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages", body, w)
	if w.status != http.StatusOK {
		t.Fatalf("write status=%d, want attempted 200 terminal", w.status)
	}
	if got := (<-controllerCh).State(); got != edgeservice.SingleRequestStateFailed {
		t.Fatalf("write-failure acknowledgement state=%s, want failed", got)
	}
}

func TestAnthropicSingleRequestCallerCancellationCancelsExecution(t *testing.T) {
	controllerCh := make(chan edgeservice.SingleRequestController, 1)
	executor := anthropicSingleRequestExecutorFunc(func(
		ctx context.Context,
		_ edgeservice.SingleRequestRequest,
		ctrl edgeservice.SingleRequestController,
	) error {
		controllerCh <- ctrl
		<-ctx.Done()
		return ctx.Err()
	})
	svc := newAdmittedAnthropicSingleRequestService(t, executor, "ws-opaque-ref")
	srv := newAnthropicSingleRequestServer(t, svc)
	ctx, cancel := context.WithCancel(context.Background())
	w := httptest.NewRecorder()
	done := make(chan struct{})
	body := `{"model":"` + testSingleRequestModel + `","max_tokens":32,"messages":[{"role":"user","content":"hello"}]}`
	go func() {
		defer close(done)
		serveAnthropicSingleRequest(t, srv, ctx, "/v1/messages", body, w)
	}()
	controller := <-controllerCh
	cancel()
	select {
	case <-done:
	case <-time.After(2 * time.Second):
		t.Fatal("handler did not return after caller cancellation")
	}
	if got := controller.State(); got != edgeservice.SingleRequestStateCancelled {
		t.Fatalf("caller-cancel state=%s, want cancelled", got)
	}
	if w.Body.Len() != 0 {
		t.Fatalf("caller cancellation wrote a terminal after disconnect: %s", w.Body.String())
	}
}

func TestAnthropicSingleRequestCountTokensBypassesExecution(t *testing.T) {
	fake := &providerFakeRunService{poolDispatchPath: string(edgeservice.ProviderPoolPathTunnel)}
	srv := newAnthropicSingleRequestServer(t, fake)
	before := testutil.ToFloat64(singleRequestIngressTotal)
	w := httptest.NewRecorder()
	body := `{"model":"` + testSingleRequestModel + `","messages":[{"role":"user","content":"count this"}]}`
	serveAnthropicSingleRequest(t, srv, context.Background(), "/v1/messages/count_tokens", body, w)
	if w.Code != http.StatusOK || !strings.Contains(w.Body.String(), `"input_tokens"`) {
		t.Fatalf("count-tokens status=%d body=%s", w.Code, w.Body.String())
	}
	if got := fake.poolSubmitCountSnapshot(); got != 0 {
		t.Fatalf("local count-tokens used provider pool: submissions=%d", got)
	}
	if got := testutil.ToFloat64(singleRequestIngressTotal) - before; got != 0 {
		t.Fatalf("count-tokens changed Messages ingress counter by %v", got)
	}
}

func TestSingleRequestLogSchemaRejectsDrift(t *testing.T) {
	validFields := func() []zapcore.Field {
		return []zapcore.Field{
			zap.String("correlation", "sr-0123456789abcdef0123456789abcdef"),
			zap.String("event_class", "request"),
			zap.String("stage", "none"),
			zap.String("operation", "total"),
			zap.String("outcome", "success"),
			zap.String("error_class", "none"),
			zap.Int64("duration_ms", 15),
			zap.Int("tool_count", 0),
			zap.Bool("has_result", false),
		}
	}

	key, corr, err := singleRequestLogKey(validFields())
	if err != nil {
		t.Fatalf("valid baseline fields rejected: %v", err)
	}
	if corr != "sr-0123456789abcdef0123456789abcdef" {
		t.Fatalf("correlation = %q, want sr-0123456789abcdef0123456789abcdef", corr)
	}
	wantKey := singleRequestMetricKey{
		eventClass: "request",
		stage:      "none",
		operation:  "total",
		outcome:    "success",
		errorClass: "none",
	}
	if key != wantKey {
		t.Fatalf("key = %+v, want %+v", key, wantKey)
	}

	fallbackFields := validFields()
	fallbackFields[0] = zap.String("correlation", "sr-fallback-1a2b3c")
	if _, _, err := singleRequestLogKey(fallbackFields); err != nil {
		t.Fatalf("valid fallback correlation rejected: %v", err)
	}

	tests := []struct {
		name    string
		mutate  func([]zapcore.Field) []zapcore.Field
		wantErr string
	}{
		{
			name: "duplicate_key",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[1] = zap.String("correlation", "sr-0123456789abcdef0123456789abcdef")
				return res
			},
			wantErr: "duplicate context key \"correlation\"",
		},
		{
			name: "missing_key",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				return f[:len(f)-1]
			},
			wantErr: "expected 9 context fields, got 8",
		},
		{
			name: "unknown_key",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[0] = zap.String("unexpected_key", "sr-0123456789abcdef0123456789abcdef")
				return res
			},
			wantErr: "unexpected context key \"unexpected_key\"",
		},
		{
			name: "wrong_numeric_type_float64",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[6] = zap.Float64("duration_ms", 15.0)
				return res
			},
			wantErr: "key \"duration_ms\" has Zap type Float64Type, want Int64Type",
		},
		{
			name: "wrong_numeric_type_int32",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[7] = zap.Int32("tool_count", 0)
				return res
			},
			wantErr: "key \"tool_count\" has Zap type Int32Type, want Int64Type",
		},
		{
			name: "wrong_string_type",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[2] = zap.Int64("stage", 1)
				return res
			},
			wantErr: "key \"stage\" has Zap type Int64Type, want StringType",
		},
		{
			name: "wrong_bool_type",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[8] = zap.String("has_result", "false")
				return res
			},
			wantErr: "key \"has_result\" has Zap type StringType, want BoolType",
		},
		{
			name: "constant_correlation",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[0] = zap.String("correlation", "constant-correlation-id")
				return res
			},
			wantErr: "invalid correlation format \"constant-correlation-id\"",
		},
		{
			name: "short_hex_correlation",
			mutate: func(f []zapcore.Field) []zapcore.Field {
				res := append([]zapcore.Field(nil), f...)
				res[0] = zap.String("correlation", "sr-12345")
				return res
			},
			wantErr: "invalid correlation format \"sr-12345\"",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mutated := tt.mutate(validFields())
			_, _, err := singleRequestLogKey(mutated)
			if err == nil {
				t.Fatalf("expected error containing %q, got nil", tt.wantErr)
			}
			if !strings.Contains(err.Error(), tt.wantErr) {
				t.Fatalf("err = %q, want error containing %q", err.Error(), tt.wantErr)
			}
		})
	}
}
