apps/fountain/test/fountain_web/live/secret_forms_live_test.exs:188 fails intermittently, most recently in a merge queue build where it ejected an unrelated PR (#1872, the sandbox capacity queue, which touches nothing in vaults or secrets).
The failing assertion
test "add_secret records an optional expiry date and renders its status"
test/fountain_web/live/secret_forms_live_test.exs:188
assert html =~ "expires in 3d"
right: "expires in 3d"
left: "<div class=..." # the rendered page, without that label
How often, out of what
One merge-queue build of six for #1872 so far. Run: https://github.com/managoat/fountain/actions/runs/34595416749 (partition 2, 2026-09-11 11:47 UTC). The two earlier #1872 queue failures were a different, real problem (an interaction with #1840) and are fixed; this one is not that.
The mechanism
FountainWeb.VaultsLive.Form.expiry_status/1 renders the label only inside its notice window:
days = Date.diff(DateTime.to_date(expires_at), Date.utc_today())
cond do
...
days <= SecretExpirySweeper.notice_days() -> {:expiring, "expires in #{days}d"}
true -> {:ok, "expires #{DateTime.to_date(expires_at)}"}
end
SecretExpirySweeper.notice_days/0 is Application.get_env(:fountain, :secret_expiry_notice_days, 7) — global.
apps/fountain/test/fountain/workers/secret_expiry_sweeper_test.exs is use Fountain.DataCase, async: true and at line 120 does:
Application.put_env(:fountain, :secret_expiry_notice_days, 0)
While that write is held, 3 <= 0 is false for every concurrent test, so the label falls to the true -> branch and the assertion fails. Nothing is wrong with either test in isolation; they only have to overlap. Note the date arithmetic is Date.diff on dates, so this is not a time-of-day boundary — it is the global write.
Why the guardrail did not catch it
apps/fountain/test/fountain/async_global_config_guardrail_test.exs exists for exactly this class and allowlists this file:
# :secret_expiry_notice_days — read only by the sweeper under test.
"apps/fountain/test/fountain/workers/secret_expiry_sweeper_test.exs",
That justification is no longer true: the key is also read by expiry_status/1 on every vault form render, and secret_forms_live_test.exs asserts on the result. The guardrail's own docstring gives the fix: "The allowlist is not a blessing... Moving one into an async: false module is always correct, and is what to do the moment one of them is suspected in a flake."
Suggested fix
Move the put_env portion of secret_expiry_sweeper_test.exs into a sibling async: false module and delete its allowlist entry, the way quotas_test.exs and user_emails_test.exs were handled. Worth re-reading the other allowlist entries with the same question — each says "read only by X", and this one shows how that goes stale when a reader is added later.
Filed rather than fixed in place because it surfaced mid-burndown of the approved PR stacks, per CLAUDE.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_016nLzDCqKwgQfuW1V5gVik4
apps/fountain/test/fountain_web/live/secret_forms_live_test.exs:188fails intermittently, most recently in a merge queue build where it ejected an unrelated PR (#1872, the sandbox capacity queue, which touches nothing in vaults or secrets).The failing assertion
How often, out of what
One merge-queue build of six for #1872 so far. Run: https://github.com/managoat/fountain/actions/runs/34595416749 (partition 2, 2026-09-11 11:47 UTC). The two earlier #1872 queue failures were a different, real problem (an interaction with #1840) and are fixed; this one is not that.
The mechanism
FountainWeb.VaultsLive.Form.expiry_status/1renders the label only inside its notice window:SecretExpirySweeper.notice_days/0isApplication.get_env(:fountain, :secret_expiry_notice_days, 7)— global.apps/fountain/test/fountain/workers/secret_expiry_sweeper_test.exsisuse Fountain.DataCase, async: trueand at line 120 does:While that write is held,
3 <= 0is false for every concurrent test, so the label falls to thetrue ->branch and the assertion fails. Nothing is wrong with either test in isolation; they only have to overlap. Note the date arithmetic isDate.diffon dates, so this is not a time-of-day boundary — it is the global write.Why the guardrail did not catch it
apps/fountain/test/fountain/async_global_config_guardrail_test.exsexists for exactly this class and allowlists this file:That justification is no longer true: the key is also read by
expiry_status/1on every vault form render, andsecret_forms_live_test.exsasserts on the result. The guardrail's own docstring gives the fix: "The allowlist is not a blessing... Moving one into anasync: falsemodule is always correct, and is what to do the moment one of them is suspected in a flake."Suggested fix
Move the
put_envportion ofsecret_expiry_sweeper_test.exsinto a siblingasync: falsemodule and delete its allowlist entry, the wayquotas_test.exsanduser_emails_test.exswere handled. Worth re-reading the other allowlist entries with the same question — each says "read only by X", and this one shows how that goes stale when a reader is added later.Filed rather than fixed in place because it surfaced mid-burndown of the approved PR stacks, per CLAUDE.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_016nLzDCqKwgQfuW1V5gVik4