"""Capability preflight lifetime contract (#470). Defines which read-only MCP tools preserve an existing capability proof and the canonical sequencing operators must follow before mutations. """ from __future__ import annotations # Read-only tools that must not invalidate capability proof (#470). # gitea_whoami is read-only but re-pins identity; capability is preserved when # identity was already verified clean (#469). READ_ONLY_PREFLIGHT_TOOLS = frozenset({ "gitea_whoami", "gitea_get_authenticated_user", "gitea_get_current_user", "gitea_view_pr", "gitea_view_issue", "gitea_list_prs", "gitea_list_issues", "gitea_list_issue_comments", "gitea_get_runtime_context", "gitea_resolve_task_capability", "gitea_check_pr_eligibility", "gitea_get_pr_review_feedback", "gitea_assess_work_issue_duplicate", "gitea_route_task_session", "gitea_audit_config", "gitea_list_labels", "gitea_get_profile", "gitea_list_profiles", }) PREFLIGHT_CONTRACT_SUMMARY = ( "Capability preflight is session-scoped per MCP process, profile, and task. " "After gitea_resolve_task_capability(task=...), interleaved read-only calls " "(whoami, view_*, list_*, get_runtime_context, eligibility checks) preserve " "the proof until a gated mutation consumes it. Each mutation consumes the proof " "once; re-resolve immediately before the next mutation. A new resolve for a " "different task replaces the prior task binding. Profile/session changes or " "workspace edits before resolve invalidate proof." ) def format_missing_capability_error(task: str | None = None) -> str: base = ( "Pre-flight order violation: Task capability " "(gitea_resolve_task_capability) has not been resolved (fail closed)" ) if task: return ( f"{base}. Re-run gitea_resolve_task_capability(task=\"{task}\") " "immediately before this mutation." ) return ( f"{base}. Re-run gitea_resolve_task_capability for the mutation task " "immediately before acting." ) def format_task_mismatch_error(resolved: str, required: str) -> str: return ( "Pre-flight task mismatch: " f"resolved '{resolved}' but mutation requires '{required}' (fail closed). " f"Re-run gitea_resolve_task_capability(task=\"{required}\") " "immediately before this mutation." )