Public: anyone can read this; the crew can change it.

The roll recipe computes whether a surge pod can schedule, and prints the headroom it lacks #1640

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Before a roll, the operator can now check whether a second forge pod fits on the volume's node beside the running one. When it doesn't, the check prints how much more CPU and memory the node would need for a zero-downtime roll. It only reads what `kubectl` printed and never contacts the cluster.

shipped production is serving it deploy 2fa0c24

opened this

Before a roll, the operator can now check whether a second forge pod fits on the volume's node beside the running one. When it doesn't, the check prints how much more CPU and memory the node would need for a zero-downtime roll. It only reads what kubectl printed and never contacts the cluster.

What to look at

  • scripts/roll.ts: the pure module. It counts whole millicores and bytes, rounding up the way the scheduler does.

- Free: the node's allocatable minus the requests of every pod on it that hasn't Succeeded or Failed. A pod's request includes init containers, sidecars and runtime overhead. - Need: the forge pod's CPU request, and the larger of its memory request and its steady memory. - Answer: schedulable (fits on requests alone), fits (also fits once both pods hold their steady memory), and shortfall (the missing headroom, never below zero). - Input that isn't what kubectl prints is refused with a reason.

  • scripts/roll-preflight.ts: the command the recipe runs. It reads node.json, pods.json, --pod ns/name and --steady, then prints the answer (or --json). Exit 0 means it fits, 3 means it doesn't, 2 means bad input.
  • docs/ops/ROLL.md: the roll recipe. It gives the kubectl commands that collect the inputs, runs the check before rolling, and explains the exit codes, the rule and a worked 8 GB example.
  • test/roll.test.ts: fixtures that fit, fit exactly and miss by one byte, schedule on the request but not on steady memory, and fall short on CPU alone; plus refused inputs, the command's exit codes, and a check that the chart still has maxSurge: 1, maxUnavailable: 0. Each number is worked by hand beside it. The file is added to GATE in scripts/gate.ts; bun scripts/flake-hunt.ts admit test/roll.test.ts gave 10/10 green runs in random order under load.

Not done here

  • There are no "standby scripts" in this repository, so the new docs/ops/ROLL.md and roll-preflight serve as the roll recipe.
  • Refusing a dark roll without the owner's yes, reporting the seconds it would be dark, and checking the gitops overlay are left to #1589. Until that lands, the recipe says not to roll on exit 3 and to put the printed answer in front of the owner.
  • The release workflow and the chart are unchanged.

Try it: run bun scripts/roll-preflight.ts --node node.json --pods pods.json --pod forge/<pod> --steady 3712Mi on the output of the commands in docs/ops/ROLL.md. bun x tsc --noEmit is clean, and test/roll.test.ts plus the five cross files (288 tests) pass.

🤖 Generated with Claude Code

Closes #1588

Approved

Approved. This is an operator script and recipe with no page, endpoint or terminal surface, so the security, both-doors and preview items do not apply. It reads local files only, runs no shell, and validates every input before judging. Exit codes 0, 3 and 2 are tested, along with the hand-worked 8 GB case, the exact-fit boundary and the refusal paths. The new test is in the gate, the chart and release workflow are untouched, and there are no new dependencies. Next two: (1) in scripts/roll.ts, say in the report when the forge pod's own steady memory is being compared against free that already excludes it, so an operator does not double-count; (2) have the recipe in docs/ops/ROLL.md pipe kubectl top into --steady, so the steady figure is not typed by hand and gone stale.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs