From 69bcac421abce77df4aeb1c086db187d5b208ff0 Mon Sep 17 00:00:00 2001 From: CroneKorkN Date: Sun, 10 May 2026 20:29:10 +0200 Subject: [PATCH] agents/bundles: triggers/triggered:True invariant + self-healing Two related lessons from the left4me integration: 1. The triggers/triggered:True invariant tripped three times in one session. When chown_src was promoted from triggered-only to self-healing-every-apply (drop triggered:True + add unless), bw rejected because it was still in git_deploy's triggers list. Same dance happened for pip_install. 2. Triggered actions can't recover from partial failure: once upstream succeeds, it's "in desired state" forever and the trigger never re-fires. For pip installs / chowns / migrations that must heal on every apply, the right shape is no triggered:True + unless:. unless semantics fold into the same bullet. Co-Authored-By: Claude Opus 4.7 (1M context) --- bundles/AGENTS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bundles/AGENTS.md b/bundles/AGENTS.md index bd1f8bf..5d096dd 100644 --- a/bundles/AGENTS.md +++ b/bundles/AGENTS.md @@ -118,6 +118,20 @@ bundles// when the reactor writes into another bundle's namespace — a static contribution to e.g. `nftables/output` belongs in `defaults`, where bw merges it with other bundles' contributions. +- **`triggers` ↔ `triggered: True` invariant.** Any item listed in + another's `triggers` list must declare `triggered: True`. bw + enforces this at `bw test` time: *"…triggered by …, but missing + 'triggered' attribute"*. Corollary: an action can't be both in an + upstream `triggers` list AND self-healing every apply — pick one. +- **Triggered actions don't recover from partial failure.** When an + upstream item's apply succeeds but its triggered downstream action + fails, subsequent applies can't recover via the trigger chain — + upstream is "already in desired state" and never re-triggers. For + actions that must self-heal (pip installs, chowns, migrations), + drop `triggered: True` and gate the command with `unless: `. + `unless` is a shell command on the target host whose exit status + decides whether the main command runs (exit 0 = skip); it's checked + at fire time, after `triggered:` filtering. ## Per-bundle README