"""Hierarchical public capability map.

This module is the architectural companion to ``smoke.features``.  The feature
inventory says which public features must be covered; this map records the
subfeature contracts, owning module boundary, and coverage owners that protect
them while the internals are refactored.
"""

from dataclasses import dataclass


@dataclass(frozen=True, slots=True)
class CapabilityContract:
    capability: str
    subfeature: str
    feature_id: str
    owner: str
    inputs: str
    outputs: str
    failure: str
    pytest_tests: tuple[str, ...]
    smoke_tests: tuple[str, ...] = ()


CAPABILITY_CONTRACTS: tuple[CapabilityContract, ...] = (
    CapabilityContract(
        "api_compatibility",
        "routes_and_probes",
        "anthropic_api_routes",
        "free_claude_code.api.routes",
        "Anthropic-compatible HTTP requests",
        "JSON or Anthropic SSE responses",
        "HTTPException or Anthropic error payload",
        ("tests/api/test_api.py",),
        ("test_probe_and_models_routes", "test_stop_endpoint_reports_no_messaging"),
    ),
    CapabilityContract(
        "api_compatibility",
        "head_options_probes",
        "probe_routes",
        "free_claude_code.api.routes",
        "HEAD/OPTIONS probe requests",
        "204 with Allow header",
        "auth failure when configured",
        ("tests/api/test_api.py::test_probe_endpoints_return_204_with_allow_headers",),
        ("test_probe_and_models_routes",),
    ),
    CapabilityContract(
        "api_compatibility",
        "client_request_shapes",
        "drop_in_claude_code_replacement",
        "free_claude_code.api.handlers.messages.MessagesHandler",
        "Claude Code, VS Code, and JetBrains shaped requests",
        "compatible streaming response",
        "provider or validation error in Anthropic shape",
        ("tests/api/test_api.py", "tests/cli/test_cli.py"),
        ("test_vscode_and_jetbrains_shaped_requests",),
    ),
    CapabilityContract(
        "api_compatibility",
        "responses_api",
        "drop_in_codex_replacement",
        "free_claude_code.api.handlers.responses.ResponsesHandler",
        "OpenAI Responses requests from Codex",
        "Responses SSE or JSON response",
        "OpenAI-shaped error or conversion error",
        (
            "tests/api/test_openai_responses.py",
            "tests/core/openai_responses/test_sse.py",
            "tests/cli/test_entrypoints.py",
            "tests/cli/test_codex_model_catalog.py",
        ),
        (
            "test_probe_and_models_routes",
            "test_provider_codex_responses_text_e2e",
        ),
    ),
    CapabilityContract(
        "api_compatibility",
        "client_extensions",
        "vscode_extension",
        "free_claude_code.api.handlers.messages.MessagesHandler",
        "VS Code beta query/header variants",
        "accepted Anthropic-compatible response",
        "HTTP error only for auth/provider failures",
        (),
        ("test_vscode_and_jetbrains_shaped_requests",),
    ),
    CapabilityContract(
        "api_compatibility",
        "client_extensions",
        "intellij_extension",
        "free_claude_code.api.handlers.messages.MessagesHandler",
        "JetBrains/ACP request variants",
        "accepted Anthropic-compatible response",
        "HTTP error only for auth/provider failures",
        (),
        ("test_vscode_and_jetbrains_shaped_requests",),
    ),
    CapabilityContract(
        "auth",
        "bearer_authorization",
        "optional_authentication",
        "free_claude_code.api.dependencies.require_proxy_auth",
        "authorization: bearer token",
        "request accepted or 401",
        "401 missing/invalid proxy authentication token",
        ("tests/api/test_auth.py",),
        ("test_bearer_auth_is_the_only_supported_header_shape",),
    ),
    CapabilityContract(
        "provider_routing",
        "provider_runtime",
        "provider_matrix",
        "free_claude_code.runtime.provider_manager.ProviderRuntimeManager",
        "provider id and Settings",
        "configured BaseProvider instance",
        "503 for missing credentials; invalid_request_error for unknown provider",
        ("tests/api/test_dependencies.py", "tests/providers/test_provider_runtime.py"),
        (
            "test_configured_provider_models_stream_successfully",
            "test_provider_matrix_presence_e2e",
        ),
    ),
    CapabilityContract(
        "provider_routing",
        "claude_model_resolution",
        "per_model_mapping",
        "free_claude_code.application.routing.ModelRouter",
        "Claude model name and configured MODEL_* values",
        "provider id plus provider model name",
        "settings validation rejects invalid provider prefixes",
        ("tests/application/test_routing.py", "tests/config/test_config.py"),
        ("test_model_mapping_configuration_is_consistent",),
    ),
    CapabilityContract(
        "provider_routing",
        "mixed_provider_resolution",
        "mixed_provider_mapping",
        "free_claude_code.application.routing.ModelRouter",
        "Fable/Opus/Sonnet/Haiku/fallback model config",
        "distinct provider selections per request",
        "skip live execution when providers are not configured",
        ("tests/application/test_routing.py", "tests/config/test_config.py"),
        ("test_mixed_provider_model_mapping_when_configured",),
    ),
    CapabilityContract(
        "provider_routing",
        "provider_runtime_config",
        "provider_proxy_timeout_config",
        "free_claude_code.providers.runtime.ProviderRuntime",
        "provider proxy, timeout, and rate-limit settings",
        "provider client and instance-owned limiter config",
        "provider construction failure",
        (
            "tests/api/test_dependencies.py",
            "tests/providers/test_provider_runtime.py",
            "tests/providers/test_provider_rate_limit.py",
        ),
    ),
    CapabilityContract(
        "provider_routing",
        "zero_cost_backends",
        "zero_cost_provider_access",
        "free_claude_code.providers.runtime.ProviderRuntime",
        "configured free/local provider",
        "streaming response from selected backend",
        "missing env or upstream unavailable skip in smoke",
        ("tests/api/test_dependencies.py", "tests/providers/"),
        ("test_configured_provider_models_stream_successfully",),
    ),
    CapabilityContract(
        "streaming_conversion",
        "anthropic_sse_lifecycle",
        "streaming_error_mapping",
        "free_claude_code.core.failures.ExecutionFailure",
        "provider stream failures before or after the HTTP commit boundary",
        "protocol-specific JSON failure or terminal stream event",
        "ordinary request failures remain distinct from terminal execution",
        (
            "tests/api/test_execution_failure_contract.py",
            "tests/api/test_ordinary_error_phases.py",
            "tests/core/test_failure_protocol_mapping.py",
            "tests/providers/test_execution_failure_boundary.py",
            "tests/providers/test_failure_policy.py",
        ),
    ),
    CapabilityContract(
        "streaming_conversion",
        "thinking_blocks",
        "thinking_token_support",
        "free_claude_code.core.anthropic.thinking",
        "reasoning_content, reasoning_details, <think> text, native thinking",
        "Claude thinking blocks or suppression",
        "thinking hidden when disabled",
        (
            "tests/contracts/test_stream_contracts.py",
            "tests/providers/test_converter.py",
            "tests/providers/test_deepseek.py",
            "tests/providers/test_nvidia_nim_request.py",
            "tests/providers/test_open_router.py",
        ),
        (
            "test_route_reasoning_config_e2e",
            "test_provider_reasoning_tool_continuation_e2e",
        ),
    ),
    CapabilityContract(
        "streaming_conversion",
        "heuristic_tools",
        "heuristic_tool_parser",
        "free_claude_code.core.anthropic.tools",
        "textual tool-call output",
        "structured Anthropic tool_use blocks",
        "text fallback when malformed",
        ("tests/providers/test_parsers.py", "tests/contracts/test_stream_contracts.py"),
        (
            "test_live_tool_use_when_configured_model_supports_tools",
            "test_provider_reasoning_tool_continuation_e2e",
        ),
    ),
    CapabilityContract(
        "streaming_conversion",
        "subagent_task_control",
        "subagent_control",
        "free_claude_code.core.anthropic.streaming.AnthropicStreamLedger",
        "Task tool call arguments",
        "run_in_background=false",
        "invalid JSON flushed as safe object",
        ("tests/providers/test_subagent_interception.py",),
    ),
    CapabilityContract(
        "request_behavior",
        "local_optimizations",
        "request_optimization",
        "free_claude_code.api.optimization_handlers",
        "Claude Code probe/title/suggestion/filepath requests",
        "local MessagesResponse without provider call",
        "falls through to provider when unmatched/disabled",
        (
            "tests/api/test_optimization_handlers.py",
            "tests/api/test_routes_optimizations.py",
        ),
        ("test_optimization_fast_paths_do_not_need_provider",),
    ),
    CapabilityContract(
        "request_behavior",
        "token_counting",
        "count_tokens_contract",
        "free_claude_code.core.anthropic.get_token_count",
        "messages, system blocks, tools, images, thinking, tool results",
        "positive input token estimate",
        "500 with readable detail on unexpected failure",
        ("tests/api/test_request_utils.py",),
        ("test_count_tokens_accepts_thinking_tools_and_results",),
    ),
    CapabilityContract(
        "config",
        "env_precedence",
        "config_env_precedence",
        "free_claude_code.config.settings.Settings",
        "process env, user env file, repo env file, FCC_ENV_FILE",
        "deterministic settings values",
        "validation error for invalid settings",
        ("tests/config/test_config.py",),
    ),
    CapabilityContract(
        "config",
        "removed_env_migration",
        "removed_env_migration",
        "free_claude_code.config.settings.Settings",
        "retired ENABLE_MODEL_THINKING or tier override in an FCC-owned dotenv",
        "owned dotenv is migrated to the typed reasoning policy",
        "explicit dotenv receives an actionable warning",
        ("tests/config/test_env_migrations.py", "tests/config/test_config.py"),
        ("test_removed_env_migration_e2e",),
    ),
    CapabilityContract(
        "provider_runtime",
        "rate_limit_and_disconnect",
        "smart_rate_limiting",
        "free_claude_code.providers.rate_limit.ProviderRateLimiter",
        "concurrent provider requests and transient upstream/disconnect failures",
        "provider-specific classification, proactive throttle, retry, cleanup",
        "mapped provider error or smoke skip for upstream disconnect",
        (
            "tests/providers/test_provider_rate_limit.py",
            "tests/providers/test_nvidia_nim_degraded_retry.py",
        ),
        ("test_client_disconnect_mid_stream_does_not_crash_server",),
    ),
    CapabilityContract(
        "provider_runtime",
        "generation_hot_swap",
        "provider_hot_swap",
        "free_claude_code.runtime.provider_manager.ProviderRuntimeManager",
        "validated Admin provider config and concurrent request streams",
        "atomic generation publication with old-stream completion",
        "failed candidate or persistence leaves current generation unchanged",
        (
            "tests/runtime/test_provider_manager.py",
            "tests/api/test_response_streams.py",
            "tests/api/test_admin.py",
        ),
        ("test_provider_hot_swap_preserves_inflight_stream_e2e",),
    ),
    CapabilityContract(
        "local_providers",
        "lmstudio_messages",
        "lmstudio_endpoint",
        "free_claude_code.providers.lmstudio.LMStudioProvider",
        "Anthropic Messages request and local LM Studio URL",
        "Anthropic SSE converted from an OpenAI Chat upstream",
        "typed provider failure for local upstream errors",
        ("tests/providers/test_lmstudio.py",),
        ("test_lmstudio_messages_e2e",),
    ),
    CapabilityContract(
        "local_providers",
        "llamacpp_openai_chat",
        "llamacpp_endpoint",
        "free_claude_code.providers.openai_chat.OpenAIChatProvider",
        "OpenAI Chat request and llama.cpp URL",
        "Anthropic SSE converted from OpenAI Chat chunks",
        "typed provider failure for local upstream errors",
        ("tests/providers/test_llamacpp.py",),
        ("test_llamacpp_models_endpoint_when_available",),
    ),
    CapabilityContract(
        "local_providers",
        "ollama_openai_chat",
        "ollama_endpoint",
        "free_claude_code.providers.openai_chat.OpenAIChatProvider",
        "OpenAI Chat request and local Ollama root URL",
        "Anthropic SSE converted from OpenAI Chat chunks",
        "typed provider failure for local upstream errors",
        ("tests/providers/test_ollama.py",),
        ("test_ollama_models_endpoint_when_available",),
    ),
    CapabilityContract(
        "openrouter",
        "openai_chat_provider",
        "provider_matrix",
        "free_claude_code.providers.open_router.OpenRouterProvider",
        "OpenAI Chat request for OpenRouter",
        "OpenAI stream mapped to Anthropic SSE",
        "Anthropic SSE error shape",
        (
            "tests/providers/test_open_router.py",
            "tests/providers/test_openai_compat_5xx_retry.py",
        ),
        ("test_configured_provider_models_stream_successfully",),
    ),
    CapabilityContract(
        "messaging",
        "discord_telegram_platforms",
        "discord_telegram_bot",
        "free_claude_code.messaging.workflow.MessagingWorkflow",
        "Discord/Telegram incoming messages and API callbacks",
        "live progress edits and final transcript",
        "platform retry/fallback or user-facing error",
        (
            "tests/messaging/test_discord_platform.py",
            "tests/messaging/test_telegram.py",
            "tests/messaging/test_limiter.py",
            "tests/messaging/test_platform_outbox.py",
            "tests/runtime/test_application_runtime.py",
        ),
        ("test_telegram_bot_api_permissions", "test_discord_bot_api_permissions"),
    ),
    CapabilityContract(
        "messaging",
        "commands",
        "messaging_commands",
        "free_claude_code.messaging.commands",
        "/stop, /clear, /stats command messages",
        "chat-wide cleanup or literal reply-subtree deletion",
        "terminal status edit, no-op feedback, or best-effort platform cleanup",
        (
            "tests/messaging/test_handler.py",
            "tests/messaging/test_handler_integration.py",
            "tests/messaging/test_tree_ownership_concurrency.py",
        ),
        (
            "test_messaging_commands_stop_clear_stats_e2e",
            "test_reply_clear_uses_literal_platform_subtree_e2e",
            "test_messaging_startup_notice_is_clearable_e2e",
            "test_messaging_active_stop_uses_status_only_e2e",
            "test_messaging_queued_scoped_cancel_e2e",
        ),
    ),
    CapabilityContract(
        "messaging",
        "tree_threading",
        "tree_threading",
        "free_claude_code.messaging.trees.TreeQueueManager",
        "reply-based message graph",
        "queued branches and scoped cancellation",
        "node error propagation",
        (
            "tests/messaging/test_tree_queue.py",
            "tests/messaging/test_tree_concurrency.py",
            "tests/messaging/test_message_tree_transitions.py",
            "tests/messaging/test_tree_ownership_concurrency.py",
        ),
        (
            "test_tree_threading_e2e",
            "test_messaging_queued_scoped_cancel_e2e",
            "test_same_message_ids_are_isolated_by_chat_e2e",
        ),
    ),
    CapabilityContract(
        "persistence",
        "restart_restore",
        "restart_restore",
        "free_claude_code.messaging.session.SessionStore",
        "stored tree JSON",
        "restored scoped reply lookup",
        "stale pending work marked lost",
        ("tests/messaging/test_restart_reply_restore.py",),
    ),
    CapabilityContract(
        "persistence",
        "session_store",
        "session_persistence",
        "free_claude_code.messaging.session.SessionStore",
        "scoped tree data and message log",
        "JSON persistence compatible with existing files",
        "best-effort flush error logging",
        ("tests/messaging/test_session_store_edge_cases.py",),
    ),
    CapabilityContract(
        "voice",
        "voice_transcription",
        "voice_notes",
        "free_claude_code.messaging.voice.Transcriber",
        "Discord/Telegram audio file and voice backend settings",
        "transcribed prompt routed to handler",
        "missing optional extra or backend error shown to user",
        (
            "tests/messaging/test_voice_handlers.py",
            "tests/messaging/test_transcription.py",
            "tests/messaging/test_transcription_nim.py",
            "tests/messaging/test_platform_voice_flow.py",
        ),
        ("test_voice_transcription_backend_when_explicitly_enabled",),
    ),
    CapabilityContract(
        "cli",
        "package_entrypoints",
        "package_cli_entrypoints",
        "free_claude_code.cli.entrypoints",
        "installed console scripts",
        "config scaffold, package version, or uvicorn server startup",
        "process cleanup in finally",
        ("tests/cli/test_entrypoints.py", "tests/core/test_version.py"),
        (
            "test_fcc_init_scaffolds_user_config",
            "test_free_claude_code_entrypoint_starts_server",
            "test_entrypoint_version_e2e",
        ),
    ),
    CapabilityContract(
        "cli",
        "claude_cli_drop_in",
        "claude_cli_drop_in",
        "free_claude_code.cli.managed.session.ManagedClaudeSession",
        "Claude CLI binary and proxy env",
        "stream-json events and session id mapping",
        "stderr/error event and process cleanup",
        ("tests/cli/test_cli.py",),
        (
            "test_claude_cli_prompt_when_available",
            "test_claude_cli_provider_error_e2e",
            "test_nvidia_nim_cli_matrix_e2e",
            "test_openrouter_free_cli_matrix_e2e",
        ),
    ),
    CapabilityContract(
        "cli",
        "codex_cli_drop_in",
        "drop_in_codex_replacement",
        "free_claude_code.cli.launchers.codex",
        "Codex CLI binary and fcc provider env",
        "Responses config, auth env, and native /model catalog injection",
        "proxy preflight and catalog fail-open warning",
        (
            "tests/cli/test_codex_model_catalog.py",
            "tests/cli/test_entrypoints.py",
        ),
        (),
    ),
    CapabilityContract(
        "cli",
        "pi_cli_integration",
        "pi_cli_integration",
        "free_claude_code.cli.launchers.pi",
        "Pi CLI binary, bundled extension, and FCC child-process environment",
        "Anthropic Messages provider with an FCC-scoped live model catalog",
        "proxy preflight, missing extension, or catalog failure exits without fallback",
        ("tests/cli/test_entrypoints.py",),
        ("test_pi_cli_prompt_e2e",),
    ),
    CapabilityContract(
        "extensibility",
        "provider_platform_abcs",
        "extensible_provider_platform_abcs",
        "free_claude_code.providers.runtime and free_claude_code.messaging.platforms.factory",
        "new provider/platform implementations",
        "registered BaseProvider or messaging component bundle",
        "unknown platform returns None; unknown provider errors",
        (
            "tests/contracts/test_feature_manifest.py",
            "tests/providers/test_provider_runtime.py",
        ),
    ),
)


def capability_names() -> set[str]:
    return {contract.capability for contract in CAPABILITY_CONTRACTS}


def contracted_feature_ids() -> set[str]:
    return {contract.feature_id for contract in CAPABILITY_CONTRACTS}
