Skip to content
Go to console
Go to console

A deploy freeze holds every deploy until it ends, and nothing passes it

Decision record 0115

Amends 0104 (a record with window may wait for the end of a freeze as well as for a window, and the freeze line joins the lines under the scan line), 0095 (a deploy on merge waits for a freeze too), 0109 (an outside record is left alone during a freeze) and 0114 (the freeze line sits above every section, with the scan line, and no layout key moves or hides it). Built as slice 5.52, from issue 280.

Record 0104 left a freeze with an end date for later: a repo could freeze only by writing windows that leave the period out and changing the file back after. The owner decided on 2026-09-25 that deploy freezes are part of the free action (issue 280). A freeze is what a sale, a release week or the end of the year asks for: a period, with a start and an end on the calendar, when nothing goes out, whatever the weekly windows say.

Decision

  • freezes names periods when nothing goes out, in the dashboard zone. Each is { from, to, reason }: from and to are YYYY-MM-DDTHH:MM on the wall of dashboard.timeZone (0089), with no zone and no seconds, on a day the calendar has, and to after from. The start is inside the freeze and the end is outside it, as for a window. reason is optional text. Empty, the default, freezes nothing, and a repo without the key is byte for byte what it was. The loader refuses a start or an end that is not one, a day the calendar lacks, and an end that is not after the start.
  • A freeze belongs to the repo, not to a stack. There is no stacks[].freezes, and stacks[].deployWindows: [], which lifts the windows of its stacks, does not lift a freeze. That is what “nothing passes a freeze” means.
  • A tick during a freeze waits, exactly as a tick outside a window does (0104). It is judged now, by the tick rule, the dependencies and the cap. Its record is opened now with what the tick approved, carries window: true, is not handed on, and is started by the first resolve that no issue edit started, the scheduled or dispatched one, once the stack may go, through the fresh preview and the hash check. A ticked destroy, a drift repair, each stack a confirm box names, a deploy on merge (0095) and the deploy after a merge from the dashboard (0054) all wait the same way. A destroy on a stack set to on-merge still waits for a tick.
  • The payload key stays window. It already means “a queued record that waits for a time and not for a stack”, and the time is read from the config of the moment, never from the record (0104). A second key would say something the run reads live anyway, and a reader of the published shape (0096) would have to learn it for no decision it could make. So the published shape does not change; the key’s description says it covers a freeze.
  • A freeze and a window together: the stack goes at the first moment both allow. From now, the rule steps forward: past the end of every freeze that holds, then to the next opening of a window, until an instant falls outside every freeze and inside a window. A freeze that ends at midnight before a Tuesday, on a stack whose window opens at 09:00, goes at 09:00. Freezes that overlap hold until the last of them ends, and the row names the one that ends last.
  • The row names the freeze. A waiting row says queued for the end of the deploy freeze (Year-end freeze) at 2027-01-05 00:00 UTC+1 · ticked by alice, and with a window after the freeze adds , and then for the deploy window, which opens 2027-01-05 09:00 UTC+1. A row behind a stack says queued behind **network:prod**, and for the end of the deploy freeze .... The reason is plain text (0112). A row whose stack has no window and that nothing holds any more says queued for the next scheduled run, which starts it: nothing holds it now, where a row of a stack with a window says the window is open, as before.
  • The dashboard names each freeze once, under the scan line, while it holds and for the seven days before it starts: Deploy freeze until 2027-01-05 00:00 UTC+1 (Year-end freeze): every deploy waits for it to end., or Deploy freeze from ... until ...: every deploy waits while it holds. for one to come. Each freeze is one line, in the order they start. It comes after the scan-running line and the waiting-run line (0108, 0086), which come and go, so those stay right under the scan line. It is part of the block above every section, with the counts line and the scan line (0114): no layout key moves or hides it. Every writer draws it from the config and its own clock, through the one function that fits a body, so a swap by resolve, apply or settle never drops it. It is no marker and decides nothing.
  • An outside record is left alone during a freeze (0109), with a line in the job log, and ends as a record nobody handed on does. A window does not hold an outside record, and that stays: the writer chose the moment. A freeze is the repo saying no moment is right.
  • settle starts the next layer only when the stack may go, and the scheduled run after the freeze starts it.
  • The check warns about a freeze that already ended. It holds nothing, and the warning names it by its place in the list, its reason and its end in the zone, and says to take it out. It is a warning and the setup stays valid.

Considered

  • A payload key freeze. Rejected above: the record would carry a fact the run reads live anyway.
  • Letting a destroy or a stack’s deployWindows: [] through. The issue says nothing passes a freeze. A person who needs a deploy during a freeze ends it early in a reviewed change, and what waited goes with the next run.
  • Holding a deploy in apply when a freeze started after resolve handed it on. A window does not do that either (0104): the rule is judged where a deploy is started. In the one-step workflow the two are seconds apart. In the split workflow a deploy waiting for an environment’s reviewers across the start of a freeze still goes when they approve, and the reviewers see the freeze line on the dashboard. A check in apply would need its own refusal and its own record ending, and is left for when someone asks.
  • One line for all the freezes. Two freezes in one week are rare, and one line per freeze keeps each start, end and reason readable.
  • A reason required. A freeze with no reason still holds; the row and the line then name none. Most repos will write one, and the docs show it.
  • Showing a freeze earlier than a week ahead. A line that sits on the page for months is read past. A week is when people plan the deploys a freeze would hold.
  • A date alone for from and to. 2026-12-20 as a start is clear, as an end it is not (the start of that day, or its end?). One spelling with the time keeps both ends exact.

Consequences

  • A freeze-only repo’s scheduled and dispatched resolve reads the deployment records as a repo with windows does, and a resolve also starts a record that waited for a window or a freeze the repo has since taken out of the file.
  • CONTEXT.md gains Deploy freeze, and the deploy window, the queued stack and the scan line say what changed.
  • docs/later.md loses the line for a freeze with an end date. Break-glass stays there.