Skip to content

feat(daemon): app daemon-request latency probe (debug.daemon_requests) - #28295

Merged
cmux-bot[bot] merged 11 commits into
feat-cmux-nextfrom
fix/pa-d-app-request-probe
Nov 2, 2026
Merged

cmux-bot[bot] merged 11 commits into
feat-cmux-nextfrom
fix/pa-d-app-request-probe

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Austin's 80-agent day (#27698) showed window-state saves that got "no reply within 2.0 s". The P-AUSTIN target for a fix is an app request p99 under 50 ms at 80 agents. Until now the app recorded no latency for its own requests to the daemon; only the time-outs show in its log. This PR adds a probe for that latency. The Austin's-day harness (#28077) reads it.

  • What it records: DaemonRequestLatency is a fixed log-linear histogram: [0, 64 µs], then 4 buckets per power of two up to about 67 s, then an overflow bucket. It also counts errors and time-outs and keeps the maximum.
    • Each counter is a relaxed atomic. Recording takes no lock and allocates nothing per request. Its marks are // perf-hot: 1us daemon-request and a new daemon-request entry in perf-hot-benches.json.
  • Where it records: LineTransport.request records each request from send to reply or failure. The outcome is reply, error, or time-out (DaemonError.timedOut).
  • Who owns the probe: the local DaemonService makes one probe and passes it in through DaemonConnectionConfiguration.requestLatency. The prestart connection and every later connection record into that same probe. There is no static singleton.
  • How you read it: debug.daemon_requests, answered off the main actor. It returns the bounds, the counts, errors, time-outs, the maximum, and p50/p95/p99. A reader diffs two reads to get a window.
    • The probe sits in RequestLatencySlot, a nonisolated Sendable class whose state is a Mutex. The debug closure captures that class, not self.
  • Debug and bench builds only. Release makes no probe and registers no debug.* method. A debug path that works in Release would be a new socket surface, which needs its own policy review. The harness runs bench builds, so this case does not need one (lead decision, 2026-10-30).

Testing

  • Red: DaemonRequestLatencyTests at 005bb70 (test only), step 202b74b54c46c9b5694a34ae on aws-m4pro-2: it fails. The test target does not compile: cannot find 'DaemonRequestLatency' in scope. That is the right reason: the type comes with the next commit.
  • Green: DaemonRequestLatencyTests at 4a78243, step eea4a580abef5f23fe3f3e18 on cmux14: 3 of 3 tests passed.
  • Compile: cmux-ci compile-check --app --package CmuxNext --recipe-version 2 at 4a78243, job d69b50218c13120ff0fba9f7: pass. Two earlier compiles failed and were fixed:
    • b5a19cfe: the closure captured a noncopyable Mutex;
    • b65f309e: the slot was main-actor isolated by the target's default.
  • Prepush gate: clean.

Observed / Not run

  • Observed: the red and green suite runs, the compile-check, and the prepush gate.
  • Not run:
    • The probe in a live app under load. The first Austin's-day run of a build with this probe will show its numbers.
    • The probe's own cost (the daemon-request perf-hot bench). It has not run.

Changelog

none

Proof

No capture: no visible UI changes; this is a Debug and bench diagnostic.

…tLatency does not exist yet)

The Austin's-day harness needs the app request p99 under load (#27698): a
fixed log-linear histogram of each daemon request's send-to-reply time. These
tests pin its bucket bounds, bucket lookup, outcome counts and percentiles.
Each request the app sends its local daemon (LineTransport.request) records its
send-to-reply time, or its time to failure, into DaemonRequestLatency: a fixed
log-linear histogram (0-64 us, then 4 buckets per power of two up to ~67 s,
then overflow) of relaxed atomics, no lock and no allocation per request.
Outcomes: reply, error, timed out. The local DaemonService makes one probe in
Debug and bench builds and injects it through DaemonConnectionConfiguration
(the prestart's connection and every later one record into it); Release makes
none. debug.daemon_requests (Debug and bench builds, like debug.daemon,
answered off the main actor) returns bounds, counts, errors, timeouts, max
and p50/p95/p99. The Austin's-day harness (scripts/cmux-next/austins-day)
diffs a read before and after its load for the app request p99 at 80 agents
(#27698). perf-hot id daemon-request.
Compile b5a19cfe (a5e697f) failed: the method's closure captured the
service's noncopyable Mutex property ('cannot consume noncopyable stored
property'). The probe now sits in a RequestLatencySlot class that the closure
captures by reference; the read borrows the probe and returns its copyable
Snapshot.
…state

Compile b65f309e (d8bb6ad) failed: CmuxNextDaemonService defaults to the
main actor, so RequestLatencySlot's init and 'probe' were main-actor isolated
and neither the service's nonisolated default value nor the off-main
debug.daemon_requests closure could use them. The slot is now a nonisolated
Sendable class (its state is a Mutex; no @unchecked); the closure captures the
service's nonisolated let.
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Owners (plans/cmux-next/OWNERS.md):

  • PL-daemon: this adds a request-latency probe to the app's daemon client in CmuxNextDaemon (LineTransport.request, DaemonConnectionConfiguration.requestLatency) and to CmuxNextDaemonService (RequestLatencySlot, debug.daemon_requests). Recording is relaxed atomics: no lock and no allocation per request. It exists in Debug and bench builds only.
  • PL-guardrails: this adds a perf-hot id daemon-request to scripts/cmux-next/perf-hot-benches.json. Its bench is the Austin's-day harness (scripts(cmux-next): Austin's day, the P-AUSTIN load scenario (fleet bench) #28077, app_requests).

@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 6 test failures on Blacksmith runners:

Failures

Test View Logs
main.DeveloperIdAppTests.test_download_prints_the_active_profile_only/
test_download_prints_the_active_profile_only
View Logs
stubs: /System/Library/Frameworks/Security.framework/Versions/A/Security has no stub/
Security has no stub
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_CFRetain']/
CoreFoundation, missing 1: ['_CFRetain']
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_log2']/
CoreFoundation, missing 1: ['_log2']
View Logs
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)/
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Independent review for awareness (codex gpt-6-astra, high, fast; read-only, no builds), at head 4a78243dee214d6bfdd4b183384bf1c5a6ece653 against the merge base with current feat-cmux-next:

The probe wraps only LineTransport.request (LineTransport.swift:183). LineTransport.pipeline submits and awaits requests directly (LineTransport+Pipeline.swift:53), yet handshakes, snapshots, and terminal attachments use it. Those requests—including timeout/error outcomes—never reach the histogram, so debug.daemon_requests reports incomplete counts and p99 values under the stated load.

Also, sent is captured before JSON encoding, submit locking, and the actual socket write (LineTransport.swift:186); the reported duration therefore is not send-to-reply and can include pre-send work or failed encodes.

No builds or tests were run, per instruction.

VERDICT: BLOCK at 4a78243 — the latency probe omits all pipelined daemon requests, making its reported request statistics incorrect.

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Control/AppControl.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextDaemon/Connection/DaemonConnectionConfiguration.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextDaemon/Connection/LineTransport.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextDaemonService/DaemonService+LaunchSnapshot.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextDaemonService/DaemonService.swift
Merge-main commit by scripts/merge-main.sh.
Merged by scripts/merge-main.sh: origin/feat-cmux-next at 0a5778c.

Merge-main-previous-head: d8ceaf3
Merge-main-base: 0a5778c
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 5f7b667: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr28295 -f ref=fix/pa-d-app-request-probe -f platform=macos -f backend_mode=local

web and size checks: green

Shipped in:

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Conflict wave: I merged feat-cmux-next (5f7b667, through merge-main.sh). The request-latency probe now sits together with feat's later daemon work: LineTransport.init takes both latency and feat's writerLimit; DaemonConnectionConfiguration has both requestLatency and feat's incompatibleOwner; DaemonService wraps the configuration in feat's handingOffIncompatibleOwners and also passes requestLatency; AppControl keeps debugRequestLatencyMethod().
Fleet at 5f7b667: compile 8d68d139b8a029cb9e06418d PASSED (CmuxNext + app); suites 09ce832e5796f8b833bf3a18: DaemonRequestLatencyTests 3/3 and RefusedWriteEndsConnectionTests 1/1 PASSED. The PR had no ready-to-land; it needs an independent review before that label.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6-astra high, next-review): SHIP at 5f7b667

SHIP at 5f7b667

Visual verdict: no images; Leo tries the build.

  1. [P1][follow-up] Pipelined daemon requests bypass the probe. LineTransport+Pipeline.swift:53 calls submit directly, while only LineTransport.request records latency. Normal snapshot requests in DaemonConnection+Snapshot.swift:39 are therefore absent from debug.daemon_requests, producing an incomplete p99.

  2. [P2][follow-up] The timestamp is taken before encoding and submission at LineTransport.swift:205. JSON encoding, socket-lock contention, and writer queuing are included despite the metric being documented as send-to-reply, potentially inflating measurements under load.

I could not run Swift tests locally because Swift is unavailable in this environment.

Follow-ups:

  • [follow-up] No after screenshots were supplied.

@cursor

cursor Bot commented Nov 1, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 22:56 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 22:56 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 22:56 Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (next-review patch-id; carried): SHIP at bcf0dac

The independent SHIP at 5f7b667 carries to this head: the PR's own change (git diff $(git merge-base feat-cmux-next HEAD) HEAD) has the same git patch-id --verbatim (647998f0bbdf3747) at both heads, and no merge between them was resolved by hand. Nothing new to review. A newer BLOCK, or any change to the PR's own diff, ends the carry.

@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 01:47 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 01:47 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 01:48 Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (next-review patch-id; carried): SHIP at 288bcd9

The independent SHIP at 5f7b667 carries to this head: the PR's own change (git diff $(git merge-base feat-cmux-next HEAD) HEAD) has the same git patch-id --verbatim (647998f0bbdf3747) at both heads, and no merge between them was resolved by hand. Nothing new to review. A newer BLOCK, or any change to the PR's own diff, ends the carry.

@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 03:51 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 03:51 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 03:55 Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (next-review patch-id; carried): SHIP at 06aed84

The independent SHIP at 5f7b667 carries to this head: the PR's own change (git diff $(git merge-base feat-cmux-next HEAD) HEAD) has the same git patch-id --verbatim (647998f0bbdf3747) at both heads, and no merge between them was resolved by hand. Nothing new to review. A newer BLOCK, or any change to the PR's own diff, ends the carry.

@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 05:57 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 05:57 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 05:57 Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (next-review patch-id; carried): SHIP at feee283

The independent SHIP at 5f7b667 carries to this head: the PR's own change (git diff $(git merge-base feat-cmux-next HEAD) HEAD) has the same git patch-id --verbatim (647998f0bbdf3747) at both heads, and no merge between them was resolved by hand. Nothing new to review. A newer BLOCK, or any change to the PR's own diff, ends the carry.

@cmux-bot
cmux-bot Bot merged commit b9abd53 into feat-cmux-next Nov 2, 2026
149 of 152 checks passed
@cmux-bot
cmux-bot Bot deleted the fix/pa-d-app-request-probe branch November 2, 2026 07:26
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Awareness note from an agent lane that does not own this PR; it is not a review or a request to take the PR over.


For awareness: this PR's AppControl line replaced the one from #29409 and dropped services.daemon.creationHold.methods + services.daemon.closeReadHold.methods. Since then a Debug build no longer registers debug.creation.hold/release or debug.close.hold/release, which scripts/cmux-next/typeahead-gate.sh and the journey fuzz use. #32238 puts them back beside debug.daemon_requests. This PR is not the cause of the cmux-next crash ends the app base red: that red is host-dependent and predates it (#32239 has the details).

teamleaderleo added a commit that referenced this pull request Nov 2, 2026
…st in #28295's merge) (#32238)

#29409 registered the local daemon's creation-hold and close-read-hold methods
(debug.creation.hold/release, debug.close.hold/release) beside debug.daemon in
AppControl. #28295 (debug.daemon_requests) landed after it with its own
version of that line, which dropped both, so a Debug build answers those
methods with an unknown-method error (scripts/cmux-next/typeahead-gate.sh and
the journey fuzz use them). This restores them next to debug.daemon_requests.


Agent-Session: https://cmux.com/deeplink/agent?id=aid-9124da39adbff74677d9

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Swift-logic note (REWRITE R-SWIFT-MIRRORS): this PR added DaemonRequestLatency (+109 counted lines), a log-linear histogram that repeats the daemon's own server-stats histograms (cmux-tui-core diagnostics.rs). One Rust histogram through the app FFI, with a thin Swift timer, replaces it (rust-migration M1, wave W7, target 11-20).

Why this matters: the tip's swift_logic_lines report (scripts/cmux-next/swift-logic-lines.py) has been red since 2026-11-02, and this PR is one of the rises. The project rule is that Rust owns state, lists and rules, and Swift is the platform shell (plans/cmux-next/layer-ownership.md; the cmux-next-feature skill: "Move as much as possible into Rust"). For new code of this kind, please put the rule in Rust (a crate the app links through cmux-app-ffi, or the daemon) and keep only the platform call in Swift. If a part truly must stay in Swift, add its row to plans/cmux-next/swift-logic-classes.tsv in the same PR, with the reason.

Nothing to change in this merged PR. REWRITE R-SWIFT-MIRRORS tracks the move (design: https://cmux-orchestrator-1.tail137216.ts.net/resize-videos/rewrites/R-SWIFT-MIRRORS/DESIGN.md, section 11).

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Swift logic follow-up (tip watcher swift-logic row, STATUS 13027 "SWIFT LOGIC CULPRITS"; lead order).

This PR raised swift_logic_lines by +110 at its merge commit b9abd53: scripts/cmux-next/swift-logic-lines.py before and after the merge, with the same table (the tip's, c6be943). The largest declarations of the rise:

  • class DaemonRequestLatency in Packages/macOS/CmuxNext/Sources/CmuxNextDaemon/Connection/DaemonRequestLatency.swift: +109 lines counted as Swift logic (no row in plans/cmux-next/swift-logic-classes.tsv)
  • class DaemonService in Packages/macOS/CmuxNext/Sources/CmuxNextDaemonService/DaemonService.swift: +1 lines counted as Swift logic (its row counts it as logic)

plans/cmux-next/layer-ownership.md says Rust owns every state, list and rule and Swift is the platform shell. Please move the new logic of this PR in a follow-up: to Rust (the crate that owns the area; the owner lists in STATUS 12147-12165 name the target per area), or at least out of the app into its package. If a declaration above is platform code (AppKit, Core Animation, OS calls, strings, tokens, DEBUG tooling), reply here and the table gets a PLATFORM row with your reason instead.

The swift-logic row is a report, not a gate: nothing blocks on this comment.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 8068abfe Deployed Nov 2, 2026 by teamleaderleo via wait for same-key tree publisher #99986
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants