Public: anyone can read this; the crew can change it.
Sleep windows follow the slider: the runtime reads its idle windows from the position, live #10186
Check · Review · Land · Live done — Landed and live in production.
Moving the profit slider now changes when apps go to sleep, starting with the next sweep (once a minute) and with no restart. Setting `app.always_on: true` in an app's `forge.json` keeps its production awake at any slider position.
shipped production is serving it deploy a5a2512
Moving the profit slider now changes when apps go to sleep, starting with the next sweep (once a minute) and with no restart. Setting app.always_on: true in an app's forge.json keeps its production awake at any slider position.
- Sweep (
src/apps/runtime.ts,src/apps/sleep_window.ts): each pass reads the slider position and picks each environment's idle window from it.
- Previews of quiet pulls follow the slider too: 1 day at 0, 3 days at 50, never at 100. FORGE_PREVIEW_IDLE_DAYS, when set, still fixes that age (src/main.ts).
- At the default position of 50, nothing changes.
- Test hooks: the runtime's
sleepAfterMsoption still fixes the window when set; the forge itself never sets it. A newclockoption lets a test move the sweep's time forward. - Log line: names the window and the position, e.g.
asleep: nothing asked for it in 10 min (economy 0); the next request wakes it. This is "10 min", the slider's own short form, where the issue's example said "10 minutes". always_on: the issue saysapp.yaml, but apps here declare themselves inforge.json, so the field isapp.always_on.
- Only true or false is accepted; any other value fails the deploy with a reason.
- It applies to production only; previews still follow the slider.
- When it is set, the app page says it never sleeps whatever the slider says.
- Docs:
docs/APPS.mdcovers the windows,always_onand theFORGE_PREVIEW_IDLE_DAYSdefault.
Not done: a line on the app page saying how long production has until it sleeps at the current position. Only the always_on exception is shown.
Why the earlier pull was parked: its last check (#10181) never reached an assertion. Shard 3 was killed after 49 s while running test/web-refs-links.test.ts, with the runner at 16% free disk. That file passes on this branch. This push merges current main into the branch; apart from that merge, nothing changed since #10181.
Tests
test/apps-sleep-slider.test.tsruns a real app:
- At 100, an app idle for 11 minutes stays up.
- Moved to 0, the next sweep puts it to sleep and the log has the new line.
- After a push that sets always_on, it stays up at 0 and its status says so.
test/sleep-window.test.tscovers the windows at 0, 50 and 100,always_onwinning over 0, the log wording, theforge.jsoncheck on the field, and the app-page line.scripts/gate.ts,tsc --noEmitanddesign-lintare clean.- These test files pass here:
sleep-window,apps-sleep-slider,web-refs-links,apps-sleep,apps-idle,apps-busy,slider,idle-pulls-boundandflow-idle-pulls. - No existing test was changed.
To try it: set the slider to 0 on the economics page and leave an app's production alone for 10 minutes. It goes to sleep and its deploy log names the window. Then add "always_on": true under app in its forge.json and push; it stays up.
🤖 Generated with Claude Code
The sweep logic is sound and well tested: windows read from the slider each pass, always_on is production-only, and the log line names window and position. Two doors-and-docs misses, so changes requested.
- Terminal door missing. The page now says production is always on, but the terminal's deploys screen (src/tui/screens/deploys.ts, near the production state at line ~156) shows nothing. Add the same fact there, in plain words, from the same EnvStatus.alwaysOn.
- No how-to. Add the always_on / slider-driven windows to docs/features/forge-sleep.md (it exists and does not mention either). docs/APPS.md carries reference only.
- Design: the new app-page line is a bare muted paragraph in prose that explains itself twice (principle 1, 7). Make it one fact row in the env's dl: 'Sleeps: never (app.always_on)'. Principle 8: say 'it never sleeps' without 'whatever the profit slider says'.
- The main.ts change drops the unconditional 3-day idle pull default; confirm in a test that FORGE_PREVIEW_IDLE_DAYS unset reaches the slider and set pins it (nothing covers main.ts wiring or idlePullAge).
First fix: the terminal line (1).
Sweep reads policyAt(position) each pass; always_on is production-only and wins over 0; log line names window and position; busy grace untouched. Terminal deploys screen, forge-sleep.md how-to, and a dl fact row are all in; README untouched. Tests cover 0/100, moving the position between sweeps, always_on over 0, and FORGE_PREVIEW_IDLE_DAYS unset vs set. Nits, not blocking: the fact row uses .row-facts (documented for rows) outside a row; the log says "10 min" not "10 minutes" (disclosed).
Moving the profit slider now changes when apps go to sleep, starting with the next sweep (once a minute) and with no restart. Setting
app.always_on: truein an app'sforge.jsonkeeps its production awake at any slider position.src/apps/runtime.ts,src/apps/sleep_window.ts): each pass reads the slider position and picks each environment's idle window from it.- Previews of quiet pulls follow the slider too: 1 day at 0, 3 days at 50, never at 100.
FORGE_PREVIEW_IDLE_DAYS, when set, still fixes that age (src/main.ts). - At the default position of 50, nothing changes.sleepAfterMsoption still fixes the window when set; the forge itself never sets it. A newclockoption lets a test move the sweep's time forward.asleep: nothing asked for it in 10 min (economy 0); the next request wakes it. This is "10 min", the slider's own short form, where the issue's example said "10 minutes".always_on: the issue saysapp.yaml, but apps here declare themselves inforge.json, so the field isapp.always_on.- Only
trueorfalseis accepted; any other value fails the deploy with a reason. - It applies to production only; previews still follow the slider. - When it is set, the app page says it never sleeps whatever the slider says.docs/APPS.mdcovers the windows,always_onand theFORGE_PREVIEW_IDLE_DAYSdefault.Not done: a line on the app page saying how long production has until it sleeps at the current position. Only the
always_onexception is shown.Why the earlier pull was parked: its last check (#10181) never reached an assertion. Shard 3 was killed after 49 s while running
test/web-refs-links.test.ts, with the runner at 16% free disk. That file passes on this branch. This push merges current main into the branch; apart from that merge, nothing changed since #10181.Tests
test/apps-sleep-slider.test.tsruns a real app:- At 100, an app idle for 11 minutes stays up. - Moved to 0, the next sweep puts it to sleep and the log has the new line. - After a push that sets
always_on, it stays up at 0 and its status says so.test/sleep-window.test.tscovers the windows at 0, 50 and 100,always_onwinning over 0, the log wording, theforge.jsoncheck on the field, and the app-page line.scripts/gate.ts,tsc --noEmitanddesign-lintare clean.sleep-window,apps-sleep-slider,web-refs-links,apps-sleep,apps-idle,apps-busy,slider,idle-pulls-boundandflow-idle-pulls.To try it: set the slider to 0 on the economics page and leave an app's production alone for 10 minutes. It goes to sleep and its deploy log names the window. Then add
"always_on": trueunderappin itsforge.jsonand push; it stays up.🤖 Generated with Claude Code
Closes #506