What
There is no hook phase that runs before containers start and can abort the deploy. post_sync_hooks run after sync and after start, and a non-zero action: exec is logged at level: warn ("Some post-sync hooks failed") while the reconcile still reports success: true.
Why it matters
The homelab repo uses a post-sync exec hook as an unresolved-template gate: it greps the rendered tree for Go's [<]no value sentinel, which a mistyped SOPS leaf key produces silently (text/template emits it and exits 0).
The comment on that hook read "it has to be a gate that runs before anything starts" — a property the mechanism does not have. It cannot block. By the time it runs, the containers are up and consuming the sentinel as a config value.
For some services that is unrecoverable rather than merely wrong. chronicle-db's POSTGRES_PASSWORD is consumed by initdb on first start and PGDATA persists — so the superuser password becomes the fixed, publicly-known string [<]no value permanently, and nothing downstream disagrees because the same expression feeds both the server and its backup.
Observed in that repo: the hook exited 1 on every real deploy from 2026-08-02 to 2026-08-05 and every one of those deploys completed and reported success.
Proposal
A pre_deploy_hooks (or pre_start_hooks) phase that runs after render/sync but before compose up, where a non-zero exit aborts the target's reconcile rather than warning.
Alternatively (or additionally): a per-hook required: true flag on post_sync_hooks that promotes a non-zero exit from warn to a failed reconcile. That is a smaller change and would at least make the failure loud and machine-visible, though it still cannot prevent the start.
Related
Adjacent to #392 (health gate false-fails skip ALL post-sync hooks) — same area, opposite direction: that one is hooks not running when they should, this one is hooks running but being unable to matter.
What
There is no hook phase that runs before containers start and can abort the deploy.
post_sync_hooksrun after sync and after start, and a non-zeroaction: execis logged atlevel: warn("Some post-sync hooks failed") while the reconcile still reportssuccess: true.Why it matters
The homelab repo uses a post-sync
exechook as an unresolved-template gate: it greps the rendered tree for Go's[<]no valuesentinel, which a mistyped SOPS leaf key produces silently (text/template emits it and exits 0).The comment on that hook read "it has to be a gate that runs before anything starts" — a property the mechanism does not have. It cannot block. By the time it runs, the containers are up and consuming the sentinel as a config value.
For some services that is unrecoverable rather than merely wrong.
chronicle-db'sPOSTGRES_PASSWORDis consumed byinitdbon first start andPGDATApersists — so the superuser password becomes the fixed, publicly-known string[<]no valuepermanently, and nothing downstream disagrees because the same expression feeds both the server and its backup.Observed in that repo: the hook exited 1 on every real deploy from 2026-08-02 to 2026-08-05 and every one of those deploys completed and reported success.
Proposal
A
pre_deploy_hooks(orpre_start_hooks) phase that runs after render/sync but beforecompose up, where a non-zero exit aborts the target's reconcile rather than warning.Alternatively (or additionally): a per-hook
required: trueflag onpost_sync_hooksthat promotes a non-zero exit fromwarnto a failed reconcile. That is a smaller change and would at least make the failure loud and machine-visible, though it still cannot prevent the start.Related
Adjacent to #392 (health gate false-fails skip ALL post-sync hooks) — same area, opposite direction: that one is hooks not running when they should, this one is hooks running but being unable to matter.