{"protocol":"clank-doc/1","frameworkVersion":"0.19.5","slug":"release-lifecycle","title":"Revision and release lifecycle","description":"Clank describes a change from UI intent through a data mutation, migration, artifact, canary, production activation, and rollback using dependency free, inspectable data envelopes.","group":{"id":"deploy","title":"Deploy and operate"},"url":"https://docs.clank.run/docs/release-lifecycle","source":"docs/release-lifecycle.md","headings":["End to end revision inspection and time travel","Provenance, promotion, and progressive delivery","Sanitized clones and portable exports","Capacity simulation"],"tableOfContents":[{"id":"end-to-end-revision-inspection-and-time-travel","title":"End-to-end revision inspection and time travel","level":2},{"id":"provenance-promotion-and-progressive-delivery","title":"Provenance, promotion, and progressive delivery","level":2},{"id":"sanitized-clones-and-portable-exports","title":"Sanitized clones and portable exports","level":2},{"id":"capacity-simulation","title":"Capacity simulation","level":2}],"markdown":"# Revision and release lifecycle\n\nClank describes a change from UI intent through a data mutation, migration, artifact, canary,\nproduction activation, and rollback using dependency-free, inspectable data envelopes.\n\n## End-to-end revision inspection and time travel\n\n`createRevisionLedger()` validates ordered events and JSON Pointer patches. `inspectRevision()`\nreplays any revision and returns its state plus its causal/correlation trace.\n\n```ts\nimport { createRevisionLedger, inspectRevision } from \"@clank.run/framework/lifecycle\";\n\nconst ledger = createRevisionLedger({ todos: {} }, [\n  {\n    id: \"ui-1\", revision: 1, at: new Date().toISOString(),\n    kind: \"ui\", actor: user.id, summary: \"Submitted todo\",\n    correlationId: \"request-8\",\n  },\n  {\n    id: \"mutation-1\", revision: 2, at: new Date().toISOString(),\n    kind: \"mutation\", actor: user.id, summary: \"Created todo\",\n    correlationId: \"request-8\", parentId: \"ui-1\",\n    patches: [{ op: \"set\", path: \"/todos/todo-1\", value: { title: \"Ship\" } }],\n  },\n]);\n\nconst beforeMutation = inspectRevision(ledger, 1);\nconst current = inspectRevision(ledger);\n```\n\nThis is application-state replay, not an encrypted backup replacement. Do not put secrets or raw\nauthorization data in event metadata. Ledgers are bounded, monotonic, and may only reference an\nearlier parent.\n\n## Provenance, promotion, and progressive delivery\n\n`createReleaseProvenance()` hashes the artifact, source revision, configuration, immutable\nmigrations, framework, builder, and time. `verifyReleaseProvenance()` detects later mutation.\nPromotion pins that release while traffic moves through ordered stages.\n\n```ts\nconst promotion = createPromotionPlan(provenance, [\n  { name: \"canary\", trafficPercent: 5, requiredChecks: [\"health\", \"journey\"] },\n  { name: \"production\", trafficPercent: 100, requiredChecks: [\"health\"], requiresApproval: true },\n]);\n\nconst rollout = assessRollout(\n  { samples: 800, errorRate: 0.004, p95Ms: 240 },\n  { minimumSamples: 500, maximumErrorRate: 0.01, maximumP95Ms: 500 },\n);\n```\n\nInsufficient samples pause. A mature stage breaching error, latency, or saturation guardrails\nrolls back. This layers over health-gated atomic activation; it never replaces the last healthy\nrelease during a failed activation.\n\n## Sanitized clones and portable exports\n\n`createSanitizedClone()` supports `keep`, `hash`, `redact`, `email`, and `drop`. Use a separate\nsecret salt for each trust boundary and provide it through the environment:\n\n```sh\nCLANK_CLONE_SALT=\"$SAFE_RANDOM_VALUE\" \\\n  clank workbench sanitize rows.json clone-policy.json \\\n  --output=sanitized.json\n```\n\nPortable exports contain sorted files, per-file SHA-256, and a whole-export digest. The CLI\nexcludes `.git`, `.clank`, `.env`, packages, SQLite files, and prior exports; rejects symbolic\nlinks and oversized files; omits common registry, cloud, SSH, and environment credential files;\nand writes mode 0600.\n\n```sh\nclank workbench export . --name=todo --framework=0.19.5 \\\n  --output=todo.clank-export.json\n```\n\nExports intentionally omit platform identity, domains, deployment tokens, billing data, and the\nproduction database. Call `verifyPortableProjectExport()` before importing.\n\n## Capacity simulation\n\n`estimateCapacity()` exposes requests, transfer, storage, realtime connections, job CPU, replicas,\nand the caller-supplied rate card. `clank workbench capacity workload.json rate-card.json --json`\nreturns the calculated units, cost drivers, and assumptions. It is a transparent estimate, not a\nbill.\n"}