{"coderifts_version":"1.0","timestamp":"2026-10-23T03:47:45.311Z","framework":"langgraph","language":"python","snippet":"# --- Block 1: QUICK CHECK (demo / first contact) ---\n# Question answered: \"What does this tool see in ONE published OpenAPI document?\"\n# NOT a pre-call guard for a mutating tool, NOT a merge/deploy decision, NO receipt.\n# Single-spec quality / hallucination pre-screen only (breaking_changes is always 0).\n# Keyless on purpose — try CodeRifts with no account. Rate-limited public surface.\nimport requests\n\nCODERIFTS_PUBLIC = \"https://app.coderifts.com/api/v1/public/preflight\"\n\ndef coderifts_quick_check(spec_url: str) -> dict:\n    \"\"\"Demo: fetch one OpenAPI URL and return a quality-style Decision Spec-ish body.\n    Do not treat ALLOW as permission to mutate contracts or call tools with drift.\n    \"\"\"\n    resp = requests.get(CODERIFTS_PUBLIC, params={\"url\": spec_url}, timeout=5)\n    return resp.json()\n\n# Example (demo only):\n# quality = coderifts_quick_check(\"https://api.example.com/openapi.json\")\n# print(quality.get(\"decision\"), quality.get(\"risk_score\"), quality.get(\"scope_note\"))\n\n# --- Block 2: ENFORCEMENT (pending change) ---\n# Question answered: \"May this pending base→head contract change proceed (for this operation)?\"\n# Requires API key. Posts a change set — not a public URL.\n# Host must supply full BEFORE and AFTER content for every changed artifact\n# (framework nodes do not invent base/head). Operation is explicit (merge ≠ deploy).\n#\n# HOST SUPPLY (LangGraph): put artifacts on state before this node runs, e.g.\n#   state[\"artifacts\"] = [{\n#     \"id\": \"public-api\", \"type\": \"openapi\",\n#     \"before\": open(\"base/openapi.yaml\").read(),\n#     \"after\": open(\"head/openapi.yaml\").read(),\n#   }]\n#   state[\"operation\"] = \"merge\"\n# The graph does not load git for you — a prior node or the process that builds\n# state must fill before/after (or resolve them from a snapshot you control).\n#\n# pip install coderifts-sdk\nfrom coderifts import CodeRifts\n\nclient = CodeRifts(api_key=\"cr_live_...\")  # set from env in production: os.environ[\"CODERIFTS_API_KEY\"]\n\ndef coderifts_enforce_may_proceed(artifacts, operation=\"merge\", environment=\"staging\"):\n    \"\"\"Fail-closed gate for a pending change set.\n    artifacts: non-empty list; each item must include \"id\", \"type\", \"before\", \"after\"\n    (full base and head document strings — host-supplied, never invented).\n    \"\"\"\n    # Shape reminder (host fills real strings):\n    # artifacts=[{\"id\": \"api\", \"type\": \"openapi\", \"before\": base_yaml, \"after\": head_yaml}]\n    result = client.authorize_change_set(\n        artifacts=artifacts,\n        context={\"operation\": operation, \"environment\": environment},\n    )\n    # Whitelist execution_action (proceed only on known-good); decision explains why.\n    # CONTINUE_WITH_MONITORING requires @coderifts/agent-guard monitoringSinkWired:true\n    # (plus a real monitor callback; JS package). This Python snippet has no sink —\n    # proceed only on CONTINUE. Unknown / missing action is not permission.\n    action = result.execution_action\n    decision = result.decision\n    if action != \"CONTINUE\":\n        raise RuntimeError(\n            f\"CodeRifts aborted: execution_action={action!r} (decision={decision}); \"\n            f\"patterns={getattr(result, 'patterns', None)}; \"\n            f\"risk_score={getattr(result, 'risk_score', None)}\"\n        )\n    if result.safe_for_agent is not True:\n        raise RuntimeError(\n            f\"CodeRifts not safe_for_agent (decision={decision}, execution_action={action})\"\n        )\n    # A valid signature is not authorization: currently_authorized comes from verify_receipt,\n    # bound to the SAME operation/environment this gate authorized. Required, not optional —\n    # a receipt scoped to a different act does not authorize this one.\n    # Full verifier context (target_id + fingerprint + decision_result) is required for the\n    # live server to evaluate currently_authorized — token+operation+environment alone yields\n    # currently_authorized:false (receipt_context_required / scope mismatch). Matches website\n    # agent-frameworks snippets (ID827 / a731888 pattern).\n    receipt = getattr(result, \"chain_receipt\", None)\n    if not receipt:\n        raise RuntimeError(\"CodeRifts: authorize returned no chain_receipt to verify\")\n    decision_result = getattr(result, \"decision_result\", None)\n    if decision_result is None:\n        raise RuntimeError(\"CodeRifts: missing decision_result\")\n    authz = client.verify_receipt(\n        token=receipt,\n        operation=operation,\n        environment=environment,\n        target_id=getattr(decision_result, \"artifact_digest\", None),\n        fingerprint=getattr(result, \"verdict_fingerprint\", None),\n        decision_result=decision_result.to_dict(),\n    )\n    if authz.currently_authorized is not True:\n        # None means \"could not be evaluated\" — neither authorized nor unauthorized. Not a pass.\n        raise RuntimeError(\n            f\"CodeRifts: receipt not currently_authorized \"\n            f\"(currently_authorized={authz.currently_authorized!r}, \"\n            f\"authz_status={getattr(authz, 'authz_status', None)!r})\"\n        )\n    return result\n\n# Graph glue — enforcement node (not the demo URL check):\n# from langgraph.graph import END  # use END on abort edges if you prefer graph-level stop\ndef coderifts_enforce_node(state):\n    artifacts = state[\"artifacts\"]  # required: host-supplied base→head\n    operation = state.get(\"operation\", \"merge\")\n    result = coderifts_enforce_may_proceed(artifacts, operation=operation)\n    state[\"coderifts_decision\"] = result.decision\n    state[\"coderifts_execution_action\"] = result.execution_action\n    state[\"coderifts_blocked\"] = False\n    return state\n\n# builder.add_node(\"coderifts_enforce\", coderifts_enforce_node)\n# builder.add_edge(\"coderifts_enforce\", \"api_call_node\")\n# builder.add_conditional_edges(\"coderifts_enforce\", lambda s: END if s.get(\"coderifts_blocked\") else \"api_call_node\")","description":"LangGraph: quick public quality check (demo), then SDK change-set enforcement before a tool node. Host puts before/after on state.","preflight_url":"https://app.coderifts.com/api/v1/public/preflight","correlation_id":"2a4e77e1-e245-4fb3-98e5-eae9f9c9801d"}