Skip to content

feat(desktop): consolidate consent-based runtime takeover and ownership contracts - #5564

Closed
luvs01 wants to merge 16 commits into
devfrom
takeover/desktop-claim-5459
Closed

luvs01 wants to merge 16 commits into
devfrom
takeover/desktop-claim-5459

Conversation

@luvs01

@luvs01 luvs01 commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Consolidate #5459 and #5457 into one desktop ownership review. When the desktop finds an existing runtime, show the endpoint, configuration home and recorded owner before offering takeover. Approval uses the bundled CLI to stop, claim and start the runtime; declining preserves guest attachment. Unknown ownership, incompatible managing CLIs and unproven stop outcomes remain explicit failures or blocked takeover states.

  • Carry all seven implementation contributions from feat(desktop): ask consent on attach and take over a foreign runtime with the bundled CLI #5459, preserve its inline consent script after the current desktop CSP/bootstrap changes, and retain contributor attribution.
  • Carry docs(desktop): state runtime takeover acceptance #5457's ownership acceptance documentation and four contract tests. Clarify the existing distinction: relaunch consent reuse compares owner and installation ID, while a pending write revalidates the complete ownership subject, including consent generation.
  • Integrate consent waiting with the current startup deadline. Consent, deadline and expiry publication share one lock; terminal state protection also covers delayed progress reports, so a late run cannot reopen a prompt after expiry. A reporting gate serializes state publication with event dispatch, preserving the same order on the page.

The source PRs remain open and unchanged. This proposal does not decide the separate policy questions around a stopped-but-unclaimed runtime or plain ocx start with a foreign owner. The existing retry rejection while a stalled run remains active is also unresolved; clearing the running flag alone would permit overlapping runs.

Verification

  • Source heads: feat(desktop): ask consent on attach and take over a foreign runtime with the bundled CLI #5459 c0c6dd2ba4c81e4e40425020649573145e857073; docs(desktop): state runtime takeover acceptance #5457 8ed791675d6254e9eb09ca333888ab2a7bfa3dd8.
  • Final integration head: 8d6b1e15d8cf9afed0d15c075810af4bb53e8275, based on dev a6b54297b03fc218105273887ce147c901848d89. All seven source carries preserve author, author date and credit. Five clean carries have equal zero-context patch IDs; two adapted carries preserve the current bootstrap and deadline integration. All 20 source file occurrences were classified; 13 implementation or test files match feat(desktop): ask consent on attach and take over a foreign runtime with the bundled CLI #5459 byte-for-byte, and docs(desktop): state runtime takeover acceptance #5457's four added contract tests are preserved.
  • Earlier integrated CLI/desktop/service focused checks: 75 passed. The carried ownership contract file separately passed 13 tests. TypeScript and structure checks passed at the earlier integration head. The consent/expiry correction's surface checks passed 21 tests; these executions are separate evidence, not a final full-suite result.
  • Integrated desktop contract/surface checks at e6277c19: 49 passed / 0 failed / 260 assertions across four files. The subsequent two commits contain only Rust formatting and terminal-payload indirection; TypeScript, documentation and test files are unchanged. The test wrapper installed missing dashboard dependencies into a normal directory in the isolated worktree; no shared dependency junction or live runtime was changed.
  • Integrated TypeScript, structure SSOT, privacy and whitespace checks passed. Independent static review found the reported consent, terminal-publication and event-order races closed.
  • Six new Rust regressions cover expiry publication, pending and answered consent, terminal prompt refusal, superseded guards, late reports and event order. Hosted validation first required one method-chain formatting correction, then flagged the 264-byte terminal payload in the expiry enum. 8d6b1e15d8 boxes that payload without changing the state machine or emitted data. The exact-head desktop shell job now passed Rust formatting, Clippy and Rust unit tests. Earlier failures are retained as such; no local Cargo execution is claimed.
  • The consent page was rendered headlessly from the actual inline bootstrap page with synthetic IPC, endpoint and ownership data. This proves the displayed fixture only; actual takeover and platform WebView behavior remain unverified. Consent surface capture.
  • The same hosted run subsequently ended cancelled with the remaining macOS jobs cancelled; its aggregate ci check reports failure. The completed Rust job remains a pass, but this is not a full cross-platform pass. Cancellation cause is not established by the available job records, and no automatic rerun is claimed.
  • This remains draft. Full cross-platform CI, explicit security review and real desktop takeover validation are outstanding. No timeout, test skip or production budget was relaxed.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Co-authored-by: jun bitkyc08@gmail.com
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: sanggyulee andy53295774@gmail.com

lidge-jun and others added 14 commits September 22, 2026 22:51
…d service claim

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 1cc2446)
…he bundled CLI

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 9457ae0)
…g prompt on retry

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 6649301)
…ries

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 2fdcf94)
…ver start path

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 07697f9)
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 5143843)
…laim honest about unknown records

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit c0c6dd2)
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… boundaries

Carries the acceptance text and contract tests of upstream #5457 (source 8ed7916). The generation clause is corrected: relaunch reuse compares owner and installId only, while the write path revalidates the full subject including consentGeneration.

Co-authored-by: sanggyulee <andy53295774@gmail.com>
Synthetic fixture render of desktop/ui/index.html at cd58b63 under headless Chrome; the consent panel shows the port, the configuration home and the recorded owner with both choices enabled. No live app, proxy or service was touched.
…ansitions

The guard previously read consent and the deadline under separate locks and published
the terminal state after releasing them, so a prompt posted between the check and the
publish could be overwritten by Failed while the run kept waiting on a decision nobody
could see. The consent state and the deadline now live under the run's live lock:
expire_run performs the expiry check and the failure publish in one critical section,
await_consent refuses to post a prompt once the run is terminal, and the answer's
deadline extension and prompt clear land as one write.

Adds synchronous unit tests for the expired-publish, pending-blocks-expiry,
terminal-posts-no-prompt and superseded-guard paths. Not run: no cargo toolchain on
this machine.
A probe resuming after the expiry landed could move the terminal state back to a live phase, which also reopened the consent gate the terminal state had just ruled out. Live::publish now refuses any report once the run is settled, emit follows that refusal so a stale event never reaches the page, and finish does not navigate the window away from a terminal state it could not publish. The expire -> late report -> await_consent sequence is pinned by a regression test.
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 22, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 58 / 80

이 PR은 데스크톱이 이미 떠 있는 런타임을 만났을 때, 그냥 손님으로 붙을지 주인으로 가져갈지 사용자에게 묻고, 가져가기로 하면 번들 CLI로 멈추고·소유를 적고·다시 시작하는 흐름을 한곳에 모은 작업이다. 원래 열려 있던 #5459(실제 가져가기·동의 UI·클레임)와 #5457(소유 수락 규칙·계약 테스트)을 dev 위로 한데 합쳤고, 동의 대기와 시작 마감·만료 실패·늦은 진행 보고가 서로 끼어들어 화면이 다시 열리거나 실패가 덮이지 않도록 잠금/보고 게이트도 고쳤다. 거절하면 손님으로 붙고, 소유를 못 읽거나 관리 CLI가 맞지 않으면 가져가기를 막는다. 초안(draft)이며 작성자도 정책·실기기 검증이 아직이라고 적어 두었다.

라인 - desktop/src-tauri/src/startup.rs take_over: 정지는 됐는데 service claim이 실패하면 런타임은 꺼진 채 소유 기록이 없는 상태로 끝난다. 코드/문서상 “다음 실행이 부재로 시작”을 허용하지만, 다른 설치·CLI가 그 공백을 어떻게 봐야 하는지는 아직 정책으로 닫히지 않았다.
라인 - desktop/ui/index.html 동의 안내: 가져가기 후에도 터미널의 평문 ocx start는 아직 막지 않는다고 화면에 적어 두었다. 동의로 주인이 바뀌었다고 사용자가 믿기 쉬운데, 실제 차단 범위는 ocx service start 쪽에 가깝다.
라인 - Startup.running / 재시도: PR 본문이 말하듯, 멈춘 채 running만 남은 실행이 있을 때 Retry만으로 겹쳐 돌 수 있는 문제는 이 PR에서 풀지 않았다. 동의·만료 레이스는 줄였지만 재시도 겹침은 남는다.
라인 - 검증 구멍: 작성 머신에 Cargo가 없어 로컬 Rust 실행이 없고, 보안 체크리스트도 미체크·draft다. TS/표면 테스트와 Rust 회귀 추가는 있으나, 실기기 가져가기·호스트 Rust/Clippy 통과를 머지 전 증거로 못 본다.
라인 - 원본 PR: #5459, #5457이 여전히 OPEN이다. 이 PR이 둘을 통합·대체하는 제안이면 무효/중복으로 닫을지 정리해야 한다.

메인테이너의 판단이 필요한 지점

정지 후 클레임 실패를 “허용된 부재”로 둘지, 아니면 복구·재시도·명시적 handback이 필요한 실패로 올릴지. 평문 ocx start를 언제 ownership-aware로 막을지(이 PR 범위 밖인지). draft를 ready로 올리기 전에 필수인 증거 목록(호스트 Rust 테스트, 실기기 takeover, 보안 리뷰)을 어디까지로 할지. #5459/#5457을 이 PR에 흡수해 닫을지.

너의 추천

방향(동의→정지 증명→클레임→시작, unknown/비호환은 손님·차단, 동의·마감 원자성)은 dev에 올릴 만한 한 줄기다. 다만 draft인 채 머지하지 말고, 호스트 Rust/포맷/Clippy와 실제 데스크톱 가져가기를 통과시킨 뒤 ready로 올린다. 정지·미클레임과 평문 ocx start는 머지 차단 이슈가 아니면 follow-up 이슈로 번호를 박고, #5459·#5457은 이 PR이 대체한다면 닫는 쪽이 맞다. 보안·소유권 경계라 체크리스트와 별도 보안 리뷰는 비워 두지 말 것.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun

Copy link
Copy Markdown
Owner

Carried into #5619 at 8d6b1e1 with your authorship and the co-author trailers kept. The review screenshot stays in the #5619 description instead of the tree. Follow-ups revalidate ownership right before the stop and bind it to the approved runtime through an opt-in guarded stop. Unresolved or unreadable outcomes now fail closed before any claim. Closing in favor of #5619. Thank you!

@lidge-jun lidge-jun closed this Sep 23, 2026
lidge-jun added a commit that referenced this pull request Sep 23, 2026
… fixes (#5619)

* fix(cursor): bound capability reads and buffered tool budgets (#5533)

Carries #5533 (and the closed #5233 it consolidates) onto current dev.

Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(moonshot): bound normalized tool-schema expansion (#5547)

Carries #5547, which consolidates #5464 and the request-wide inline budget, onto current dev.

Co-authored-by: yeongjunyoo <47925973+yeongjunyoo@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(moonshot): restore rejected inline budgets and charge nested growth once

A rejected sibling-reference expansion now restores the byte, node and expansion allowances it consumed, and outer growth no longer re-charges nested copies, so later independent expansions in the same request keep their allowance. Documents the provider-driven object type inference as a deliberate tradeoff and rewrites ADR-0355 in English.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* feat(reasoning): consolidate replay, opt-in tag parsing, and summary policy (#5566)

Carries #5566, which consolidates #5449, #5205 and #5491, onto current dev. The provider guide keeps the current bridge replay paragraph and adds the inline-tag and summary paragraphs.

Co-authored-by: Joonsuh Park <trckstr4422@gmail.com>
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
Co-authored-by: alexph-dev <alexph-dev@users.noreply.github.com>
Co-authored-by: Yum-wu <1172989563@qq.com>

* fix: bound Fernet slot runs, Kiro error-body read, and skill-path line slice (#5310)

Carries #5310 onto current dev. The follow-up commit makes the Fernet run cap fail closed and moves the Kiro regression out of the capped stream suite.

* docs(reasoning): reconcile inline-tag whitespace contract

Interleaved inline-tag parsing preserves answer whitespace; only Kiro single-block mode drops the whitespace after its leading block.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(responses): fail closed on Fernet run overflow and keep the Kiro suite under its cap

A slot with more than 64 structurally valid Fernet runs is now treated as unreadable or omitted as a whole, so no unexamined tail reaches the provider as text. The bounded Kiro fallback error-body regression moves byte for byte into a registered sibling file, and the Kiro, Responses and inbound contracts document the new bounds.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): scan inline think tags with a moving cursor

The parser copied, rescanned and reserved the whole remaining response after every block, so one upstream chunk carrying many short blocks cost quadratic work. It now scans each chunk from an offset and charges the translator budget only for retained carry: undecided leading input or a trailing tag fragment.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): keep undecided leading whitespace incremental

Before the format was decided, every content delta rebuilt, trimmed and re-reserved the whole leading prefix, so a stream of one-character whitespace deltas cost quadratic work. Leading whitespace is now kept in segments whose bytes are reserved once and joined only when the format is decided or the stream flushes.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(meta-muse): consolidate login admission and bounded response handling (#5591)

Carries #5591, which consolidates the closed #5234 and #5432, onto current dev. The provider contract keeps the inline-tag paragraph and adds the Meta Muse admission paragraph.

Co-authored-by: Epinephrine <luvs01@hanmail.net>

* fix(claude-desktop): keep applied state consistent across profile edits (#5590)

Carries #5590, which consolidates the closed #5337, onto current dev.

Co-authored-by: Epinephrine <luvs01@hanmail.net>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>

* fix(claude-desktop): commit applied markers only over the observed baseline

Both Desktop writers, provider-change auto-apply and client sync, now capture the desired profile and its applied marker before the Desktop write and commit the new marker only if profile presence, content, fingerprint and timestamp are unchanged. A concurrent edit, deletion or newer marker keeps its state and the write reports a skipped marker. The provider-change path no longer saves a whole stale config snapshot.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude-desktop): commit profile edits against the persisted marker

The Desktop profile PUT built its response from an earlier snapshot and saved that whole snapshot, so a marker committed by another writer during the awaited state build could be replaced by an older one. The edit now commits in one persisted-config mutation that keeps the latest marker for unchanged content and answers 409 when the profile itself changed meanwhile. The Meta Muse overflow test now asserts that the bounded-body limit, not a generic failure, produced the error.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude-desktop): report an unreadable config separately from an edit conflict

A missing or invalid config now answers 500 with its reason; only a concurrent profile change or exhausted rebase answers 409.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* feat(desktop): consolidate consent-based runtime takeover and ownership contracts (#5564)

Carries #5564, which consolidates #5459 and #5457, onto current dev. The review screenshot stays in the pull request description rather than the tree.

Co-authored-by: jun <bitkyc08@gmail.com>
Co-authored-by: sanggyulee <andy53295774@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(desktop): bind takeover stop to the approved runtime and fail closed

Desktop takeover re-resolves ownership immediately before stopping and passes the approved PID, endpoint, config home, CLI version and compatibility token to an opt-in guarded stop. The guard is checked under the ownership mutation lease before any manager or signal stop; the approved PID and endpoint must settle and the service manager must then be proven inactive, otherwise the stop answers approval-changed or manager-still-active and the desktop neither waits for silence nor claims. Unreadable or unparseable stop output is terminal as well. A second unreadable service-state read now blocks takeover, Windows managing-CLI discovery follows PATHEXT with file-only candidates and refuses command-interpreter metacharacters, the claim refusal test uses real sandbox state, and the runtime and desktop contracts record that the claim token is a consistency check rather than consent proof. Plain ocx stop is unchanged.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(desktop): keep plain stop entry points and format the takeover changes

Desktop exit keeps its plain runtime_stop::run entry while takeover uses run_approved, AttachPlan::Ask no longer carries an unread field, the Rust changes follow rustfmt, the plain CLI stop path keeps its literal outcome return, the stop source oracles follow the reader and outcome union that now include the two guarded refusals, and the runtime contract fits its 600-line budget.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(desktop): run takeover seam tests without tokio macros and harden manager and shim checks

The two async takeover seam tests now run on the shell runtime already used by the crate instead of tokio test macros, which this crate does not enable. Windows command-shim probes refuse command-interpreter metacharacters in every recorded argument as well as the executable, and the guarded stop re-inspects the service manager identity immediately before the manager command, answering approval-changed without stopping if it moved.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(responses): keep effort-based reasoning visible after routing

Final-route normalization recomputed hideThinkingSummary without the validated active-effort condition, so routed Chat and Kiro requests with an active effort and an omitted summary still hid raw reasoning. It now uses the same predicate as the parser; explicit "none" and requests without an active effort stay hidden.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): match the running CLI case-insensitively only on Windows

On case-sensitive filesystems a PATH executable that differs only in case is a different file, so it must get its own version probe instead of reporting the running CLI version.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(meta-muse): require the dashboard session for manual login codes

The manual-code continuation now applies the same dashboard-session admission as the login start, so a management token cannot advance a pending Meta Muse login.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(reasoning): reserve the joined leading-whitespace copy

Joining retained leading whitespace allocated a second copy outside the translator budget; the join is now reserved first and released once the segments are cleared.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): skip CLI probes for an absent runtime and treat failed systemd units as stopped

Resolve no longer spawns managing-CLI version probes when no runtime is live, since takeover is only offered for a live runtime. A systemd unit reported failed with no main PID is stopped, so a guarded stop that leaves it failed succeeds and a leftover failed unit does not block takeover.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): keep failed systemd units fail-closed and assess takeover only for a live runtime in tests

systemd can report failed before an automatic restart, so failed with no main PID is again treated as unknown rather than stopped. The resolve contract tests that assert ownership and takeover fields now use a live runtime, matching the skip of managing-CLI probes when no runtime is live.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: Epinephrine <luvs01@hanmail.net>
Co-authored-by: yeongjunyoo <47925973+yeongjunyoo@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Joonsuh Park <trckstr4422@gmail.com>
Co-authored-by: Daniel Sjöstrand <16033062+Danielsjostrand1979@users.noreply.github.com>
Co-authored-by: alexph-dev <alexph-dev@users.noreply.github.com>
Co-authored-by: Yum-wu <1172989563@qq.com>
Co-authored-by: luvs01 <luvs01@users.noreply.github.com>
Co-authored-by: sanggyulee <andy53295774@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants