The channel is declared twice: in lembas.env, which this process reads and the
page prints, and baked into the systemd unit, which is what the helper actually
deploys. install.sh writes both together so they agree by construction -- and
the moment somebody edits one by hand they diverge, with the page naming one
channel down every card and the button deploying the other. Nothing anywhere
would have said so.
It cannot be collapsed to one place. Reading it from lembas.env at deploy time
would mean the service account decides what gets deployed, since it owns that
file -- and "the request carries no channel" is the property the whole design
rests on. So the two stay, and the marker file the page already reads to know
the helper exists now carries the channel it was installed with. A disagreement
is an alert.
Display only, deliberately: the service account can write that marker, so a
compromised process could lie about what the helper will do -- but not change
it, because the helper's own channel lives in /etc where that account cannot
reach. Lying about the channel is a much smaller thing than choosing it.
An empty marker -- every host installed before this -- reads as unknown rather
than as a mismatch. Claiming one would put a red alert on every existing host.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit meant to do this and edited a heading that exists only in
the planning notes, not in PLAN.md -- so the replacement matched nothing and
said nothing, which is the failure mode this file is half a catalogue of.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every version bump gets an entry in the same commit. Not afterwards: the reason
a change was made is known while it is being made and gone a week later, and a
changelog assembled from commit subjects at release time is a list of things
nobody can act on.
Backfilled 0.8.2 through 0.9.8, because those shipped as a running deployment
rather than as releases and 1.0.0's notes have to be assembled from something.
The rule that earns the file its place is the last one in CLAUDE.md: a fix to
something that *looked* like it worked gets a line, always. Those are the
entries somebody stops working around a bug because of, and they are invisible
from outside -- nobody reports a control that silently does nothing, they just
quietly stop using it. Half of what is in here is that shape: a group delete
that left its grants, a share panel that only saved if you also saved the
resource, an update script that stopped after "== fetching ==".
A release is a signed annotated tag whose message is that version's entry, and
that is not decoration -- /admin/updates reads release notes out of the tag
object, so the tag message is literally what an administrator sees on the update
page.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Found by documenting it. `_notes_for` stripped `-----BEGIN PGP SIGNATURE-----`
from an annotated tag's contents and nothing else, and which header appears
depends on `gpg.format`: `openpgp` writes that one, `ssh` writes
`-----BEGIN SSH SIGNATURE-----`. This repository signs with an SSH key, so the
first signed release tag would have rendered its whole signature block as the
release notes on the update page.
`%(contents:subject)` and `%(contents:body)` would have avoided the question,
and would also have thrown away every blank line in a body written as a list --
which is what release notes are.
The suite caught the other half of the same change: `tag.gpgSign` makes a bare
`git tag <name>` behave as `-s`, so the lightweight tags a test was making now
wait for an editor it does not have.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>