{
  "version": "act 2.0.0",
  "slug": "refactor-receipt",
  "name": "refactor-receipt",
  "description": "Emit durable refactor receipts \u2014 content-addressed JSON artifacts proving a refactor was verified. Delegates to the shipped gate machinery (act gate --receipts / MCP gate with receipts:true) rather than re-running verification ops manually.",
  "url": "https://act101.ai/docs/skills/refactor-receipt",
  "body_md": "# refactor-receipt\n\nEmit durable **refactor receipts** \u2014 content-addressed JSON files stored in\n`.act/receipts/` that record the full verification evidence for each changed\nfunction. The receipt machinery is built into `act gate`; this skill describes\nhow to drive it, where the files live, what validity means, and how to read one.\n\n## Honesty caveat (read first)\n\nA receipt is evidence, not proof of equivalence. The `modeled_kinds` field\nrecords what the grammar can actually judge; every dimension the grammar cannot\njudge is reported as `unknown:\u2026` in the `contract` field, never silently treated\nas preserved. Per-grammar degradation is real \u2014 some languages cover fewer\ndimensions. When citing a receipt, always quote `modeled_kinds` for any\n`unknown` dimension; omitting it misrepresents the receipt's confidence.\nRename receipts always record `contract: \"unknown:rename\"` because names differ\nby construction; that is not a verification gap, it is the correct honest answer.\n\n## Tier\n\n**Engineer.** The gate tool (which writes receipts) requires the Engineer tier.\nThe `receipt: true` parameter on the four refactor tools also requires Engineer;\nit is silently ignored in preview mode.\n\n## Emitting receipts\n\n### Whole changed set \u2014 `act gate --receipts`\n\nRun after a refactor session to verify and record every changed function in one\npass:\n\n```\nact gate --receipts\n```\n\nMCP equivalent:\n\n```\ngate(receipts=true)\n```\n\nThe gate discovers changed functions from the git diff (working tree vs HEAD by\ndefault, or vs `base_ref` when supplied), runs the full verification pipeline\nper function, and writes one `<id>.json` receipt to `.act/receipts/` per\nverified function. The overall verdict (MERGE / REVIEW / BLOCK / UNKNOWN) is\nreturned; receipt writing does not change the verdict rules \u2014 those live in the\ngate engine.\n\n### Single refactor op \u2014 `receipt: true`\n\nThe four refactor tools (`rename`, `extract_function`, `move_symbol`, `inline`)\naccept `receipt: true` to write a receipt immediately after applying the change.\nCLI usage (dev builds, `--features dev-cli`):\n\n```\nact refactor --receipt rename --file src/lib.ts --old-name foo --new-name bar\n```\n\nMCP equivalent (pass `receipt=true` as a parameter):\n\n```\nrename(file=\u2026, old_name=\u2026, new_name=\u2026, receipt=true)\n```\n\nOn success the result carries `receipt.id`. On failure it carries\n`receipt_error`. In preview mode (`preview: true`) the field is ignored and no\nreceipt is written.\n\n## Where receipts live\n\nAll receipts are stored flat in `.act/receipts/<id>.json` at the workspace\nroot. The `<id>` is the first 16 hex characters of\n`sha256(\"<file>\\0<symbol>\\0<before_hash>\\0<after_hash>\")` \u2014 a content-addressed\nkey that encodes the exact before/after state.\n\n## Validity \u2014 content-addressed, never stale\n\nReceipt consumption is **always on** when `.act/receipts/` exists: before using\na cached result the engine recomputes `before_hash` and `after_hash` from the\nlive span text and confirms they match the stored values. A mismatch means the\ncode changed since verification ran \u2014 the receipt is discarded and the function\nis re-verified from scratch. There is no \"stale pass\": a hash mismatch is always\na re-verify signal.\n\nReceipts with an unrecognised `schema_version` are also silently skipped and\ntreated as re-verify signals.\n\n## Reading a receipt\n\nEach receipt is a JSON file with these fields:\n\n| Field | What it means |\n|---|---|\n| `verdict` | `MERGE` / `REVIEW` / `BLOCK` / `UNKNOWN` \u2014 the gate's top-line decision |\n| `contract` | `\"preserved\"` / `\"broken:<dims>\"` / `\"unknown:<dims>\"` |\n| `diff_semantics` | Array of hunk classifications: `format`, `signature`, `behavior` |\n| `effects_added` / `effects_removed` | Side-effect delta |\n| `dropped_cleanup` | `true` if a cleanup effect was removed |\n| `impacted_tests` | Test files whose call graph reaches the changed function |\n| `modeled_kinds` | Bitmask of what the grammar could judge \u2014 cite this for any `unknown` dimension |\n| `before_hash` / `after_hash` | `\"sha256:<hex>\"` of the function's span text at verification time |\n| `id` | Content-addressed key (see above) |\n| `tool_version` / `timestamp` | Provenance |\n\nWhen citing a receipt in a review or audit:\n\n1. Quote the `verdict` and `contract` fields.\n2. For any `unknown:\u2026` or `broken:\u2026` contract, quote `modeled_kinds` and name\n   the unmodeled dimension \u2014 do not present an `unknown` dimension as preserved.\n3. The verdict decision rules live in the gate engine (`full_description` of the\n   `gate` catalog entry); do not re-derive them here."
}