skillscript-runtime v0.27.0
Upgrade impact: none (additive; no re-approval). A (fallback:) that previously did nothing against a throw now fires — a skill that used to abort now degrades. No skill breaks; see the one behavior note below.
The 0.26.4–0.26.6 arc surfaced that (fallback:) was inconsistent: it contained a failure for shell / $ dispatch / file_read, but the execute_skill and $ json_parse intercepts threw directly, bypassing the trailer — so a per-leg (fallback:) on a throwing execute_skill leg did nothing and aborted the whole gather (the 2026-07-05 morning-brief class). 0.26.6 documented that split; 0.27.0 removes it at the source (Perry decision B, c052581b).
(fallback: "…")now contains ANY failure from every fallible op, including anexecute_skillchild-throw (e.g. a child whose output template references an unset var) and a$ json_parseoff-shape input. The intercepts now consultop.fallbackon their raised throw, mirroring the existingfile_readpath. The author-facing mental model is finally uniform: a failing op with(fallback:)degrades and continues, whatever the failure shape — no more reasoning about which ops return-empty vs raise.- The throw stays diagnosable. A caught throw records its message in the result's
fallbacks[].reason(degrade-loud), so it isn't silently erased — it moves fromerrors[]tofallbacks[]. - Security is unaffected. A child's own op-level failure — including a policy/security refusal (shell-allowlist, disallowed-tool, fs-deny) — is captured in the child's
result.errors[]and never escapes as a parent throw, so a parent(fallback:)cannot swallow it (verified: a child hitting the shell allowlist surfaces in the bound child result, the parent fallback does not fire). - One behavior note: a skill that today aborts before a side effect (e.g.
$ json_parse … (fallback:"{}")followed by a$ data_write) will now proceed into that op with the degraded value. This is identical to howshell/$fallbacks already behave — writing(fallback:)opts into continue-with-default. Rule 5 (degrade loud) still applies. - Docs: the
help({topic:"error-handling"})topic + quickstart + server-instructions were re-simplified to the uniform model;else:is reframed as target-level recovery logic (not the throw-container of last resort), the structural guard as the most-robust prevention. (# OnError:remains parsed-but-unwired — flagged, tracked separately.)