A job the runner kills never runs its own cleanup trap, and the
platform's CI leaked a whole migration stack that way. The harness
follows the platform's three-layer rule:
- everything it starts is named and labeled as a CI stack;
- it cleans up in a trap;
- the template workflow sweeps stale CI stacks before running it, and
removes its own in a final if: always() step.
The sweep ships in the harness image.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signage reached production with three defects that appear only inside
Ekklesia in a real browser, and no CI that ran it there. The ADR
proposes:
- a versioned harness image, ekklesia-module-harness:<platform version>,
built and pushed by the platform's release CI;
- what the harness does: assemble a module into that platform, validate
and build it, migrate a disposable database, start the split reference
deployment, and mount every declared UI surface in headless Chromium;
- what fails it: console errors, unexpected 4xx/5xx, unhandled
rejections, a display soak, and generic no-dead-ends injections;
- testing at the lowest and newest platform versions of a module's
range;
- extra smoke steps in ekklesia.harness.json, beside the manifest
rather than in it;
- a later data-access and egress check against declarations;
- a short template workflow that calls the harness by digest with one
`docker run`. Not a reusable workflow: thinly supported on Gitea
1.24, and private sources only arrive in 1.26.
Co-Authored-By: Claude Opus 5.5 <[email protected]>