The platform leaked a whole CI stack for two days: a job the runner
kills never runs its cleanup trap. The platform's rule now applies here:
the job that starts Docker stacks (integration) has its own
EKKLESIA_CI_JOB_KEY, sweeps stale CI stacks first, removes its own in a
final if: always() step, and labels the image it builds.
ci/check-cleanup.sh checks that, and the lint job runs it. It fails
today on all five counts.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signage had no CI. Its tests passed while three defects shipped that
appear only inside Ekklesia, in a real browser. Every job now assembles
Signage into a pinned platform commit, as an instance does, and
installs that workspace with --frozen-lockfile:
- lint, typecheck, test: Signage's own checks;
- build: the platform's gates against exactly this module set (boundary
rules, module manifest, migrations), then the build;
- integration: the deployment image from the platform's Dockerfile,
then the platform's split-topology smoke. It pairs a kiosk display,
restarts it on the same profile, and runs the scenarios in
ci/display-scenarios.
The supporting files:
- ci/platform.env pins one platform commit. ci/assemble.sh fetches the
platform's main and refuses a pinned commit that is not on it, so CI
only runs reviewed platform code.
- ci/pnpm-lock.yaml is the assembled workspace's lockfile, regenerated
with ci/update-lock.sh.
Same trust rules as the platform: actions pinned by SHA,
persist-credentials false, no secrets, no pull_request_target.
Co-Authored-By: Claude Opus 5.5 <[email protected]>