Skip to content

feat(vpn): adaptive memory monitor for the mobile VPN daemon#550

Merged
garmr-ulfr merged 13 commits into
mainfrom
feature/mobile-memory-monitor
Jul 6, 2026
Merged

feat(vpn): adaptive memory monitor for the mobile VPN daemon#550
garmr-ulfr merged 13 commits into
mainfrom
feature/mobile-memory-monitor

Conversation

@garmr-ulfr

@garmr-ulfr garmr-ulfr commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an adaptive memory monitor for the mobile VPN daemon (vpn/memmon). On iOS the Network Extension runs under a hard per-process jetsam limit (~50 MB); this watches the process footprint and reclaims proactively so the OS doesn't kill the extension. On Android it runs observe-only, since there's no comparable per-process budget to steer against.

How it works

A single serial loop — sample → decide → react — on one goroutine:

  • Sensor — reads the platform footprint plus Go runtime metrics without runtime.ReadMemStats (no stop-the-world). On iOS the cap is dynamic (phys_footprint + os_proc_available_memory); Android/dev use a fixed cap.
  • Decision engine — normalizes to a [0,1] pressure ratio and derives graded levels (Normal / Soft / Hard) with separate enter/exit thresholds for hysteresis, an EWMA-slope cliff predictor, and an adaptive sample cadence (1 s → 500 ms → 100 ms as pressure rises).
  • ExecutorSoft evicts the oldest connections in batches + a rate-limited FreeOSMemory; Hard closes all connections and scavenges immediately; a pre-cliff crash dump with all the memory stats is written preemptively in case it's killed by the jetsam.
  • Admission gate — refuses new connections under sustained high pressure (iOS), using single-flighted footprint reads on the dial path so a burst of dials costs one syscall.

Platform behavior

  • iOS — full reactive stack (admission gate + executor + monitor) against the dynamic jetsam-headroom cap.
  • Android — observe-only (nil executor), a 512 MB display cap, and throttled heartbeat logging.

Field validation (iOS)

Thresholds were calibrated against on-device logs. The NE's resting footprint sits at ~0.8 of its ~50 MB ceiling, so SoftEnter/SoftExit are 0.88/0.80. In the latest run the monitor stays in Normal during casual browsing, enters Soft only under load, recovers to Normal on its own, and never reached Hard or a jetsam kill. Soft eviction + FreeOSMemory demonstrably walked the footprint back down under heavy connection load.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added adaptive memory monitoring with platform-aware sampling and pressure-driven connection management.
    • Added an iOS early admission gate to reject new connections during high memory pressure.
    • Added support for including a memory dump file in issue reports when available.
  • Bug Fixes

    • Improved low-memory handling with automatic recovery as pressure decreases.
    • Updated mobile tunnel behavior to use the new memory-monitoring flow and revised connection reset handling.

Add vpn/memmon, a Normal/Soft/Hard memory-pressure monitor with hysteresis and cliff prediction, plus an admission gate that rejects new connections at the clashServer dial path while pressure is high. Both are wired into the tunnel on mobile only and torn down with it.

Native signals are platform-gated: iOS reads phys_footprint via task_info and jetsam headroom via os_proc_available_memory; Android reads /proc/self/statm RSS; other targets fall back to the Go heap. Crash dumps are written atomically so a jetsam SIGKILL mid-write cannot truncate them.
Active reclamation and admission gating only make sense on iOS, where the
Network Extension is a dedicated process under a real jetsam cap. Android
exposes no queryable per-process memory budget and the OS already protects
the foreground VPN service, so reacting on a synthetic cap only misfires.

- Restrict the admission gate and reclaim executor to iOS; on Android the
  monitor runs observe-only (nil executor, no gate) against a generous
  display-only cap so it logs usage without acting.
- Scope the box high-memory reject rule to iOS to match.
- Add structured logging to the monitor: per-tick DEBUG (throttled to a
  heartbeat while Normal), level-change INFO, and reclaim, crash-dump, and
  admission-gate events.
- Read the Android footprint from /proc/self/status VmRSS instead of
  /proc/self/statm, whose resident field the kernel documents as approximate.
- Drop noisy bypass-proxy trace log.
radiance's slog handler casts any attribute keyed "level" (slog.LevelKey)
to slog.Level, so the "memory tick" log passing a string under that key
panicked on the first tick and crashed the daemon on connect. Rename the
attribute to "pressure_level".
The iOS Network Extension's resting footprint runs at ~0.8 of its
~50 MB jetsam ceiling, which sat above the old SoftEnter (0.75) and
above SoftExit (0.65) — a threshold the process can never reach. The
monitor therefore entered Soft within seconds of connect and never
recovered to Normal, soft-evicting the oldest connections every ~2s
for the entire session without meaningfully reducing the footprint.

Raise SoftEnter to 0.88 and SoftExit to 0.80 so the resting footprint
stays Normal, Soft is reserved for a genuine climb toward the 0.92
Hard line, and SoftExit is reachable so the monitor can recover.

Pin explicit thresholds into the engine-mechanics tests so they assert
hysteresis/dwell/settle/prediction independent of production tuning,
and add a guard that the production defaults keep a resting series in
Normal while still entering Soft on a climb.
Soft eviction and the Hard close-all shared one FreeOSMinInterval gate,
so a Hard reclaim firing within the interval of a soft scavenge skipped
FreeOSMemory — suppressing the forced page release exactly when the
footprint is closest to the cliff. On iOS, Hard can follow Soft within
the window, since escalation is not blocked while the footprint rises.

Route the Hard path through an unconditional freeOSMemoryNow; the
rate-limited path now serves soft eviction only. The decision core
already edge-triggers and hardCooldown-spaces Hard reclaim, so dropping
the executor's floor for it cannot spin FreeOSMemory into a GC spiral.
# Conflicts:
#	common/settings/settings.go
#	internal/paths.go
Throttle the per-tick DEBUG log while pressure is elevated to
elevatedTickLogInterval (5s) instead of one line per sub-second tick,
and demote the per-batch soft-reclaim line from INFO to DEBUG since a
soft episode is already bracketed by the INFO level-change lines.

Level changes, hard reclaim, crash-dump, and admission-gate lines keep
their levels — the noise reduction targets steady-state and soft-episode
volume, not the rare high-signal events.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 81890303-69a9-4f2f-9fa2-4495852411f8

📥 Commits

Reviewing files that changed from the base of the PR and between fffc9b4 and 5dfddab.

📒 Files selected for processing (2)
  • backend/radiance.go
  • vpn/boxoptions.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/radiance.go
  • vpn/boxoptions.go

📝 Walkthrough

Walkthrough

Adds a memory-pressure monitoring pipeline with sampling, decisioning, reclamation, crash dumps, and dial admission control. It wires the system into clash-server and tunnel startup, updates mobile memory-limit handling, and adds related config, env, and issue-report changes.

Changes

Memory monitor and admission control

Layer / File(s) Summary
Core memmon types and sampling
vpn/memmon/types.go, vpn/memmon/config.go, vpn/memmon/reclaimer.go, vpn/memmon/goprobe.go, vpn/memmon/native_*, vpn/memmon/sensor.go, vpn/memmon/monitor.go
Defines the memmon data model, runtime/native memory sampling, and the monitor configuration and loop that produces samples.
Decision engine and monitor loop
vpn/memmon/decision_engine.go, vpn/memmon/decision_engine_test.go, vpn/memmon/monitor_test.go
Implements pressure transitions, prediction, hysteresis, interval selection, and the monitor tick/apply loop with tests.
Reclaimer, executor, and crash dumps
vpn/memmon/executor.go, vpn/memmon/dumpfile.go, vpn/memmon/executor_test.go, vpn/memmon/dumpfile_test.go
Implements connection reclamation, FreeOSMemory gating, and atomic dump-file generation with tests.
Dial admission gate
vpn/memmon/admissiongate.go, vpn/memmon/admissiongate_test.go
Adds pressure-triggered reject latching, burst-dial detection, cached sampling, and gate behavior tests.
Clash server admission and conntrack wiring
vpn/clash.go, vpn/conntrack.go
Adds admission-gate plumbing, reject mode, routed-connection admission tracking, and conntrack record closing helpers.
Tunnel integration and mobile monitor startup
vpn/memmon.go, vpn/tunnel.go, vpn/tunnel_test.go, vpn/boxoptions.go, vpn/memmon_test.go
Starts the monitor from tunnel setup, changes mobile memory-limit handling, adds the iOS reject rule, and updates integration tests.
Settings, env keys, and issue attachments
common/env/env.go, common/settings/settings.go, internal/paths.go, backend/radiance.go, bypass/bypass.go
Adds the memory-limit env key, admission-rejection setting, dump filename constant, conditional dump attachment, and removes bypass fallback trace logging.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Monitor
  participant DecisionEngine
  participant Executor
  participant Reclaimer
  Monitor->>DecisionEngine: Decide(Sample)
  DecisionEngine-->>Monitor: Decision(level, flags, interval)
  Monitor->>Executor: Apply(Decision, now)
  Executor->>Reclaimer: CloseOldest / CloseAllConnections / FreeOSMemory
Loading
sequenceDiagram
  participant Dialer
  participant ClashServer
  participant AdmissionGate
  Dialer->>ClashServer: RoutedConnection/RoutedPacketConnection
  ClashServer->>AdmissionGate: admitConnection / RecordDial(now)
  AdmissionGate-->>ClashServer: setRejectMode(true/false)
  ClashServer-->>Dialer: route connection or reject
Loading

Possibly related PRs

  • getlantern/radiance#541: Also changes vpn/tunnel.go mobile/iOS memory-limit behavior during tunnel initialization.

Suggested reviewers: myleshorton

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an adaptive memory monitor for the mobile VPN daemon.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/mobile-memory-monitor

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new adaptive memory monitoring subsystem (vpn/memmon) and wires it into the mobile VPN tunnel to proactively reclaim resources (and optionally refuse new connections) under iOS jetsam pressure, while running observe-only on Android for visibility.

Changes:

  • Introduces vpn/memmon (sensor + decision engine + executor + admission gate + dump writer) with unit tests.
  • Integrates the monitor into tunnel bring-up, adds iOS-only reject routing rule, and provides tracker-backed connection eviction/close-all paths.
  • Adds a single-slot memory dump file and includes it in issue-report attachments when present.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vpn/tunnel.go Starts the memory monitor on mobile; limits Go memory settings to iOS; replaces mode-switch conntrack close with routed-connection close helper.
vpn/tunnel_test.go Updates memory-limit ordering assertions to use the monitor budget constant.
vpn/memmon/types.go Defines core types (Sample/Decision/Snapshot/levels), pressure ratio helpers, and logging helpers.
vpn/memmon/sensor.go Implements sampling logic combining native footprint/headroom + runtime/metrics Go stats.
vpn/memmon/reclaimer.go Defines the executor-side reclamation interface and connection reference type.
vpn/memmon/native_stub.go Provides a non-iOS/non-Android stub native reader.
vpn/memmon/native_ios.go Adds iOS native sampling via task_info phys_footprint and optional os_proc_available_memory.
vpn/memmon/native_android.go Adds Android native sampling via /proc/self/status VmRSS parsing.
vpn/memmon/monitor.go Implements the single-goroutine sample→decide→apply loop with rate-limited logging.
vpn/memmon/monitor_test.go Tests monitor run-loop ticking and cancellation behavior.
vpn/memmon/goprobe.go Adds alloc-free Go memory sampling via runtime/metrics.
vpn/memmon/executor.go Implements soft eviction, hard close-all, OS memory freeing, dump writing, and admission-gate observation.
vpn/memmon/executor_test.go Verifies batch sizing, hard edge-triggering, and FreeOSMemory rate limiting behavior.
vpn/memmon/dumpfile.go Implements atomic single-slot crash-dump formatting and writing.
vpn/memmon/dumpfile_test.go Tests dump output contents and alloc-free behavior after warmup.
vpn/memmon/decision_engine.go Implements hysteresis/dwell/settle, slope-based prediction, adaptive cadence, and snapshot ring.
vpn/memmon/decision_engine_test.go Exercises thresholds, prediction, dumping, settle semantics, interval selection, and clamp behavior.
vpn/memmon/config.go Adds executor-side tuning defaults (soft batch divisor/cap, FreeOSMemory minimum interval).
vpn/memmon/admissiongate.go Adds the dial-path admission gate with single-flight sampling and burst-trigger arming.
vpn/memmon/admissiongate_test.go Tests arming/disarming, single-flight sampling, burst trigger, hysteresis, and concurrency.
vpn/memmon.go Wires memmon into vpn (iOS vs fixed-budget modes), provides tracker-backed reclaimer, and monitor runner.
vpn/memmon_test.go End-to-end tests for reclaimer ordering, reject-mode masking, gate→clashServer wiring, and monitor behavior.
vpn/conntrack.go Extends connection records with closers and adds per-conn / close-all tracked shutdown helpers.
vpn/clash.go Adds reject-mode plumbing, admission-gate hook on dial path, and stores per-connection closers.
vpn/boxoptions.go Prepends an iOS-only reject rule keyed on a dedicated Clash mode.
internal/paths.go Adds a filename constant for the memory dump artifact.
common/settings/settings.go Reorganizes settings keys and adds a dev-only flag to disable admission rejection.
common/env/env.go Adds RADIANCE_MEM_LIMIT_MB env var key for the fixed iOS monitor budget override.
bypass/bypass.go Removes a trace log (and its imports) when bypass proxy is unreachable.
backend/radiance.go Includes the memory dump file in issue-report attachments when it exists (prioritized first).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread vpn/memmon/dumpfile.go Outdated
Comment thread vpn/memmon.go
Comment thread vpn/memmon/admissiongate.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
backend/radiance.go (1)

427-442: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Minor TOCTOU on memdump attachment check.

os.Stat confirms the dump exists before adding it to files, but the file could be deleted or actively rewritten by the memmon dump writer before the report actually reads/uploads it, since dumps can be overwritten each episode. Low risk given this only affects best-effort issue-report attachments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/radiance.go` around lines 427 - 442, The memdump existence check in
baseIssueAttachments has a small TOCTOU window because os.Stat is only used to
decide whether to include the dump path, while the file may be deleted or
rewritten before report collection uses it. Keep the logic in
baseIssueAttachments and the memdump handling, but avoid relying on the
pre-check for correctness; instead, always add the computed
internal.MemoryDumpFileName path to the attachment list only as a best-effort
candidate and let the later read/upload step handle missing or changed files
safely.
vpn/memmon/types.go (1)

19-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Doc comments deviate from the required format.

The per-value comments use // LevelNormal: description instead of the // Foo does X. sentence form the guideline requires.

✏️ Suggested rewording
 const (
-	// LevelNormal: GC and the scavenger handle memory; the monitor only observes.
+	// LevelNormal is the level at which GC and the scavenger handle memory; the monitor only observes.
 	LevelNormal PressureLevel = iota
-	// LevelSoft: close oldest connections first, reclaiming gradually.
+	// LevelSoft closes the oldest connections first, reclaiming gradually.
 	LevelSoft
-	// LevelHard: force-close all connections and reclaim maximally.
+	// LevelHard force-closes all connections and reclaims maximally.
 	LevelHard
 )

As per coding guidelines, "Go doc comments must start with the identifier's name and a concise summary in the format // Foo does X., with additional context following."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vpn/memmon/types.go` around lines 19 - 26, The doc comments on the
PressureLevel constants are not in the required Go doc format. Update the
comments in the PressureLevel const block so each one starts with the constant
name and a concise sentence summary, following the `// LevelNormal ...` / `//
LevelSoft ...` / `// LevelHard ...` style expected by the guideline. Keep the
descriptions brief and sentence-form, and ensure the comments still clearly
describe the behavior of each level.

Source: Coding guidelines

vpn/memmon/native_stub.go (1)

1-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a doc comment for consistency with the android/ios variants.

The sibling implementations (native_android.go, native_ios.go) document why readNative returns what it does; this stub doesn't explain that returning (0, 0, false) intentionally routes the Sensor to the goBytes fallback path.

📝 Suggested doc comment
+// readNative always reports no native reading available, so Sensor.Sample
+// falls back to Go runtime memory stats on this platform.
 func readNative() (footprint, available uint64, availableSupported bool) { return 0, 0, false }
As per coding guidelines, "Use Go doc comments (`// Foo ...`) for exported identifiers and any unexported ones with non-obvious contracts."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vpn/memmon/native_stub.go` around lines 1 - 5, Add a Go doc comment to
readNative in the native stub to match the android/ios variants and explain the
contract: this build-tagged fallback intentionally returns (0, 0, false) so
Sensor uses the goBytes fallback path. Keep the comment near readNative in
native_stub.go and make it consistent in tone and purpose with the sibling
native_android.go and native_ios.go comments.

Source: Coding guidelines

vpn/memmon/admissiongate.go (1)

92-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale parameter name in doc comment.

The doc comment says src is the dedicated footprint sampler, but the parameter is named sampler, not src. Likely left over from a rename.

📝 Proposed fix
-// NewAdmissionGate builds a gate. src is the dedicated footprint sampler;
+// NewAdmissionGate builds a gate. sampler is the dedicated footprint sampler;
 // setReject toggles reject mode.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vpn/memmon/admissiongate.go` around lines 92 - 96, The doc comment for
NewAdmissionGate still refers to the sampler parameter as src, which is stale
after the rename. Update the comment on NewAdmissionGate to use the current
parameter name sampler and keep the description of setReject accurate; make sure
the wording matches the function signature so the documentation stays in sync
with the API.
vpn/clash.go (1)

27-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing Go doc comments on new admission-control identifiers.

dialAdmissionGate and SetAdmissionGate/setRejectMode have non-obvious contracts (e.g., when reject actually takes effect, idempotency of the swap) but no doc comments, unlike HistoryStorage just below which does have one.

As per coding guidelines, "Use Go doc comments (// Foo ...) for exported identifiers and any unexported ones with non-obvious contracts" and comments should start with the identifier's name.

📝 Example doc comments
+// dialAdmissionGate lets the memory monitor's admission gate record dials and
+// latch/lift clashServer's reject mode based on sampled pressure.
 type dialAdmissionGate interface {
 	RecordDial(time.Time)
 }

Also applies to: 142-157

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vpn/clash.go` around lines 27 - 31, Add Go doc comments for the new
admission-control identifiers with non-obvious behavior: document
`dialAdmissionGate`, `SetAdmissionGate`, and `setRejectMode` so their contracts
are clear, especially when reject mode takes effect and whether repeated swaps
are idempotent. Place the comments directly above the relevant
declarations/methods in `clash.go`, and make sure each comment starts with the
identifier’s name to follow the Go doc convention, similar to `HistoryStorage`
below.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vpn/memmon/executor.go`:
- Around line 24-29: Update the doc comment for NewExecutor so it starts with
NewExecutor and accurately describes the current signature and behavior. Remove
the stale mention of a nil emit disabling pressure events, and keep the summary
concise while still documenting dumpDir, platform/version stamping, and the gate
parameter as they relate to newExecutor and reactionConfig.
- Around line 106-120: The maybeDump method in executor marks the dump as
written even when e.dump.write fails, which suppresses later retries for the
same episode. Update maybeDump so e.dumped is set only after a successful write
in the success branch, and leave it false when the write returns an error; keep
the existing behavior in executor.maybeDump and the write/logging flow unchanged
otherwise.

---

Nitpick comments:
In `@backend/radiance.go`:
- Around line 427-442: The memdump existence check in baseIssueAttachments has a
small TOCTOU window because os.Stat is only used to decide whether to include
the dump path, while the file may be deleted or rewritten before report
collection uses it. Keep the logic in baseIssueAttachments and the memdump
handling, but avoid relying on the pre-check for correctness; instead, always
add the computed internal.MemoryDumpFileName path to the attachment list only as
a best-effort candidate and let the later read/upload step handle missing or
changed files safely.

In `@vpn/clash.go`:
- Around line 27-31: Add Go doc comments for the new admission-control
identifiers with non-obvious behavior: document `dialAdmissionGate`,
`SetAdmissionGate`, and `setRejectMode` so their contracts are clear, especially
when reject mode takes effect and whether repeated swaps are idempotent. Place
the comments directly above the relevant declarations/methods in `clash.go`, and
make sure each comment starts with the identifier’s name to follow the Go doc
convention, similar to `HistoryStorage` below.

In `@vpn/memmon/admissiongate.go`:
- Around line 92-96: The doc comment for NewAdmissionGate still refers to the
sampler parameter as src, which is stale after the rename. Update the comment on
NewAdmissionGate to use the current parameter name sampler and keep the
description of setReject accurate; make sure the wording matches the function
signature so the documentation stays in sync with the API.

In `@vpn/memmon/native_stub.go`:
- Around line 1-5: Add a Go doc comment to readNative in the native stub to
match the android/ios variants and explain the contract: this build-tagged
fallback intentionally returns (0, 0, false) so Sensor uses the goBytes fallback
path. Keep the comment near readNative in native_stub.go and make it consistent
in tone and purpose with the sibling native_android.go and native_ios.go
comments.

In `@vpn/memmon/types.go`:
- Around line 19-26: The doc comments on the PressureLevel constants are not in
the required Go doc format. Update the comments in the PressureLevel const block
so each one starts with the constant name and a concise sentence summary,
following the `// LevelNormal ...` / `// LevelSoft ...` / `// LevelHard ...`
style expected by the guideline. Keep the descriptions brief and sentence-form,
and ensure the comments still clearly describe the behavior of each level.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e6d2b01e-7f6d-4ca8-98c3-72bb2e58cf85

📥 Commits

Reviewing files that changed from the base of the PR and between 4e1b9fb and ad63f22.

📒 Files selected for processing (30)
  • backend/radiance.go
  • bypass/bypass.go
  • common/env/env.go
  • common/settings/settings.go
  • internal/paths.go
  • vpn/boxoptions.go
  • vpn/clash.go
  • vpn/conntrack.go
  • vpn/memmon.go
  • vpn/memmon/admissiongate.go
  • vpn/memmon/admissiongate_test.go
  • vpn/memmon/config.go
  • vpn/memmon/decision_engine.go
  • vpn/memmon/decision_engine_test.go
  • vpn/memmon/dumpfile.go
  • vpn/memmon/dumpfile_test.go
  • vpn/memmon/executor.go
  • vpn/memmon/executor_test.go
  • vpn/memmon/goprobe.go
  • vpn/memmon/monitor.go
  • vpn/memmon/monitor_test.go
  • vpn/memmon/native_android.go
  • vpn/memmon/native_ios.go
  • vpn/memmon/native_stub.go
  • vpn/memmon/reclaimer.go
  • vpn/memmon/sensor.go
  • vpn/memmon/types.go
  • vpn/memmon_test.go
  • vpn/tunnel.go
  • vpn/tunnel_test.go
💤 Files with no reviewable changes (1)
  • bypass/bypass.go

Comment thread vpn/memmon/executor.go
Comment thread vpn/memmon/executor.go
@garmr-ulfr garmr-ulfr merged commit 138000e into main Jul 6, 2026
3 checks passed
@garmr-ulfr garmr-ulfr deleted the feature/mobile-memory-monitor branch July 6, 2026 18:49
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.

3 participants