{
  "record_type": "teleon_cas_object_envelope/v1",
  "swhid": "swh:1:cnt:2855ca434e9b308d3dcee870460f28a07dc136cd",
  "sha256_hex": "39dad8e525307c1181a7f57e963ffedeb97822858de7fd564692250d1ca3f3ee",
  "r2_object_key": "sha256/39/39dad8e525307c1181a7f57e963ffedeb97822858de7fd564692250d1ca3f3ee",
  "storage_backend": "cloudflare_r2_plus_d1_index",
  "teleon_uri": "teleon://swh:1:cnt:2855ca434e9b308d3dcee870460f28a07dc136cd",
  "vault_url": "https://files.teleon.dev/objects/swh:1:cnt:2855ca434e9b308d3dcee870460f28a07dc136cd",
  "raw_stream_url": "https://files.teleon.dev/raw/sha256/39dad8e525307c1181a7f57e963ffedeb97822858de7fd564692250d1ca3f3ee",
  "slug": "since-cutoff-lockfile-api-diff",
  "title": "Zero-Model Lockfile Public-API Drift Scanner (since_cutoff_scan.py)",
  "artifact_kind": "tool_adapter",
  "filename": "since_cutoff_scan.py",
  "content_type": "text/x-python; charset=utf-8",
  "byte_length": 891,
  "spdx_license": "MIT",
  "facets": {
    "edge.typed_ports@v1": {
      "input": "symbol_pair_json/v1",
      "output": "api_drift_context_note/v1",
      "model_calls": 0
    },
    "search.l0_card@v1": {
      "keywords": [
        "tool",
        "python",
        "ast",
        "lockfile",
        "since-cutoff",
        "deterministic"
      ]
    }
  },
  "provenance": {
    "submitter": "teleon-deterministic-lab",
    "verified_maintainer": "teleon-deterministic-lab",
    "repo_owner": "teleon-dev",
    "inspired_by": "MohammadHijjawi97/since-cutoff & trevhud/rote",
    "evidence_status": "clean_room_deterministic_implementation"
  },
  "verification": {
    "tier": "deterministic_verified",
    "pass_at_k": 1,
    "pass_hat_k": 1,
    "k": 5,
    "spec_hash": "spec_tool_since_cutoff_v1",
    "unreadable_inputs": []
  },
  "inline_text": "\"\"\"Zero-model AST public-signature diff generator for AGENTS.md / CLAUDE.md notes.\"\"\"\nimport ast, json\n\ndef public_signatures(py_source: str) -> dict[str, list[str]]:\n    tree = ast.parse(py_source)\n    out: dict[str, list[str]] = {}\n    for node in tree.body:\n        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and not node.name.startswith('_'):\n            out[node.name] = [a.arg for a in node.args.args]\n    return out\n\ndef diff_cutoff_vs_pinned(before_src: str, pinned_src: str) -> dict[str, object]:\n    old_s, new_s = public_signatures(before_src), public_signatures(pinned_src)\n    added = sorted(k for k in new_s if k not in old_s)\n    removed = sorted(k for k in old_s if k not in new_s)\n    changed = sorted(k for k in new_s if k in old_s and new_s[k] != old_s[k])\n    return {'model_calls': 0, 'added': added, 'removed': removed, 'changed_signatures': changed}\n",
  "created_at": "2026-10-24T22:58:10.605Z"
}
