# Canonical self-propagating handoff schema (#626) **Applies to:** every workflow actor — author, reviewer, merger, controller, operator, reconciler. `#494`–`#507` defined the ledger, the canonical state comments, and the Canonical Thread Handoff shape. This schema owns the *chain*: each actor consumes exactly one canonical handoff, performs exactly one authorized role, records the result durably in Gitea, and emits the next complete handoff — until the controller records final closure. Implemented and enforced by `self_propagating_handoff.py`; wired into `final_report_validator.py` as rule `shared.self_propagating_handoff`. ## The block Post this block into the Gitea issue or PR thread, and include it verbatim in the final report. It is not an optional prose section. ```md ## Canonical Handoff ```text REPOSITORY: / ISSUE: PR: WORKFLOW_STATE: HEAD_SHA: BASE_BRANCH: BASE_OR_MERGE_SHA: ACTING_ROLE: ACTING_IDENTITY: COMPLETED_ACTIONS: VALIDATION_EVIDENCE: MUTATION_LEDGER: BLOCKERS: NEXT_ACTOR: NEXT_ACTION: PROHIBITED_ACTIONS: NEXT_PROMPT: WORKFLOW_FAILURE_ISSUES: LAST_UPDATED: ``` ``` ## Workflow states and the single authorized actor | `WORKFLOW_STATE` | `NEXT_ACTOR` | | --------------------------- | ------------ | | `needs-author` | `author` | | `needs-review` | `reviewer` | | `approved-awaiting-merge` | `merger` | | `merged-awaiting-controller`| `controller` | | `blocked` | `operator` | | `complete` | `none` | A merged PR is **not** accepted work: merge transitions to `merged-awaiting-controller` unless the configured workflow explicitly authorizes automatic acceptance. ## Fail-closed rules * Every field is required. Only `PR`, `HEAD_SHA`, `BASE_OR_MERGE_SHA`, `BLOCKERS`, `WORKFLOW_FAILURE_ISSUES`, `NEXT_ACTION`, and `NEXT_PROMPT` may carry `none`, and `PR`/`HEAD_SHA` only in `needs-author` or `blocked`. * `NEXT_ACTOR` must equal the actor the declared state authorizes. * `blocked` requires a concrete `BLOCKERS` entry. * A non-terminal handoff requires a concrete `NEXT_ACTION` and a `NEXT_PROMPT` long enough to be ready to run. * `complete` must carry no `NEXT_ACTION` and no `NEXT_PROMPT`: a finished workflow terminates instead of manufacturing more work. * `NEXT_PROMPT` must name the repository and the issue, and must not depend on outside chat history. The issue or PR thread, workflow documentation, and live repository state must be sufficient to recover the task. * The handoff must be posted to Gitea. A chat-only report is not durable workflow state. ## Live-state recovery before acting The receiving actor re-derives truth from live state instead of trusting the inherited handoff. `assess_handoff_live_state` detects and fails closed on: `changed_pr_head`, `stale_approval`, `issue_closed`, `issue_reopened`, `pr_merged`, `pr_closed_unmerged`, `stale_lease`, `foreign_lease`, `missing_worktree`, `dirty_worktree`, `namespace_mismatch`, `stale_runtime`, `changed_base`, and `conflicting_canonical_comments`. A changed head invalidates any inherited review or merge handoff; the chain recovers to `needs-review`. ## Controller closure `accept` is only honored with all four closure proofs recorded: `acceptance_criteria_satisfied`, `cleanup_complete`, `canonical_final_state_posted`, `issue_closed_through_workflow`. Otherwise the work item stays at `merged-awaiting-controller`. `request_tests`, `request_proof`, `request_corrections`, and `reopen` return the work to the author; `return_to_actor` returns it to a named earlier actor. ## Workflow-failure escalation Tooling or workflow defects found while working an item never get folded into the active feature issue. Each distinct failure carries `classification`, `linked_issue`, `temporary_impact`, `next_valid_actor`, and `recovery_prompt`. A failure whose signature already has a durable issue must reuse that issue instead of filing a duplicate. ## Applicability Enforcement is applicability-gated exactly like the #495 canonical-state gate: once a report carries the `sph:v1` marker, the `Canonical Handoff` heading, or a `WORKFLOW_STATE:` line, the full schema is enforced and incomplete handoffs are rejected. Reports written before the protocol existed are unaffected.