Failure semantics
Failure semantics are a first-class part of an interpreter’s contract. How an interpreter signals success, failure, or partial completion directly affects user trust, automation reliability, and the ability to reason about outcomes.
Interpreters must make failure states explicit, predictable, and understandable without requiring users to inspect logs or infer meaning from side effects.
Success vs failure
An interpreter must clearly distinguish between success, failure, and partial success.
- Success indicates that the intended outcome was achieved within the bounds of the interpreter contract.
- Failure indicates that the intended outcome wasn’t achieved and that corrective action may be required.
- Partial success indicates that some (but not all) elements of the intended outcome were achieved.
Partial success isn’t an error condition by itself. It must be explicitly represented when applicable, along with structured details describing:
- Which actions succeeded
- Which actions failed or were skipped
- The implications for downstream steps
Interpreters must avoid ambiguous outcomes. Users and automation should never be required to infer success or failure from exit codes, logs, or side effects alone.
Error messaging
Error messages are part of the user experience and must be designed accordingly.
Interpreters should distinguish between:
- Human-readable, actionable errors, intended to help users understand what went wrong and how to correct it
- Diagnostic details, intended for troubleshooting and support
Human-readable errors:
- Use clear, plain language
- Explain what failed and why
- Indicate whether retrying is appropriate
- Avoid exposing raw engine errors as the primary message
Diagnostic information:
- May include engine output, stack traces, or low-level details
- Should be captured in stdout or stderr
- Must not be required to interpret the structured outcome
By separating actionable errors from diagnostic detail, interpreters support both usability and effective debugging without conflating the two.
Determinism and idempotency guidance
Interpreters should behave deterministically whenever possible.
A deterministic interpreter produces the same structured output when invoked with the same inputs under the same conditions. Determinism improves predictability, testability, and user confidence.
Idempotency is strongly preferred for interpreters that perform changes. An idempotent interpreter can be safely re-run without causing unintended side effects.
When determinism or idempotency can’t be guaranteed:
- The limitation must be explicitly documented
- Output must clearly indicate when non-deterministic behavior occurred
- Users must be informed how to reason about retries and re-execution
Silent non-determinism undermines trust and makes automation fragile.
Retries, re-execution, and safety
Interpreters don’t control retries, but they must be designed to behave safely when re-executed.
Interpreter contracts should:
- Clearly indicate whether retrying is safe
- Distinguish transient failures from permanent ones where possible
- Avoid side effects that make retries dangerous without warning
Where re-execution may cause additional changes or risk, the interpreter must make this explicit through its structured output and documentation.
Timeouts, cancellation, and incomplete execution
Interpreters may be interrupted due to timeouts, cancellation, or environmental failure.
Interpreter output must clearly communicate when execution was:
- Completed
- Partially completed
- Aborted before meaningful work occurred
Users should never be left guessing whether changes were applied when execution is interrupted. Structured output must reflect the final known state as accurately as possible.
Where precise state can’t be determined, the interpreter must explicitly state that uncertainty exists.