Skip to content

fix(daemon): harden approval response correlation - #8

Draft
xuan2261 wants to merge 4 commits into
jeikl:betafrom
xuan2261:fix/daemon-approval-timeout
Draft

xuan2261 wants to merge 4 commits into
jeikl:betafrom
xuan2261:fix/daemon-approval-timeout

Conversation

@xuan2261

@xuan2261 xuan2261 commented Oct 6, 2026 •

Copy link
Copy Markdown

变更类型

  • 修复(bug / 回归)
  • 功能
  • 文档 / 规范 / 发版基建(不夹带进功能 PR;同类文档改动合并为一个 PR)
  • 是否为大功能更改、修复、更新

基于的分支与版本号

  • Base branch: beta
  • Base SHA: 5fa1f27e78988140fafeff2a21b8a124d39cbee7
  • Head SHA: 3b3a4258e6f8b605c3fe1eb9e349ea302f6acd0d
  • PR merge-ref validated by CI: 184192626f88682221029926ac1071ee2400a0d7
  • Workspace version: 7.1.53-beta.11

当前问题、对用户使用体验会产生什么问题或影响

Interactive approvals could race across /chat, native /live, clients, and desktop notifications:

  • stale or duplicate approval responses could outlive the request that created them;
  • /chat/permission could report success before the runtime had actually consumed the decision;
  • daemon and kernel approval timers could compete for ownership of the same request;
  • the first timeout-owner fix also exposed a liveness regression: setting the runtime interactive disabled the kernel timeout and caused the derived daemon-side request_timeout to become None, so /chat permission/user-input waits could become unbounded;
  • native live request ids could be reused across runtime generations without generation correlation;
  • clients could correlate permission UI primarily by provider call_id, which can be reused;
  • uncorrelated desktop approval actions could expose Approve/Deny without an exact approval identity.

User-visible impact includes stale approval cards, a reported successful approval that the runtime did not accept, a late decision being applied to the wrong request/policy boundary, or an interactive /chat request that never times out.

解决方案

  • Correlate /chat approvals by exact (session_id, approval_id) and keep per-turn Expired tombstones for timeout/cancel/duplicate rejection.
  • Derive approval_id from the persisted pending-permission checkpoint so reused provider call ids across checkpoints remain distinct.
  • Acknowledge /chat/permission only after the runtime driver accepts the exact response; dropped/rejected runtime responses fail closed.
  • Make the daemon the interactive request-timeout owner: snapshot the configured timeout before enabling interactive runtime mode, disable the kernel's competing request timeout, and use the saved timeout at the daemon permission/user-input wait seam.
  • Correlate native live approval responses by exact (session_id, generation, request_id) and reject stale runtime generations before a reused request id can be consumed.
  • Defer persistent MCP approval until the approved tool actually starts; stale/offline approvals cannot mutate policy.
  • Propagate exact approval identity through WebUI, VS Code, and JetBrains; late results cannot clear/relabel a newer reused-call-id card.
  • Only expose desktop Approve/Deny actions for correlated /chat approval URIs; notification actions post only to /chat/permission.

提交清单(组内独立、可单独回退)

提交 作用 可否单独 revert
0e9fc26a fix(daemon): harden approval response correlation End-to-end approval correlation, runtime ACK, client identity propagation and notification hardening 是
3b3a4258 fix(daemon): preserve interactive request timeout Preserve daemon-owned liveness after disabling the competing kernel timeout; add stale-generation/reused-request-id regression coverage 是

每项提交引起的变化和影响面

0e9fc26a changes the Rust approval trust boundary plus the WebUI, VS Code, JetBrains and OS-notification consumers that must carry the same exact identity.

3b3a4258 is deliberately narrow: live_api.rs preserves the configured driver timeout before interactive mode disables the kernel timeout, and live_hub.rs adds a generation-correlation regression test. No CI/release/installer/documentation changes are mixed into this PR.

Rollback: revert the relevant commit(s); no persistent schema migration or history rewrite is required.

自检(与 CI 相同的命令)

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets — not run as a new local repo-wide gate; current AGENTS.md requires targeted Rust checks and delegates broad validation to GitHub Actions.
  • cargo check --locked --lib -p jeikcode-daemon
  • cd webui && npm run build(涉及前端变动时)
  • 改动涉及的模块已在本地运行单测

Fresh exact-head verification on Windows (3b3a4258e6f8b605c3fe1eb9e349ea302f6acd0d), with isolated JEIKCODE_HOME:

  • cargo test --locked -p jeikcode-daemon permission_bridge::tests:: — 7/7 PASS
  • cargo test --locked -p jeikcode-daemon chat_permission_ — 5/5 PASS
  • cargo test --locked -p jeikcode-daemon chat_user_input_wait_ — 2/2 PASS
  • cargo test --locked -p jeikcode-daemon confirmed_response_rejects_stale_generation_before_reused_request_id — PASS
  • cargo check --locked --lib -p jeikcode-daemon — PASS
  • cargo fmt --all -- --check — PASS
  • git diff --check origin/beta...HEAD — PASS

Earlier validation of unchanged approval surfaces from 0e9fc26a also passed: live-permission/runtime-generation Rust tests, notify feature tests, WebUI targeted tests + build, VS Code compile and lane-specific permission regressions. JetBrains local execution remains environment-blocked as noted below.

Live GitHub CI on actual PR merge-ref 184192626f88682221029926ac1071ee2400a0d7 (run 37416734681):

  • Version consistency — PASS
  • Installer integrity (ubuntu-latest) — PASS
  • Installer integrity (windows-latest) — PASS
  • WebUI quality — PASS
  • Rust quality — PASS

Rust and WebUI checkout logs explicitly fetch and checkout refs/pull/8/merge and report:

HEAD is now at 184192626 Merge 3b3a4258e6f8b605c3fe1eb9e349ea302f6acd0d into 5fa1f27e78988140fafeff2a21b8a124d39cbee7

This is merge-result validation, not source-branch-only validation.

Independent review:

  • exact-head timeout/generation liveness review — CLEAN; no residual Critical/Important blocker in that seam;
  • broad final approval/cancel/persistence/client/notification liveness review — pending. This PR stays Draft until that report is inspected.

NOT YET VERIFIED:

  • JetBrains SseParserTest locally: this Windows host has no Java/JBR/JDK in PATH or common install locations. No new toolchain was installed outside this PR scope.

Known unrelated/pre-existing origin/beta issues were not changed merely to make this suite green:

  • rendering-regression.test.ts contains an LF-only source extractor that fails against a CRLF Windows checkout.
  • provider-queue-regression.test.ts calls _watchJeikCodeAuth, while origin/beta provider.ts does not define that method.
  • /chat/user-input currently correlates by raw (session_id, request_id) and the kernel interactive request counter is per newly built RequestCtx; this correlation shape already exists on origin/beta and is not an approval/policy authorization boundary. It is being tracked as a separate Phase-3 hardening follow-up rather than expanding this focused approval PR.

This PR remains Draft until the pending broad independent liveness review is available/inspected. No merge is requested.

署名

xuan2261 / JeikCode

xuan2261 and others added 2 commits October 6, 2026 11:40
Co-Authored-By: JeikCode <code@jeikcode.top>
Co-Authored-By: JeikCode <code@jeikcode.top>
@xuan2261
xuan2261 marked this pull request as ready for review October 6, 2026 06:39
Co-Authored-By: JeikCode <code@jeikcode.top>
@xuan2261
xuan2261 marked this pull request as draft October 6, 2026 07:33
Co-Authored-By: JeikCode <code@jeikcode.top>
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.

1 participant