What is version-bound approval?
A reviewer's decision on a Cenelira external review link is bound to the SHA-256 fingerprint of the schedule's content and delivery settings at the moment the link was issued.
Decision commit
Every Cenelira external review link captures a SHA-256 fingerprint of the schedule's content and delivery settings at issue time. That fingerprint is the schedule's current reviewVersion. The reviewer's decision is committed inside a transaction whose WHERE clause also matches the current reviewVersion.
If the schedule was edited after the link was issued, the fingerprint changed. The decision update matches zero rows, the link is reclassified as SUPERSEDED, and the external decision endpoint returns HTTP 410 with a typed supersessionReason. This page describes that binding, names the code that enforces it, and maps it to the proof fields that survive the subscription.
A reviewer's decision on a Cenelira external review link is bound to the SHA-256 fingerprint of the schedule's content and delivery settings at the moment the link was issued.
Inside the decision transaction. The link carries the captured scheduleVersion. The update targets the schedule row with a WHERE clause that also matches the current reviewVersion. If the edit bumped reviewVersion, the update matches zero rows and the link is reclassified SUPERSEDED.
External reviewer identity is self-declared, not authenticated. Decisions that were already committed against a matching earlier version remain committed; this page is about rejecting new decisions whose captured version has since drifted.
Who this is for
Version-bound approval earns its rent on teams where an approval that means "yes to the version I read" is different from an approval that means "yes in general". It adds less value when the content rarely changes between approval and publish.
Failure scenario
The failure mode on a tool without version-bound approval is that "yes" sticks to the schedule, not to the version. The reviewer clicks approve on Monday's draft. An operator tweaks the caption on Tuesday. On Wednesday the tweaked draft publishes under Monday's approval record. The reviewer never saw the copy that shipped.
reviewVersion as scheduleVersion and writes that value onto the link artifact.refreshScheduleReviewVersion in src/lib/schedules/reviewVersion.ts recomputes the SHA-256 fingerprint and writes a new reviewVersion onto the schedule row.updateMany whose WHERE clause matches the schedule id, the item state, and reviewVersion: item.scheduleVersion. Because the current reviewVersion has changed, the update matches zero rows.SUPERSEDED with supersessionReason: 'review_version_changed'. The external decision API returns HTTP 410 Gone. The reviewer sees a terminal card titled "Content changed" with the badge "Superseded".Mechanism
The fingerprint is computed by computeScheduleReviewVersion and written by refreshScheduleReviewVersion in src/lib/schedules/reviewVersion.ts. The review link service carries the captured scheduleVersion on the link artifact. At commit time, the decision transaction refuses to update any row whose current reviewVersion does not equal the captured one. The ScheduleReviewLinkSupersessionReason union has eight values; the three below are the version-bound subset.
At external decision commit, the link-captured scheduleVersion does not equal the schedule row's current reviewVersion. The update is rejected before a decision is recorded.
HTTP 410 link_supersededThe schedule has no reviewVersion at decision commit time, so the link cannot verify the captured fingerprint against the current one. The decision is refused.
HTTP 410 link_supersededThe delivery set captured on the link no longer matches the schedule's current scope. A delivery was added or removed after the link was issued.
HTTP 410 link_supersededProof artifact
The decision binding is not a private server detail. Five fields in the signed 17-field proof record carry the version and the approval state that survives export.
versionFingerprint is resolved by collectWorkspaceProofRecords in src/lib/exports/workspaceProofExport.ts as the first non-empty value in this order: the SCHEDULE_HANDOFF_COMPLETED event's reviewVersion, the latest REVIEW_APPROVED or EXTERNAL_REVIEW_APPROVED event's reviewVersion, or the current schedule row's reviewVersion. When none of those sources carry a value, the field is null.
approverIdentity stores the label of who decided, read from the latest approval event. For internal decisions that is the workspace user label. For external decisions it is the self-declared reviewer label captured on the link.
approverSource records whether the decision came from an internal workspace approval or from an external review link. It defaults to internal for REVIEW_APPROVED events and external_self_declared for EXTERNAL_REVIEW_APPROVED events, so the row is never ambiguous on provenance.
approvalTimestamp records when the decision was committed, taken from the approval event's createdAt. Paired with versionFingerprint, it answers "which version was approved, and when" from a single row.
invalidationReason is derived from a REVIEW_LINK_EXPIRED or REVIEW_LINK_SUPERSEDED event for the same schedule. Expired links write expired; superseded links write the supersession reason recorded on the event. The field is null when no such event exists for the schedule. The signed PDF and CSV twin both carry these columns. See the proof record schema for the full 17-field inventory.
What this does not claim
Version-bound approval is one gate in the publish path. This page is explicit about where the gate stops.
reviewVersion remains committed. The later edit does not erase the prior approval from the proof record.ScheduleReviewVersionPayload. Edits to fields outside that payload do not trigger supersession on their own.FAQ
Anything that changes the schedule's reviewVersion fingerprint: caption, first comment, publishAt, destination, connected account, media bundle order, per-platform settings (for example TikTok privacy level and YouTube upload kind), and composition signatures. These are the fields in ScheduleReviewVersionPayload that the SHA-256 fingerprint is computed from.
The review page replaces the content surface with a terminal card. The card carries the badge "Superseded" and the title "Content changed". The body tells the reviewer a newer link is required to review the current version. Below the card the page shows the 8-character link fingerprint, the target account label if one was recorded, the decision timestamp if one was recorded, the supersession reason with underscores replaced by spaces, and a prompt to contact the team that sent the link. The original caption, media, and version are no longer rendered on the link; it is a terminal receipt, not a snapshot of the content the reviewer first saw.
No. A decision that was already committed against a matching reviewVersion stays committed. Version-bound approval rejects new decisions whose captured version no longer matches. The subsequent edit does not erase the prior approval from the proof record.
In the signed 17-field proof record, versionFingerprint is resolved by collectWorkspaceProofRecords in src/lib/exports/workspaceProofExport.ts as the first non-empty value across the SCHEDULE_HANDOFF_COMPLETED event's reviewVersion, the latest REVIEW_APPROVED or EXTERNAL_REVIEW_APPROVED event's reviewVersion, or the current schedule row's reviewVersion. approverIdentity, approverSource, and approvalTimestamp are read from the latest approval event. approverSource defaults to internal for REVIEW_APPROVED events and external_self_declared for EXTERNAL_REVIEW_APPROVED events. invalidationReason is derived from a REVIEW_LINK_EXPIRED or REVIEW_LINK_SUPERSEDED event for the same schedule: expired links write 'expired'; superseded links write the supersession reason. The field is null when no such event exists.
This page describes how Cenelira enforces version-binding at decision commit time. It does not make claims about what other approval tools store in their own version history. The testable difference is that the decision transaction refuses to commit when the captured fingerprint does not equal the current one.
Last reviewed 2026-04-24
A short checklist for teams whose clients approve by link, covering what should invalidate an approval, how to read the proof fields that record the decision, and what an external reviewer should expect on a stale link. Leave an email and we will send it when the checklist is ready.