Skip to content

diag(cloud-agent-next): quiet control workload stats and attribute memory on restart - #7249

Merged
eshurakov merged 3 commits into
mainfrom
kilo/young-willow-xg9
Oct 8, 2026
Merged

eshurakov merged 3 commits into
mainfrom
kilo/young-willow-xg9

Conversation

@eshurakov

@eshurakov eshurakov commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Three related changes to control-workload diagnostics.

1. Sample stats off the containment sweep

WORKLOAD_SWEEP_INTERVAL_MS = 1000 drives sweepManaged once per second and every sweep emitted a control.workload / workloadPhase=stats record. The reporter dedups by value, but the record carries monotonic cumulative counters and a fluctuating memory.current, so under load it emitted ~1 record/sec/scope and drowned lifecycle, lease, and shutdown records.

The 1s sweep still migrates new server/tool PIDs into their cgroups (enforcement). Stats now sample every WORKLOAD_STATS_INTERVAL_MS (30s), and sooner on an actionable change (a new cpu throttle, memory.events max/oom count, or the first crossing of 90% of the group cap) bounded by WORKLOAD_STATS_EVENT_COOLDOWN_MS (10s) so monotonic counters cannot re-emit on every sweep. The pressure signal latches at 90% and releases only below 80% (hysteresis). OOM and migration events keep their immediate emissions.

2. Attribute memory and name OOM restarts

  • readWorkloadStats reads the memory.stat anon/file/shmem split and reports pressureAvailable, confirming whether the kernel exposes memory.pressure (PSI). Without PSI, triage falls back to memory.events and memory.stat.
  • The control.workload stats record adds anonBytes/fileBytes/shmemBytes and toolCurrentBytes/toolPeakBytes and serverCurrentBytes/serverPeakBytes, so a full headroom is traceable to the tools subgroup vs the Kilo server and to page cache (file, e.g. Docker storage I/O) vs process memory (anon).
  • createOwnedProcessScope publishes a per-scope WorkloadSnapshot on every sweep (not just the 30s cadence), and each runtime reads its own scope, so a restart is never attributed to a sibling runtime's memory.
  • A health_probe_false restart attaches the latest snapshot under the restarting log line's workload key.
  • When that snapshot is at 95% of the cap, the turn fails with the closed reason sandbox_out_of_memory instead of agent_restarted, so run-state classification stays wrapper_disconnected rather than regressing to unclassified. The callback message is "The sandbox ran out of memory"; the numeric current/cap detail remains in the diagnostic snapshot and stats record.

3. Docs

DEBUG.md states the 30s/10s cadences, the 90%/95%/80% fractions, the new memory fields, and the sandbox_out_of_memory reason.

Verification

  • pnpm -C wrapper run typecheck and pnpm run typecheck (service) — clean
  • oxlint and oxfmt — clean
  • bun test src/control src/control-plane — green apart from the pre-existing control-plane/main-cert-refusal.test.ts process test that fails in this sandbox (spawned child never exits; untouched here)
  • vitest run src/telemetry src/shared src/control-plane/session — green
  • Added coverage for the memory.stat split, absent PSI, event cooldown, pressure hysteresis, the cap reason, the restart-diagnostic snapshot, the turn outcome reason, and the failure classification.

@kilo-code-bot

kilo-code-bot Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up commit resolves every previously reported workload-diagnostics finding, and the new cooldown/hysteresis, per-scope snapshot attribution, and closed sandbox_out_of_memory reason are internally consistent with their tests and docs.

Files Reviewed (13 files)
  • services/cloud-agent-next/DEBUG.md
  • services/cloud-agent-next/src/control-plane/session/callbacks.ts
  • services/cloud-agent-next/src/shared/control-diagnostics.ts
  • services/cloud-agent-next/src/shared/control-plane-protocol.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.test.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-health-diagnostic.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.ts
  • services/cloud-agent-next/wrapper/src/control/owned-processes.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts
Previous Review Summaries (3 snapshots, latest commit b600ea7)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit b600ea7)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts 207 Immediate-emission triggers (throttle_increase / memory_events / memory_pressure) bypass WORKLOAD_STATS_INTERVAL_MS with no cooldown, so a scope under sustained pressure can re-emit once per 1s sweep. (carried forward)
services/cloud-agent-next/wrapper/src/control-plane/main.ts 238 The workload snapshot is wrapper-global; a restart can be attributed to another runtime's memory, and per-scope currentBytes is compared against the shared aggregateMaxBytes.
services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts 830 outcomeReason is derived for every non-credentials restart without an OOM signal, disagreeing with the health-only workload diagnostic gate.
services/cloud-agent-next/wrapper/src/control-plane/turn.ts 1171 The free-form OOM reason is outside the closed failure-reason set, so run-state classification regresses from wrapper_disconnected to unclassified.

SUGGESTION

File Line Issue
services/cloud-agent-next/DEBUG.md 183 Doc says the OOM reason fires at the group cap, but the code emits it at 95% of aggregateMaxBytes.
Files Reviewed (10 files)
  • services/cloud-agent-next/DEBUG.md - 1 suggestion
  • services/cloud-agent-next/src/shared/control-diagnostics.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-health-diagnostic.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control-plane/main.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control-plane/turn.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/turn.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control/owned-processes.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts - 1 warning (carried forward)

Fix these issues in Kilo Cloud

Previous review (commit b352f96)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts 207 Immediate-emission triggers (throttle_increase / memory_events / memory_pressure) bypass WORKLOAD_STATS_INTERVAL_MS with no cooldown, so a scope under sustained pressure can re-emit once per 1s sweep. (carried forward)
services/cloud-agent-next/wrapper/src/control-plane/main.ts 238 The workload snapshot is wrapper-global; a restart can be attributed to another runtime's memory, and per-scope currentBytes is compared against the shared aggregateMaxBytes.
services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts 830 outcomeReason is derived for every non-credentials restart without an OOM signal, disagreeing with the health-only workload diagnostic gate.
services/cloud-agent-next/wrapper/src/control-plane/turn.ts 1171 The free-form OOM reason is outside the closed failure-reason set, so run-state classification regresses from wrapper_disconnected to unclassified.

SUGGESTION

File Line Issue
services/cloud-agent-next/DEBUG.md 183 Doc says the OOM reason fires at the group cap, but the code emits it at 95% of aggregateMaxBytes.
Files Reviewed (10 files)
  • services/cloud-agent-next/DEBUG.md - 1 suggestion
  • services/cloud-agent-next/src/shared/control-diagnostics.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-health-diagnostic.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control-plane/main.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control-plane/turn.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control-plane/turn.ts - 1 warning
  • services/cloud-agent-next/wrapper/src/control/owned-processes.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts - 1 warning (carried forward)

Fix these issues in Kilo Cloud

Previous review (commit c573dff)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The workload-stats emission state machine is correct and unit-tested, but its immediate-emission triggers have no cooldown, so a scope under sustained CPU/memory pressure can still emit a stats record once per 1s sweep.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts 154 throttle_increase / memory_events / memory_pressure bypass WORKLOAD_STATS_INTERVAL_MS with no cooldown; sustained counter increases can re-emit once per sweep, partially reintroducing the flood this PR removes.
Files Reviewed (4 files)
  • services/cloud-agent-next/DEBUG.md - 0 issues
  • services/cloud-agent-next/wrapper/src/control/owned-processes.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 123.5K · Output: 27.7K · Cached: 2.5M

Review guidance: REVIEW.md from base branch main

@eshurakov eshurakov changed the title diag(cloud-agent-next): sample control workload stats off the containment sweep diag(cloud-agent-next): quiet control workload stats and attribute memory on restart Oct 7, 2026
Comment thread services/cloud-agent-next/DEBUG.md Resolved
…ment sweep

The one-second cgroup sweep emitted a `control.workload` stats record on almost
every tick because its values include monotonic cpu/io counters and fluctuating
`memory.current`. Under any real load that is ~1 record per second per scope,
flooding the diagnostic upload buffer and Axiom.

Split the two jobs the sweep was doing. The sweep still runs every second to
migrate new server/tool processes into their cgroups, where the short cadence is
enforcement. Stats now sample every `WORKLOAD_STATS_INTERVAL_MS` (30s) and emit
immediately when an actionable counter changes: a new cpu throttle, a new
`memory.events` max/oom count, or the first crossing of 90% of the group memory
cap. OOM and migration events keep their existing immediate emissions.

Verification: wrapper typecheck and oxlint clean; `bun test src/control` passes.
Added `decideWorkloadStatsEmission` unit coverage for the cadence gate and each
immediate trigger.
A health-probe restart only said `agent_restarted`, and the workload stats
recorded the parent scope alone, so triage could not tell whether Kilo grew or
tools plus page cache filled the shared headroom.

Stats and snapshot:
- `readWorkloadStats` now reads the `memory.stat` anon/file/shmem split and
  reports `pressureAvailable`, confirming whether the kernel exposes
  `memory.pressure` (PSI). Without PSI, triage falls back to `memory.events`
  and `memory.stat`.
- The `control.workload` stats record adds `anonBytes`/`fileBytes`/`shmemBytes`
  and `toolCurrentBytes`/`toolPeakBytes` and
  `serverCurrentBytes`/`serverPeakBytes`, so a full headroom is traceable to
  the tools subgroup or the Kilo server and to page cache versus process
  memory.
- `createOwnedProcessScope` publishes a `WorkloadSnapshot` on every sweep, not
  only on the 30s stats cadence, so a restart decision sees the current state.

Restart attribution:
- A `health_probe_false` restart attaches the latest snapshot under the
  restarting log line's `workload` key.
- When the snapshot is at the cap, the turn fails with
  `sandbox out of memory: <current>/<cap> GiB` instead of `agent_restarted`,
  so triage can classify it as the user's workload.

Verification: wrapper and service typecheck clean; oxlint and oxfmt clean;
`bun test src/control src/control-plane` green apart from the pre-existing
sandbox cert-refusal process test; added coverage for the memory.stat split,
absent PSI, the cap reason, the restart diagnostic snapshot, and the turn
outcome reason.
…art attribution

Address review on the workload diagnostics.

- Event-driven stats (throttle/memory-event increases, first pressure crossing)
  now share `WORKLOAD_STATS_EVENT_COOLDOWN_MS` (10s), and the pressure signal
  releases only below 80% (hysteresis). A scope parked at its limit can no
  longer re-emit on every one-second sweep, matching the PR's own goal.
- The restart snapshot now comes from the runtime's own process scope rather
  than a wrapper-global sink, so a restart is not attributed to a sibling
  runtime's memory. The snapshot is still compared against the shared parent
  cap, which is the only aggregate limit available.
- The sandbox-out-of-memory outcome is now the closed reason
  `sandbox_out_of_memory` instead of a free-form string, gated to health-probe
  restarts and mapped in the failure classifier and callback message table, so
  run-state classification stays `wrapper_disconnected` instead of regressing
  to `unclassified`. The native `session_outcome` diagnostic keeps it too.
- DEBUG.md states the 95% at-cap fraction, the 10s event cooldown, and the
  pressure release fraction.

Verification: wrapper and service typecheck clean; oxlint and oxfmt clean;
`bun test src/control src/control-plane` green apart from the pre-existing
sandbox cert-refusal process test; `vitest run src/telemetry src/shared
src/control-plane/session` green. Updated the cadence, hysteresis, cap, health
diagnostic, outcome, and classification tests.
@eshurakov
eshurakov force-pushed the kilo/young-willow-xg9 branch from b600ea7 to 5272bcc Compare October 8, 2026 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants