Workflow Terminal-State Reference¶
Home > Reference > Workflow Terminal State
This reference defines the target contract for development workflow terminal
closure. Development workflows fail closed unless they reach a proven terminal
state. default-workflow, routed smart-orchestrator development workstreams,
and their publish/finalize sub-recipes must use the same terminal-state gate so
planning, analysis, design, or worktree setup cannot be reported as successful
code-change completion.
Contents¶
- What the Gate Protects
- Valid Success Evidence
- Default Workflow Agentic Finalization
- Evidence Precedence
- Evidence Marker API
- Recipe Output Contract
- Shell Helper API
- Configuration
- Failure Semantics
- Examples
- Security Invariants
What the Gate Protects¶
The terminal-state gate applies to workflow classifications that can modify code:
DevelopmentDefaultFeatureBugfixRefactor- routed
smart-orchestratorworkstreams that invokedefault-workflow
The gate does not turn investigation, Q&A, or operations workflows into development workflows. It only enforces the completion contract once a task has been routed to code-change semantics.
For protected workflows, these states are never enough for success by themselves:
- requirements clarification
- analysis
- architecture or design output
- issue creation
- worktree or branch preparation
- skipped implementation
- skipped verification
- empty agent output
- a shell process exiting
0without terminal evidence
Valid Success Evidence¶
A protected workflow exits 0 only when one of these evidence groups is present.
| Evidence group | Required proof | Typical producer |
|---|---|---|
| Implementation and verification complete | implementation_completed=true and verification_completed=true with non-empty reason text or structured detail |
workflow-tdd, workflow-precommit-test, review/feedback phases |
| Publish or change-request state reached | publish_state_reached=true with a known publish state such as FOLLOWUP_CREATED, SUPERSEDED, MERGED, NO_DIFF_SUCCESS, or CLOSED_OBSOLETE |
workflow-publish, workflow-finalize |
| Explicit terminal no-op | terminal_no_op=true, a known no-op state, and a non-empty reason |
no-diff, merged, obsolete, superseded, or allow_no_op paths |
terminal_failure=true is valid terminal evidence, but it is never success
evidence. It proves the workflow reached a known failing terminal state and must
exit nonzero.
Unknown, empty, malformed, or contradictory evidence is failure evidence.
Default Workflow Agentic Finalization¶
default-workflow finalization uses the terminal-state gate as its deterministic
classifier, not as a brittle text parser. Deterministic shell/JSON steps collect
Git, PR, CI, implementation, verification, publish, and observed-phase evidence
into typed recipe state. The classifier derives one terminal state from that
typed evidence, applying guards before any success state, and chooses the recipe
exit status.
An agentic finalizer step contributes a human-readable narrative only. That
narrative is captured as an artifact and is never parsed with jq, regex,
fence stripping, or JSON extraction to drive control flow. A successful run
cannot be reported as failed merely because the finalizer emitted prose instead
of parser-compatible JSON. Malformed or contradictory typed evidence fails
closed as FAILED_INVALID_EVIDENCE; a failed reporting step after a successful
implementation classifies as FAILED_REPORTING and preserves durable evidence.
See Default Workflow Agentic Finalization for the evidence document, finalizer output schema, configuration, and examples.
Evidence Precedence¶
The gate evaluates evidence in this order. Implementations and tests must use the same precedence so ambiguous marker combinations do not behave differently across helper, recipe, and CLI layers.
| Precedence | Evidence | Result |
|---|---|---|
| 1 | terminal_failure=true, or a known failing terminal_state |
Fail nonzero. Failure evidence overrides all success-looking markers. |
| 2 | Malformed, unknown, empty, or contradictory evidence | Fail nonzero with FAILED_INVALID_EVIDENCE. |
| 3 | Valid publish/PR/merge/no-diff state with required details | Succeed, because publish/finalize proves the workflow reached terminal semantics. |
| 4 | terminal_no_op=true with known no-op state and non-empty reason |
Succeed only for eligible no-op paths. |
| 5 | implementation_completed=true and verification_completed=true |
Succeed only when the selected workflow path does not require publish/finalize evidence. |
| 6 | Anything else | Fail nonzero with FAILED_MISSING_TERMINAL_EVIDENCE. |
Contradictory examples include terminal_failure=true with
terminal_success=true, terminal_no_op=true without a no-op state and reason,
or implementation_completed=true with verification_completed=false and no
valid publish or no-op state.
Evidence Marker API¶
Recipes communicate terminal progress through structured markers. Marker values may be emitted as recipe context keys, JSON step output fields, or exported shell environment variables. The terminal-state gate normalizes all three forms into the same contract.
Input may use native JSON booleans or boolean strings. The canonical emitted
form is the lowercase string "true" or "false" because shell helpers and
recipe key/value output are string-based. Consumers should accept either native
booleans or canonical strings, but producers for this feature should emit the
canonical strings.
Boolean Markers¶
| Marker | Type | Meaning |
|---|---|---|
implementation_completed |
boolean | Code, docs, config, or other requested repository changes were applied. |
verification_completed |
boolean | Required checks for the selected workflow path completed. |
publish_state_reached |
boolean | The workflow reached PR, merge, no-diff, obsolete, or follow-up publication semantics. |
terminal_no_op |
boolean | The workflow intentionally ends without file changes or new publication work. Requires a valid state and reason. |
terminal_failure |
boolean | The workflow has a known failing terminal state and must exit nonzero. |
Detail Markers¶
| Marker | Type | Required when | Meaning |
|---|---|---|---|
terminal_state |
enum | Always | Stable machine-readable state. |
terminal_reason |
string | Always | Actionable human-readable explanation. |
observed_phases |
list/string | Failure diagnostics | Phases that produced evidence before the gate ran. |
missing_evidence |
list/string | Failure diagnostics | Evidence required for success but not observed. |
change_request_url |
URL string | Publish/change-request states | Provider change request that represents the completed work. |
change_request_id |
string | Publish/change-request states | Provider change-request identifier when available. |
pr_url |
URL string | GitHub compatibility output | GitHub pull request that represents the completed work. |
pr_number |
positive integer string | GitHub compatibility output | GitHub pull request number when available. |
verification_summary |
string/object | Verification completed | Commands or checks that satisfied verification. |
required_next_action |
string | Finalization output | Operator or agent action needed after the terminal decision. |
hollow_success_detected |
boolean | Finalization output | Whether finalization detected a success-looking run without meaningful completion evidence. |
evidence_used |
list/string | Finalization output | Stable typed-evidence keys used by the deterministic classifier. |
reporting_failure |
boolean | Finalization output | true when a reporting/finalization step itself failed (from that step's exit status). The classifier combines it with implementation/verification evidence to produce FAILED_REPORTING while durable evidence is preserved. |
Terminal State Vocabulary¶
| State | Success? | Meaning |
|---|---|---|
IMPLEMENTED_VERIFIED |
Yes | Implementation and verification both completed. |
FOLLOWUP_CREATED |
Yes | Meaningful work was published or represented by a follow-up PR. |
MERGED |
Yes | The workflow-owned PR is merged or has merge evidence. |
NO_DIFF_SUCCESS |
Yes | The checkout is clean and has no meaningful diff against the intended base. |
CLOSED_OBSOLETE |
Yes | The PR or branch is obsolete and equivalent work is already upstream or no meaningful work remains. |
SUPERSEDED |
Yes | A newer workflow-owned PR or issue explicitly supersedes this run. |
ALLOW_NO_OP |
Yes | allow_no_op=true was set for an eligible non-code-change path and includes a reason. |
MANUAL_REQUIRED |
No | A provider action is intentionally manual; required_next_action names the action. |
BLOCKED_MANUAL_PROVIDER |
No | Required provider tooling, credentials, permissions, or APIs are unavailable. |
FAILED_MISSING_TERMINAL_EVIDENCE |
No | The workflow stopped before implementation, verification, publish, or valid no-op evidence. |
FAILED_INVALID_EVIDENCE |
No | Typed evidence is malformed, unknown, empty, or contradictory. |
FAILED_IMPLEMENTATION |
No | Durable implementation or verification evidence is absent or failed while meaningful work remains. |
FAILED_REPORTING |
No | Implementation succeeded but a reporting/finalization step failed. Durable evidence (pr_url, pr_number, implementation/verification markers) is preserved and reported. |
FAILED_DIRTY_WORKTREE |
No | Uncommitted work exists and terminal success cannot be proven. |
FAILED_MEANINGFUL_DIFF |
No | Meaningful branch changes remain but no validated publish, merge, follow-up, no-op, or implementation-plus-verification path proves closure. |
FAILED_WRONG_BRANCH |
No | The target checkout is not on the expected branch. |
FAILED_INVALID_INPUT |
No | Required context such as repository path, branch, or PR identity is invalid. |
FAILED_MISSING_TOOLING |
No | Required deterministic tooling is unavailable for the selected finalization path. |
FAILED_PR_METADATA_UNAVAILABLE |
No | Provider change-request proof is required but metadata, auth, or provider output is unavailable or ambiguous. |
FAILED_CLOSED_UNMERGED |
No | A PR is closed without merge evidence and meaningful local branch diff remains. |
BLOCKED_CI |
No | Required checks are failing or unavailable. |
HOLLOW_SUCCESS |
No | The recipe appeared successful but lacked implementation, verification, publish, or valid no-op evidence. |
INCOMPLETE |
No | Work remains and no more specific terminal failure state applies. |
Retired:
FAILED_FINALIZER_OUTPUTno longer exists. Terminal classification is derived from typed evidence, so an agentic finalizer can no longer produce a machine-control parse failure. Reporting-step failures now classify asFAILED_REPORTING(durable evidence preserved), and malformed deterministic evidence classifies asFAILED_INVALID_EVIDENCE.Vocabulary scope:
MANUAL_REQUIREDandBLOCKED_MANUAL_PROVIDERare part of this broader terminal-state vocabulary but are not emitted by the agentic finalizer's own classifier. They reach a finalization result only throughprior_terminal_statepropagation from an upstream deterministic probe.
Recipe Output Contract¶
workflow-terminal-state.yaml is the target recipe-level gate. It wraps the
shell evaluator and preserves terminal success or failure as recipe success or
failure.
The canonical finalization result is a workflow_result object in full recipe
JSON. Shell helpers and individual recipe steps may expose the same fields as
flattened key/value output; those flattened fields must have the same names and
semantics.
Successful workflow_result content includes:
{
"terminal_success": "true",
"terminal_state": "IMPLEMENTED_VERIFIED",
"terminal_reason": "implementation and verification evidence present",
"required_next_action": "No further action is required.",
"hollow_success_detected": "false",
"evidence_used": "implementation.completed=true,verification.completed=true",
"reporting_failure": "false",
"implementation_completed": "true",
"verification_completed": "true",
"publish_state_reached": "false",
"terminal_no_op": "false",
"terminal_failure": "false",
"observed_phases": "workflow-prep,workflow-worktree,workflow-design,workflow-tdd,workflow-precommit-test",
"missing_evidence": ""
}
Failure workflow_result content includes:
{
"terminal_success": "false",
"terminal_state": "FAILED_MISSING_TERMINAL_EVIDENCE",
"terminal_reason": "development workflow stopped after workflow-worktree; implementation, verification, publish, or explicit no-op evidence is required",
"required_next_action": "Continue into implementation and verification, publish a meaningful diff, or emit a valid no-op state.",
"hollow_success_detected": "false",
"evidence_used": "observed_phases=workflow-prep,workflow-worktree",
"reporting_failure": "false",
"implementation_completed": "false",
"verification_completed": "false",
"publish_state_reached": "false",
"terminal_no_op": "false",
"terminal_failure": "true",
"observed_phases": "workflow-prep,workflow-worktree",
"missing_evidence": "implementation_completed,verification_completed,publish_state_reached,terminal_no_op"
}
A reporting-failure workflow_result preserves durable evidence:
{
"terminal_success": "false",
"terminal_state": "FAILED_REPORTING",
"terminal_reason": "implementation succeeded but a reporting step failed",
"required_next_action": "Re-run the reporting step; the implementation is intact.",
"hollow_success_detected": "false",
"evidence_used": "implementation.completed=true,verification.completed=true,finalizer_step_status.reporting_failure=true",
"reporting_failure": "true",
"implementation_completed": "true",
"verification_completed": "true",
"publish_state_reached": "true",
"terminal_no_op": "false",
"terminal_failure": "true",
"pr_url": "https://github.com/rysweet/amplihack-rs/pull/123",
"pr_number": "123"
}
The recipe runner treats a nonzero terminal-state step as recipe failure.
smart-execute-routing.yaml and smart-orchestrator.yaml must propagate that
failure instead of converting it into orchestration success.
workflow-finalize emits the same normalized fields after classifying the
terminal state from typed evidence. The agentic finalizer narrative is never
parsed; if a reporting/finalization step fails after successful implementation,
the normalized result uses terminal_state=FAILED_REPORTING,
terminal_success=false, and reporting_failure=true, and preserves durable
pr_url/pr_number and implementation/verification markers. Malformed typed
evidence uses terminal_state=FAILED_INVALID_EVIDENCE.
Shell Helper API¶
amplifier-bundle/tools/workflow_final_status.sh is the target canonical
evaluator for this feature. Recipes call it from the repository checkout or
workflow worktree.
Inputs¶
The helper reads normalized environment variables. Recipe context fields map to
the same names through RECIPE_VAR_* variables when invoked by the runner.
| Environment variable | Type | Description |
|---|---|---|
WORKFLOW_CLASSIFICATION |
enum string | Workflow class such as Development, Default, Investigation, or Ops. |
RECIPE_NAME |
string | Current recipe name. Used for diagnostics and protected-workflow detection. |
REPO_PATH |
path | Repository root used for Git evidence. |
WORKTREE_SETUP_WORKTREE_PATH |
path | Preferred workflow checkout when step 04 created or reused a worktree. |
BRANCH_NAME |
git ref name | Expected branch for development completion. |
BASE_REF |
git ref name | Intended comparison base. |
PR_URL |
URL string | Pull request URL, when publication happened or recovery is in progress. |
PR_NUMBER |
positive integer string | Pull request number, when available. |
ALLOW_NO_OP |
boolean string | Explicit opt-out for eligible no-op paths. Defaults to false. |
IMPLEMENTATION_COMPLETED |
boolean string | Direct implementation evidence. |
VERIFICATION_COMPLETED |
boolean string | Direct verification evidence. |
PUBLISH_STATE_REACHED |
boolean string | Direct publish/finalize evidence. |
TERMINAL_NO_OP |
boolean string | Direct no-op evidence. |
TERMINAL_FAILURE |
boolean string | Direct failure evidence. |
TERMINAL_STATE |
enum string | Existing state from a publish/finalize step. |
TERMINAL_REASON |
string | Existing reason from a publish/finalize step. |
OBSERVED_PHASES |
comma-separated string | Optional explicit phase list. |
Outputs¶
The helper prints human-readable diagnostics to stderr and key/value evidence
to stdout.
terminal_success=false
terminal_state=FAILED_MISSING_TERMINAL_EVIDENCE
terminal_reason=development workflow stopped after workflow-worktree; implementation, verification, publish, or explicit no-op evidence is required
observed_phases=workflow-prep,workflow-worktree
missing_evidence=implementation_completed,verification_completed,publish_state_reached,terminal_no_op
Exit codes:
| Code | Meaning |
|---|---|
0 |
Terminal success is proven, or the workflow is not protected by development terminal-state validation. |
1 |
Protected workflow lacks required evidence or has an explicit terminal failure. |
2 |
Helper invocation is invalid, required tooling is missing, or input is malformed before evaluation can run. |
These are direct helper exit codes. Through amplihack recipe run, any nonzero
helper result is surfaced as recipe failure and the CLI exits nonzero; current
CLI behavior reports recipe failures as exit 1 rather than preserving the
helper's numeric code.
Configuration¶
allow_no_op¶
allow_no_op is the explicit no-op escape hatch. It is valid only when the
workflow classification allows a no-op path and the terminal evidence includes a
reason.
amplihack recipe run default-workflow \
-c task_description="Review workflow docs and report findings without editing files" \
-c repo_path=. \
-c allow_no_op=true
allow_no_op=true does not hide errors. It succeeds only with
terminal_no_op=true, terminal_state=ALLOW_NO_OP or another valid no-op
state, and a non-empty terminal_reason.
No Silent Relaxation¶
There is no configuration flag that makes development terminal validation
advisory. CI, local recipe runs, and nested smart-orchestrator routing all use
the same fail-closed behavior.
Agentic Finalizer¶
No separate feature flag enables the agentic finalizer. It is part of the
default-workflow finalization path. The active agent runtime is inherited from
the workflow environment, including AMPLIHACK_AGENT_BINARY when nested
workflows are launched by Copilot, Claude Code, Amplifier, or Codex wrappers.
The finalizer produces a human-readable narrative artifact only. Its output is
never parsed for control flow. If the finalizer step fails, the deterministic
classifier records a reporting failure: when implementation and verification
evidence is present, the terminal state is FAILED_REPORTING and durable
evidence is preserved; otherwise the classifier falls through to the applicable
evidence-based failure state rather than to a success-shaped shell guess.
Node Memory Preference¶
When workflow checks run Node-based tooling, use the configured memory ceiling:
This affects child tool memory limits only. It does not change terminal-state success rules.
Failure Semantics¶
The terminal-state gate fails visibly when required evidence is missing.
Example diagnostic:
ERROR: development terminal state not proven
recipe: default-workflow
state: FAILED_MISSING_TERMINAL_EVIDENCE
observed phases: workflow-prep, workflow-worktree, workflow-design
missing evidence: implementation_completed, verification_completed, publish_state_reached, terminal_no_op
next action: continue into workflow-tdd/workflow-precommit-test/workflow-publish or emit an explicit terminal no-op/failure state with a reason
This failure exits nonzero from:
workflow-terminal-state.yamldefault-workflow.yamlsmart-execute-routing.yamlsmart-orchestrator.yamlamplihack recipe run smart-orchestrator ...
Callers must treat that as an incomplete workflow, not a successful planning run.
Examples¶
Early Stop After Worktree Prep Fails¶
amplihack recipe run smart-orchestrator \
-c task_description="Fix cache invalidation bug" \
-c repo_path=. \
--format json
If the routed development workstream stops after analysis or worktree setup, the
command exits 1 and the JSON result contains a failed terminal-state step.
{
"status": "FAILURE",
"failure_context": {
"step_id": "workflow-terminal-state",
"status": "failed"
}
}
Implementation and Verification Succeed¶
terminal_success=true
terminal_state=IMPLEMENTED_VERIFIED
terminal_reason=implementation, pre-commit, and targeted tests completed
implementation_completed=true
verification_completed=true
The workflow may then continue to publish/finalize, or finish successfully if the current recipe path ends at verification.
No Diff Succeeds Explicitly¶
terminal_success=true
terminal_state=NO_DIFF_SUCCESS
terminal_reason=clean branch has no meaningful diff or commits against origin/main
terminal_no_op=true
No-diff success is evidence-based. A clean status alone is not enough if the workflow also observed dirty work, branch mismatch, invalid PR identity, or malformed terminal markers.
Contradictory Evidence Fails¶
implementation_completed=true
verification_completed=false
terminal_no_op=false
publish_state_reached=false
Result:
terminal_success=false
terminal_state=FAILED_MISSING_TERMINAL_EVIDENCE
missing_evidence=verification_completed,publish_state_reached,terminal_no_op
Security Invariants¶
- Structured typed markers and deterministic evidence, not free-form agent prose, determine terminal success.
- The agentic finalizer narrative is treated as untrusted, opaque text. It is
never parsed, evaluated, or interpolated to drive control flow, so adversarial
tokens such as
terminal_state: MERGEDcannot flip a decision. - Protected workflow classifications are validated against a small known set.
- Missing, empty, unknown, malformed, and contradictory evidence fails closed.
terminal_failure=trueoverrides all success-looking markers.- No-op states require explicit state and reason text.
- Git and PR evidence is read only from the workflow checkout or configured repository path.
- Branch names, PR numbers, and PR URLs are validated before use.
- Diagnostics do not print full environments, tokens, credentials, or auth headers.
- Nonzero exit codes are preserved through nested recipe routing.