Skip to content

refactor(nav): fold Orchestration under Brain + daemon/health cleanup - #5080

Closed
senamakel wants to merge 26 commits into
tinyhumansai:mainfrom
senamakel:chore/app-cleanup
Closed

refactor(nav): fold Orchestration under Brain + daemon/health cleanup#5080
senamakel wants to merge 26 commits into
tinyhumansai:mainfrom
senamakel:chore/app-cleanup

Conversation

@senamakel

@senamakel senamakel commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

  • Fold Orchestration under Brain: removes the top-level Orchestration sidebar tab and surfaces it as a Brain sub-tab (/brain?tab=orchestration) via a new OrchestrationView, whose views (Overview/Chat/Agent graph/Tasks/Network) become an in-content chip row so Brain keeps a single sidebar. Legacy /orchestration + /brain/tinyplace-orchestration deep links redirect, mapping ?tab=/?sub= onto the new ?ov=/?sub= scheme.
  • Daemon health / connectivity: fold component health into app_state_snapshot (drop the separate health poll), arm the baseline disconnect watchdog independent of first ingest, widen the watchdog to tolerate slow snapshots, and dedupe concurrent health-snapshot pollers.
  • Polling/perf cleanup: back off app_state_snapshot to 5s once stable, drive the local-AI download snackbar off folded core state (no idle inference poll), coalesce duplicate boot harness_init_status polls.
  • Config/keyring hygiene: treat empty OPENHUMAN_SHELL_HIDE_WINDOW as unset, change-gate keyring-consent cache init to stop per-snapshot log spam.
  • Docs: point the about_app Orchestration how_to strings at Brain > Orchestration.

Problem

  • The sidebar carried Orchestration as a first-class destination even though it is conceptually part of Brain's agent/memory surface, bloating the top-level nav.
  • Health/connectivity ran on independent polls that could race, spam logs, and mis-report disconnects during slow app_state snapshots.

Solution

  • Introduce OrchestrationView (chip-nav, query-param driven) embedded in Brain.tsx; drop OrchestrationPage and its top-level NAV_TABS entry; add redirects in AppRoutes.tsx and update the settings/brain deep links. Rename the stale brain.tabs.tinyplaceOrchestration i18n key to brain.tabs.orchestration with real translations across all locales.
  • Consolidate component health into the single app_state_snapshot stream and make the disconnect watchdog time-based rather than ingest-gated, with dedup guards.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/ci-lite.yml; focused Vitest suites + Rust checks run locally, full gate enforced by CI.
  • N/A: Coverage matrix — navigation reorg is behaviour-preserving and the bundled infra/perf fixes add no new feature rows; no docs/TEST-COVERAGE-MATRIX.md rows changed.
  • N/A: No new matrix feature IDs affected (see above).
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • N/A: No release-cut smoke surfaces changed by this branch.
  • N/A: No linked issue to close.

Impact

  • Desktop UI: Orchestration moves from a top-level tab to Brain > Orchestration; old deep links redirect, so bookmarks keep working. No behaviour change to the orchestration surfaces themselves.
  • Runtime: fewer/coalesced background polls and a more robust disconnect watchdog; reduced log spam. No migration or security implications.

Related

  • Closes: N/A
  • Follow-up PR(s)/TODOs: N/A

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: chore/app-cleanup
  • Commit SHA: 1546c38c4

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: Vitest src/components/orchestration, src/config, src/pages/__tests__/Brain.test.tsx, src/components/layout/shell/CollapsedNavRail.test.tsx (88 passing); pnpm i18n:check / i18n:english:check clean
  • Rust fmt/check (if changed): cargo fmt --all --check, GGML_NATIVE=OFF cargo check -p openhuman
  • Tauri fmt/check (if changed): cargo check --manifest-path app/src-tauri/Cargo.toml (via pre-push hook)

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: Orchestration is reached via Brain instead of a top-level sidebar tab; legacy routes redirect.
  • User-visible effect: one fewer top-level nav item; Orchestration lives under Brain with a chip sub-nav.

Parity Contract

  • Legacy behavior preserved: all orchestration views/functionality unchanged; deep links redirected with param mapping.
  • Guard/fallback/dispatch parity checks: OrchestrationRedirect maps ?tab=/?sub=?ov=/?sub=; Brain legacy tinyplace-orchestration slug bounces to the sub-tab.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this PR
  • Resolution: N/A

Summary by CodeRabbit

  • New Features

    • Added Orchestration as a Brain sub-tab (agent, tasks, and network views) with session-aware deep links.
    • Legacy orchestration URLs now redirect into the Brain orchestration view and preserve relevant query state.
    • Brain snapshots now include daemon health data for improved system status.
  • Bug Fixes

    • Reduced duplicate initialization/status polling during startup (including StrictMode double-mount).
    • Improved Local AI download snackbar: polling is now tied to core state and stops when downloads finish or become inactive.
    • Pre-push checks now exit immediately and reliably on interrupts.
  • Translations

    • Updated the displayed Brain orchestration label across supported languages.

senamakel added 23 commits July 21, 2026 11:36
useDaemonHealth mounts in several places at once (SocketProvider via
useDaemonLifecycle; ServiceBlockingGate directly + via useDaemonLifecycle).
setupHealthListener awaited the first poll before assigning pollingIntervalId,
so all concurrent callers raced past the singleton guard and each spawned their
own setInterval — emitting multiple openhuman.health_snapshot RPCs per tick.

Assign the interval id synchronously and reference-count consumers: the shared
loop starts on the first consumer and is torn down only when the last releases,
so one component unmounting can't stop polling for the rest. Adds a regression
test covering concurrent setup and partial release.
LocalAIDownloadSnackbar (mounted app-wide) polled inference_status +
inference_downloads_progress every 2s forever, even with no download active.
Make the poll self-scheduling: 2s while a download is in flight, 15s when idle.
React.StrictMode double-mounts HarnessInitOverlay in dev (effect → cleanup →
effect); each setup fires an immediate poll, booting two harness_init_status
RPCs at the same instant. Coalesce overlapping status fetches onto one in-flight
request (cleared once settled, so ongoing sequential polling is unaffected).
Also guards a genuine remount during the boot window.
…valid

A bare `OPENHUMAN_SHELL_HIDE_WINDOW=` (empty/whitespace-only, common when a
.env or launcher exports the key with no value) fell through to the
"unrecognized value ignored" warn arm and logged a warning on every boot.
Treat an empty value as absent — silently keep the current setting. Extends the
existing env-override test to cover the empty and whitespace-only cases.
…shot log spam

policy::initialize() is documented as a once-at-startup call but is wired into
build_app_state_snapshot, so it runs on every app_state_snapshot RPC — logging
`[keyring_consent] initialize` at INFO each time (several per boot as the
frontend polls the snapshot). Hold the write lock across a compare-and-set and
return early when the persisted consent is unchanged, so it writes + logs only
on a genuine transition. Adds PartialEq/Eq to ConsentPreference and a
change-gating regression test.
Points the tauri-cef submodule at fix/cef-helper-verbose-logging, which gates
the per-subprocess [cef-helper-*] eprintln! traces behind
OPENHUMAN_CEF_HELPER_VERBOSE (silent by default).

Note: takes effect in bundled builds only after reinstalling the vendored
tauri-cli (cargo install --locked --path app/src-tauri/vendor/tauri-cef/crates/tauri-cli).
CoreStateProvider polled the expensive app_state_snapshot RPC every 2s for the
life of the session, only slowing on repeated bootstrap failure. Once booted and
authenticated the snapshot changes rarely and mostly via event-driven refreshes,
so steady state now polls at STABLE_POLL_MS (5s); bootstrapping/unauthenticated
stays at 2s so boot/login transitions still surface promptly.
…lth poll

The frontend ran a second dedicated health_snapshot poller (daemonHealthService)
alongside the app_state_snapshot poll. Fold the core's health snapshot into
app_state_snapshot (new snake_case `health` field) and hydrate the daemon-health
store from that one poll instead:

- core: AppStateSnapshot carries HealthSnapshot; ComponentHealth/HealthSnapshot
  gain Deserialize. json_rpc_e2e asserts the folded health shape.
- frontend: daemonHealthService drops all polling and becomes an ingestion sink
  (ingestHealthSnapshot: parse + store update + 30s disconnect watchdog);
  CoreStateProvider feeds each snapshot's health payload to it; useDaemonHealth
  no longer starts a poll. Older cores that omit `health` degrade gracefully.

Supersedes the earlier health_snapshot poller dedupe (d34101f) — there is now
no separate health poll at all. Regression tests rewritten for the sink API.
…e inference poll

LocalAIDownloadSnackbar polled inference_status + inference_downloads_progress on
its own timer even when idle. inference_status returns the same LocalAiStatus the
app_state_snapshot already carries as runtime.localAi, so detect download activity
from core state instead: when idle the snackbar issues ZERO inference calls; only
once runtime.localAi.state reports loading/downloading/installing does it run the
fast 2s poll for granular progress/speed/ETA (downloads-progress detail the 2-5s
snapshot cadence can't provide), stopping when the download settles.

LocalModelDebugPanel (settings-only, opt-in) keeps its own live poll.
The rule referenced `worktree/*` (singular) but the directory is `worktrees/`,
so local `git worktree` checkouts under worktrees/ were never ignored and
showed as untracked. Match the real directory name; keep the .gitkeep negation.
Updates .github/tauri-cef-expected-sha to match the tauri-cef submodule bump
(11ef51ed), which gates the CEF helper's per-subprocess diagnostic prints behind
OPENHUMAN_CEF_HELPER_VERBOSE. 11ef51ed is a direct child of the prior pin
5ec3d883, so the Linux AppImage glibc/NSS library-exclusion fixes the pin guards
(tinyhumansai#1996, tinyhumansai#2032, tinyhumansai#2154/tinyhumansai#2088) are preserved. Submodule commit pushed to
tinyhumansai/tauri-cef (branch fix/cef-helper-verbose-logging) so CI can resolve
the pin.
- LocalAIDownloadSnackbar: gate isDownloading on coreDownloadActive so a
  download the core no longer reports active can't leave the overlay stuck
  visible; on a transient poll error keep retrying while core state is active
  (previously one blip permanently stopped progress polling for the download).
- CoreStateProvider: ingest folded health AFTER the snapshot is committed and
  only when the refresh is still current, so daemon health is written under the
  freshly-committed identity, not a stale/pre-commit/superseded token.
- coreStateApi: type health last_ok/last_error as string | null to match the
  Rust Option<String> wire contract.
- keyring_consent::initialize now returns whether it applied a change, so the
  change-gate's suppressed write/log is asserted directly (not just unchanged
  state); config shell-hide-window parsing extracted into a testable classifier
  that distinguishes Unset (empty → silent) from Unrecognized (warns).
- Add trace-level diagnostics to the no-op env/keyring paths and namespaced
  debug logging to the harness-init coalescing + snackbar poll lifecycles.
…pshots

Folding health into app_state_snapshot coupled the 30s disconnect watchdog to an
RPC allowed to run up to 90s (first-launch snapshots take 30–40s), so a slow-but-
alive core could be marked `disconnected` mid-boot. Widen HEALTH_TIMEOUT_MS to
120s to cover one worst-case slow snapshot plus poll cadence; genuine
disconnection (snapshots stop succeeding) is still detected. Addresses Codex
review P2.
Per the repo's verbose-diagnostics guideline, log privacy-safe namespaced events
for the folded-health ingest branch (request freshness, health presence,
component count — never payload/tokens) and the poll-delay selection (delay +
reason: bootstrap / authenticated / failure-backoff). Addresses CodeRabbit.
…tructure

- Added `OrchestrationRedirect` component to handle legacy `/orchestration` route, redirecting to `/brain?tab=orchestration` with query parameter mapping.
- Updated `AppRoutes` to use the new redirect and removed the direct route to `OrchestrationPage`.
- Modified `Brain` component to include `orchestration` as a sub-tab, ensuring legacy deep links are correctly routed.
- Enhanced documentation for clarity on routing changes and tab structure.
…cution

- Improved the pre-push hook to handle abort signals (Ctrl+C/SIGTERM) more effectively, ensuring that the script exits with the correct status code.
- Introduced a `run_check` function to encapsulate command execution and error handling, allowing for cleaner and more maintainable code.
- Removed the `OrchestrationPage` component and its associated tests, as part of a broader refactor to streamline the application structure.
…gest

The refactor armed the disconnect watchdog only inside a successful health
parse, so a core whose app_state_snapshots never carry parseable health (repeated
timeouts, after the one-shot agent probe already set `running`) would never arm a
watchdog and stick at `running`. Arm a baseline watchdog when tracking starts
(CoreStateProvider → ensureWatchdogArmed, idempotent) and treat any arriving
snapshot as liveness that re-arms it — even a health-less/older-core payload —
while only updating the store on a valid parse. Addresses Codex review P2.
Remove the top-level Orchestration sidebar tab and surface it as a Brain
sub-tab (/brain?tab=orchestration) via the new OrchestrationView, whose
top-level views (Overview/Chat/Agent graph/Tasks/Network) become an
in-content chip row so Brain keeps a single sidebar.

- navConfig: drop the orchestration NAV_TABS entry (6 tabs now)
- settings + legacy /orchestration deep links redirect to the Brain tab,
  mapping ?tab=/?sub= onto the ?ov=/?sub= scheme
- i18n: rename brain.tabs.tinyplaceOrchestration → brain.tabs.orchestration
  with real translations across all locales
- tests: OrchestrationView unit tests, updated navConfig/Brain/nav-rail/e2e
The workflow-orchestration and session-orchestration capability entries
still pointed at the retired 'Intelligence > Orchestration' path. Update
both to the new home now that Orchestration is a Brain sub-tab.
@senamakel
senamakel requested a review from a team July 21, 2026 11:05
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request folds orchestration into Brain, migrates daemon health into app-state snapshots, changes local-AI and harness polling behavior, updates Rust configuration and consent handling, and adjusts repository tooling and navigation metadata.

Changes

Brain orchestration integration

Layer / File(s) Summary
Orchestration view and Brain integration
app/src/components/orchestration/*, app/src/pages/Brain.tsx, app/src/pages/__tests__/Brain.test.tsx
Adds the query-driven OrchestrationView, Brain integration, Medulla/demo panels, session handling, tasks, network sub-tabs, and tests.
Legacy route migration
app/src/AppRoutes.tsx, app/src/config/*, app/src/lib/i18n/*, app/src/components/settings/settingsRouteElements.tsx, app/test/e2e/specs/navigation.spec.ts
Redirects legacy orchestration destinations to Brain, removes the standalone navigation tab, and updates translated labels and route tests.

Daemon health snapshot pipeline

Layer / File(s) Summary
Health snapshot contract
app/src/services/coreStateApi.ts, src/openhuman/app_state/ops.rs, src/openhuman/health/core.rs, tests/json_rpc_e2e.rs
Adds serialized health data to app-state snapshots and validates the resulting runtime shape.
Health ingestion and watchdog
app/src/services/daemonHealthService.ts, app/src/services/__tests__/daemonHealthService.test.ts
Replaces standalone health polling with snapshot ingestion and disconnect-watchdog management.
Provider refresh integration
app/src/providers/CoreStateProvider.tsx, app/src/hooks/useDaemonHealth.ts
Feeds current snapshots into the health service and introduces slower authenticated steady-state polling.

Polling reliability

Layer / File(s) Summary
Boot status request coalescing
app/src/components/InitProgressScreen/HarnessInitOverlay.tsx, app/src/components/InitProgressScreen/HarnessInitOverlay.test.tsx
Shares pending initialization-status requests across remounts and tests StrictMode behavior.
Core-gated local-AI polling
app/src/components/LocalAIDownloadSnackbar.tsx, app/src/components/__tests__/LocalAIDownloadSnackbar.test.tsx
Polls local-AI status only while core reports an active download, using recursive timeouts and transient-error handling.
Conditional subconscious polling
app/src/hooks/useSubconscious.ts, app/src/hooks/__tests__/useSubconscious.test.ts
Adds an enabled flag that suppresses subconscious status polling when the Brain tab is inactive.

Rust runtime behavior

Layer / File(s) Summary
Configuration and consent behavior
src/openhuman/config/schema/load/env_overlay.rs, src/openhuman/config/schema/load_tests.rs, src/openhuman/keyring_consent/*
Distinguishes unset shell-window overrides and makes consent cache updates change-gated.
Capability navigation metadata
src/openhuman/about_app/catalog_data.rs
Updates orchestration capability instructions to use the Brain navigation path.

Repository maintenance

Layer / File(s) Summary
Tooling and repository updates
.husky/pre-push, .gitignore, .github/tauri-cef-expected-sha, app/src-tauri/vendor/tauri-cef, app/src/features/conversations/*, app/src/store/*
Updates repository ignores and pins, improves interrupted pre-push handling, and applies non-functional formatting changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: rust-core, feature, bug

Suggested reviewers: m3ga-mind

Poem

I’m a rabbit routing tabs through Brain,
While watchdogs guard the health-data train.
Polls now hop only when downloads are near,
Old paths find new destinations clear.
Rust caches nap when values stay the same—
A tidy burrow, with orchestration fame!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: moving Orchestration under Brain and cleaning up daemon/health handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1546c38c4f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// the inference RPCs. When idle this component issues ZERO inference calls;
// the snapshot's `runtime.localAi.state` is what flips us into the fast poll.
const { snapshot: coreSnapshot } = useCoreState();
const coreDownloadActive = isInFlightState(coreSnapshot.runtime.localAi?.state ?? undefined);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep a fresh trigger for local-AI download polling

When a download starts just after an app_state_snapshot, runtime.localAi can remain at the cached idle value because build_runtime_snapshot serves cached runtime snapshots for the 10s RUNTIME_SNAPSHOT_TTL. Since this line makes the fast inference poll start only after coreDownloadActive flips, the snackbar won't call inference_status / inference_downloads_progress during that window, and short downloads can finish without ever showing progress; the previous 2s poll caught those transitions. Please trigger a refresh/fast poll from the download-start path or bypass the cached runtime for this predicate.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Deferred (design decision). This gap is inherent to the deliberate perf(local-ai): drive download snackbar off folded core state, no idle inference poll commit on this branch — starting a fast trigger from the download-start path or bypassing the cached runtime snapshot re-introduces the polling that commit intentionally removed. Leaving this thread open for the branch author to decide the tradeoff rather than silently reverting their optimization in this cleanup PR.

Comment thread app/src/pages/Brain.tsx
@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team. labels Jul 21, 2026

@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: 5

🧹 Nitpick comments (1)
app/src/components/LocalAIDownloadSnackbar.tsx (1)

39-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated currentState/in-flight derivation between isDownloadInFlight and the render body.

The same "loading/downloading/installing else fall back to status.state ?? downloads.state ?? 'idle'" logic is written twice (lines 43-46 and 132-136), and line 134 re-implements isInFlightState via manual string comparisons instead of reusing it. Consider extracting one shared deriveCurrentState(status, downloads) helper and reusing isInFlightState in both places to avoid future divergence between the polling-stop decision and the render-visibility decision.

Also applies to: 132-146

🤖 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 `@app/src/components/LocalAIDownloadSnackbar.tsx` around lines 39 - 51, The
current-state derivation is duplicated between isDownloadInFlight and the render
body, with the render path manually comparing in-flight states. Extract a shared
deriveCurrentState(status, downloads) helper using isInFlightState and the
existing fallback order, then reuse it in both locations while preserving the
current polling and visibility behavior.
🤖 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 `@app/src/AppRoutes.tsx`:
- Around line 49-67: Add namespaced, grep-friendly diagnostics to
OrchestrationRedirect covering redirect entry, the selected mapping branch, and
exit. Log only allowlisted branch identifiers and whether a session is present;
never include the session value or unsanitized query parameters.

In `@app/src/components/LocalAIDownloadSnackbar.tsx`:
- Around line 99-108: Update the settlement logic in the polling try block of
LocalAIDownloadSnackbar so settled is evaluated only when at least one of
statusRes.result or downloadsRes.result is present. Preserve the existing state
updates, and keep an empty successful response transient so it does not stop the
fast poll.

In `@app/src/providers/CoreStateProvider.tsx`:
- Around line 354-369: The health ingestion in the current-request branch of
CoreStateProvider must use the freshly resolved destination identity rather than
reading potentially stale React state through
daemonHealthService.ingestHealthSnapshot. Update the ingest path and its service
API to pass the resolved userId explicitly, or synchronize the non-React core
snapshot before ingestion, ensuring identity flips never store health under the
previous or __pending__ user.

In `@app/src/services/daemonHealthService.ts`:
- Around line 41-63: Add namespaced verbose diagnostics to ensureWatchdogArmed
and ingestHealthSnapshot covering initial arm versus existing watchdog,
unconditional rearm, payload presence and parse acceptance/rejection, and
whether the daemon store update is performed or skipped. Include only
privacy-safe structural metadata such as validity and component count; never log
health payload contents, and preserve the existing watchdog and store-update
behavior.

In `@tests/json_rpc_e2e.rs`:
- Around line 6078-6100: Update the health assertions in the JSON-RPC contract
test to require the top-level health.updated_at field and validate that it is a
string, alongside the existing pid, uptime_seconds, and components checks.

---

Nitpick comments:
In `@app/src/components/LocalAIDownloadSnackbar.tsx`:
- Around line 39-51: The current-state derivation is duplicated between
isDownloadInFlight and the render body, with the render path manually comparing
in-flight states. Extract a shared deriveCurrentState(status, downloads) helper
using isInFlightState and the existing fallback order, then reuse it in both
locations while preserving the current polling and visibility behavior.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16b2e649-2521-4fa5-9006-e62fcf038295

📥 Commits

Reviewing files that changed from the base of the PR and between 684ad0d and 1546c38.

📒 Files selected for processing (54)
  • .github/tauri-cef-expected-sha
  • .gitignore
  • .husky/pre-push
  • app/src-tauri/vendor/tauri-cef
  • app/src/AppRoutes.tsx
  • app/src/components/InitProgressScreen/HarnessInitOverlay.test.tsx
  • app/src/components/InitProgressScreen/HarnessInitOverlay.tsx
  • app/src/components/LocalAIDownloadSnackbar.tsx
  • app/src/components/__tests__/LocalAIDownloadSnackbar.test.tsx
  • app/src/components/layout/shell/CollapsedNavRail.test.tsx
  • app/src/components/orchestration/AgentChatPanel.tsx
  • app/src/components/orchestration/ConnectionsPanel.tsx
  • app/src/components/orchestration/OrchestrationView.tsx
  • app/src/components/orchestration/__tests__/OrchestrationView.test.tsx
  • app/src/components/settings/settingsRouteElements.tsx
  • app/src/config/__tests__/navConfig.test.ts
  • app/src/config/navConfig.ts
  • app/src/features/conversations/Conversations.tsx
  • app/src/features/conversations/components/InterruptedAnswer.tsx
  • app/src/hooks/useDaemonHealth.ts
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • app/src/pages/Brain.tsx
  • app/src/pages/OrchestrationPage.tsx
  • app/src/pages/__tests__/Brain.test.tsx
  • app/src/pages/__tests__/OrchestrationPage.test.tsx
  • app/src/providers/CoreStateProvider.tsx
  • app/src/services/__tests__/daemonHealthService.test.ts
  • app/src/services/coreStateApi.ts
  • app/src/services/daemonHealthService.ts
  • app/src/store/__tests__/chatRuntimeSlice.thunk.test.ts
  • app/src/store/chatRuntimeSlice.test.ts
  • app/test/e2e/specs/navigation.spec.ts
  • src/openhuman/about_app/catalog_data.rs
  • src/openhuman/app_state/ops.rs
  • src/openhuman/config/schema/load/env_overlay.rs
  • src/openhuman/config/schema/load_tests.rs
  • src/openhuman/health/core.rs
  • src/openhuman/keyring_consent/policy.rs
  • src/openhuman/keyring_consent/types.rs
  • tests/json_rpc_e2e.rs
  • worktrees/.gitkeep
💤 Files with no reviewable changes (3)
  • app/src/pages/tests/OrchestrationPage.test.tsx
  • app/src/pages/OrchestrationPage.tsx
  • app/src/components/layout/shell/CollapsedNavRail.test.tsx

Comment thread app/src/AppRoutes.tsx Outdated
Comment thread app/src/components/LocalAIDownloadSnackbar.tsx Outdated
Comment thread app/src/providers/CoreStateProvider.tsx Outdated
Comment thread app/src/services/daemonHealthService.ts
Comment thread tests/json_rpc_e2e.rs
- AppRoutes: add privacy-safe entry/exit diagnostics to OrchestrationRedirect
  (allowlisted branch ids + session-presence only) and cover it with a new
  OrchestrationRedirect.test.tsx exercising every mapping branch.
- LocalAIDownloadSnackbar: treat an empty-but-successful RPC response as
  transient, not "download complete", so a soft failure no longer freezes the
  fast poll for the rest of the download.
- daemonHealthService: resolve the health-store user from the refresh's own
  sessionToken passed by CoreStateProvider, not the deferred non-React store
  (commitState writes it inside a React setState updater) — fixes health being
  filed under the prior/__pending__ user during an identity flip. Add
  privacy-safe watchdog/ingest diagnostics.
- json_rpc_e2e: assert health.updated_at in the RPC contract test (the frontend
  rejects the payload without it).
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 21, 2026
Folding Orchestration under Brain mounted the full Brain component for
/brain?tab=orchestration (and the redirected /orchestration), whose effect
unconditionally called memoryTreeGraphExport on mount + memory-tree events —
an unrelated graph RPC the standalone Orchestration page never issued. Gate the
effect off when the orchestration tab is active (re-running when returning to a
graph-bearing tab). Addresses Codex review on PR tinyhumansai#5080.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 21, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9dcd7cc66d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/src/pages/Brain.tsx
Brain calls useSubconscious() unconditionally, which fires subconsciousStatus /
openhumanHeartbeatSettingsGet and installs a 5s poll. Folding Orchestration
under Brain meant opening Brain > Orchestration (and the redirected
/orchestration) now kept those unrelated heartbeat/subconscious RPCs running —
which the standalone OrchestrationPage never did. Add an `enabled` param to
useSubconscious (default true, back-compat) that skips the initial fetch + poll
when false, and pass `activeTab === 'subconscious'` from Brain. The status is
consumed only on that tab. Addresses Codex review on PR tinyhumansai#5080.
@coderabbitai coderabbitai Bot added bug feature Net-new user-facing capability or product behavior. and removed working A PR that is being worked on by the team. labels Jul 21, 2026

@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: 3

🧹 Nitpick comments (1)
app/src/hooks/__tests__/useSubconscious.test.ts (1)

84-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover enabled-state transitions, not only initial disabled mounting.

Add a rerender test that starts enabled, verifies polling, switches to false and verifies it stops, then switches back to true and verifies polling resumes. This would exercise the cleanup and dependency behavior introduced by the hook change.

🤖 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 `@app/src/hooks/__tests__/useSubconscious.test.ts` around lines 84 - 98, Add a
rerender-based test for useSubconscious that mounts enabled and verifies RPC
polling, rerenders with false and confirms polling stops, then rerenders with
true and confirms polling resumes. Use the existing subconsciousStatus and
openhumanHeartbeatSettingsGet mocks and timer advancement, ensuring the
assertions exercise cleanup and dependency behavior across enabled-state
transitions.
🤖 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 `@app/src/hooks/useSubconscious.ts`:
- Around line 160-167: Add namespaced debug diagnostics to the polling effect
around the enabled guard and interval lifecycle: log when polling is skipped
because enabled is false, when the interval is started, and when cleanup tears
it down. Use the repository’s established diagnostics/logging mechanism and
fixed grep-friendly messages only; do not include sensitive data.
- Around line 160-167: Update the refresh lifecycle in useSubconscious so
disabling and re-enabling cannot allow overlapping requests or stale responses
to update state. Keep fetchingRef.current associated with the active refresh
request, or add generation/abort handling so cleanup invalidates the prior
request and its results are ignored; preserve the existing interval behavior for
enabled state.

In `@app/src/services/daemonHealthService.ts`:
- Around line 162-172: Update startHealthTimeout to associate each scheduled
callback with the currently active timeout identity or generation, and have
callbacks return without changing status or clearing healthTimeoutId when they
are stale. Preserve the existing disconnected transition only for the active
watchdog, and add a fake-timer regression test covering re-arming exactly at the
timeout boundary.

---

Nitpick comments:
In `@app/src/hooks/__tests__/useSubconscious.test.ts`:
- Around line 84-98: Add a rerender-based test for useSubconscious that mounts
enabled and verifies RPC polling, rerenders with false and confirms polling
stops, then rerenders with true and confirms polling resumes. Use the existing
subconsciousStatus and openhumanHeartbeatSettingsGet mocks and timer
advancement, ensuring the assertions exercise cleanup and dependency behavior
across enabled-state transitions.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 79765fd8-6ac8-4e88-b5bf-9b7feff41025

📥 Commits

Reviewing files that changed from the base of the PR and between 1546c38 and 42bf4eb.

📒 Files selected for processing (10)
  • app/src/AppRoutes.tsx
  • app/src/components/LocalAIDownloadSnackbar.tsx
  • app/src/hooks/__tests__/useSubconscious.test.ts
  • app/src/hooks/useSubconscious.ts
  • app/src/pages/Brain.tsx
  • app/src/pages/__tests__/Brain.test.tsx
  • app/src/pages/__tests__/OrchestrationRedirect.test.tsx
  • app/src/providers/CoreStateProvider.tsx
  • app/src/services/daemonHealthService.ts
  • tests/json_rpc_e2e.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/json_rpc_e2e.rs
  • app/src/pages/tests/Brain.test.tsx
  • app/src/pages/Brain.tsx
  • app/src/providers/CoreStateProvider.tsx
  • app/src/components/LocalAIDownloadSnackbar.tsx

Comment on lines +160 to +167
if (!enabled) return;
refresh();
const interval = setInterval(refresh, 5000);
return () => {
clearInterval(interval);
fetchingRef.current = false;
};
}, [refresh]);
}, [refresh, enabled]);

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add namespaced diagnostics for the polling lifecycle.

The new skip/start/cleanup branches should emit grep-friendly debug logs for disabled polling, interval setup, and teardown without logging sensitive data. This is required for new or changed flows by the repository diagnostics guideline.

🤖 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 `@app/src/hooks/useSubconscious.ts` around lines 160 - 167, Add namespaced
debug diagnostics to the polling effect around the enabled guard and interval
lifecycle: log when polling is skipped because enabled is false, when the
interval is started, and when cleanup tears it down. Use the repository’s
established diagnostics/logging mechanism and fixed grep-friendly messages only;
do not include sensitive data.

Source: Coding guidelines


🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Prevent overlapping refreshes across enabled-state transitions.

When enabled changes to false, cleanup resets fetchingRef.current without cancelling or invalidating the existing refresh(). A rapid false → true transition can start a second Promise.all; whichever response finishes last may overwrite status/settings with stale data. Keep the in-flight guard tied to the request, or add request-generation/abort handling that ignores stale results.

🤖 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 `@app/src/hooks/useSubconscious.ts` around lines 160 - 167, Update the refresh
lifecycle in useSubconscious so disabling and re-enabling cannot allow
overlapping requests or stale responses to update state. Keep
fetchingRef.current associated with the active refresh request, or add
generation/abort handling so cleanup invalidates the prior request and its
results are ignored; preserve the existing interval behavior for enabled state.

Comment on lines +162 to 172
private startHealthTimeout(sessionToken?: string | null): void {
if (this.healthTimeoutId) {
clearTimeout(this.healthTimeoutId);
}

const userId = this.getUserId();
const userId = this.getUserId(sessionToken);
this.healthTimeoutId = setTimeout(() => {
console.warn('[DaemonHealth] Health timeout reached - setting status to disconnected');
setDaemonStatus(userId, 'disconnected');
this.healthTimeoutId = null;
}, this.HEALTH_TIMEOUT_MS);

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant service and test files.
git ls-files 'app/src/services/daemonHealthService.ts' 'app/src/services/__tests__/daemonHealthService.test.ts'

echo '--- daemonHealthService.ts outline ---'
ast-grep outline app/src/services/daemonHealthService.ts --view expanded || true

echo '--- daemonHealthService.test.ts outline ---'
ast-grep outline app/src/services/__tests__/daemonHealthService.test.ts --view expanded || true

echo '--- relevant snippets ---'
sed -n '130,230p' app/src/services/daemonHealthService.ts
echo '--- tests around timer behavior ---'
sed -n '1,260p' app/src/services/__tests__/daemonHealthService.test.ts

Repository: tinyhumansai/openhuman

Length of output: 8538


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for timer re-arming, clearTimeout, and status transitions in the service.
rg -n "healthTimeoutId|clearTimeout|setTimeout|disconnected|re-arm|snapshot" app/src/services/daemonHealthService.ts app/src/services/__tests__/daemonHealthService.test.ts

Repository: tinyhumansai/openhuman

Length of output: 6707


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the exact service/test snippets and look for existing coverage.
sed -n '1,260p' app/src/services/daemonHealthService.ts
echo '---'
sed -n '1,260p' app/src/services/__tests__/daemonHealthService.test.ts
echo '--- timer usage ---'
rg -n "startHealthTimeout|clearTimeout|setTimeout|healthTimeoutId|disconnected" app/src/services/daemonHealthService.ts app/src/services/__tests__/daemonHealthService.test.ts

# Small Node probe: once a timeout callback is already queued/running, clearTimeout cannot stop it.
node - <<'JS'
const events = [];
let id = setTimeout(() => {
  events.push('old-fired');
}, 0);

setTimeout(() => {
  clearTimeout(id);
  id = setTimeout(() => {
    events.push('new-fired');
  }, 10);
}, 0);

setTimeout(() => {
  console.log(events.join(','));
}, 30);
JS

Repository: tinyhumansai/openhuman

Length of output: 15874


Guard against stale watchdog callbacks. A timeout that’s already queued can still run after clearTimeout(), so an old watchdog can flip a healthy daemon to disconnected and clear the replacement timer. Track the active timeout by identity or generation and ignore stale callbacks; add a fake-timer regression test that re-arms at the timeout boundary.

🤖 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 `@app/src/services/daemonHealthService.ts` around lines 162 - 172, Update
startHealthTimeout to associate each scheduled callback with the currently
active timeout identity or generation, and have callbacks return without
changing status or clearing healthTimeoutId when they are stale. Preserve the
existing disconnected transition only for the active watchdog, and add a
fake-timer regression test covering re-arming exactly at the timeout boundary.

@senamakel

Copy link
Copy Markdown
Member Author

Superseded by #5075, which merged the same Orchestration-under-Brain fold + daemon-health/local-AI cleanup into main. The net-new review fixes from this PR (daemon-health identity-flip race, LocalAI poll-freeze guard, Orchestration sub-tab graph/subconscious gating, redirect diagnostics + tests, and the health.updated_at RPC assertion) have been salvaged onto a fresh branch off main in #5085. Closing as a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant