From 487ba4ddd13e25749e13f354ccef1107be4a046e Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 7 Jul 2026 22:09:26 -0400 Subject: [PATCH] docs(#2009): add changeset fragment (PR #2075) --- .changeset/2009-load-failed-capability-fail-open.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/2009-load-failed-capability-fail-open.md diff --git a/.changeset/2009-load-failed-capability-fail-open.md b/.changeset/2009-load-failed-capability-fail-open.md new file mode 100644 index 000000000..22ce740cf --- /dev/null +++ b/.changeset/2009-load-failed-capability-fail-open.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2075 +--- +**Load-failed capability gates now fail open with a loud warning instead of blocking the whole project** — when an installed overlay (third-party) capability failed to load (e.g. an incompatible `engines.gsd` range) but had declared a `gate`-kind loop hook, the loop resolver injected a blocking synthetic gate (`blocking:true`, `onError:halt`) at every point where that capability declared a gate. A single incompatible capability therefore halted every `ship:pre` and `verify:post` in the project — unrelated to what the gate would have checked, and with no remediation surfaced. The resolver now injects no gate and instead emits a loud warning — to stderr and in the `loop render-hooks` envelope's `warnings` array — naming the load-failure reason and the exact `gsd capability remove ` remediation, and the loop proceeds (fail open). The capability id embedded in that remediation is validated against the canonical id shape first, so a malformed overlay directory name cannot inject shell metacharacters into the surfaced command. The loader still records `_overlay.blockedGates`; only the consequence changes from block to warn. `step`/`contribution` overlays were already skip-open. (#2009)