Make adaptive refresh agent-aware with explicit local activity consent#2111
Make adaptive refresh agent-aware with explicit local activity consent#2111hhh2210 wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR makes Adaptive refresh agent-aware by default by feeding recent local Codex/Claude activity into the adaptive cadence decision, while keeping the Agent Sessions UI (and all remote discovery/SSH behavior) explicitly opt-in.
Changes:
- Extend the shared
AdaptiveRefreshPolicyCoredecision table with an optionallastCodingActivityAtsignal that caps otherwise-slower unconstrained delays at 5 minutes. - Make missing/unrecognized
refreshFrequencyresolve to.adaptive, and enable bounded local session monitoring when Adaptive is effective—without enabling the Agent Sessions UI. - Update replay tooling to treat activity-aware Adaptive as production (
adaptive), preserve the historical baseline asadaptive-menu-only, and keepadaptive-activityas a CLI alias.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| Tests/CodexBarTests/SettingsStoreTests.swift | Update default/fallback expectations for refresh frequency; add explicit 5m preservation test. |
| Tests/CodexBarTests/CodexSessionRolloutTests.swift | Add bounded-rollout parsing coverage for local scanner limits. |
| Tests/CodexBarTests/ClaudeSessionMappingTests.swift | Add transcript list limiting coverage. |
| Tests/CodexBarTests/AgentSessionMenuDescriptorTests.swift | Cover Adaptive-only monitoring enablement, projection, and constraint pausing. |
| Tests/CodexBarTests/AdaptiveRefreshTimerTests.swift | Add timer pull-forward behavior tests for coding activity; ensure fixed-mode behavior stays in-memory only. |
| Tests/CodexBarTests/AdaptiveRefreshPolicyTests.swift | Verify app adapter forwards coding activity into policy decisions. |
| Tests/AdaptiveReplayKitTests/MenuOnlyAdaptivePolicyTests.swift | Reframe replay tests around production adaptive and the historical menu-only baseline. |
| Tests/AdaptiveReplayKitTests/AdaptiveRefreshPolicyCoreTests.swift | Add core policy tests for coding-activity cap, boundaries, and constraints. |
| Tests/AdaptiveReplayCLITests/CLIArgumentsTests.swift | Ensure adaptive-activity remains accepted and maps to production adaptive. |
| Sources/CodexBarCore/LocalAgentSessionScanner.swift | Bound process/rollout/transcript candidate handling to configured limits. |
| Sources/CodexBarCore/AgentSession.swift | Extend scan config with bounds; add transcript limiting support. |
| Sources/CodexBar/UsageStore+AdaptiveRefresh.swift | Wire lastCodingActivityAt through adaptive decisions and timer advancement behavior. |
| Sources/CodexBar/UsageStore.swift | Track lastCodingActivityAt in-memory; refactor timer restart helper. |
| Sources/CodexBar/StatusItemController+AgentSessions.swift | Forward activity timestamp into adaptive refresh; centralize agent session settings sync. |
| Sources/CodexBar/StatusItemController.swift | Track refresh-frequency changes alongside agent-session settings; use new wiring helpers. |
| Sources/CodexBar/SettingsStore.swift | Change missing/unrecognized refresh-frequency fallback to .adaptive. |
| Sources/CodexBar/AgentSessionsStore.swift | Enable local monitoring under Adaptive without enabling UI; project activity timestamp-only when UI is off. |
| Sources/CodexBar/AdaptiveRefreshPolicy.swift | Thread coding activity input through the production policy adapter into the shared core. |
| Sources/AdaptiveReplayKit/README.md | Update replay docs to reflect production activity-aware Adaptive and historical baseline. |
| Sources/AdaptiveReplayKit/HistoricalPolicies.swift | Add historical menu-only Adaptive baseline policy (adaptive-menu-only). |
| Sources/AdaptiveReplayKit/CandidatePolicies.swift | Remove replay-only activity candidate (now folded into production policy). |
| Sources/AdaptiveReplayKit/BaselinePolicies.swift | Feed coding activity into production replay policy; add helper for omitting the signal. |
| Sources/AdaptiveReplayCLI/main.swift | Update CLI help text and document alias behavior. |
| Sources/AdaptiveReplayCLI/CLIArguments.swift | Replace candidate policy with historical baseline; implement adaptive-activity alias parsing. |
| Sources/AdaptiveRefreshCore/AdaptiveRefreshPolicyCore.swift | Add coding-activity signal, reason, thresholds, and cap behavior to shared decision table. |
| README.md | Update high-level feature description and privacy note for adaptive local scan behavior. |
| docs/refresh-loop.md | Document new default fallback, activity signal, scanner bounds, and pause conditions. |
| docs/predictive-refresh-policy.md | Update decision record to reflect agent-aware adaptive default extension and constraints. |
| CHANGELOG.md | Document default/fallback change, activity cap behavior, and bounded/local-only scan implications. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.localRefreshInFlight = true | ||
| let sessions = await self.localScanner.scan() | ||
| self.localRefreshInFlight = false | ||
| guard !Task.isCancelled, self.settings.agentSessionsEnabled else { return } | ||
| self.localSessions = sessions | ||
| self.lastUpdatedAt = Date() | ||
| guard !Task.isCancelled, self.localMonitoringEnabled else { return } | ||
| self.applyLocalScanResult(sessions) |
There was a problem hiding this comment.
Fixed in 04df269. LocalAgentSessionScanner.scan is now @concurrent, so the synchronous ps/lsof work and transcript parsing do not inherit a MainActor caller. I kept structured concurrency instead of using a detached task, which preserves cancellation, priority, and task-local values. The 37 repair-focused tests pass and make check is clean.
|
Codex review: found issues before merge. Reviewed July 13, 2026, 2:11 AM ET / 06:11 UTC. Summary Reproducibility: not applicable. This PR proposes a new refresh default, consent preference, and activity-aware mode rather than fixing a defined current-main failure. Its runtime branches are nevertheless demonstrated with exact-head packaged proof. Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review findings
Review detailsBest possible solution: Keep the consent-gated activity signal for users who explicitly choose Adaptive, preserve the five-minute behavior for all ambiguous existing installations unless a reliable fresh-install marker is available, request notification authorization after the consent modal in the same launch, and remove the changelog edit. Do we have a high-confidence way to reproduce the issue? Not applicable: this PR proposes a new refresh default, consent preference, and activity-aware mode rather than fixing a defined current-main failure. Its runtime branches are nevertheless demonstrated with exact-head packaged proof. Is this the best way to solve the issue? No, not in its current breadth: reusing the existing scanner behind separate consent is maintainable, but coupling that feature to an ambiguous fresh-install default and delaying notification authorization creates avoidable upgrade and onboarding regressions. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c852c135e10c. Label changesLabel justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (5 earlier review cycles)
|
|
@clawsweeper re-review The two current-head blockers are fixed in
The new settings suite covers fresh persistence, both launch markers, existing config, String and non-String invalid values, and all 7 valid cadence values across fresh and marked states. The PR body now states the only historical ambiguity: a completely untouched, configless v0.1-v0.3 install left no durable signal that differs from a new install.
|
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review Head
The PR body now puts this blocker-resolution matrix before the older policy replay and states the proof limits explicitly. |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Problem
#2029 found that the replay-only activity candidate did not improve global p95 menu staleness, so that result did not support a broad production claim. Main now has the local Agent Sessions scanner from #1968, which provides an attributable Codex/Claude activity signal without adding another detector.
This PR has a narrower target: while local coding is active, an unconstrained Adaptive decision should not wait longer than the old 5-minute default. Global p95 remains unchanged.
Consent and upgrade boundary
Adaptive cadence is not permission to inspect local process or session metadata.
undecided,allowed, ordeclinedchoice. Onlyallowedenables Adaptive-only scanning.undecidedafter upgrade and perform no Adaptive-only scan until they allow it.The historical edge case is unchanged: a completely untouched, configless v0.1-v0.3 install left no durable state that can distinguish it from a new install, so that cohort follows the fresh-install default.
Consent UI
Use Menu Activity Onlyalso responds to Escape. The same six consent/settings strings are present in all supported app language catalogs.Packaged runtime proof
Redacted exact-head proof report
The proof bundle came from clean commit
2c0a41479602a8aa804139cbf50bef358e32d3da. Its embeddedCodexGitCommitis2c0a4147; the debug executable SHA-256 iseb3361e2a96e9cae269ce4490e96ed555da09ce9f802268e33af24dfc4712499.The bundle ran with network access denied, Keychain access disabled, and synthetic
HOME/CODEX_HOMEdata containing one recent fixture rollout. It did not read a real Codex or Claude transcript.adaptive+undecided; showed the prompt; 0 local session scans before a decisionadaptive, consent missingundecided; showed the prompt; 0 local session scansfiveMinutes; no prompt; 0 local session scansallowedreplayedlongIdle 1800stocodingActivity 300s; 0 Tailscale/SSH eventsdeclinedreplayedThe persisted
allowedanddeclinedstates were replayed on relaunch to isolate the two runtime branches. Focused tests cover setter persistence, reload, invalid-value repair, existing-Adaptive behavior, and the Agent Sessions bypass.Sustained scan profile
The allowed process produced scanner starts at
t+0.000s,t+31.350s, andt+63.336s. The first scan pulled the pending Adaptive timer from 30 minutes to 5 minutes eight milliseconds later. No remote discovery, remote fetch, or SSH subprocess label appeared.A 65.646-second Time Profiler recording covered the next two scans:
AgentSessionsStore.refreshLocal,LocalAgentSessionScanner.scan,LocalAgentSessionScanner.processOutput, andSubprocessRunner.run;The raw trace SHA-256 is
be7943ea0588bdb6f60d60d3ddaa3ef65453f65dea5cc505f14cd1badae786a2. The trace stays local because Instruments embeds local paths and environment values. These are sampled runtime figures, not an energy claim.Policy replay
Frozen trace: 1,780 JSONL records, SHA-256
b1e4aa33180b7c177293eb9ed16b45e24e026d259600fba2b1b67b931b904f0b.Compared with menu-only Adaptive, the activity signal adds 2 simulated refreshes (
+0.29%) and removes all 4 observed active-coding delays above 5 minutes. Compared with fixed 5 minutes, it schedules 49.7% fewer simulated refreshes. These are policy-clock results, not observed provider requests.The trace comes from one machine. Activity covers 462 of 733 decision records, and p95 remains 1093 seconds. It samples activity at reconstructed decision points rather than replaying the 30-second scanner callback; the packaged profile above covers that callback.
Validation
make check: pass; SwiftFormat clean and SwiftLint reported 0 violationsThe released
adaptive-activityreplay CLI spelling remains a deprecated alias foradaptive, whileadaptive-menu-onlynames the historical baseline.