{"serverInfo":{"name":"CodeRifts API Governance","version":"1.0.2"},"authentication":{"required":false},"tools":[{"name":"preflight_change_set","description":"Preflight a COMPLETE base→head change set of contract artifacts and return\nrisk score and breaking-change analysis — plus, on the AUTHORIZE path only, a governance decision\n(ALLOW / WARN / REQUIRE_APPROVAL / BLOCK) and a signed chain-receipt when applicable. ANALYZE\nreturns informational risk only: analysis_outcome, may_execute:false, no decision, no receipt.\n\nRequires a pending base→head (before/after) contract change you are about to\nact on (merge, deploy, publish, or register tools). No pending change set →\ndo not call this tool.\n\nUse this when:\n- You are about to merge, push, deploy, publish, or register/expose agent tools,\n  AND the change includes ≥1 contract artifact (OpenAPI/Swagger, GraphQL SDL,\n  gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas: type=agent_tools,\n  including before re-registering tools with a runtime).\n- You have (or can assemble) FULL base and head for every changed contract\n  artifact in this set — not a single-file subset when other contract files also\n  change.\n- You need a NEW decision for the CURRENT change; you do not already hold a\n  currently-valid receipt for this exact target/operation.\n- You hold a receipt for a different operation or target than the act you will\n  perform (e.g. ALLOW for merge, now deploying). A receipt authorizes ONE\n  operation: a merge receipt does not authorize a deploy. Run a NEW preflight\n  with context.operation set to that operation (deploy, publish); a\n  differently-scoped receipt is not reusable authorization and will fail at\n  the gate.\n\nDo not use when:\n- The change is documentation-only (README, guides, comments) with no contract\n  artifact content change — do not call any CodeRifts tool.\n- You already hold a signed receipt and only need to check it is authentic and\n  currently valid — use coderifts.verify_receipt instead.\n- You need details of a PREVIOUS decision by decision_id — use\n  coderifts.get_decision_details instead.\n- You want a static 0–100 \"agent readiness\" score for one OpenAPI/MCP file and\n  there is no pending base→head mutate — use coderifts.agent_readiness_score\n  (advanced / opt-in; not one of the three default tools). If that tool is not\n  in your available list, call none of the CodeRifts tools; do not substitute\n  preflight_change_set.\n- You cannot supply both before and after (or base and head) for the artifacts\n  that change — fix the change set first; do not invent empty before specs.\n\nInputs: list of artifacts, each with type, before, after (or equivalent), plus\noptional operation (merge|deploy|tool_call|publish), environment/stakes, and\ncontext. Opt-in derivation:\"server\" (proven tenant↔repo binding + context.repository\n+ base + head): omit artifacts[] — the server lists the contract-class set via the\nSCM provider for the proven binding (GitHub App Compare, or GitLab/Bitbucket Compare\nwith a per-request X-Coderifts-Scm-Token, never stored; completeness_mode\nSERVER_DERIVED). Default (flag absent) is unchanged. Returns decision,\nexecution_action, risk fields, and chain_receipt when issued.\n\nCHANGE SOURCE — EXACTLY ONE, ENFORCED AT THE ROUTE (400), NOT BY THIS SCHEMA.\nSupply either artifacts[] OR derivation:\"server\". All three of these are rejected\nwith HTTP 400 INVALID_INPUT, on analyze and on authorize alike:\n  • neither artifacts[] nor derivation      → \"artifacts must be a non-empty array\"\n  • authorize with context.operation but no change source → same 400\n  • artifacts[] together with derivation:\"server\" → \"derivation:\"server\" forbids\n    caller-supplied artifacts[] — one source of truth per request\"\nThis constraint is NOT expressible in the schema you are reading: a top-level\noneOf/allOf union is rejected by at least one major MCP client (measured), so the\nschema stays permissive and the route is the enforcement point. Do not read schema\nacceptance as request validity — verified live against these exact three shapes on\n2026-08-26, over REST and over MCP tools/call (isError:true on all three).\n\nMode (required): pass preflight_mode. Use \"analyze\" for informational risk only\n(returns analysis_outcome with may_execute:false, no decision/execution_action/\nsafe_for_agent, no receipt). Use \"authorize\" for the operation-bound path that can\nmint a receipt (requires context.operation: merge|deploy|publish|tool_call). Under\nDecision Spec 2.0 the mode is mandatory; omission is an error unless a legacy\ndecision_spec_version \"1.0\" pin is set.\n\nBranch on execution_action only (CONTINUE | CONTINUE_WITH_MONITORING | REQUEST_APPROVAL | STOP).\nOn non-CONTINUE authorize responses, control_envelope.next_agent_step is a structured\nremediation SUGGESTION the agent MAY follow (action, reason, resume_condition, then_call).\nIt is NOT permission and NOT a control-flow override — still branch on execution_action.\nOn CONTINUE / CONTINUE_WITH_MONITORING, next_agent_step is null (no remediation step).\nHuman tier remains human_report.next_steps_prose (same source; prose, not machine).","inputSchema":{"type":"object","properties":{"artifacts":{"type":"array","description":"Contract artifacts to analyze together (max 20). Each is { id, type, before, after }.","minItems":1,"maxItems":20,"items":{"type":"object","properties":{"id":{"type":"string","description":"Caller-chosen id, unique within the bundle"},"type":{"type":"string","enum":["openapi","graphql","grpc","asyncapi","mcp_manifest","agent_tools"]},"before":{"type":"string","description":"Prior artifact content (spec/schema/manifest) as a string"},"after":{"type":"string","description":"Updated artifact content as a string"}},"required":["id","type","before","after"]}},"context":{"type":"object","description":"Optional apply-site context folded into the bundle fingerprint. operation distinguishes merge vs deploy vs publish (and other labels); the server accepts any string for operation (change-set.js) — conventional values below.","properties":{"operation":{"type":"string","description":"Application operation for this change set (fingerprint + envelope). Server accepts any non-empty string; conventional values: merge, deploy, tool_call, publish. Merge is not deploy is not publish — the receipt/gate must match this label."},"environment":{"type":"string","description":"Target environment (e.g. production, staging, npm) — optional; folded into fingerprint when set."},"repository":{"type":"string","description":"Repository identity (optional; fingerprint context)"},"branch":{"type":"string","description":"Branch name (optional; fingerprint context)"},"pull_request":{"description":"Pull request id when applicable (optional; fingerprint context)","oneOf":[{"type":"string"},{"type":"number"}]},"policy_profile":{"type":"string","description":"Policy profile name (optional; fingerprint context)"},"base":{"type":"string","description":"Base commit/ref SHA the change set was computed against (optional; PR/commit identity)"},"head":{"type":"string","description":"Head commit/ref SHA of the proposed change (optional; PR/commit identity)"},"target_id":{"type":"string","description":"Optional apply-site target (IntentContext parity; not folded into the bundle fingerprint)"},"fingerprint":{"type":"string","description":"Optional change fingerprint (IntentContext parity; not folded into the bundle fingerprint)"},"audience":{"type":"string","description":"Optional audience (IntentContext parity; REST/MCP accept, server-derived audience still wins on the envelope)"}}},"previous_receipt":{"type":"string","description":"Optional prior chain receipt token to link"},"include_execution_grant":{"type":"boolean","description":"Opt-in (authorize only). When true on allow-class authorize, the response includes a signed execution_grant (cr.exec.v1) alongside chain_receipt, or HTTP 503 SIGNER_UNAVAILABLE — never unsigned. Default false. Analyze ignores this flag. See docs/cr-exec-v1.md."},"state_nonce":{"type":"string","description":"Optional ATOMIC-profile nonce. When include_execution_grant is true, copied into the signed grant as state_nonce (a separate signed field — NOT folded into scope_hash). Absent → BEARER grant (today's default). See docs/cr-exec-v1.md."},"idempotency_key":{"type":"string","description":"Optional client key; in authorize mode, a repeat with the same key + body replays the original decision (24h). Analyze responses are not replayed."},"preflight_mode":{"type":"string","enum":["analyze","authorize"],"description":"REQUIRED. \"analyze\" = informational risk only (no decision/execution_action/safe_for_agent; analysis_outcome + may_execute:false). \"authorize\" = operation-bound path; may mint a receipt (requires context.operation). Decision Spec 2.0: omission is an error unless decision_spec_version is '1.0' (30-day legacy pin with soft-default analyze)."},"decision_spec_version":{"type":"string","enum":["1.0","2.0"],"description":"Optional pin. '1.0' = legacy contract (soft-default mode + analyze still carries decision/execution_action) until the sunset date. Omit or '2.0' = current contract."},"derivation":{"type":"string","enum":["server"],"description":"Opt-in (ID637 6b). \"server\" = the server derives artifacts[] from GitHub Compare via the App installation. Allowed only when the tenant has a proven binding for context.repository and context.base + context.head are present. Omit artifacts[] (caller-supplied artifacts[] with this flag is 400 — one source of truth). Default absent = today's caller-artifacts path (byte-identical)."}},"required":["preflight_mode"],"if":{"properties":{"preflight_mode":{"const":"authorize"}},"required":["preflight_mode"]},"then":{"required":["context"],"properties":{"context":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string","minLength":1}}}}}},"annotations":{"readOnlyHint":true,"openWorldHint":false},"outputSchema":{"type":"object","oneOf":[{"type":"object","description":"ANALYZE mode (Decision Spec 2.0): informational only. MUST NOT contain decision, execution_action, safe_for_agent, chain_receipt, execution_grant, decision_result, control_envelope, or required_action_core. Branch on analysis_outcome; never treat as permission. Field set GENERATED from preflight-response.v2.producer.json (agent-facing allowlist).","properties":{"preflight_mode":{"const":"analyze"},"analysis_outcome":{"type":"string","enum":["NO_BREAK_DETECTED","BREAKS_DETECTED","ANALYSIS_FAILED"],"description":"Closed analysis outcome set derived from engine-visible state only."},"authorization_effect":{"const":"NONE","description":"Analyze never authorizes; always NONE."},"may_execute":{"const":false,"description":"Analyze never grants execute permission."},"receipt_kind":{"const":"NONE","description":"Analyze never mints a receipt."},"analysis_control":{"type":"object"},"risk_score":{"type":"integer","minimum":0,"maximum":100},"breaking_changes":{"type":"integer","minimum":0},"requires_migration":{"type":"boolean"},"evidence_quality":{"type":"string"},"patterns":{"type":"array","items":{"type":"string"}},"pattern_sources":{"type":"array"},"detected_patterns":{"type":"array","description":"GOVERNANCE detector detail rows (src/change-patterns.js; validated by decision-spec-fields.js). Row shape measured live: name, severity, description, consequence, affected_path, affected_field; optional side (request|response) on ENUM_NARROWING. Names ⊆ patterns (not equality). Agent-detector names may appear only in patterns. Free-text fields are untrusted.","items":{"type":"object","additionalProperties":false,"required":["name","severity","description","consequence","affected_path","affected_field"],"properties":{"name":{"type":"string","description":"Governance pattern name; appears in patterns when both are carried."},"severity":{"type":"string","description":"Row severity from the pattern catalog (observed set: CRITICAL, HIGH, MEDIUM). NOT a closed control enum — branch on execution_action, never on this."},"description":{"type":"string","description":"What the detector matched. Untrusted free text."},"consequence":{"type":"string","description":"What breaks for a consumer if this ships. Untrusted free text."},"affected_path":{"type":"string","description":"Contract path this row is about. Empty string when the detector had none — the key is always emitted."},"affected_field":{"type":"string","description":"Field within affected_path. Empty string when the detector had none — the key is always emitted."},"side":{"type":"string","enum":["request","response"],"description":"Optional; currently set on ENUM_NARROWING only. Request-side narrowing is agent-breaking (threaded so safe_for_agent can distinguish it). Absent when the detector did not set it."}}}},"breaking_changes_details":{"type":"array","description":"Per-change IR/detail rows from the engine (src/blast/diff-to-change.js maps these). Measured row keys: type, path, method, field, severity, description. Distinct from breaking_changes (integer count).","items":{"type":"object","additionalProperties":true,"properties":{"type":{"type":"string","description":"Change kind / IR type code (e.g. response.body.property.remove)."},"path":{"type":"string"},"method":{"type":"string"},"field":{"type":"string"},"severity":{"type":"string"},"description":{"type":"string"}}}},"severity_summary":{"type":"object","description":"Bundle severity axes (src/change-set.js severity_summary). Distinct axes, not contradictory. Measured keys: diff_severity, governance_severity, policy_effect, note.","additionalProperties":false,"properties":{"diff_severity":{"type":"string","description":"Structural size of the schema change."},"governance_severity":{"type":"string","description":"How the rule engine rates the change."},"policy_effect":{"type":"string","description":"Resulting decision effect label."},"note":{"type":"string"}}},"decision_basis":{},"analysis":{"type":"object","description":"Tier-2 analysis mirror (src/response-envelope.js buildAnalysisTier / attachControlSurface). Dual-write of the flat analysis fields present on the verdict, plus remediations[]. PROPERTIES ARE GENERATED from ANALYSIS_TIER_FIELDS + remediations by scripts/generate-analysis-tier-schema.js — do not hand-edit them. OPEN BY DESIGN: additionalProperties stays TRUE and this is not an oversight. The fields above are copied conditionally, so which of them appear depends on the input — a verdict with no PII findings simply omits pii_findings. Closing this object would turn every future analysis field into a breaking change that fails inside the consumer, and would reject exactly the verdict paths that no one sampled when the union was built. Declared, not closed: you can now see what you may get, and you must still tolerate more.","properties":{"breaking_changes":{"type":"integer"},"breaking_changes_details":{"type":"array"},"change_ir":{"type":"array"},"changelog":{"type":"array"},"compatibility_suggestions":{"type":"array"},"coverage_gap":{"type":"object","additionalProperties":true},"coverage_gap_reason":{"type":"string"},"decision_basis":{"type":"object","additionalProperties":true},"degraded":{"type":"boolean"},"detected_patterns":{"type":"array"},"evidence_quality":{"type":"string"},"fallback_reason":{"type":"string"},"non_breaking_changes":{"type":"array"},"pattern_sources":{"type":"array"},"patterns":{"type":"array"},"pii_findings":{"type":"array"},"policy_violations":{"type":"array"},"remediations":{"type":"array","items":{"type":"object","description":"One remediation for one detected breaking change. `instruction` is imperative prose that a model may read and act on; it is generated per input and is NOT a fixed string, so the schema declares that the field exists and does not pin its text.","properties":{"change_type":{"type":"string"},"precise_label":{"type":"string"},"target":{"type":"string"},"target_ref":{"type":"object","additionalProperties":true},"recommended_transform":{"type":"string"},"effort":{"type":"string"},"instruction":{"type":"string","description":"Imperative remediation text. Model-visible. Generated per input; not a closed vocabulary."},"evidence":{"type":"object","additionalProperties":true}},"additionalProperties":true}},"requires_migration":{"type":"boolean"},"risk_dimensions":{"type":"object","additionalProperties":true},"risk_level":{"type":"string"},"risk_score":{"type":"integer"},"security_findings":{"type":"array"},"semver_suggestion":{"type":"string"},"should_block":{"type":"boolean"},"stats":{"type":"object","additionalProperties":true},"token_cost_impact":{"type":"object","additionalProperties":true}},"additionalProperties":true},"human_report":{"type":"object","description":"Human-readable report tier (src/response-envelope.js buildHumanReport / analyze v2 stub). Measured keys: summary, breaking_highlights, suggestions, next_steps_prose.","additionalProperties":false,"properties":{"summary":{"type":"string"},"breaking_highlights":{"type":"array"},"suggestions":{"type":"array"},"next_steps_prose":{"type":"string"}}},"verdict_fingerprint":{"type":"string"},"bundle_fingerprint":{"type":"string"},"decision_spec_version":{"type":"string","description":"Decision Spec major for this response (typically '2.0')."},"artifacts":{"type":"array"},"evidence":{"type":"array"},"operation":{},"timestamp":{"type":"string"},"scorer_version":{"type":["string","null"],"description":"Fingerprint-bound scorerVersion() (observation; not permission)."},"calibration_version":{"type":["string","null"]},"policy_pin_status":{"type":["object","null"],"additionalProperties":true},"blast_radius":{"type":"object","additionalProperties":false,"description":"ID27 additive COUNTS (not a score). Pure function of the change-set + request graphs. Not in the verdict_fingerprint preimage.","required":["endpoints","fields","params","consumers_declared","consumers_observed","graph_source"],"properties":{"endpoints":{"type":"integer","minimum":0},"fields":{"type":"integer","minimum":0},"params":{"type":"integer","minimum":0},"consumers_declared":{"type":"integer","minimum":0},"consumers_observed":{"type":"integer","minimum":0},"graph_source":{"type":"string","enum":["none","declared","observed","declared+observed"]}}}},"required":["preflight_mode","analysis_outcome","authorization_effect","may_execute","receipt_kind","decision_spec_version"],"not":{"anyOf":[{"required":["decision"]},{"required":["execution_action"]},{"required":["safe_for_agent"]},{"required":["chain_receipt"]},{"required":["execution_grant"]},{"required":["decision_result"]},{"required":["control_envelope"]},{"required":["required_action_core"]}]},"additionalProperties":true},{"type":"object","description":"AUTHORIZE mode: operation-bound decision. Branch on execution_action (not decision, not safe_for_agent). Field set GENERATED from preflight-response.v2.producer.json (agent-facing allowlist). Compatibility: https://coderifts.com/schemas/decision-result.v1.consumer.json","properties":{"preflight_mode":{"const":"authorize"},"receipt_kind":{"type":"string","enum":["operation_authorization","NONE"],"description":"operation_authorization when a chain receipt was issued; NONE if signer unconfigured."},"decision":{"type":"string","enum":["ALLOW","WARN","REQUIRE_APPROVAL","BLOCK"],"description":"Compatibility mirror of control_envelope.decision (same value). Prefer control_envelope for branching; use decision as explanation only."},"execution_action":{"type":"string","enum":["CONTINUE","CONTINUE_WITH_MONITORING","REQUEST_APPROVAL","STOP"],"description":"Compatibility mirror of control_envelope.execution_action (same value). Canonical branch key; unrecognised values are not permission (fail closed)."},"safe_for_agent":{"type":"boolean","description":"Compatibility mirror of control_envelope.safe_for_agent (same value). Not a branch key — do not branch on safe_for_agent (use execution_action)."},"control_envelope":{"type":"object","description":"Branch source (control/1.0). Machine-control surface from attachControlSurface / buildControlEnvelope. Agents and @coderifts/agent-guard branch on control_envelope.execution_action. Top-level decision/safe_for_agent/execution_action mirror these values for compatibility. Includes next_agent_step (structured remediation SUGGESTION derived from execution_action + required_action; null on CONTINUE*; not permission — still branch on execution_action)."},"risk_score":{"type":"integer","minimum":0,"maximum":100},"breaking_changes":{"type":"integer","minimum":0},"requires_migration":{"type":"boolean"},"evidence_quality":{"type":"string"},"patterns":{"type":"array","items":{"type":"string"}},"pattern_sources":{"type":"array"},"detected_patterns":{"type":"array","description":"GOVERNANCE detector detail rows (src/change-patterns.js; validated by decision-spec-fields.js). Row shape measured live: name, severity, description, consequence, affected_path, affected_field; optional side (request|response) on ENUM_NARROWING. Names ⊆ patterns (not equality). Agent-detector names may appear only in patterns. Free-text fields are untrusted.","items":{"type":"object","additionalProperties":false,"required":["name","severity","description","consequence","affected_path","affected_field"],"properties":{"name":{"type":"string","description":"Governance pattern name; appears in patterns when both are carried."},"severity":{"type":"string","description":"Row severity from the pattern catalog (observed set: CRITICAL, HIGH, MEDIUM). NOT a closed control enum — branch on execution_action, never on this."},"description":{"type":"string","description":"What the detector matched. Untrusted free text."},"consequence":{"type":"string","description":"What breaks for a consumer if this ships. Untrusted free text."},"affected_path":{"type":"string","description":"Contract path this row is about. Empty string when the detector had none — the key is always emitted."},"affected_field":{"type":"string","description":"Field within affected_path. Empty string when the detector had none — the key is always emitted."},"side":{"type":"string","enum":["request","response"],"description":"Optional; currently set on ENUM_NARROWING only. Request-side narrowing is agent-breaking (threaded so safe_for_agent can distinguish it). Absent when the detector did not set it."}}}},"breaking_changes_details":{"type":"array","description":"Per-change IR/detail rows from the engine (src/blast/diff-to-change.js maps these). Measured row keys: type, path, method, field, severity, description. Distinct from breaking_changes (integer count).","items":{"type":"object","additionalProperties":true,"properties":{"type":{"type":"string","description":"Change kind / IR type code (e.g. response.body.property.remove)."},"path":{"type":"string"},"method":{"type":"string"},"field":{"type":"string"},"severity":{"type":"string"},"description":{"type":"string"}}}},"severity_summary":{"type":"object","description":"Bundle severity axes (src/change-set.js severity_summary). Distinct axes, not contradictory. Measured keys: diff_severity, governance_severity, policy_effect, note.","additionalProperties":false,"properties":{"diff_severity":{"type":"string","description":"Structural size of the schema change."},"governance_severity":{"type":"string","description":"How the rule engine rates the change."},"policy_effect":{"type":"string","description":"Resulting decision effect label."},"note":{"type":"string"}}},"decision_basis":{},"analysis":{"type":"object","description":"Tier-2 analysis mirror (src/response-envelope.js buildAnalysisTier / attachControlSurface). Dual-write of the flat analysis fields present on the verdict, plus remediations[]. PROPERTIES ARE GENERATED from ANALYSIS_TIER_FIELDS + remediations by scripts/generate-analysis-tier-schema.js — do not hand-edit them. OPEN BY DESIGN: additionalProperties stays TRUE and this is not an oversight. The fields above are copied conditionally, so which of them appear depends on the input — a verdict with no PII findings simply omits pii_findings. Closing this object would turn every future analysis field into a breaking change that fails inside the consumer, and would reject exactly the verdict paths that no one sampled when the union was built. Declared, not closed: you can now see what you may get, and you must still tolerate more.","properties":{"breaking_changes":{"type":"integer"},"breaking_changes_details":{"type":"array"},"change_ir":{"type":"array"},"changelog":{"type":"array"},"compatibility_suggestions":{"type":"array"},"coverage_gap":{"type":"object","additionalProperties":true},"coverage_gap_reason":{"type":"string"},"decision_basis":{"type":"object","additionalProperties":true},"degraded":{"type":"boolean"},"detected_patterns":{"type":"array"},"evidence_quality":{"type":"string"},"fallback_reason":{"type":"string"},"non_breaking_changes":{"type":"array"},"pattern_sources":{"type":"array"},"patterns":{"type":"array"},"pii_findings":{"type":"array"},"policy_violations":{"type":"array"},"remediations":{"type":"array","items":{"type":"object","description":"One remediation for one detected breaking change. `instruction` is imperative prose that a model may read and act on; it is generated per input and is NOT a fixed string, so the schema declares that the field exists and does not pin its text.","properties":{"change_type":{"type":"string"},"precise_label":{"type":"string"},"target":{"type":"string"},"target_ref":{"type":"object","additionalProperties":true},"recommended_transform":{"type":"string"},"effort":{"type":"string"},"instruction":{"type":"string","description":"Imperative remediation text. Model-visible. Generated per input; not a closed vocabulary."},"evidence":{"type":"object","additionalProperties":true}},"additionalProperties":true}},"requires_migration":{"type":"boolean"},"risk_dimensions":{"type":"object","additionalProperties":true},"risk_level":{"type":"string"},"risk_score":{"type":"integer"},"security_findings":{"type":"array"},"semver_suggestion":{"type":"string"},"should_block":{"type":"boolean"},"stats":{"type":"object","additionalProperties":true},"token_cost_impact":{"type":"object","additionalProperties":true}},"additionalProperties":true},"human_report":{"type":"object","description":"Human-readable report tier (src/response-envelope.js buildHumanReport / analyze v2 stub). Measured keys: summary, breaking_highlights, suggestions, next_steps_prose.","additionalProperties":false,"properties":{"summary":{"type":"string"},"breaking_highlights":{"type":"array"},"suggestions":{"type":"array"},"next_steps_prose":{"type":"string"}}},"chain_receipt":{"type":"string"},"execution_grant":{"type":"string","description":"Opt-in cr.exec.v1 execution grant (PHASE-0). Issued only when include_execution_grant is true on authorize. Short-lived mutation-bound sibling of chain_receipt; never unsigned. Optional inner state_nonce (ATOMIC profile) is additive and is NOT in scope_hash. See docs/cr-exec-v1.md / docs/cr-exec-attest-v1.md."},"chain_status":{"type":"string"},"decision_result":{"type":"object","description":"decision-result.v1 envelope (control enums closed). Additive fields may appear and are not permission. Full schema: https://coderifts.com/schemas/decision-result.v1.consumer.json (producer: https://coderifts.com/schemas/decision-result.v1.producer.json).","properties":{"spec_version":{"type":"string","pattern":"^decision-result\\.v1(\\.[0-9]+)?$"},"decision":{"type":"string","enum":["ALLOW","WARN","REQUIRE_APPROVAL","BLOCK"]},"execution_action":{"type":"string","enum":["CONTINUE","CONTINUE_WITH_MONITORING","REQUEST_APPROVAL","STOP"]},"safe_for_agent":{"type":"boolean"},"decision_id":{"type":"string"},"fingerprint":{"type":"string"},"input_fingerprint":{"type":"string"},"decision_body_hash":{"type":["string","null"]},"operation":{"type":["string","null"]},"environment":{"type":["string","null"]},"repository":{"type":["string","null"]},"base":{"type":["string","null"]},"head":{"type":["string","null"]},"audience":{"type":["string","null"]},"authority":{"type":["object","null"],"description":"ID963 additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL."},"derivation":{"type":["object","null"],"description":"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."},"receipt":{"type":"object"},"expires_at":{"type":"string"},"blast_radius":{"type":"object","description":"ID27 additive COUNTS (not a score). Not permission.","properties":{"endpoints":{"type":"integer","minimum":0},"fields":{"type":"integer","minimum":0},"params":{"type":"integer","minimum":0},"consumers_declared":{"type":"integer","minimum":0},"consumers_observed":{"type":"integer","minimum":0},"graph_source":{"type":"string"}}}},"additionalProperties":true},"verdict_fingerprint":{"type":"string"},"bundle_fingerprint":{"type":"string"},"decision_spec_version":{"type":"string","description":"Decision Spec major for this response (typically '2.0')."},"coderifts_version":{"type":"string"},"artifacts":{"type":"array"},"evidence":{"type":"array"},"operation":{},"timestamp":{"type":"string"},"scorer_version":{"type":["string","null"],"description":"Fingerprint-bound scorerVersion() (same as decision_result.scorer_version / FP preimage)."},"calibration_version":{"type":["string","null"],"description":"Calibration model version when set; null until a calibrated model ships."},"policy_pin_status":{"type":["object","null"],"description":"policy_pin observation (898). match null=no pin; false=drift warning (non-blocking).","additionalProperties":true},"blast_radius":{"type":"object","additionalProperties":false,"description":"ID27 additive COUNTS (not a score). Pure function of the change-set + request graphs. Not in the verdict_fingerprint preimage.","required":["endpoints","fields","params","consumers_declared","consumers_observed","graph_source"],"properties":{"endpoints":{"type":"integer","minimum":0},"fields":{"type":"integer","minimum":0},"params":{"type":"integer","minimum":0},"consumers_declared":{"type":"integer","minimum":0},"consumers_observed":{"type":"integer","minimum":0},"graph_source":{"type":"string","enum":["none","declared","observed","declared+observed"]}}}},"required":["preflight_mode","decision","execution_action","safe_for_agent","receipt_kind","decision_spec_version"],"additionalProperties":true,"allOf":[{"if":{"properties":{"receipt_kind":{"const":"operation_authorization"}},"required":["receipt_kind"]},"then":{"required":["chain_receipt"]}},{"if":{"properties":{"execution_action":{"enum":["CONTINUE","CONTINUE_WITH_MONITORING"]}},"required":["execution_action"]},"then":{"properties":{"receipt_kind":{"const":"operation_authorization"}},"required":["receipt_kind","chain_receipt","decision_result"]}}]}]}},{"name":"verify_receipt","description":"Verify a CodeRifts signed chain-receipt you ALREADY HOLD: cryptographic\nauthenticity (signature + key id), body binding, and — when lifecycle indices\nare available — whether it is currently valid authorization (not expired,\nsuperseded, or revoked) for a stated operation/target.\n\nUse this when:\n- You already obtained a chain_receipt / receipt token from a prior preflight\n  (or CI artifact) and are about to act (merge/deploy) under that receipt.\n- A contract-gate or policy requires offline/online proof that the receipt is\n  authentic for this change before proceeding.\n- You must distinguish \"signature ok\" from \"currently authorized\" (stale or\n  superseded receipts must not be treated as live approval).\n\nDo not use when:\n- You do not have a receipt yet — call coderifts.preflight_change_set first.\n- You need a NEW decision for a changed base→head set — preflight again;\n  verify_receipt does not re-diff specs.\n- The receipt you hold binds a different operation or target than the one you\n  are about to perform — call coderifts.preflight_change_set with\n  context.operation set to that operation (a merge receipt does not authorize\n  a deploy); verify_receipt cannot re-scope or re-issue a decision.\n- You only need human-readable history of an old decision_id without a receipt\n  token — use coderifts.get_decision_details.\n- The change set itself is unknown or incomplete — fix the change set and\n  preflight; do not \"verify\" a placeholder.\n\nInputs: receipt token (required); optional intended context (operation, environment,\nfingerprint, target_id, audience, repository/branch/pull_request, base/head) and the\nbody_hash-bound decision_result envelope. 30s clock-skew leeway on expiry; 0s for\ndestructive operations in production when the intended context declares them.\nReturns { valid, status, currently_authorized (bool|null), reason, payload, authz_* }.\nBranch on currently_authorized; null = not evaluated.\n\nWhen a decision envelope is also in hand (e.g. from a prior preflight), its\ncontrol_envelope.next_agent_step (if present) is structured remediation guidance\nthe agent MAY follow after a non-CONTINUE decision — still branch on\nexecution_action; next_agent_step is suggestion, not permission.","inputSchema":{"type":"object","description":"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, audience, repository/branch/pull_request, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject.","properties":{"token":{"type":"string","description":"The chain receipt token (base64url(body).base64url(signature))"},"operation":{"type":"string","description":"Intended operation the receipt must authorize (conventional: merge|deploy|tool_call|publish). Triggers authorization evaluation when non-empty; supply decision_result for full scope binding."},"target_id":{"type":"string","description":"Intended apply-site target the receipt must bind"},"environment":{"type":"string","description":"Intended environment (e.g. production) — must match the receipt"},"fingerprint":{"type":"string","description":"Intended change fingerprint — must equal the receipt fp"},"audience":{"type":"string","description":"Intended audience — must match the receipt"},"repository":{"type":"string","description":"Intended repository the receipt must bind (place binding; optional)"},"branch":{"type":"string","description":"Intended branch the receipt must bind (place binding; optional)"},"pull_request":{"description":"Intended pull-request id the receipt must bind (place binding; optional)","oneOf":[{"type":"string"},{"type":"number"}]},"base":{"type":"string","description":"Intended base commit/ref SHA the receipt must match (signed-wins vs envelope.base)"},"head":{"type":"string","description":"Intended head commit/ref SHA the receipt must match (signed-wins vs envelope.head)"},"decision_result":{"type":"object","description":"The body_hash-bound decision envelope (carries operation/target/decision). Required for a meaningful AUTHORIZATION evaluation of scope; without it, intended context alone fails closed on authorization (currently_authorized false) while signature status remains independent. Full schema: https://coderifts.com/schemas/decision-result.v1.consumer.json.","properties":{"spec_version":{"type":"string","pattern":"^decision-result\\.v1(\\.[0-9]+)?$"},"decision":{"type":"string","enum":["ALLOW","WARN","REQUIRE_APPROVAL","BLOCK"]},"execution_action":{"type":"string","enum":["CONTINUE","CONTINUE_WITH_MONITORING","REQUEST_APPROVAL","STOP"]},"safe_for_agent":{"type":"boolean"},"decision_id":{"type":"string"},"fingerprint":{"type":"string"},"input_fingerprint":{"type":"string"},"decision_body_hash":{"type":["string","null"]},"operation":{"type":["string","null"]},"environment":{"type":["string","null"]},"repository":{"type":["string","null"]},"base":{"type":["string","null"]},"head":{"type":["string","null"]},"audience":{"type":["string","null"]},"authority":{"type":["object","null"],"description":"ID963 additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL."},"derivation":{"type":["object","null"],"description":"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."},"receipt":{"type":"object"},"expires_at":{"type":"string"},"blast_radius":{"type":"object","description":"ID27 additive COUNTS (not a score). Not permission.","properties":{"endpoints":{"type":"integer","minimum":0},"fields":{"type":"integer","minimum":0},"params":{"type":"integer","minimum":0},"consumers_declared":{"type":"integer","minimum":0},"consumers_observed":{"type":"integer","minimum":0},"graph_source":{"type":"string"}}}},"additionalProperties":true}},"required":["token"]},"annotations":{"readOnlyHint":true,"openWorldHint":false},"outputSchema":{"type":"object","description":"Receipt signature/status plus optional authorization layer. additionalProperties true: additive fields may appear and are not permission. Envelope compatibility when a decision_result is supplied: https://coderifts.com/schemas/decision-result.v1.consumer.json schema description (single source).","properties":{"valid":{"type":"boolean","description":"true iff status is VERIFIED_CURRENT or RETIRED_KEY_VALID_AT_ISSUE"},"status":{"type":"string","enum":["VERIFIED_CURRENT","VERIFIED_EXPIRED","VERIFIED_WRONG_AUDIENCE","VERIFIED_WRONG_ENVIRONMENT","VERIFIED_SUPERSEDED","VERIFIED_SCOPE_MISMATCH","UNKNOWN_KEY","RETIRED_KEY_VALID_AT_ISSUE","INVALID_SIGNATURE","MALFORMED","UNSUPPORTED_VERSION","REGISTRY_UNREACHABLE"]},"reason":{"type":["string","null"]},"correlation_id":{"type":"string","description":"Route-owned trace id (ID828); always a non-empty string on 200"},"payload":{"type":"object"},"currently_authorized":{"type":["boolean","null"],"description":"Whether the receipt currently authorizes the intended operation/target/fp (§106). null means authorization could not be evaluated (e.g. no intended context) — not unauthorized and not authorized."},"authz_reason":{"type":"string","description":"When currently_authorized=false: the deny reason (operation_mismatch, decision_not_allow, superseded, expired, target_mismatch, environment_mismatch, …)"},"authz_status":{"type":"string","description":"Authorization-level status (VERIFIED_WRONG_ENVIRONMENT / VERIFIED_SUPERSEDED / VERIFIED_SCOPE_MISMATCH / …)"},"authz_state":{"type":"string","description":"Lifecycle state from isCurrentlyAuthorized when authorization is evaluated (optional; omitted when currently_authorized is null)"},"authz_note":{"type":"string","description":"Present when no intended context supplied: status reflects signature+expiry only"},"binding_level":{"type":"string","description":"place_and_content | content_only — forensic, not a second verdict"},"signed_value":{"type":["string","null"],"description":"Signed envelope slot when signed-wins fail-closed (source_binding_mismatch)"},"caller_value":{"type":["string","null"],"description":"Caller claim that differed from the signed envelope"}},"required":["valid","status","currently_authorized"],"additionalProperties":true}},{"name":"get_decision_details","description":"Retrieve a PAST CodeRifts decision by decision_id (or fingerprint): full\nreport payload, breaking changes list, scores, and linked receipt metadata\nif stored.\n\nUse this when:\n- You have a decision_id (or fingerprint) from a previous preflight, PR\n  comment, or CI log and need to inspect or explain that past decision.\n- You are auditing why a prior ALLOW/WARN/BLOCK was issued.\n- You are NOT requesting a new analysis of current before/after specs.\n\nDo not use when:\n- You need a decision for the CURRENT uncommitted or PR head change set —\n  call coderifts.preflight_change_set with the current artifacts.\n- You hold a receipt token and only need cryptographic/lifecycle verification —\n  use coderifts.verify_receipt.\n- You have no decision_id/fingerprint — run preflight first to create one.\n\nInputs: at least one of decision_id (preferred) or fingerprint is required\n(empty {} is rejected by the server as INVALID_INPUT). Returns the stored\ndecision document or not_found.\n\nScoping — fingerprint lookup returns only YOUR OWN decisions. A fingerprint is\nderived from content, not from an account, so two callers who preflight\nbyte-identical specs derive the same one; the lookup is therefore constrained\nto the decisions your credential can prove it owns.\n\nA decision that exists but is not yours returns the SAME not_found as one that\nwas never issued. This is deliberate: a distinguishable \"exists but forbidden\"\nwould confirm to any caller that a given content hash had been decided on by\nsomeone, which is the fact the scoping exists to withhold. Do not read\nnot_found as proof that no such decision exists anywhere.\n\nDecisions persisted without context.repository cannot currently be attributed\nto an account, and are not retrievable by fingerprint at all — not by their\nowner either. Retrieve those by decision_id, which is unchanged and unscoped.\nThis is a limitation of what older stored rows carry, not a property of the\nlookup: rows written from now on record the account directly, so the gap\nnarrows as older rows age out. If a fingerprint you expect returns not_found,\nuse the decision_id before concluding the decision is missing.\n\nWhen the stored envelope carries control fields, control_envelope.next_agent_step\nis structured remediation guidance the agent MAY follow for non-CONTINUE\nexecution_action values (null on CONTINUE*). Still branch on execution_action;\nnext_agent_step is a suggestion, not permission.","inputSchema":{"type":"object","properties":{"decision_id":{"type":"string","minLength":1,"description":"The decision_id from a prior decision_result envelope. Provide this and/or fingerprint (at least one non-empty string required)."},"fingerprint":{"type":"string","minLength":1,"description":"A verdict fingerprint (sha256:...); returns the latest matching decision. Provide this and/or decision_id (at least one non-empty string required)."}},"minProperties":1,"additionalProperties":false},"annotations":{"readOnlyHint":true,"openWorldHint":false},"outputSchema":{"type":"object","description":"A stored CodeRifts decision: the original decision_result.v1 envelope + lookup meta. Retrieval-path control fields (safe_for_agent/execution_action/verdict_fingerprint/control_envelope) mirror the fresh preflight response and are present only when the stored envelope carries their source field. additionalProperties true: additive fields may appear and are not permission. Compatibility rule (single source): https://coderifts.com/schemas/decision-result.v1.consumer.json schema description.","properties":{"decision":{"type":"string","enum":["ALLOW","WARN","REQUIRE_APPROVAL","BLOCK"]},"preflight_mode":{"type":"string","enum":["analyze","authorize"]},"safe_for_agent":{"type":"boolean"},"execution_action":{"type":"string","enum":["CONTINUE","CONTINUE_WITH_MONITORING","REQUEST_APPROVAL","STOP"]},"verdict_fingerprint":{"type":"string"},"control_envelope":{"type":"object","description":"Control envelope (control/1.0) derived from the stored decision_result. Includes next_agent_step (structured remediation SUGGESTION for non-CONTINUE execution_action; null on CONTINUE*; not permission — still branch on execution_action)."},"required_action_core":{"type":"object","description":"Branchable required-action core { type, reason_code, recheck_required } when present on the envelope."},"risk_score":{"type":"integer","minimum":0,"maximum":100},"breaking_changes":{"type":"integer","minimum":0},"patterns":{"type":"array","items":{"type":"string"}},"pattern_sources":{"type":"array"},"coderifts_version":{"type":"string"},"decision_spec_version":{"type":"string"},"timestamp":{"type":"string"},"evidence_quality":{"type":"string"},"requires_migration":{"type":"boolean"},"chain_receipt":{"type":"string"},"receipt_kind":{"type":"string","enum":["NONE","operation_authorization"]},"operation":{"type":"string"},"evidence":{"type":["object","array","null"]},"decision_semantic_hash":{"type":"string"},"decision_result":{"type":"object","description":"decision-result.v1 envelope (control enums closed). Additive fields may appear and are not permission. Full schema: https://coderifts.com/schemas/decision-result.v1.consumer.json (producer: https://coderifts.com/schemas/decision-result.v1.producer.json).","properties":{"spec_version":{"type":"string","pattern":"^decision-result\\.v1(\\.[0-9]+)?$"},"decision":{"type":"string","enum":["ALLOW","WARN","REQUIRE_APPROVAL","BLOCK"]},"execution_action":{"type":"string","enum":["CONTINUE","CONTINUE_WITH_MONITORING","REQUEST_APPROVAL","STOP"]},"safe_for_agent":{"type":"boolean"},"decision_id":{"type":"string"},"fingerprint":{"type":"string"},"input_fingerprint":{"type":"string"},"decision_body_hash":{"type":["string","null"]},"operation":{"type":["string","null"]},"environment":{"type":["string","null"]},"repository":{"type":["string","null"]},"base":{"type":["string","null"]},"head":{"type":["string","null"]},"audience":{"type":["string","null"]},"authority":{"type":["object","null"],"description":"ID963 additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL."},"derivation":{"type":["object","null"],"description":"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."},"receipt":{"type":"object"},"expires_at":{"type":"string"},"blast_radius":{"type":"object","description":"ID27 additive COUNTS (not a score). Not permission.","properties":{"endpoints":{"type":"integer","minimum":0},"fields":{"type":"integer","minimum":0},"params":{"type":"integer","minimum":0},"consumers_declared":{"type":"integer","minimum":0},"consumers_observed":{"type":"integer","minimum":0},"graph_source":{"type":"string"}}}},"additionalProperties":true},"meta":{"type":"object","properties":{"decision_id":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string"},"retrieval_mode":{"type":"string","enum":["stored"]},"omitted_sections":{"type":"array"}},"additionalProperties":true}},"required":["decision_result","meta"],"additionalProperties":true}}],"surface":{"profile":{"endpoint":"https://app.coderifts.com/mcp","method":"tools/list","header_names":[],"surface_params":{},"id":"sha256:308ea7fa66f0aaa5"},"tools_sha256":"sha256:db5cea2fbc69be86e514ea529ec1b1d2ed952bc086e49b85824eeb3d489967fd","tool_count":3,"digest_input":"sha256 over the canonical JSON of the served tools[]: object keys sorted lexicographically at every depth (arrays keep order), no whitespace, RAW UTF-8 with no \\uXXXX escaping. Python consumers must pass ensure_ascii=False -- the default escapes the 58 non-ASCII characters in this surface and produces a different digest over identical data.","source_ref":"https://raw.githubusercontent.com/coderifts/api-governance/surface-db5cea2f/tools.wire.v1.json","source_ref_commit":"95999b6553c1f91ed9fd140f60440ee3e1f0dcd6","source_ref_status":"PINNED TO ONE REVISION. source_ref is the wire-format tools[] as served, published in the public coderifts/api-governance repo at tag surface-db5cea2f (commit 95999b6553c1f91ed9fd140f60440ee3e1f0dcd6). Verified at fill time: the file's own tools_sha256, its tools[] recomputed under the canonical rule in digest_input, and this anchor's tools_sha256 are the same value. HOW TO USE IT: fetch it, recompute the digest yourself, and compare it to tools_sha256 here. IF THEY DIFFER, TRUST NEITHER -- it means the surface moved and this ref was not re-tagged. A tag can be force-moved; the commit SHA above cannot, so pin the SHA URL if you want the stronger form. OUR OBLIGATION: every surface change requires a NEW tag and a NEW source_ref in this file. Skipping that leaves this field pointing at an old surface while still looking authoritative, which is worse than the null it replaced. HOW THE OBLIGATION IS ENFORCED, on both sides: this repo CI-runs generate-surface-anchor.js --check --verify-source-ref, which fetches the ref above, recomputes its digest under the rule in digest_input, and FAILS if it is stale, self-inconsistent, or its tag is gone. The target repo runs scripts/validate-tools-wire.mjs from its own npm test and a CI workflow -- on push, on PR, and daily, because the wire target can go stale without anything in that repo changing. Both SKIP LOUDLY rather than fail on a transport error, and both treat a 404 as a real verdict rather than a network problem. Neither this ref nor those gates is a root of trust: pin the digest at YOUR approval time -- see honesty.pin_at_approval_time.","honesty":{"pins_bytes_not_behaviour":"This anchor pins BYTES, not behaviour. It says the tool text you received is the text that was published. It says nothing about whether the model read it, understood it, or obeyed it.","scoped_to_its_profile":"This digest is scoped to the profile named above and to nothing else. The default-profile digest says NOTHING about the surface served with include_advanced_tools, which is a different tool set with a different digest. A hash without its profile does not identify a surface.","pin_at_approval_time":"Comparing the live surface to THIS card proves only that the two agree. Change both and they still match. To get the property you actually want, record the digest AT APPROVAL TIME and compare the live surface against your recorded value. This card is a convenience, not the root of trust.","says_nothing_about_results":"This anchor covers the tools/list surface ONLY. It says NOTHING about tool RESULTS, which carry instruction-shaped prose today with no anchor at all: measured 2026-08-25, a single preflight_change_set result carried 611 bytes of prose including human_report.next_steps_prose (\"Call preflight_mode=authorize...\") and analysis.remediations[].instruction -- and `instruction` is not in the declared outputSchema, whose analysis tier is additionalProperties:true. Do not read this anchor as covering anything a tool returns."}},"resources":[],"prompts":[]}