What happened
On 05.09.2026 the same root cause shipped to dev twice, and both times the person who found it was Dawid, on his phone, using the product.
- Changing a profile address failed with
Saving failed. Try again.
- Uploading a photo failed with
Something went wrong. Try again.
Both were one mistake: a new CHECK constraint plus an upsert that spelled a now-empty column into its INSERT values. PostgreSQL evaluates constraints on the tuple being inserted before ON CONFLICT turns it into an update, so the constraint fired on writes that never touched the constrained column.
The gate was green for both. The deployment reported healthy for both.
Why nothing caught them
The full journey does not run on a pull request, or on a push to main. e2e-full — register → verify → name → address → photo → public page — runs only on workflow_dispatch and on version tags. Both faults sit squarely on that path. This was raised on 05.09.2026 and deliberately deferred; the deferral is what let both through. Measured cost of running it: 227 seconds.
The unit fixtures describe a world that no longer exists. Every account in profile.test.ts and profile-handle.test.ts is created with a non-empty users.name. Registration stopped filling that field in #36 — so the tests kept proving the old reality, and the new one was untested by construction. A change to a shared assumption made every existing test simultaneously less true and still green.
The deploy proves liveness, not function. remote-deploy.sh waits for the container's HEALTHCHECK, which asks whether the process answers. Neither fault stopped it answering.
One fix, one instance. The first was fixed in setHandle while the comment beside it read "setAvatar does the same". Nothing made the second location visible; nothing checked whether the class was closed rather than the case.
Acceptance criteria
Verification
Why this matters more than the two bugs
Both were cheap to fix and neither destroyed data. What they cost was confidence: two stages of a pipeline passed something a person found in under a minute of ordinary use. A release process that needs the product owner as its last line of defence is not a release process.
Spec: SPEC.md §6 · Size: M · Label: enhancement
What happened
On 05.09.2026 the same root cause shipped to dev twice, and both times the person who found it was Dawid, on his phone, using the product.
Saving failed. Try again.Something went wrong. Try again.Both were one mistake: a new
CHECKconstraint plus an upsert that spelled a now-empty column into its INSERT values. PostgreSQL evaluates constraints on the tuple being inserted beforeON CONFLICTturns it into an update, so the constraint fired on writes that never touched the constrained column.The gate was green for both. The deployment reported healthy for both.
Why nothing caught them
The full journey does not run on a pull request, or on a push to
main.e2e-full— register → verify → name → address → photo → public page — runs only onworkflow_dispatchand on version tags. Both faults sit squarely on that path. This was raised on 05.09.2026 and deliberately deferred; the deferral is what let both through. Measured cost of running it: 227 seconds.The unit fixtures describe a world that no longer exists. Every account in
profile.test.tsandprofile-handle.test.tsis created with a non-emptyusers.name. Registration stopped filling that field in #36 — so the tests kept proving the old reality, and the new one was untested by construction. A change to a shared assumption made every existing test simultaneously less true and still green.The deploy proves liveness, not function.
remote-deploy.shwaits for the container's HEALTHCHECK, which asks whether the process answers. Neither fault stopped it answering.One fix, one instance. The first was fixed in
setHandlewhile the comment beside it read "setAvatar does the same". Nothing made the second location visible; nothing checked whether the class was closed rather than the case.Acceptance criteria
main, not only on demandVerification
Why this matters more than the two bugs
Both were cheap to fix and neither destroyed data. What they cost was confidence: two stages of a pipeline passed something a person found in under a minute of ordinary use. A release process that needs the product owner as its last line of defence is not a release process.
Spec: SPEC.md §6 · Size: M · Label: enhancement