Skip to content

fix: harden desktop startup and diagnostics - #343

Merged
pedronauck merged 3 commits into
mainfrom
app-start-issue
Aug 11, 2026
Merged

pedronauck merged 3 commits into
mainfrom
app-start-issue

Conversation

@pedronauck

@pedronauck pedronauck commented Aug 11, 2026 •

Copy link
Copy Markdown
Member

Summary

  • make the packaged desktop start or attach to its managed daemon without requiring a manual compozy daemon start, while refusing to kill or replace a process whose ownership cannot be proved
  • replace the unhelpful crash-only boot path with retryable, typed startup errors and safe diagnostics available from both the desktop and compozy app diagnose
  • gate desktop publication on clean-home DMG/AppImage smoke checks and document the new startup, support-bundle, and release contracts

Root cause

The reported api: stream shutdown bridge not provided warning was construction-time noise, not the crash cause. The failure involved daemon identity timing, publishing readiness state before startup was actually complete, and release provisioning paths that were not proven from a clean machine. Removing ~/.compozy happened to clear the stale state, but it was not a safe or acceptable recovery mechanism.

Changes

Daemon and desktop lifecycle

  • record the daemon's real operating-system start time and publish daemon.json only after fallible initialization and transports are ready
  • remove the misleading stream-shutdown warning when the caller context is the intended fallback
  • start, attach, wait, or recover through one ownership-aware resolver
  • require bounded forward timestamp drift, PID identity, executable hash, and desktop provenance before recovery can terminate a managed process
  • never delete the user's Compozy home and never terminate an unproven operator-owned daemon
  • preserve graceful TERM plus the existing timeout for normal update shutdown; force termination is limited to ownership-proven recovery
  • flow the packaged Tauri version into app state and diagnostics instead of relying on the Rust crate version

Visible startup errors and diagnostics

  • keep the Tauri event loop alive for expected control-server and boot-window failures, publish typed safe errors, and expose retry from the boot window
  • show real download, verify, install, and start progress with attempt information
  • persist a required schema-version-1 DiagnosticReport in app.json, including boot phase, app/runtime versions, safe current error, and correlated previous-crash metadata
  • add a locked startup marker and panic/bootstrap logging so concurrent launches and PID reuse cannot corrupt crash attribution
  • add desktop actions for loading, copying, and explicitly exporting diagnostics
  • add compozy app diagnose [-o json] plus --bundle --yes [--bundle-output], with offline fallback only when the desktop socket is absent
  • export an atomic, no-clobber, mode-0600 archive containing only manifest.json and optional redacted current-boot desktop log tails; daemon logs, configuration, credentials, sessions, transcripts, and raw home paths are excluded

Release, docs, and QA

  • fail release builds when channel or signing inputs are absent
  • run signed macOS DMG and Linux AppImage clean-home smoke after desktop-build and before desktop-publish
  • verify daemon PID/home/status and app, diagnostic, runtime, provenance, and channel metadata in the artifact smoke
  • update desktop operations, support-bundle, getting-started, CLI, official Compozy skill, release-contract, journey, charter, scenario, and automation-backlog documentation

The artifact smoke intentionally provisions the current signed production runtime manifest because the immutable package embeds the production channel. Candidate runtime bytes and signatures are verified later by desktop-publish; publication cannot happen until the package smoke passes.

Test plan

  • make gate-full — full monorepo gate, fingerprint 89ed220f2d88122c11399671a97197fcbee8868c
  • focused Go race tests for CLI, daemon, and API control surfaces
  • desktop formatting, check, all-target tests, lint, and desktop test targets
  • release-build missing-input failure contract
  • site typecheck, generated CLI reference, and codegen checks
  • isolated macOS runtime/CLI walk covering self-start, same-PID attach, one listener, runtime survival after desktop quit, live/offline diagnostics, stale-socket failure, consent, redaction, permissions, allowlisting, and no-clobber export
  • QA evidence audit with zero blockers and zero warnings; teardown recorded clean: true with no survivors
  • signed macOS DMG and Linux AppImage UI/artifact smoke — mandatory release CI gate before publication

QA report: docs/qa/reports/2026-08-11-desktop-startup-diagnostics.md

QA status

BLOCKED only for the signed-package verification that cannot be produced from this local working tree. Every locally executable runtime and CLI leg passed. The four affected scenarios remain blocked-verify until the mandatory release artifact matrix runs; they are not recorded as product passes prematurely.

Compozy Impact Audit

  • Native tools: no tool IDs, toolsets, descriptors, schemas, digests, risk flags, or capability gates changed; checked the native-tool registry and metadata surfaces. The new agent-manageable interface is the existing CLI/private desktop-control path.
  • Extensibility and hooks: no extensions, hooks, registries, bridge SDKs, MCP sidecars, capabilities, or config.toml keys changed; checked runtime config and desktop release configuration. Desktop/runtime references in the official skill were updated for the public CLI behavior.
  • Workspace data isolation: diagnostics and startup ownership data are global to the selected COMPOZY_HOME; no workspace-, session-, or agent-scoped data is included. HTTP, UDS, SSE, cache, and event ownership paths are unchanged, and support bundles explicitly exclude workspace/session content.
  • Official Compozy skill: updated skills/compozy/references/desktop.md and skills/compozy/references/runtime-operations.md for self-start, typed diagnosis, offline behavior, consent, and support-bundle limits.

Release notes

🐛 Bug Fixes

  • Harden CompozyOS desktop startup, recovery, and offline diagnostics.

Summary by CodeRabbit

  • New Features
    • Added clearer startup progress, retry actions, and accessible boot status messaging.
    • Added structured diagnostics with crash history, runtime details, error codes, and technical details.
    • Added app diagnose output in multiple formats, including consent-based diagnostic bundle export.
    • Diagnostic bundles include redacted, size-limited logs and secure archive handling.
  • Bug Fixes
    • Improved runtime detection and recovery after restarts, updates, and timestamp mismatches.
    • Improved update progress and verification feedback.
    • Prevented sensitive local paths from appearing in reported errors.
  • Reliability
    • Improved startup failure reporting and release-build configuration validation.

@vercel

vercel Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
compozy-site Ready Ready Preview Aug 11, 2026 9:55pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cab91777-0c23-4dd7-b70c-204aca1ddff7

📥 Commits

Reviewing files that changed from the base of the PR and between eb33046 and b3a5580.

📒 Files selected for processing (4)
  • desktop/src-tauri/src/diagnostics/export_tests.rs
  • desktop/src-tauri/src/diagnostics/report.rs
  • internal/cli/app_diagnose_bundle_logs.go
  • scripts/smoke-desktop-release-artifact.sh
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/cli/app_diagnose_bundle_logs.go
  • scripts/smoke-desktop-release-artifact.sh
  • desktop/src-tauri/src/diagnostics/export_tests.rs
  • desktop/src-tauri/src/diagnostics/report.rs

Walkthrough

The desktop now validates release inputs, records structured startup diagnostics, handles verified runtime recovery, renders boot progress, exposes diagnostic controls, and supports secure diagnostic bundle creation through the desktop and CLI.

Changes

Desktop diagnostics and runtime lifecycle

Layer / File(s) Summary
Release validation and daemon metadata
desktop/src-tauri/build.rs, desktop/src-tauri/release_build_contract.rs, internal/daemon/..., desktop/src-tauri/tests/contracts.rs
Release builds validate channel, Tauri configuration, updater settings, and signing credentials. Daemon metadata records the operating-system process start time after startup completes.
Structured diagnostics and startup state
desktop/src-tauri/src/diagnostics/..., desktop/src-tauri/src/app_state.rs, desktop/src-tauri/src/record.rs, desktop/src-tauri/src/main.rs, desktop/src-tauri/src/errors.rs
Startup markers, diagnostic reports, redacted logs, typed errors, runtime metadata, and persisted diagnostic records were added.
Runtime resolution and recovery
desktop/src-tauri/src/runtime/..., desktop/src-tauri/src/shell.rs
Runtime resolution now handles recorded daemons and bounded boot-timestamp drift. Verified runtimes can attach or recover through controlled termination.
Boot progress and control actions
desktop/src-tauri/pages/boot.*, desktop/src-tauri/src/boot_window.rs, desktop/src-tauri/src/controller.rs
The boot page renders progress and structured diagnostics. Retry, report, copy, and export actions validate control responses and expose accessible status information.
CLI diagnostic reports and bundles
internal/cli/app_diagnose*.go, internal/cli/app.go, internal/cli/app_control.go
The app diagnose command retrieves live or persisted reports, emits several formats, and creates consent-gated diagnostic bundles with archive and path validation.
Validation and smoke tests
desktop/src-tauri/tests/*, internal/cli/app_test.go, scripts/*, internal/api/core/*
Tests cover release contracts, runtime recovery, diagnostic redaction, archive safety, permissions, symlink rejection, and packaged release startup.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.40% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes to desktop startup hardening and diagnostics.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch app-start-issue

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.

@greptile-apps

greptile-apps Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

Greptile Summary

The PR hardens desktop startup, daemon ownership checks, diagnostics, and release validation.

  • Delays daemon readiness publication until initialization and transports are ready.
  • Adds ownership-aware desktop runtime attachment, startup recovery, and retryable errors.
  • Adds structured diagnostics and consent-based support-bundle export.
  • Gates desktop publication on packaged macOS and Linux smoke checks.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the available follow-up review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
desktop/src-tauri/src/runtime/resolver.rs Centralizes ownership-aware runtime attachment, startup, and recovery decisions.
desktop/src-tauri/src/diagnostics/export.rs Adds constrained, no-clobber diagnostic bundle export with private output permissions.
internal/cli/app_diagnose.go Adds structured live and offline desktop diagnosis with explicit bundle consent.
internal/daemon/boot.go Moves daemon discovery publication behind fallible initialization and readiness.
.github/workflows/release.yml Adds packaged desktop smoke jobs as prerequisites for publication and finalization.
scripts/smoke-desktop-release-artifact.sh Validates clean-home packaged startup, runtime identity, diagnostics, and teardown.

Sequence Diagram

sequenceDiagram
  participant Desktop
  participant Resolver
  participant Daemon
  participant Diagnostics
  participant ReleaseCI

  Desktop->>Resolver: Resolve installed or running runtime
  Resolver->>Daemon: Verify PID, start time, hash, and provenance
  alt Compatible daemon is ready
    Daemon-->>Desktop: Identity and product origin
  else No compatible daemon
    Resolver->>Daemon: Provision and start managed runtime
    Daemon-->>Desktop: Publish readiness after transports start
  else Startup fails
    Resolver-->>Desktop: Typed safe startup error
    Desktop->>Diagnostics: Persist report and offer retry/export
  end
  ReleaseCI->>Desktop: Smoke packaged app with clean home
  Desktop-->>ReleaseCI: Runtime and diagnostic metadata
  ReleaseCI->>ReleaseCI: Permit publication only after smoke passes
Loading

Reviews (3): Last reviewed commit: "fix: remove review teardown injection ri..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🧹 Nitpick comments (15)
internal/daemon/restart_integration_test.go (1)

199-201: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the persisted replacement start time.

Lines 199-201 inject the replacement process start time, but the test does not verify that the restart operation stores it. A regression that omits or replaces this identity value can still pass. Assert that the persisted replacement start-time field equals the injected value.

As per path instructions, “Ensure tests verify behavior outcomes, not just function calls.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/daemon/restart_integration_test.go` around lines 199 - 201, Update
the restart integration test around the processStartedAt stub to retain the
injected timestamp and assert that the persisted replacement start-time field
equals that exact value after the restart operation. Verify the stored outcome
rather than only the injected function call, while preserving the existing
restart assertions.

Source: Path instructions

desktop/src-tauri/src/health_monitor.rs (1)

279-322: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the negative case for boot-timestamp drift.

The test asserts only is_some(). FakeProbe returns a Compozy identity for every call, so the assertion passes whenever the drift branch attaches, including when ownership verification is removed. Add a case where the executable is not app-owned, or where the provenance hash does not match, and assert observed_identity returns None. Also assert that the returned identity carries the recorded PID, so the test fails when the branch attaches to the wrong process.

💚 Suggested additional assertions
-        assert!(observed_identity(&home, &processes, &probe).is_some());
+        let observed = observed_identity(&home, &processes, &probe).expect("drift runtime attaches");
+        assert_eq!(observed.record.pid, record.pid);
+
+        let foreign = FakeProcesses {
+            starts: HashMap::from([(record.pid, observed_start)]),
+            executables: HashMap::from([(record.pid, PathBuf::from("/usr/bin/other"))]),
+        };
+        assert!(observed_identity(&home, &foreign, &probe).is_none());

As per path instructions: "Verify tests can fail when business logic changes".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/health_monitor.rs` around lines 279 - 322, Add negative
coverage to the test around observed_identity: use a non-app-owned executable or
mismatched provenance hash and assert it returns None, while retaining the valid
case and asserting the returned identity contains record.pid. Ensure the test
verifies both ownership/provenance rejection and correct PID attachment for the
forward boot-timestamp drift branch.

Source: Path instructions

desktop/src-tauri/src/shell.rs (1)

235-292: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the shared RecordedDaemonStart handling.

The Awaiting and StartTimeMismatch arms are identical except for the recovery call. Both repeat the recovery_attempted guard and the four-outcome match. A small helper removes the duplication and keeps the two paths in sync when outcomes change.

♻️ Suggested consolidation
+    fn handle_recorded_start(
+        &self,
+        recovery_attempted: &mut bool,
+        start: impl FnOnce() -> RecordedDaemonStart,
+    ) -> bool {
+        if *recovery_attempted {
+            self.publish_error(ShellErrorCode::RuntimeStartFailed);
+            return false;
+        }
+        match start() {
+            RecordedDaemonStart::Attached { identity, owned } => {
+                self.finish_attach(*identity, owned);
+                false
+            }
+            RecordedDaemonStart::Recovered => {
+                *recovery_attempted = true;
+                true
+            }
+            RecordedDaemonStart::Unverified => {
+                self.publish_error(ShellErrorCode::RuntimeUnhealthy);
+                false
+            }
+            RecordedDaemonStart::Failed => {
+                self.publish_error(ShellErrorCode::RuntimeStartFailed);
+                false
+            }
+        }
+    }

Each arm then calls the helper and continues the loop only when it returns true.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/shell.rs` around lines 235 - 292, Extract the shared
recovery-attempt guard and RecordedDaemonStart outcome match into a helper near
the surrounding shell logic, accepting the appropriate recovery result and
returning whether the caller should continue. Update both Resolution::Awaiting
and Resolution::StartTimeMismatch arms to call this helper, preserving their
distinct recovery functions and existing attach, retry, unhealthy, and failure
behavior.
desktop/src-tauri/src/diagnostics/export_tests.rs (1)

140-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the size limit.

The suite covers consent, redaction, permissions, collisions, and symlinks. DiagnosticExportError::TooLarge and the removal of the oversized bundle at export.rs lines 72-75 are untested. Write a log file large enough to exceed MAX_DIAGNOSTIC_BUNDLE_BYTES, then assert both the error and that no bundle file remains.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/diagnostics/export_tests.rs` around lines 140 - 195,
The diagnostic export tests need coverage for oversized bundles. Add a test
alongside the existing export tests that creates a log file exceeding
MAX_DIAGNOSTIC_BUNDLE_BYTES, invokes export, asserts
DiagnosticExportError::TooLarge, and verifies the generated bundle path does not
remain.
internal/cli/app_diagnose_bundle_logs.go (2)

129-148: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Confirm the intended behavior when a line exceeds the remaining budget.

The loop calls continue when a redacted line would cross appDiagnosticBundleLogTailMaxBytes. Later, shorter lines are still appended. The result is a tail with gaps in the middle rather than a contiguous suffix. If a contiguous tail is the contract for the support bundle, use break instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/app_diagnose_bundle_logs.go` around lines 129 - 148, The
redacted log tail should remain a contiguous suffix when a line exceeds the
remaining appDiagnosticBundleLogTailMaxBytes budget. Update
redactAppDiagnosticBundleLogTail to stop processing subsequent lines at that
boundary instead of skipping the oversized line and appending later lines.

207-226: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Resolve the user home directory once per tail, not once per line.

redactAppDiagnosticBundleLogMessage calls os.UserHomeDir() for every log line. Pass the resolved home from redactAppDiagnosticBundleLogTail instead. This also makes the failure behavior explicit: today a os.UserHomeDir() error silently drops every line in the tail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/app_diagnose_bundle_logs.go` around lines 207 - 226, Resolve
os.UserHomeDir once in redactAppDiagnosticBundleLogTail and pass the result into
redactAppDiagnosticBundleLogMessage for each line. Update the redaction helper
signature and remove its per-line home-directory lookup, while preserving
explicit handling of resolution errors in the tail flow rather than silently
dropping individual lines.
internal/cli/app_diagnose_bundle_archive.go (1)

219-221: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Report an empty bundle file with an accurate message.

The size check returns "exceeds its size limit" for both an empty file and an oversized file. An operator who receives this message for a 0-byte bundle gets misleading guidance. Split the two conditions.

♻️ Proposed message split
-	if info.Size() < 1 || info.Size() > appDiagnosticBundleMaxBytes {
-		return errors.New("app diagnose: app control bundle exceeds its size limit")
-	}
+	if info.Size() < 1 {
+		return errors.New("app diagnose: app control bundle is empty")
+	}
+	if info.Size() > appDiagnosticBundleMaxBytes {
+		return errors.New("app diagnose: app control bundle exceeds its size limit")
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/app_diagnose_bundle_archive.go` around lines 219 - 221, Update
the size validation in the app diagnose bundle archive flow to handle
info.Size() < 1 separately from info.Size() > appDiagnosticBundleMaxBytes:
return an accurate empty-bundle error for zero-byte files, while preserving the
existing size-limit error for oversized bundles.
internal/cli/app_test.go (1)

345-379: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the remaining archive validation rules.

This subtest covers the unexpected-entry rejection only. validateAppDiagnosticBundleArchiveEntry in internal/cli/app_diagnose_bundle_archive.go also rejects duplicate entries, oversized manifest entries, oversized log entries, and an aggregate size above appDiagnosticBundleContentMaxBytes. These are the boundary rules that protect the bundle reader from a hostile archive. Extend this suite with table cases for each rule.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/app_test.go` around lines 345 - 379, Extend the diagnostic
bundle archive validation tests around the existing “Should reject an unexpected
live bundle entry” subtest with table-driven cases covering duplicate entries,
manifest entries exceeding their limit, log entries exceeding their limit, and
aggregate content exceeding appDiagnosticBundleContentMaxBytes. Build valid
archive fixtures for each case, invoke readAppDiagnosticBundleManifest, and
assert rejection with the appropriate validation error.

Source: Path instructions

desktop/src-tauri/src/diagnostics/report.rs (1)

75-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share one phase vocabulary with the startup marker.

boot_phase_from_state produces the phase strings, and is_diagnostic_phase in diagnostics/startup_marker.rs validates them from a second hardcoded list. If one list changes, marker_document_is_valid silently rejects valid markers and previous-crash data disappears. Consider a shared constant slice, or make is_diagnostic_phase reuse the same source list.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/diagnostics/report.rs` around lines 75 - 87, The phase
vocabulary in boot_phase_from_state and is_diagnostic_phase is duplicated;
centralize it so both validation and state mapping use the same source of truth.
Update the diagnostics phase definition and make is_diagnostic_phase reuse it,
while preserving the existing strings returned by boot_phase_from_state and
marker_document_is_valid behavior.
desktop/src-tauri/src/runtime/update_cadence.rs (1)

6-13: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

The cadence thread cannot be stopped.

The loop never exits and the thread holds a strong Arc<DesktopController>. The controller is therefore never dropped, and an update check can start while the application shuts down. Hold a Weak reference so the thread ends after the controller is dropped, or pass an explicit stop flag.

♻️ Proposed change using a weak reference
-pub fn spawn(controller: Arc<DesktopController>, interval: Duration) {
+pub fn spawn(controller: &Arc<DesktopController>, interval: Duration) {
+    let controller = Arc::downgrade(controller);
     std::thread::spawn(move || {
         loop {
             std::thread::sleep(interval);
-            controller.check_updates();
+            let Some(controller) = controller.upgrade() else {
+                return;
+            };
+            controller.check_updates();
         }
     });
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/runtime/update_cadence.rs` around lines 6 - 13, Update
update-cadence::spawn to downgrade the controller Arc to a Weak reference before
starting the thread, then upgrade it inside the loop before calling
check_updates and exit when upgrading fails. Ensure the spawned thread no longer
retains a strong DesktopController reference during shutdown.
desktop/src-tauri/src/main.rs (1)

182-197: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

The panic guard suppresses every panic after the first one.

writing_panic is set to true and is never reset. After the first panic is written, any later panic on another thread skips logging::bootstrap_error. The guard appears to be intended as re-entrancy protection, not as a one-shot switch. Reset the flag after the write so later panics are still recorded.

♻️ Proposed change to reset the re-entrancy guard
     panic::set_hook(Box::new(move |info| {
         if !writing_panic.swap(true, Ordering::AcqRel) {
             let message = sanitize_public_text(&info.to_string());
             if let Err(error) = logging::bootstrap_error(&logs_dir, &boot_id, "panic", &message) {
                 eprintln!(
                     "{}",
                     sanitize_public_text(&format!("write panic fallback log: {error}"))
                 );
             }
+            writing_panic.store(false, Ordering::Release);
         }
         previous_hook(info);
     }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/main.rs` around lines 182 - 197, Update
install_panic_hook so writing_panic is reset after each attempted
logging::bootstrap_error call, while remaining set during the write to prevent
re-entrant panic handling. Ensure the reset occurs even when bootstrap_error
returns an error, allowing later independent panics to be recorded.
desktop/src-tauri/src/runtime/boot_timestamp_drift_tests.rs (1)

161-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the Unreachable outcome.

The tests cover Attached, NotOwned, and IdentityMismatch. No test drives Identity::Unreachable into BoundBootTimestampDrift::Unreachable. That variant is the only outcome a caller can distinguish from a hard mismatch, so a mapping regression would pass unnoticed.

♻️ Proposed additional case
     let foreign = FakeProbe(Identity::Foreign);
+    let unreachable = FakeProbe(Identity::Unreachable);
@@
+    assert!(matches!(
+        bound_app_owned_runtime_with_boot_timestamp_drift(
+            &home, &processes, &unreachable, &record, observed
+        ),
+        BoundBootTimestampDrift::Unreachable
+    ));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/runtime/boot_timestamp_drift_tests.rs` around lines 161
- 190, Add a test case in
should_require_a_compozy_identity_for_a_boot_timestamp_drift_runtime using a
FakeProbe configured with Identity::Unreachable, then call
bound_app_owned_runtime_with_boot_timestamp_drift and assert it returns
BoundBootTimestampDrift::Unreachable. Keep the existing identity mismatch
assertions unchanged.
desktop/src-tauri/src/runtime/update_lifecycle_tests.rs (1)

305-330: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test covers StalledRuntimeRecovery::Failed.

FakeRecoveryProcesses::force_terminate on line 53 always removes the pid, so the process always exits. stop_process therefore never returns an error and recover_verified_runtime never returns StalledRuntimeRecovery::Failed. That variant reports an unrecoverable runtime to the user and has no coverage.

Add a fake that keeps the process alive after the forced termination.

♻️ Proposed additional case
+#[test]
+fn should_report_a_failed_recovery_when_the_runtime_survives_forced_termination() {
+    let (_directory, home, record) = owned_runtime();
+    let processes = FakeRecoveryProcesses {
+        starts: Mutex::new(HashMap::from([(record.pid, record.started_at)])),
+        executables: HashMap::from([(record.pid, home.app_binary.clone())]),
+        graceful_stops: AtomicUsize::new(0),
+        forced_stops: AtomicUsize::new(0),
+        stop_on_graceful: false,
+        stop_on_forced: false,
+    };
+    let delay = FakeDelay;
+
+    assert_eq!(
+        recover_stalled_runtime(
+            &home,
+            &record,
+            &processes,
+            &delay,
+            Duration::from_millis(1),
+            Duration::from_millis(1),
+        ),
+        StalledRuntimeRecovery::Failed
+    );
+    assert!(home.daemon_info.exists());
+}

The fake needs a stop_on_forced field that gates the removal on line 55.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/runtime/update_lifecycle_tests.rs` around lines 305 -
330, Extend FakeRecoveryProcesses with a stop_on_forced flag and gate the pid
removal in force_terminate on that flag, then add a test covering
recover_verified_runtime returning StalledRuntimeRecovery::Failed when forced
termination leaves the process alive. Keep the existing recovery test configured
to stop on forced termination so its Recovered behavior remains unchanged.
desktop/src-tauri/src/record.rs (1)

241-255: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

This test asserts only a constructor field assignment.

should_preserve_the_observed_operating_system_process_start_time passes started_at into AppRecord::new and then reads back record.started_at. No business logic can break this assertion. The test cannot fail when startup-time behavior changes.

Make it meaningful by asserting the serialized contract, which is what consumers read:

♻️ Proposed change to assert the persisted contract
-        let record = AppRecord::new(
-            42,
-            started_at,
-            report(&ShellState::Resolving),
-            ShellState::Resolving,
-        );
-
-        assert_eq!(record.started_at, started_at);
+        let record = AppRecord::new(
+            42,
+            started_at,
+            report(&ShellState::Resolving),
+            ShellState::Resolving,
+        );
+
+        let value = serde_json::to_value(record).expect("record serializes");
+        assert_eq!(value["started_at"], "2026-08-11T12:00:00Z");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/record.rs` around lines 241 - 255, Update
should_preserve_the_observed_operating_system_process_start_time to serialize
the constructed AppRecord and assert the persisted representation contains the
observed started_at value, rather than directly comparing record.started_at.
Reuse the existing serialization approach and expected field format used by
AppRecord consumers or nearby tests.
desktop/src-tauri/src/runtime/update_lifecycle.rs (1)

273-289: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

stop no longer escalates to a forced termination, and it drops the error detail.

Two points:

  1. stop calls only self.processes.terminate(pid) and waits. stop_process on line 137 already implements graceful termination, waiting, and forced escalation. A runtime that ignores SIGTERM now fails the update instead of being stopped. If the removal of the forced path is intentional, add a short comment that states why the update path must not force-kill.
  2. map_err(|_| RuntimeUpdaterError::Lifecycle) on line 288 discards the io::Error. Other failures in this file are logged, for example line 310. Log the cause before mapping.
♻️ Proposed change to reuse `stop_process` and log the cause
     fn stop(&self, pid: u32) -> Result<(), RuntimeUpdaterError> {
         let delay = ThreadDelay;
-        self.processes
-            .terminate(pid)
-            .and_then(|()| {
-                wait_for_exit(
-                    &self.processes,
-                    pid,
-                    &delay,
-                    STOP_DEADLINE,
-                    STOP_POLL_INTERVAL,
-                )
-                .then_some(())
-                .ok_or_else(|| io::Error::other("runtime process did not exit after termination"))
-            })
-            .map_err(|_| RuntimeUpdaterError::Lifecycle)
+        stop_process(
+            &self.processes,
+            pid,
+            &delay,
+            STOP_DEADLINE,
+            STOP_POLL_INTERVAL,
+        )
+        .map_err(|error| {
+            crate::logging::error(format!("stop runtime process {pid}: {error}"));
+            RuntimeUpdaterError::Lifecycle
+        })
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src-tauri/src/runtime/update_lifecycle.rs` around lines 273 - 289,
Update stop to reuse the existing stop_process flow so runtime termination waits
gracefully and escalates to forced termination when necessary, unless the
removal is intentional—in that case, document the reason inline. Preserve the
wait deadline and interval behavior, and log the underlying termination or wait
error before mapping it to RuntimeUpdaterError::Lifecycle instead of discarding
it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src-tauri/src/controller.rs`:
- Around line 470-472: Restrict the shell_control command in the
command-dispatch logic so it is only callable by the intended authorized
webview, rather than relying on the missing AppManifest::commands registration.
Update export::resolve_output_path, used by export_diagnostics, to accept only
.gz paths contained within home.support_bundles_dir and reject traversal or
outside paths without creating arbitrary parent directories.

In `@desktop/src-tauri/src/diagnostics/actions.rs`:
- Around line 41-59: Update export to validate params.output_path against the
approved home.support_bundles_dir root before calling export::export or creating
any parent directories. Apply the same traversal, symlink-parent, and
containment checks used for the default path to custom paths, rejecting paths
outside CompozyHome’s approved support-bundles directory while preserving valid
custom exports.

In `@desktop/src-tauri/src/diagnostics/startup_marker.rs`:
- Around line 94-133: Validate boot_id at the start of begin_with_owner using
the same constraints enforced by marker_document_is_valid, rejecting empty or
over-long values with an appropriate io::Error before acquiring the lock or
writing the marker. Preserve valid boot behavior; optionally reuse the
already-read previous marker instead of calling read_previous_crash again.

In `@desktop/src-tauri/src/logging.rs`:
- Around line 38-70: Update bootstrap_error to use a platform-specific
open_private_append helper: on Unix create the file with mode 0o600 and
O_NOFOLLOW, while preserving the non-Unix fallback. Change
set_private_file_permissions to operate on the opened fs::File handle rather
than the path, and call it after opening; add a Unix test verifying the
resulting file mode is 0o600, following the startup marker test pattern.

In `@desktop/src-tauri/src/runtime/control_server_startup.rs`:
- Around line 67-71: Update the control-server startup logic around app.manage
and publish_failure so a failed manage call checks whether ControlServer is
already managed: log the duplicate/non-fatal case and return true without
publishing ShellState::ShellError, while retaining publish_failure and a false
result only when no control server remains managed.

In `@desktop/src-tauri/src/runtime/provision.rs`:
- Around line 151-153: Update stage_update to validate the downloaded artifact’s
digest after download_verified and before extract_binary, matching the
integrity-check behavior used by the normal provisioning path. Reuse the
existing artifact validation helper and verified metadata, and propagate
validation failures before extraction proceeds.

In `@desktop/src-tauri/src/runtime/update_lifecycle.rs`:
- Around line 137-168: The process-exit check must distinguish the original
process from a PID-reused process. In
desktop/src-tauri/src/runtime/update_lifecycle.rs:137-168, pass the recorded
started_at through stop_process and wait_for_exit, treating a missing PID or
changed start time as exited; in
desktop/src-tauri/src/runtime/update_lifecycle_tests.rs:15-61, update
FakeRecoveryProcesses so terminate can replace a PID with a different start time
and add coverage asserting force_terminate is not called after reuse.

In `@internal/cli/app_diagnose_bundle_logs.go`:
- Around line 180-205: Decouple the app diagnostic bundle filters from unrelated
CLI constants: update isAppDiagnosticBundleLogLevelAllowed to use a local
constant for the error level, and update
containsAppDiagnosticBundleNonShareableContent to use local constants for the
config and session terms. Preserve the existing matching behavior while ensuring
changes to other CLI output domains cannot alter these allowlists or redaction
terms.

In `@internal/cli/app_diagnose_bundle.go`:
- Around line 59-79: Update createAppDiagnosticBundle to omit output_path when
the operator did not specify --bundle-output, allowing desktop default-directory
hardening to run; preserve the explicit path for custom outputs. Move bundle
path validation ahead of manifest loading by passing the expected path into
decodeAppDiagnosticBundleExport, comparing it before
readAppDiagnosticBundleManifest.

In `@internal/cli/app_test.go`:
- Around line 533-539: The forbidden-content assertions in the diagnostic
archive test are ineffective because “transcript” and “runtime.db” are absent
from its fixtures and do not match production filters. Update the test fixture
setup to write a log line containing an actual filtered term, such as
“compozy.db” or “sqlite”, and assert that term is absent from the archive
alongside the existing forbidden values.

In `@internal/daemon/restart_integration_test.go`:
- Around line 199-201: Update the test case containing d.processStartedAt in
internal/daemon/restart_integration_test.go (lines 199-201) by moving it into a
t.Run("Should ...") subtest and adding t.Parallel(); apply the same structure to
the affected case in internal/daemon/daemon_test.go (lines 1033-1035),
preserving each test’s existing behavior.

In `@scripts/smoke-desktop-release-artifact.sh`:
- Around line 15-18: Update the isolated-runtime lifecycle in the smoke script
around smoke_home, app_pid, and app_process_group to use the required QA
teardown flow instead of ad hoc cleanup. Register long-lived processes under
<QA_OUTPUT_PATH>/qa/pids/, invoke the bootstrap manifest teardown command or
make qa-reap on every exit path, and require a teardown.json result confirming
clean: true before release validation completes.
- Line 141: Update the curl status request in the smoke-test flow to enforce
connection and total timeouts shorter than the 180-second deadline, while
preserving its existing silent, error-reporting, and failure-tolerant behavior.
- Around line 55-61: Update the daemon cleanup flow around stop_process to
compare daemon.json’s started_at with the live process start time and signal the
PID only when they match. Ensure the bootstrap teardown command runs on every
exit path and writes teardown.json with clean: true. Add connection and total
request timeouts to the status curl invocation so it cannot stall past the
180-second deadline.

---

Nitpick comments:
In `@desktop/src-tauri/src/diagnostics/export_tests.rs`:
- Around line 140-195: The diagnostic export tests need coverage for oversized
bundles. Add a test alongside the existing export tests that creates a log file
exceeding MAX_DIAGNOSTIC_BUNDLE_BYTES, invokes export, asserts
DiagnosticExportError::TooLarge, and verifies the generated bundle path does not
remain.

In `@desktop/src-tauri/src/diagnostics/report.rs`:
- Around line 75-87: The phase vocabulary in boot_phase_from_state and
is_diagnostic_phase is duplicated; centralize it so both validation and state
mapping use the same source of truth. Update the diagnostics phase definition
and make is_diagnostic_phase reuse it, while preserving the existing strings
returned by boot_phase_from_state and marker_document_is_valid behavior.

In `@desktop/src-tauri/src/health_monitor.rs`:
- Around line 279-322: Add negative coverage to the test around
observed_identity: use a non-app-owned executable or mismatched provenance hash
and assert it returns None, while retaining the valid case and asserting the
returned identity contains record.pid. Ensure the test verifies both
ownership/provenance rejection and correct PID attachment for the forward
boot-timestamp drift branch.

In `@desktop/src-tauri/src/main.rs`:
- Around line 182-197: Update install_panic_hook so writing_panic is reset after
each attempted logging::bootstrap_error call, while remaining set during the
write to prevent re-entrant panic handling. Ensure the reset occurs even when
bootstrap_error returns an error, allowing later independent panics to be
recorded.

In `@desktop/src-tauri/src/record.rs`:
- Around line 241-255: Update
should_preserve_the_observed_operating_system_process_start_time to serialize
the constructed AppRecord and assert the persisted representation contains the
observed started_at value, rather than directly comparing record.started_at.
Reuse the existing serialization approach and expected field format used by
AppRecord consumers or nearby tests.

In `@desktop/src-tauri/src/runtime/boot_timestamp_drift_tests.rs`:
- Around line 161-190: Add a test case in
should_require_a_compozy_identity_for_a_boot_timestamp_drift_runtime using a
FakeProbe configured with Identity::Unreachable, then call
bound_app_owned_runtime_with_boot_timestamp_drift and assert it returns
BoundBootTimestampDrift::Unreachable. Keep the existing identity mismatch
assertions unchanged.

In `@desktop/src-tauri/src/runtime/update_cadence.rs`:
- Around line 6-13: Update update-cadence::spawn to downgrade the controller Arc
to a Weak reference before starting the thread, then upgrade it inside the loop
before calling check_updates and exit when upgrading fails. Ensure the spawned
thread no longer retains a strong DesktopController reference during shutdown.

In `@desktop/src-tauri/src/runtime/update_lifecycle_tests.rs`:
- Around line 305-330: Extend FakeRecoveryProcesses with a stop_on_forced flag
and gate the pid removal in force_terminate on that flag, then add a test
covering recover_verified_runtime returning StalledRuntimeRecovery::Failed when
forced termination leaves the process alive. Keep the existing recovery test
configured to stop on forced termination so its Recovered behavior remains
unchanged.

In `@desktop/src-tauri/src/runtime/update_lifecycle.rs`:
- Around line 273-289: Update stop to reuse the existing stop_process flow so
runtime termination waits gracefully and escalates to forced termination when
necessary, unless the removal is intentional—in that case, document the reason
inline. Preserve the wait deadline and interval behavior, and log the underlying
termination or wait error before mapping it to RuntimeUpdaterError::Lifecycle
instead of discarding it.

In `@desktop/src-tauri/src/shell.rs`:
- Around line 235-292: Extract the shared recovery-attempt guard and
RecordedDaemonStart outcome match into a helper near the surrounding shell
logic, accepting the appropriate recovery result and returning whether the
caller should continue. Update both Resolution::Awaiting and
Resolution::StartTimeMismatch arms to call this helper, preserving their
distinct recovery functions and existing attach, retry, unhealthy, and failure
behavior.

In `@internal/cli/app_diagnose_bundle_archive.go`:
- Around line 219-221: Update the size validation in the app diagnose bundle
archive flow to handle info.Size() < 1 separately from info.Size() >
appDiagnosticBundleMaxBytes: return an accurate empty-bundle error for zero-byte
files, while preserving the existing size-limit error for oversized bundles.

In `@internal/cli/app_diagnose_bundle_logs.go`:
- Around line 129-148: The redacted log tail should remain a contiguous suffix
when a line exceeds the remaining appDiagnosticBundleLogTailMaxBytes budget.
Update redactAppDiagnosticBundleLogTail to stop processing subsequent lines at
that boundary instead of skipping the oversized line and appending later lines.
- Around line 207-226: Resolve os.UserHomeDir once in
redactAppDiagnosticBundleLogTail and pass the result into
redactAppDiagnosticBundleLogMessage for each line. Update the redaction helper
signature and remove its per-line home-directory lookup, while preserving
explicit handling of resolution errors in the tail flow rather than silently
dropping individual lines.

In `@internal/cli/app_test.go`:
- Around line 345-379: Extend the diagnostic bundle archive validation tests
around the existing “Should reject an unexpected live bundle entry” subtest with
table-driven cases covering duplicate entries, manifest entries exceeding their
limit, log entries exceeding their limit, and aggregate content exceeding
appDiagnosticBundleContentMaxBytes. Build valid archive fixtures for each case,
invoke readAppDiagnosticBundleManifest, and assert rejection with the
appropriate validation error.

In `@internal/daemon/restart_integration_test.go`:
- Around line 199-201: Update the restart integration test around the
processStartedAt stub to retain the injected timestamp and assert that the
persisted replacement start-time field equals that exact value after the restart
operation. Verify the stored outcome rather than only the injected function
call, while preserving the existing restart assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a1a1841-98b7-4613-8300-ea9bb03be23d

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec3d15 and 12cb3e5.

⛔ Files ignored due to path filters (24)
  • .github/workflows/ci.yml is excluded by !**/*.yml
  • .github/workflows/release.yml is excluded by !**/*.yml
  • desktop/schema/app-state.schema.json is excluded by !**/*.json
  • desktop/schema/fixtures/error.json is excluded by !**/*.json, !**/fixtures/**
  • desktop/schema/fixtures/product.json is excluded by !**/*.json, !**/fixtures/**
  • desktop/src-tauri/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • desktop/src-tauri/Cargo.toml is excluded by !**/*.toml
  • docs/qa/automation-backlog/desktop-boot-control-bridge.md is excluded by !**/*.md
  • docs/qa/charters/CH-desktop-agent-headless-cli.md is excluded by !**/*.md
  • docs/qa/charters/CH-desktop-update-rehearsal-macos.md is excluded by !**/*.md
  • docs/qa/journeys/J-desktop-agent-headless.md is excluded by !**/*.md
  • docs/qa/reports/2026-08-11-desktop-startup-diagnostics.md is excluded by !**/*.md
  • docs/qa/scenarios/APP-agent-cli-app-verbs.md is excluded by !**/*.md
  • docs/qa/scenarios/APP-attach-running-daemon.md is excluded by !**/*.md
  • docs/qa/scenarios/APP-install-first-run-provision.md is excluded by !**/*.md
  • docs/qa/scenarios/APP-start-installed-daemon.md is excluded by !**/*.md
  • docs/release/v0.3-single-cut.md is excluded by !**/*.md
  • packages/site/content/docs/cli/app/diagnose.mdx is excluded by !**/*.mdx
  • packages/site/content/docs/cli/app/index.mdx is excluded by !**/*.mdx
  • packages/site/content/docs/getting-started/desktop-app.mdx is excluded by !**/*.mdx
  • packages/site/content/docs/operations/desktop-app.mdx is excluded by !**/*.mdx
  • packages/site/content/docs/operations/support-bundles.mdx is excluded by !**/*.mdx
  • skills/compozy/references/desktop.md is excluded by !**/*.md
  • skills/compozy/references/runtime-operations.md is excluded by !**/*.md
📒 Files selected for processing (73)
  • desktop/src-tauri/build.rs
  • desktop/src-tauri/pages/boot.css
  • desktop/src-tauri/pages/boot.html
  • desktop/src-tauri/pages/boot.js
  • desktop/src-tauri/release_build_contract.rs
  • desktop/src-tauri/src/app_state.rs
  • desktop/src-tauri/src/boot_window.rs
  • desktop/src-tauri/src/controller.rs
  • desktop/src-tauri/src/diagnostics/actions.rs
  • desktop/src-tauri/src/diagnostics/export.rs
  • desktop/src-tauri/src/diagnostics/export_archive.rs
  • desktop/src-tauri/src/diagnostics/export_tests.rs
  • desktop/src-tauri/src/diagnostics/mod.rs
  • desktop/src-tauri/src/diagnostics/report.rs
  • desktop/src-tauri/src/diagnostics/startup_marker.rs
  • desktop/src-tauri/src/diagnostics/startup_marker_tests.rs
  • desktop/src-tauri/src/errors.rs
  • desktop/src-tauri/src/health_monitor.rs
  • desktop/src-tauri/src/home.rs
  • desktop/src-tauri/src/lib.rs
  • desktop/src-tauri/src/logging.rs
  • desktop/src-tauri/src/main.rs
  • desktop/src-tauri/src/record.rs
  • desktop/src-tauri/src/runtime/artifacts.rs
  • desktop/src-tauri/src/runtime/boot_timestamp_drift.rs
  • desktop/src-tauri/src/runtime/boot_timestamp_drift_tests.rs
  • desktop/src-tauri/src/runtime/control_server_startup.rs
  • desktop/src-tauri/src/runtime/discovery.rs
  • desktop/src-tauri/src/runtime/mod.rs
  • desktop/src-tauri/src/runtime/provision.rs
  • desktop/src-tauri/src/runtime/readiness.rs
  • desktop/src-tauri/src/runtime/recorded_start.rs
  • desktop/src-tauri/src/runtime/resolver.rs
  • desktop/src-tauri/src/runtime/resolver_tests.rs
  • desktop/src-tauri/src/runtime/startup_failure.rs
  • desktop/src-tauri/src/runtime/supervisor.rs
  • desktop/src-tauri/src/runtime/supervisor_tests.rs
  • desktop/src-tauri/src/runtime/update_cadence.rs
  • desktop/src-tauri/src/runtime/update_lifecycle.rs
  • desktop/src-tauri/src/runtime/update_lifecycle_tests.rs
  • desktop/src-tauri/src/runtime/update_recovery.rs
  • desktop/src-tauri/src/shell.rs
  • desktop/src-tauri/tests/contracts.rs
  • desktop/src-tauri/tests/runtime_resolution.rs
  • desktop/src-tauri/tests/update_system.rs
  • internal/api/core/base_handlers.go
  • internal/api/core/handlers_test.go
  • internal/cli/app.go
  • internal/cli/app_control.go
  • internal/cli/app_diagnose.go
  • internal/cli/app_diagnose_bundle.go
  • internal/cli/app_diagnose_bundle_alias_darwin.go
  • internal/cli/app_diagnose_bundle_alias_other.go
  • internal/cli/app_diagnose_bundle_archive.go
  • internal/cli/app_diagnose_bundle_logs.go
  • internal/cli/app_diagnose_bundle_sync_unix.go
  • internal/cli/app_diagnose_bundle_sync_windows.go
  • internal/cli/app_test.go
  • internal/cli/app_types.go
  • internal/cli/roles.go
  • internal/cli/root.go
  • internal/cli/tool_artifacts.go
  • internal/cli/tool_operator_output.go
  • internal/daemon/boot.go
  • internal/daemon/boot_extension_publishers.go
  • internal/daemon/boot_runtime_foundation.go
  • internal/daemon/boot_runtime_services.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_options.go
  • internal/daemon/daemon_test.go
  • internal/daemon/restart_integration_test.go
  • scripts/smoke-desktop-release-artifact.sh
  • scripts/verify-desktop-release-build-contract.sh
💤 Files with no reviewable changes (3)
  • internal/api/core/base_handlers.go
  • internal/daemon/boot_extension_publishers.go
  • internal/daemon/boot_runtime_services.go

Comment thread desktop/src-tauri/src/controller.rs
Comment thread desktop/src-tauri/src/diagnostics/actions.rs
Comment thread desktop/src-tauri/src/diagnostics/startup_marker.rs
Comment thread desktop/src-tauri/src/logging.rs
Comment thread desktop/src-tauri/src/runtime/control_server_startup.rs Outdated
Comment thread internal/cli/app_test.go
Comment thread internal/daemon/restart_integration_test.go Outdated
Comment thread scripts/smoke-desktop-release-artifact.sh Outdated
Comment thread scripts/smoke-desktop-release-artifact.sh Outdated
Comment thread scripts/smoke-desktop-release-artifact.sh Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/smoke-desktop-release-artifact.sh`:
- Line 32: Replace the string-based TEARDOWN_COMMAND in the teardown flow with a
Bash array containing the script path and each argument as separate elements,
then invoke it as "${teardown_command[@]}" without eval. Preserve the existing
repo_root and manifest_path values while preventing their contents from being
reparsed as shell syntax.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e91601be-27eb-4eb2-a85a-a075a00b9c74

📥 Commits

Reviewing files that changed from the base of the PR and between 12cb3e5 and eb33046.

⛔ Files ignored due to path filters (2)
  • desktop/src-tauri/capabilities/boot.json is excluded by !**/*.json
  • desktop/src-tauri/permissions/autogenerated/shell_control.toml is excluded by !**/*.toml
📒 Files selected for processing (24)
  • desktop/src-tauri/build.rs
  • desktop/src-tauri/src/diagnostics/export.rs
  • desktop/src-tauri/src/diagnostics/export_tests.rs
  • desktop/src-tauri/src/diagnostics/report.rs
  • desktop/src-tauri/src/diagnostics/startup_marker.rs
  • desktop/src-tauri/src/diagnostics/startup_marker_tests.rs
  • desktop/src-tauri/src/health_monitor.rs
  • desktop/src-tauri/src/logging.rs
  • desktop/src-tauri/src/main.rs
  • desktop/src-tauri/src/record.rs
  • desktop/src-tauri/src/runtime/boot_timestamp_drift_tests.rs
  • desktop/src-tauri/src/runtime/control_server_startup.rs
  • desktop/src-tauri/src/runtime/update_cadence.rs
  • desktop/src-tauri/src/runtime/update_lifecycle.rs
  • desktop/src-tauri/src/runtime/update_lifecycle_tests.rs
  • desktop/src-tauri/src/shell.rs
  • desktop/src-tauri/tests/contracts.rs
  • internal/cli/app_diagnose_bundle.go
  • internal/cli/app_diagnose_bundle_archive.go
  • internal/cli/app_diagnose_bundle_logs.go
  • internal/cli/app_test.go
  • internal/daemon/daemon_test.go
  • internal/daemon/restart_integration_test.go
  • scripts/smoke-desktop-release-artifact.sh
🚧 Files skipped from review as they are similar to previous changes (12)
  • desktop/src-tauri/tests/contracts.rs
  • desktop/src-tauri/src/runtime/update_cadence.rs
  • desktop/src-tauri/build.rs
  • desktop/src-tauri/src/health_monitor.rs
  • desktop/src-tauri/src/record.rs
  • internal/cli/app_diagnose_bundle.go
  • desktop/src-tauri/src/runtime/control_server_startup.rs
  • desktop/src-tauri/src/main.rs
  • desktop/src-tauri/src/runtime/update_lifecycle.rs
  • internal/daemon/daemon_test.go
  • internal/cli/app_test.go
  • desktop/src-tauri/src/diagnostics/startup_marker.rs

Comment thread scripts/smoke-desktop-release-artifact.sh Outdated
@pedronauck
pedronauck merged commit 214ecd1 into main Aug 11, 2026
36 of 38 checks passed
@pedronauck
pedronauck deleted the app-start-issue branch August 11, 2026 23:23
@coderabbitai coderabbitai Bot mentioned this pull request Aug 13, 2026
9 of 11 tasks
This was referenced Aug 27, 2026
@pedronauck pedronauck mentioned this pull request Sep 7, 2026

This branch was successfully deployed

1 active deployment
Preview — b3a55806 Deployed Aug 11, 2026 by vercel[bot]
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