Caught during the left4me-integration nginx 80.conf move: the
agent declared a redundant 'source': '80.conf' on a file: item
whose destination already ended in 80.conf. The maintainer
flagged it as noise. Document the rule: only declare source
when the basename differs from the destination (e.g. .mako
template to a non-suffixed destination).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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:<fast-check>. unless semantics fold
into the same bullet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The left4me bundle's first cut had two reactors that returned
static dicts without calling metadata.get(...): systemd_services
(enable/run flags) and nftables_output (two static rule strings).
Both passed bw test (no consumer yet). Once attached to
ovh.left4me, bw raised "did not request any metadata, you might
want to use defaults instead". Fix was to fold both into defaults.
Document the pitfall, with the verbatim error wording and the
note that this applies to cross-namespace contributions too.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the left4me bundle was first integrated, ovh.left4me's node
file carried ~40 lines of left4me-related metadata (git_url,
secret_key, full nginx vhost, monitoring, backups, nftables
rules). The maintainer pushed back: per-node metadata should be
only what genuinely varies per host. Refactor brought it down to
{'domain': 'left4.me'} with everything else in bundle defaults
or in a reactor deriving from the domain.
Add the rule to bundles/AGENTS.md from the bundle-author angle
(use defaults / vault-keyed-on-node for secrets, cite left4me
and postgresql for the established pattern). Add the reviewer's
form to nodes/AGENTS.md Pitfalls.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bw test (no args) is a parsing gate, not a behaviour gate. A
bundle's reactors only resolve when some node's metadata is
built, so reactor bugs stay dormant until a node opts in. The
left4me-integration session shipped 8 commits that all "passed
bw test" with latent reactor-rejection bugs that surfaced only
once the bundle was attached to ovh.left4me.
Rewrites the verify-list in bundles/AGENTS.md to require attach-
first and uses richer command invocations (bw items --blame,
bw metadata -k <key>). Adds a Bundle-validation workflow section
to commands.md spelling out why step 2 is non-optional.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
drops the per-bundle AGENTS.md convention and the rigid template
that went with it. each bundle has (or gets) one README.md that
serves humans and agents both.
bundles/AGENTS.md now has a "Per-bundle README" section pointing
at the more substantial existing READMEs (flask, dm-crypt, apt,
nextcloud) for orientation, plus loose guidance on what to cover
and what to skip. no required structure — match the bundle's
actual surface.
removes bundles/AGENTS.template.md; the template was prescriptive
in a way that wouldn't survive contact with this repo's actual
bundles, where READMEs range from one-paragraph balanced docs to
operational scratchpads.
phase-2 seed-bundle work stays deferred and will land as plain
README updates when bundles are materially edited.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>