Run 4 built both apps successfully and then emailed to say the build had FAILED.
Two separate faults.
The notification step died on bash 3.2, which macOS still ships as /bin/bash. It
mis-parses a heredoc inside command substitution when the text contains an
apostrophe: the word "anyone's" was enough to produce "unexpected EOF while
looking for matching '". Reproduced on the ingest Mac before and after the fix.
The body is written to a file first, which avoids the construct entirely.
The failure alert was then sent because it keyed off failure() for the whole job,
so a bug in the success notification presented as a broken build. It is now scoped
to steps.build.outcome, so it reports only what it claims to report.
An alert that fires when nothing is wrong trains you to ignore it, which costs more
than the missing alert it replaced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The alert steps passed their message body as a bare multi-line argument starting
at column 0. That ends the YAML block scalar, which makes the whole file invalid:
"a multiline key may not be an implicit key". Gitea still listed the workflow as
active and simply never created a run for it — no error anywhere, which is why two
pushes appeared to do nothing.
The bodies are built with indented heredocs now, so every line stays inside the
block scalar. Validated by parsing the file rather than by eye; a workflow that is
registered but silently never triggers looks exactly like one that works.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The web app has deployed on push since earlier today, but the phone apps carry
their own frozen copy of the UI, so a change to server/public silently left them
behind until someone remembered to cut a release. Remembering was the weak part.
A second Actions runner now runs on the ingest Mac — in host mode, because an app
build needs Xcode, the Android SDK and the signing keys, none of which exist in
the NAS runner's Linux container. A push touching server/public, mobile/src or
the Capacitor config rebuilds and signs both apps, then emails to say the shipped
apps are behind, or that the build broke.
It deliberately stops before uploading. An upload needs a build number that has
never been used, Play refuses to reuse or lower a versionCode, and bumping it
means committing the new number back from the build machine on every run. That
needs write access from that machine and permanently changes the numbering
scheme — a one-way door, so shipping stays an explicit ./release.sh.
release.config.json is excluded from the trigger paths so that bumping a build
number by hand cannot set off a rebuild of what was just built.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>