Separate measurement from degradation policy
The existing CPU measurement guide explains Game.cpu.getUsed(), limit, tickLimit, and bucket. This guide owns a different intent: what the loop should stop, slow down, or preserve after the measurements show a sustained decline.
An occasional bucket drop is not enough evidence by itself. Pathfinding, a global reset, the first Memory parse, combat, or a larger visible object set can make individual ticks expensive. The production risk is a persistent decline while market scans, path rebuilds, statistics, and RoomVisual work continue at their normal cadence.
Use four operating modes
| Mode | Purpose | Default policy |
|---|---|---|
NORMAL | Healthy operation | Run planned work |
CONSERVE | Slow the decline | Keep critical work, throttle important work, heavily throttle optional work |
EMERGENCY | Preserve room survival | Keep critical work, run important work rarely, disable optional work |
RECOVERY | Verify that recovery is stable | Restore important work first and delay optional work |
RECOVERY prevents every expensive subsystem from restarting on the first healthy-looking tick. Without a recovery stage, one market scan, path rebuild, and visual pass can create a second spike immediately.
Protect critical tasks first
Typical critical work includes emergency Spawn recovery, normal Spawn ownership, core harvesting and hauling, hostile detection, Tower defense, and Controller downgrade protection. These tasks must not be wrapped in a high-bucket condition.
Important work may run less often: non-emergency construction, Link or Lab coordination, remote-room refreshes, and ordinary maintenance. Optional work can stop in emergency mode: broad market scans, bulk path precomputation, detailed RoomVisual output, and reports that do not affect the current tick.
The tier is a local business decision. During combat, remote intelligence that is normally optional may need to become critical.
Prevent threshold flapping
A single threshold such as bucket < 5000 will repeatedly disable and enable work near that value. Use different entry and exit thresholds, consecutive-tick confirmation, and a minimum mode duration.
enter CONSERVE below 7000
leave CONSERVE above 8500
confirm degradation for 3 ticks
confirm recovery for 20 ticks
These numbers are local examples, not official recommendations. The official API provides the measurements; your room count, CPU allocation, war state, and task costs determine the policy.
Use a testable transition function
function selectDesiredCpuMode(state, metrics, policy) {
const { bucket, usedRatio } = metrics;
if (!Number.isFinite(bucket) || !Number.isFinite(usedRatio)) {
return { mode: 'EMERGENCY', reason: 'invalid-cpu-metrics', immediate: true };
}
if (bucket <= policy.hardEmergencyBucket || usedRatio >= policy.hardUsedRatio) {
return { mode: 'EMERGENCY', reason: 'hard-cpu-risk', immediate: true };
}
if (bucket <= policy.emergencyBelow) {
return { mode: 'EMERGENCY', reason: 'bucket-emergency', immediate: false };
}
if (state.mode === 'NORMAL') {
return bucket < policy.conserveBelow || usedRatio >= policy.conserveUsedRatio
? { mode: 'CONSERVE', reason: 'conserve-threshold', immediate: false }
: { mode: 'NORMAL', reason: 'healthy', immediate: false };
}
if (state.mode === 'CONSERVE') {
return bucket >= policy.normalAbove && usedRatio <= policy.normalUsedRatio
? { mode: 'NORMAL', reason: 'normal-threshold', immediate: false }
: { mode: 'CONSERVE', reason: 'conserve-hold', immediate: false };
}
if (state.mode === 'EMERGENCY') {
return bucket >= policy.recoveryAbove && usedRatio <= policy.recoveryUsedRatio
? { mode: 'RECOVERY', reason: 'recovery-threshold', immediate: false }
: { mode: 'EMERGENCY', reason: 'emergency-hold', immediate: false };
}
if (bucket < policy.conserveBelow || usedRatio >= policy.conserveUsedRatio) {
return { mode: 'CONSERVE', reason: 'recovery-regressed', immediate: false };
}
return bucket >= policy.normalAbove && usedRatio <= policy.normalUsedRatio
? { mode: 'NORMAL', reason: 'recovery-complete', immediate: false }
: { mode: 'RECOVERY', reason: 'recovery-hold', immediate: false };
}
The full Chinese implementation adds candidate counters, minimum hold time, bounded transition and failure history, stable task offsets, remaining-CPU headroom checks, and a complete integration scaffold.
Malformed task entries are partitioned before sorting. A null entry, missing name, missing callback, or unknown tier cannot throw in the comparator before critical work runs.
Throttle and stagger lower-tier work
Critical work keeps its original cadence in every mode. Important work may move from every tick to every 2 or 10 ticks. Optional work may move to every 20 ticks in conserve mode, stop in emergency mode, and restart only after a recovery warm-up.
Do not schedule every 100-tick task on Game.time % 100 === 0. Derive a stable offset from the task name so market scans, path rebuilding, and statistics do not return on the same tick.
Before starting a noncritical task, compare current getUsed() with tickLimit. This is a start guard, not a prediction of final tick cost. A task can still cost more than expected, so critical work belongs earlier in the loop.
Measure whether degradation helped
Track whether bucket stopped declining, rolling average and peak CPU changed, critical-task failures increased, and modes are switching too often. A recovering bucket does not prove harvesting, spawning, Controller safety, or defense still behaves correctly; CPU evidence and room-behavior evidence are separate.
Record notifications only on real transitions such as NORMAL → CONSERVE or EMERGENCY → RECOVERY. Use the notification guide for rate limiting instead of sending a low-bucket message every tick.
Evidence boundaries
Thirty offline cases passed: hard emergency entry, three-tick degradation confirmation, twenty-tick recovery confirmation, minimum mode duration, candidate reset, recovery regression, task intervals across all four modes, malformed task isolation, and stable critical-first ordering. The complete Chinese scheduler passed JavaScript syntax checking.
Node.js does not reproduce Screeps CPU units. Live Console measurements, official-shard bucket trends, multi-room costs, combat load, private-server settings, and proof that critical room behavior remains healthy are still pending.