---
title: "Authoring History / Undo-Redo Contract (generated)"
description: "Sources: `web_client/spa/src/authoring-history/types.ts`, `web_client/spa/src/workspace/workbench-surface-contracts.ts`, `web_client/spa/src/authoring/actionPolicy.ts`."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/spec/generated/authoring-history-contract/
---
<!-- GENERATED FILE: do not edit by hand. -->
<!-- Regenerate with `npm run gen-docs`. -->

Sources: `web_client/spa/src/authoring-history/types.ts`, `web_client/spa/src/workspace/workbench-surface-contracts.ts`, `web_client/spa/src/authoring/actionPolicy.ts`.

# Authoring History / Undo-Redo Contract (generated)

The launch-grade undo/redo subsystem. Undo/redo is scoped by the active
editable document, descriptor-backed (not closures), durable, and re-submitted
through the authoritative Project Graph transaction path. See
`docs/architecture/authoring-history-undo-redo-contract-final-plan.md`.

Descriptor schema version: `authoring.history.v2`.

## Descriptor fields (AuthoringHistoryEntryV1)

| Field | Meaning |
| --- | --- |
| schemaVersion | versioned descriptor tag (authoring.history.v2) |
| id | stable entry id |
| projectId / actorId | owning project + actor (per-actor undo) |
| scopeKind / scopeKey | document \| workspace \| project + the canonical scope key |
| surfaceId / resourceKind / resourceId | resolved active surface + resource identity |
| label | human-readable history label |
| forwardOps / inverseOps | graph ops to redo / undo (op-inverse derived) |
| forwardScript / inverseScript | script-IR redo / undo payload (Semantic Patch entries) |
| baseRevision | graph revision the entry's state is valid at |
| baseTargetVersions | targetKey -> the resource version this entry's write produced |
| idempotencyKey | stable key for retry-safe submission |
| createdAt / committedAt / undoneAt / redoneAt | lifecycle timestamps |
| status | lifecycle status enum (below) |
| receipt | { transactionId, revision } when known |
| conflict | { code, message, target } typed conflict when blocked |

## Status lifecycle

`pending`, `committed`, `queued`, `undo-queued`, `redo-queued`, `conflicted`, `undone`, `redone`, `rejected`

## Typed conflict codes (non-destructive, per-actor + per-scope)

`authoring_history_conflict_target_changed`, `authoring_history_conflict_deleted_target`, `authoring_history_conflict_revision_gap`, `authoring_history_conflict_scope_unavailable`

## Per-surface undo scope

| Surface | undoScope | Scope key format |
| --- | --- | --- |
| design | authoring-history | design:world:<worldId> |
| ui | authoring-history | ui:ui-panel:<panelId> (or ui) |
| script | authoring-history | script:<resourceKind>:<resourceId> |
| workflows | authoring-history | workflows:<resourceKind>:<resourceId> |
| prefab | authoring-history | prefab:<resourceKind>:<resourceId> |
| material-editor | authoring-history | material-editor:<resourceKind>:<resourceId> |
| model-editor | none | model-editor:<resourceKind>:<resourceId> |
| data | none | data:<resourceKind>:<resourceId> |

`authoring-history` = the canonical scoped kernel. `surface-local` is allowed
only for genuine native/editor text state. `none` = read-only/non-authoring.

## Operations that MUST produce a descriptor (undoPolicy: required)

`entity.create`, `entity.update`, `entity.delete`, `component.put`, `component.patch`, `component.field.patch`, `component.delete`, `prefab.override.mutate`, `script.semantic_patch.apply`, `project.graph.transaction.apply`
