Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
a88a4b9
test: cover bounded latest-wins batching
azooz2003-bit Jul 9, 2026
0a5c0b5
Coalesce auxiliary UI invalidation bursts
azooz2003-bit Jul 9, 2026
bfc9bcf
Add failing hidden surface occlusion lifecycle tests
azooz2003-bit Jul 9, 2026
7709ee0
Persist hidden renderer state across recreation
azooz2003-bit Jul 9, 2026
7cb63ee
test: cover shared process snapshot ownership
azooz2003-bit Jul 9, 2026
5cb8e16
test: cover shared port scan process data
azooz2003-bit Jul 9, 2026
dd17d9f
perf: share process snapshots across background scans
azooz2003-bit Jul 9, 2026
e6aa1ab
test: cover stable renderer profiling metadata
azooz2003-bit Jul 9, 2026
70c0f16
feat: attribute terminal renderer profiling intervals
azooz2003-bit Jul 9, 2026
ae7b5de
Fix integrated performance instrumentation build
azooz2003-bit Jul 10, 2026
d94dfd4
test: cover disabled renderer profiling path
azooz2003-bit Jul 10, 2026
29701b1
fix: expose renderer signposts to Instruments
azooz2003-bit Jul 10, 2026
c7c8680
test: cover process performance metrics
azooz2003-bit Jul 10, 2026
013d233
perf: expose process scan proof metrics
azooz2003-bit Jul 10, 2026
a7f2c49
test: isolate process metric counters
azooz2003-bit Jul 10, 2026
a8d5f79
perf: retain renderer updates through backpressure
azooz2003-bit Jul 10, 2026
c92bd2c
test: cover Ghostty renderer event profiling
azooz2003-bit Jul 10, 2026
b356384
perf: trace exact Ghostty renderer intervals
azooz2003-bit Jul 10, 2026
33bae97
fix: give process metrics unique project IDs
azooz2003-bit Jul 10, 2026
c846e0f
fix: count processes through snapshot map
azooz2003-bit Jul 10, 2026
8e8f9d0
test: cover shared lsof scan ownership
azooz2003-bit Jul 10, 2026
f9e3cb5
test: cover process snapshot centralization
azooz2003-bit Jul 10, 2026
606c662
test: cover foreground capture snapshot ownership
azooz2003-bit Jul 10, 2026
d700ba6
perf: replace lsof scans with libproc owner
azooz2003-bit Jul 10, 2026
a74c517
perf: centralize process snapshot capture
azooz2003-bit Jul 10, 2026
6088c25
test: cover renderer trace observer effects
azooz2003-bit Jul 10, 2026
d2c7a17
test: import renderer event ABI directly
azooz2003-bit Jul 10, 2026
1716d40
perf: preserve renderer trace integrity
azooz2003-bit Jul 10, 2026
24f6f57
test remote orphan process snapshot sharing
azooz2003-bit Jul 10, 2026
d8ff056
test process snapshot generation invariants
azooz2003-bit Jul 10, 2026
f751560
test: cover workspace save capture consistency
azooz2003-bit Jul 10, 2026
47e7e2f
fix process snapshot generation isolation
azooz2003-bit Jul 10, 2026
da49a47
perf: snapshot workspace save state once
azooz2003-bit Jul 10, 2026
8cecb80
perf: centralize remote orphan process capture
azooz2003-bit Jul 10, 2026
5242f30
perf: expose remote process scan metrics
azooz2003-bit Jul 10, 2026
2bb70c8
test: prove memory startup skips pane polling
azooz2003-bit Jul 10, 2026
657d481
perf: retire dead pane memory polling
azooz2003-bit Jul 10, 2026
d30cd3d
test: expose hidden workspace panel mounting
azooz2003-bit Jul 10, 2026
5be534d
test: cover headless background prime scheduling
azooz2003-bit Jul 10, 2026
ca86837
test: prove scoped pwd reports avoid main actor
azooz2003-bit Jul 10, 2026
0df764c
perf: keep scoped pwd reports off main actor
azooz2003-bit Jul 10, 2026
5bd1400
perf: bound workspace mounting to visible runtimes
azooz2003-bit Jul 10, 2026
65253a2
test: prove portal geometry never forces ancestor layout
azooz2003-bit Jul 10, 2026
9fcf928
perf: make portals passive geometry consumers
azooz2003-bit Jul 10, 2026
1dd86af
test: prove browser geometry refresh stays local
azooz2003-bit Jul 10, 2026
5e9b0cd
perf: keep browser geometry invalidation local
azooz2003-bit Jul 10, 2026
7a29dd2
perf: suppress duplicate layout geometry callbacks
azooz2003-bit Jul 10, 2026
d4915d5
perf: preserve disabled renderer hot path
azooz2003-bit Jul 10, 2026
ae7e358
fix: reject stale port scan UI mutations
azooz2003-bit Jul 10, 2026
0352cc1
test: expose stale browser focus suppression
azooz2003-bit Jul 10, 2026
7649fe7
fix: scope browser focus to view lifetime
azooz2003-bit Jul 10, 2026
9150f5e
test: expose duplicate git snapshot scans
azooz2003-bit Jul 10, 2026
d935226
perf: single-flight tracked git snapshots
azooz2003-bit Jul 10, 2026
be2e064
test: expose duplicate PR source reseeding
azooz2003-bit Jul 10, 2026
a7a0b10
perf: dedupe pull request source seeding
azooz2003-bit Jul 10, 2026
205a2eb
test: expose stale git fallback authority
azooz2003-bit Jul 10, 2026
769fcaa
test: expose dirty-only PR poll traversal
azooz2003-bit Jul 10, 2026
df6c870
test: pin process-wide git fallback rounds
azooz2003-bit Jul 10, 2026
2b385a0
perf: dedupe branch report PR refreshes
azooz2003-bit Jul 10, 2026
98a950b
test: exercise composed git fallback windows
azooz2003-bit Jul 10, 2026
34e419e
test: expose duplicate PR follow-up traversal
azooz2003-bit Jul 10, 2026
f425e6d
fix: coalesce PR seed follow-ups
azooz2003-bit Jul 10, 2026
7dcea26
test: await PR scheduling signals deterministically
azooz2003-bit Jul 10, 2026
3a77e92
test: expose snapshot authority cancellation races
azooz2003-bit Jul 10, 2026
372cf2e
test: pin stale snapshot suppression before rerun
azooz2003-bit Jul 10, 2026
0a42537
fix: coordinate process-wide git snapshot refreshes
azooz2003-bit Jul 10, 2026
00a4f20
test: coalesce duplicate window watcher deliveries
azooz2003-bit Jul 10, 2026
de3d115
fix: deduplicate cross-window git watcher events
azooz2003-bit Jul 10, 2026
7f36318
Merge audited Git snapshot coordination fixes
azooz2003-bit Jul 10, 2026
7d7df4b
Merge origin/main into typing lag performance branch
azooz2003-bit Jul 10, 2026
0d49cec
Fix rendered-frame delivery policy conventions
azooz2003-bit Jul 10, 2026
3790922
Pin renderer GhosttyKit release
azooz2003-bit Jul 10, 2026
d3e1615
Refactor Swift files under length budget
azooz2003-bit Jul 11, 2026
875614a
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
azooz2003-bit Jul 11, 2026
aa732a6
Fix Swift test split boundaries
azooz2003-bit Jul 11, 2026
9f59f79
Keep browser test helpers with their callers
azooz2003-bit Jul 11, 2026
f63f40d
Address performance review findings
azooz2003-bit Jul 11, 2026
ebe3a55
Preserve Bonsplit geometry delivery state
azooz2003-bit Jul 11, 2026
4953fca
Test orphan cleanup ownership boundaries
azooz2003-bit Jul 11, 2026
62ca350
Require exact orphan transport ownership
azooz2003-bit Jul 11, 2026
cebfc77
Pin renderer visibility error reconciliation
azooz2003-bit Jul 11, 2026
7eb288c
Pin reconciled GhosttyKit archive
azooz2003-bit Jul 11, 2026
fd8f51e
Pin retained Ghostty reveal recovery
azooz2003-bit Jul 11, 2026
4cebe7a
Pin retained reveal GhosttyKit archive
azooz2003-bit Jul 11, 2026
8e254f7
Test FSEvent identity recovery after resets
azooz2003-bit Jul 11, 2026
2a5844c
Restore FSEvent dedup after sequence resets
azooz2003-bit Jul 11, 2026
b81a8b9
Test performance paths through production behavior
azooz2003-bit Jul 11, 2026
f927938
Test delayed FSEvent watermarks after wrap
azooz2003-bit Jul 11, 2026
48df6d7
Order FSEvent IDs across sequence wraps
azooz2003-bit Jul 11, 2026
24d420f
Document wrapped FSEvent serial ordering
azooz2003-bit Jul 11, 2026
5a9eff5
Avoid deprecated browser focus observer
azooz2003-bit Jul 11, 2026
24da5e7
Trim unprofiled report_pwd scope
azooz2003-bit Jul 11, 2026
c88cfd3
Trim unprofiled remote cleanup scope
azooz2003-bit Jul 11, 2026
857eb50
Trim unprofiled workspace save scope
azooz2003-bit Jul 11, 2026
b510efc
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
azooz2003-bit Jul 11, 2026
386fe6b
Trim unproven portal geometry scope
azooz2003-bit Jul 12, 2026
0b36a08
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
azooz2003-bit Jul 12, 2026
0b90a45
Add release performance proof counters
Jul 12, 2026
3bdb373
Fix performance metrics ownership and test race
Jul 12, 2026
76a167f
Prove bounded mobile and focus invalidations
Jul 12, 2026
b9217de
Avoid disabled metrics recorder locks
Jul 12, 2026
c4f40eb
Anchor latest-wins scheduler deadlines
Jul 12, 2026
6dd2bc7
Prove Git and PR refresh ownership
Jul 12, 2026
c90ce33
Make process owner proof deterministic
Jul 12, 2026
760de3d
Expose Git request ownership metrics
Jul 12, 2026
139603e
Preserve cross-panel PR refreshes
Jul 13, 2026
22878ea
Bind process proof to measurement epoch
Jul 13, 2026
d0a637b
Exercise Git and PR ownership paths
Jul 13, 2026
969301d
Expose live Git and PR owner proof
Jul 13, 2026
fd855d8
Respect sidebar metrics actor isolation
Jul 13, 2026
541948b
Fix scheduler sendability warnings
Jul 13, 2026
cadc409
Test cancellation of Git PR diagnostic waits
Jul 13, 2026
a9033b4
Cancel Git PR diagnostic waits safely
Jul 13, 2026
3f9780c
Merge current main into typing lag fixes
Jul 13, 2026
bcca3b0
Test socket ancestry authorization cost
Jul 13, 2026
c2b4349
Cache socket client ancestry per connection
Jul 13, 2026
c8793c2
Let descendants bypass exhausted socket auth slots
Jul 13, 2026
5677599
Instantiate Git performance exercises
Jul 13, 2026
b83a08c
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
Jul 13, 2026
7a9575f
Extract socket capabilities from TerminalController
Jul 13, 2026
d49fdca
test: cover scale-aware live-agent reload cadence
Jul 14, 2026
83e81d2
perf: scale live-agent reload cadence
Jul 14, 2026
c5aa69a
test: expose lost input-demand key event
Jul 14, 2026
cadf484
fix: preserve input and callback ownership during recovery
Jul 14, 2026
18225e6
fix: keep teardown ownership internal
Jul 14, 2026
9624f3a
perf: avoid full decoding for non-agent processes
Jul 14, 2026
947a800
perf: reuse sanitized event frames
Jul 14, 2026
561aa69
perf: remove terminal output subscription locks
Jul 14, 2026
35c5dd8
fix: activate raw process scanning in live agent loader
Jul 14, 2026
37aaad8
test: await runtime readiness before input recovery
Jul 14, 2026
0496247
perf: bound terminal scrollback per surface
Jul 14, 2026
449ec2e
fix: retain argument-only agent detections
Jul 14, 2026
5b06ae7
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
Jul 14, 2026
78fa146
Merge remote-tracking branch 'origin/main' into perf-typing-lag-bottl…
Jul 14, 2026
4b37633
Pin GhosttyKit checksum for scrollbar build
Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@
{"timestamp":"2026-07-13T12:00:00.000Z","type":"event_msg","payload":{"type":"agent_message","message":"Event-only prose /tmp/parity/CODEX-event-agent.png","phase":"commentary"}}
{"timestamp":"2026-07-13T12:00:00.000Z","type":"event_msg","payload":{"type":"exec_command_begin","call_id":"event-exec","command":"cat /tmp/parity/CODEX-event-command.txt"}}
{"timestamp":"2026-07-13T12:00:00.000Z","type":"event_msg","payload":{"type":"exec_command_end","call_id":"event-exec","stdout":"saved /tmp/parity/CODEX-event-output.txt","stderr":"","exit_code":0}}

Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public protocol ControlCommandContext:
ControlSurfaceContext,
ControlSystemContext,
ControlProjectContext,
ControlPerformanceContext,
ControlDebugContext,
ControlSidebarContext,
ControlBrowserPanelContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public final class ControlCommandCoordinator {
if let result = handleSurface(request) { return result }
if let result = handleSystem(request) { return result }
if let result = handleProject(request) { return result }
if let result = handlePerformance(request) { return result }
if let result = handleDebug(request) { return result }
// The v2 browser.* domain stays app-side: PR 5778 moved its
// JS-evaluating methods onto the socket-worker lane (nonisolated
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ public protocol ControlDebugContext: AnyObject {
/// unavailable (the legacy `unavailable` error).
func controlDebugSessionSnapshotSeedScrollback(charactersPerTerminal: Int) -> JSONValue?

/// Reads the DEBUG-only process enumeration, filtering, apply, and lsof
/// counters without mutating app or focus state.
func controlDebugReadProcessPerformanceMetrics() -> JSONValue?

/// Resets the DEBUG-only process counters and returns the zeroed snapshot.
func controlDebugResetProcessPerformanceMetrics() -> JSONValue?

// MARK: - v1-shared command forwards (raw v1 response strings)

/// Runs the shared v1 `set_shortcut` body for `debug.shortcut.set`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
internal import Foundation

extension ControlCommandCoordinator {
/// Handles the opt-in aggregate performance counter surface in optimized
/// builds. The context owns collection and redaction; this package only
/// routes typed JSON values.
func handlePerformance(_ request: ControlRequest) -> ControlCallResult? {
switch request.method {
case "performance.metrics.read":
return performanceMetricsResult(context?.controlPerformanceMetricsRead())
case "performance.metrics.reset":
return performanceMetricsResult(context?.controlPerformanceMetricsReset())
case "performance.metrics.stop":
return performanceMetricsResult(context?.controlPerformanceMetricsStop())
default:
return nil
}
}

private func performanceMetricsResult(_ payload: JSONValue?) -> ControlCallResult {
guard let payload else {
return .err(
code: "unavailable",
message: "Performance metrics unavailable",
data: nil
)
}
return .ok(payload)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public import Foundation

/// Release-safe observability seam for opt-in, aggregate performance counters.
/// Payloads contain counts and durations only, never workspace names, paths,
/// command lines, or terminal contents.
@MainActor
public protocol ControlPerformanceContext: AnyObject {
func controlPerformanceMetricsRead() -> JSONValue?
func controlPerformanceMetricsReset() -> JSONValue?
func controlPerformanceMetricsStop() -> JSONValue?
}

public extension ControlPerformanceContext {
func controlPerformanceMetricsRead() -> JSONValue? { nil }
func controlPerformanceMetricsReset() -> JSONValue? { nil }
func controlPerformanceMetricsStop() -> JSONValue? { nil }
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
public import Darwin

/// Authorizes peer processes for cmux-only control socket requests.
public struct SocketClientAuthorization {
/// Creates an authorization helper with no retained process state.
/// Authorizes one peer connection for cmux-only control socket requests.
public struct SocketClientAuthorization: Sendable {
private var cachedAncestryAuthorization: (peerProcessID: pid_t, isAllowed: Bool)?

/// Creates an authorization helper for one accepted socket connection.
public init() {}

/// Returns whether a peer process is allowed to use cmux-only socket operations.
Expand All @@ -29,11 +31,36 @@ public struct SocketClientAuthorization {
return false
}

/// Evaluates and caches process ancestry for one peer PID.
///
/// Call this when connection admission must fall back to ancestry before
/// the first command is available. Later command authorization reuses the
/// cached result and does not walk the process tree again.
///
/// - Parameters:
/// - peerProcessID: The PID reported by the accepted socket.
/// - isDescendant: Predicate that verifies current process ancestry.
/// - Returns: The cached or newly evaluated ancestry result.
public mutating func cacheAncestryAuthorization(
peerProcessID: pid_t?,
isDescendant: (pid_t) -> Bool
) -> Bool {
guard let peerProcessID else { return false }
if let cachedAncestryAuthorization,
cachedAncestryAuthorization.peerProcessID == peerProcessID {
return cachedAncestryAuthorization.isAllowed
}
let peerIsDescendant = isDescendant(peerProcessID)
cachedAncestryAuthorization = (peerProcessID, peerIsDescendant)
return peerIsDescendant
}

/// Returns the command carried by an authorized cmux-only request.
///
/// Descendants retain the existing process-tree authorization. The
/// capability parameters form the runtime seam for terminals whose
/// process trees are later reparented by a multiplexer.
/// A valid same-user capability is accepted before process ancestry is
/// evaluated. Ordinary clients retain process-tree authorization, with one
/// ancestry result cached for the lifetime of this authorization helper.
/// Reusing a helper with a different peer PID invalidates that cache.
///
/// - Parameters:
/// - command: The raw command line received from the client.
Expand All @@ -42,22 +69,24 @@ public struct SocketClientAuthorization {
/// - capabilityAuthority: The authority that verifies inherited tokens.
/// - isDescendant: Predicate that verifies current process ancestry.
/// - Returns: The unwrapped command when authorized, otherwise `nil`.
public func authorizedCommand(
public mutating func authorizedCommand(
_ command: String,
peerProcessID: pid_t?,
peerHasSameUID: Bool,
capabilityAuthority: SocketClientCapabilityAuthority,
isDescendant: (pid_t) -> Bool
) -> String? {
let envelope = SocketClientCapabilityCommand(command)
if let peerProcessID, isDescendant(peerProcessID) {
return envelope?.command ?? command
}
guard peerHasSameUID,
let envelope,
capabilityAuthority.verifies(envelope.capability) else {
return nil
if peerHasSameUID,
let envelope,
capabilityAuthority.verifies(envelope.capability) {
return envelope.command
}
return envelope.command

guard cacheAncestryAuthorization(
peerProcessID: peerProcessID,
isDescendant: isDescendant
) else { return nil }
return envelope?.command ?? command
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ public enum ControlCommandExecutionPolicy: Sendable, Equatable {
"mobile.terminal.set_font",
"system.top",
"system.memory",
// Owner attribution performs a fresh process + listener capture and
// awaits utility tasks. It never touches UI state, so running it on the
// main actor would contaminate the latency path it exists to prove.
"performance.metrics.exercise_process",
// Uses an isolated temporary Git repository and in-memory PR host. Git
// scanning stays off-main; only the PR state machine hops to MainActor.
"performance.metrics.exercise_git_pr",
// `surface.read_text` reads a terminal's visible or full-scrollback
// text and formats it (line tailing, candidate scoring, base64
// encoding). On the main actor that formatting stalls the run loop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Foundation
extension ControlDebugContext {
func controlDebugSessionSnapshotBenchmark(includeScrollback: Bool, persist: Bool) -> JSONValue? { nil }
func controlDebugSessionSnapshotSeedScrollback(charactersPerTerminal: Int) -> JSONValue? { nil }
func controlDebugReadProcessPerformanceMetrics() -> JSONValue? { nil }
func controlDebugResetProcessPerformanceMetrics() -> JSONValue? { nil }
func controlDebugSetShortcut(arguments: String) -> String { "ERROR: not implemented" }
func controlDebugSimulateShortcut(combo: String) -> String { "ERROR: not implemented" }
func controlDebugActivateApp() -> String { "ERROR: not implemented" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ private final class FakeDebugV1ControlCommandContext: ControlCommandContext {
var rightSidebarResolution: ControlDebugRightSidebarFocusResolution = .windowNotFound
var remoteTmuxSizingPayload: JSONValue?

var processMetrics = JSONValue.object([
"process_snapshots": .object(["capture_started": .int(3)])
])
var processMetricsReadCount = 0
var processMetricsResetCount = 0
var typedTexts: [String] = []

func controlDebugSetShortcut(arguments: String) -> String {
setShortcutArguments = arguments
return setShortcutResponse
Expand All @@ -32,6 +39,24 @@ private final class FakeDebugV1ControlCommandContext: ControlCommandContext {
return rightSidebarResolution
}

func controlDebugReadProcessPerformanceMetrics() -> JSONValue? {
processMetricsReadCount += 1
return processMetrics
}

func controlDebugResetProcessPerformanceMetrics() -> JSONValue? {
processMetricsResetCount += 1
processMetrics = .object([
"process_snapshots": .object(["capture_started": .int(0)])
])
return processMetrics
}

func controlDebugTypeText(_ text: String) -> ControlDebugTypeResolution {
typedTexts.append(text)
return .inserted
}

func controlDebugRemoteTmuxSizingSettled() -> JSONValue? {
remoteTmuxSizingPayload
}
Expand Down Expand Up @@ -121,5 +146,42 @@ struct ControlCommandCoordinatorDebugV1Tests {
let reply = coordinator.handleDebugV1(command: "debug_right_sidebar_focus", args: "split")
#expect(reply == "ERROR: mode=split active= visible=0 context=0 state=0 focus=0")
}

@Test func processMetricsReadAndResetUseSharedDebugDomain() {
let (coordinator, context) = makeCoordinator()
let read = coordinator.handle(ControlRequest(
id: .int(1),
method: "debug.process_metrics.read",
params: [:]
))
#expect(read == .ok(.object([
"process_snapshots": .object(["capture_started": .int(3)])
])))
#expect(context.processMetricsReadCount == 1)

let reset = coordinator.handle(ControlRequest(
id: .int(2),
method: "debug.process_metrics.reset",
params: [:]
))
#expect(reset == .ok(.object([
"process_snapshots": .object(["capture_started": .int(0)])
])))
#expect(context.processMetricsResetCount == 1)
}

@Test func typingDoesNotReadOrResetProcessMetrics() {
let (coordinator, context) = makeCoordinator()
let result = coordinator.handle(ControlRequest(
id: .int(1),
method: "debug.type",
params: ["text": .string("typing workload")]
))

#expect(result == .ok(.object([:])))
#expect(context.typedTexts == ["typing workload"])
#expect(context.processMetricsReadCount == 0)
#expect(context.processMetricsResetCount == 0)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Testing
@testable import CmuxControlSocket

@MainActor
private final class FakePerformanceControlCommandContext: ControlCommandContext {
private(set) var calls: [String] = []

func controlPerformanceMetricsRead() -> JSONValue? {
calls.append("read")
return .object(["enabled": .bool(true)])
}

func controlPerformanceMetricsReset() -> JSONValue? {
calls.append("reset")
return .object(["enabled": .bool(true), "reset": .bool(true)])
}

func controlPerformanceMetricsStop() -> JSONValue? {
calls.append("stop")
return .object(["enabled": .bool(false)])
}
}

@MainActor
@Suite("ControlCommandCoordinator performance metrics")
struct ControlCommandCoordinatorPerformanceTests {
@Test func routesReleaseSafeReadResetAndStop() {
let context = FakePerformanceControlCommandContext()
let coordinator = ControlCommandCoordinator(context: context)

#expect(coordinator.handle(request("performance.metrics.read")) == .ok(.object([
"enabled": .bool(true),
])))
#expect(coordinator.handle(request("performance.metrics.reset")) == .ok(.object([
"enabled": .bool(true),
"reset": .bool(true),
])))
#expect(coordinator.handle(request("performance.metrics.stop")) == .ok(.object([
"enabled": .bool(false),
])))
#expect(context.calls == ["read", "reset", "stop"])
}

@Test func unrelatedMethodFallsThrough() {
let coordinator = ControlCommandCoordinator(context: FakePerformanceControlCommandContext())
#expect(coordinator.handle(request("performance.unowned")) == nil)
}

private func request(_ method: String) -> ControlRequest {
ControlRequest(id: .int(1), method: method, params: [:])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct ControlCommandExecutionPolicyTests {
for method in [
"system.ping", "system.capabilities", "auth.status", "auth.sign_in_url",
"feed.push", "browser.download.wait", "system.top", "system.memory",
"performance.metrics.exercise_process",
"performance.metrics.exercise_git_pr",
"workspace.remote.pty_bridge", "workspace.env", "sidebar.custom.reload",
"sidebar.custom.open",
"debug.sidebar.simulate_drag", "mobile.attach_ticket.create",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,20 @@ struct SocketCapabilityRebindTests {
}

let command = "hooks claude prompt-submit"
let authorized = SocketClientAuthorization().authorizedCommand(
var authorization = SocketClientAuthorization()
var ancestryEvaluationCount = 0
let authorized = authorization.authorizedCommand(
envelope.wrap(command),
peerProcessID: reboundConnection.peerProcessID,
peerHasSameUID: true,
capabilityAuthority: authority,
isDescendant: { _ in false }
isDescendant: { _ in
ancestryEvaluationCount += 1
return false
}
)
#expect(authorized == command)
#expect(ancestryEvaluationCount == 0)
}

private func connect(to path: String) -> Int32 {
Expand Down
Loading