Skip to content

feat(orchestration): subconscious split-brain layer (stages 4-8)#4430

Merged
senamakel merged 6 commits into
tinyhumansai:mainfrom
senamakel:feat/orchestration-stage4-graph
Jul 3, 2026
Merged

feat(orchestration): subconscious split-brain layer (stages 4-8)#4430
senamakel merged 6 commits into
tinyhumansai:mainfrom
senamakel:feat/orchestration-stage4-graph

Conversation

@senamakel

@senamakel senamakel commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

  • Build the subconscious-orchestration layer: wrapped Claude Code / Codex sessions talk to the owner agent over tiny.place Signal DMs, and each inbound DM drives one autonomous wake cycle on a single tinyagents graph.
  • Wake graph (stages 4–5): normalize → frontend(1) → execute → compress → world_diff → frontend(2) → send_dm → context_guard → done, checkpointed under thread orchestration:<session_id>; two-pass Quick-LLM front end + reasoning core with sub-agent spawning, 20:1 compression, append-only world diff, and 80–90% context-eviction guard.
  • Subconscious steering (stage 6): the offline SubconsciousEngine tick reviews compressed history + the cumulative world diff and emits short steering directives injected into later reasoning prompts — no channels, no external effects.
  • RPC + UI (stage 7): openhuman.orchestration_* internal controllers + a rewired TinyPlaceOrchestrationTab reading real store classification, live socket updates, and a Master composer.
  • Hardening + observability (stage 8): scheduler-gate deferral, no-duplicate-DM on failure, orchestration.status cursor-lag/last-error, and a log-leak guard.

Problem

Wrapped coding-agent sessions had no way to be coordinated by the owner agent: stage 3 only ingested their DMs into a store. There was no autonomous reply loop, no reasoning/memory pipeline, no offline reflection, and the Brain tab bucketed raw envelopes with string heuristics rather than real classification.

Solution

  • One OrchestrationState flows through a single command-routing graph; every behaviour-bearing node is bundled behind one injected OrchestrationRuntime so the graph mechanics are hermetically unit-testable with a stub while production wires the real agents/store/memory.
  • The subconscious is a decoupled out-of-band writer (never a graph edge): it stamps a directive into an append-only store with cycle-count expiry; seed_state loads the current directive into state at cycle start.
  • Renderer-only RPC controllers + an orchestration:message socket bridge power the tab; the frontend is a presentational component over a useOrchestrationChats hook.
  • Design decisions: injected-runtime seam for testability; deterministic cycle_id for resume-idempotent store writes; strict 20:1 compression budget with a 200-token floor; loop-continuity backstop on max_supersteps.

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% — 48 orchestration + 52 loader + 28 about_app Rust tests + the tab's 8 Vitest tests cover the changed lines (graph walk, compression budget/floor, world-diff append-only, context-guard threshold, steering parse/expiry, provider-error/no-dup-DM, malformed flood, log-leak guard, read-surface round-trip).
  • N/A: Coverage matrix — no docs/TEST-COVERAGE-MATRIX.md feature-row schema exists for this domain; behaviour is covered by the tests above.
  • N/A: No matrix feature IDs apply to this change.
  • No new external network dependencies introduced (all tests hermetic; provider calls use the factory test override / stub runtimes).
  • N/A: No release-cut smoke surface touched (feature is Beta, behind the [orchestration] config block).
  • N/A: No issue to close — planned work under docs/plans/subconscious-orchestration/.

Impact

  • Desktop only (Brain → Orchestration tab). Gated by the [orchestration] config block (enabled, debounce_ms, max_supersteps, message_window, context_evict_threshold, subagent_concurrency).
  • Security: tinyplace identity stays wallet-derived; Signal bodies stay E2E (relay sees ciphertext); message bodies / plaintext / seeds are never logged (guarded by a source-scan test). Adds two internal-registry RPC namespaces (orchestration, renderer-only) and two built-in agents (frontend_agent, reasoning_agent).

Related

  • Closes:
  • Follow-up PR(s)/TODOs: full tests/json_rpc_e2e.rs harness + mock tiny.place relay, WDIO Linux lane, and the coverage-gate CI wiring (stage-8 CI-infra items); richer per-tool execution trace for compression; live AgentTurnUsage-based context utilization.

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

Linear Issue

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

Commit & Branch

  • Branch: feat/orchestration-stage4-graph
  • Commit SHA: e7bf83e

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: cargo test --lib openhuman::orchestration (48 passed), pnpm test TinyPlaceOrchestrationTab (8 passed)
  • Rust fmt/check (if changed): cargo check --manifest-path Cargo.toml green; rustfmt applied
  • N/A: Tauri fmt/check — no app/src-tauri Rust changed (socketio.rs bridge is in the root core crate)

Validation Blocked

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

Behavior Changes

  • Intended behavior change: adds an autonomous orchestration loop + Brain Orchestration tab for wrapped agent sessions, opt-in via config.
  • User-visible effect: the Brain → Orchestration tab shows master/subconscious/per-session windows on real data with live updates and a Master composer.

Summary by CodeRabbit

  • New Features

    • Added a new orchestration experience with session lists, pinned master/subconscious chats, live updates, and a message composer.
    • Introduced support for sending master chat messages with immediate on-screen updates.
    • Added orchestration status and steering information to the UI.
  • Bug Fixes

    • Improved chat refresh and read-state handling.
    • Added retry handling for loading failures and better recovery after send errors.
  • Documentation

    • Expanded architecture documentation for the orchestration workflow.
  • Localization

    • Added new UI text in multiple languages.

senamakel added 6 commits July 2, 2026 17:54
…nodes

Build the single orchestration wake graph (spec's one StateGraph) as a
tinyagents CompiledGraph: OrchestrationState flows through
normalize -> frontend -> execute -> frontend -> send_dm -> context_guard -> done,
checkpointed under thread orchestration:<session_id>. The frontend (Quick LLM,
hint:chat), reasoning core (stubbed this stage), and DM sender are injected as
trait objects so graph mechanics are unit-testable with stubs.

- graph/state.rs: OrchestrationState + CompressedEntry + WorldDiff (serde).
- graph/mod.rs: build/run/topology; command-routing frontend node with a
  terminate-on-channel_response predicate + max_supersteps backstop.
- tools.rs: reply_to_channel + defer_to_orchestrator front-end decision tools.
- frontend_agent/: hint:chat built-in package, registered in BUILTINS.
- ops.rs: debounced, idempotent invoke_orchestration_graph seeding state from
  the stage-3 store; production nodes (frontend agent, Signal DM sender).
- bus.rs: OrchestrationWakeSubscriber on OrchestrationSessionMessage.
- config: debounce_ms / max_supersteps / message_window knobs.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
…er test

- Register orchestration:wake in all_graph_topologies() for debug/inspection.
- Add loader test asserting frontend_agent resolves via hint:chat with exactly
  the two decision tools (Quick-tier verification, stage 4 acceptance).
- Extend the non-worker-tier allowlist for the new chat-tier frontend_agent.
- rustfmt.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
Replace the stage-4 execute stub with the real reasoning + memory mechanics of
the unified wake graph. New topology:
  normalize -> frontend(1) -> execute -> compress -> world_diff -> frontend(2)
    -> send_dm -> context_guard -> done

- Consolidate the graph behind one injected OrchestrationRuntime trait (frontend,
  execute, compress, world_diff, context_utilization, evict, send_dm) so the
  structure stays hermetically testable with a single stub.
- execute node: reasoning_agent built-in (hint:reasoning) with the per-cycle
  subconscious steering directive woven into its system prompt via a task-local;
  spawns worker sub-agents. Trace captured for compression.
- compress node (graph/compress.rs): strict 20:1 output budget with a 200-token
  floor (only when still compressive), retry-once-then-truncate enforcement, and
  an idempotent compressed_history store row per cycle_id.
- world_diff node (graph/world_diff.rs): append-only timeline, monotonic seq from
  genesis, terminal_state kv, idempotent by cycle_id.
- context_guard: utilization vs assumed window; at >= context_evict_threshold
  (clamped 0.8-0.9) evicts oldest compressed entries to memory RAG under
  path_scope orchestration/<session>, resets utilization. Runs after send_dm,
  before END.
- OrchestrationState gains cycle_id (deterministic, for resume-idempotent store
  writes) + execution_trace. New store tables compressed_history + world_diff.
- reasoning_agent package registered in BUILTINS; config gains
  context_evict_threshold + subagent_concurrency.

Tests: compress budget/floor/enforce, world-diff append-only+idempotence, node
ordering (guard-before-END), context-guard threshold 0.84 vs 0.86, steering in
prompt, full-cycle e2e (one DM + one compressed row + one diff entry +
checkpoints). 29 orchestration + 52 loader tests green.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
Extend the SubconsciousEngine tick with an offline 'orchestration_review' stage
that consumes stage-5 compressed history + the cumulative world-diff timeline and
emits short, dense steering directives injected into the reasoning core's prompt
on later cycles. The subconscious stays fully offline — the synthesis is a
tool-free provider chat on the hint:subconscious route under SubconsciousTainted
origin; no channels, no external effects.

- orchestration/steering.rs: SteeringDirective + ParsedSteering, the 20:1-aware
  synthesis prompt (2-3 few-shot examples, STEERING_DIRECTIVE + expires_after_cycles
  contract), and the parser (NONE vs contract-violation distinction, length cap).
- orchestration/store.rs: append-only steering_directives table (supersede chain +
  cycle-count expiry), global reasoning-cycle counter, review cursor, and
  unreviewed-compressed / recent-world-mutation readers.
- ops.rs::run_orchestration_review: load unreviewed data -> synthesize (retry once
  on contract violation, skip on 2nd) -> persist directive (supersede prior) +
  advance cursor + publish OrchestrationMessage{Subconscious} to the pinned local
  window. Idempotent (keys on new compressed rows) and cheap when idle.
- ops.rs::seed_state: out-of-band writer pattern — bump the cycle counter and load
  the current non-expired directive into state.subconscious_steering at cycle start;
  the reasoning execute node (stage 5) weaves it into its prompt.
- engine.rs: run the review stage before memory_diff, independent of source syncs;
  existing memory-diff / decide / notify_user behavior untouched.

Tests: steering parse/contract, supersede+expiry, cursor idempotence, offline
integration (seed rows -> tick -> directive persisted -> next cycle seeds it into
state + surfaces in the Subconscious window), and the isolation invariant (no
channel/outbound tools). 39 orchestration + 71 subconscious tests green.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
…rewire

Expose the orchestration layer over JSON-RPC and rewire the Brain tab onto real
store classification + live socket updates + a Master composer.

Backend (Rust):
- orchestration/schemas.rs: internal-registry controllers (renderer-only)
  openhuman.orchestration_{sessions_list, messages_list, send_master_message,
  mark_read, status}; camelCase DTOs, computed active + unread, pinned master +
  subconscious windows always present.
- orchestration/store.rs: list_sessions, list_messages_by_session (paged, keyed by
  session_id so pinned windows aggregate across peers), unread_count / mark_chat_read
  (read cursor), latest_master_peer (default send recipient).
- orchestration/bus.rs + core/socketio.rs: a broadcast bus fanned out as an
  orchestration:message socket event ({agentId, sessionId, chatKind}) for live UI;
  emitted for every persisted chat message (inbound, master, subconscious).
- core/all.rs: register the internal controllers + namespace description.

Frontend (delegated, integrated):
- app/src/lib/orchestration/orchestrationClient.ts: typed callCoreRpc wrappers +
  PaymentRequiredError passthrough.
- app/src/lib/orchestration/useOrchestrationChats.ts: sessions/messages loads,
  mark_read on open, status/steering, optimistic master send with rollback, and the
  orchestration:message socket subscription doing targeted refetch.
- TinyPlaceOrchestrationTab.tsx: presentational over the hook; dropped
  buildChats/chatKindForEnvelope heuristics; preserved pairing UX + testids; added
  Master composer, steering chip, per-pane loading, unread badges.
- i18n keys across en + 13 locales.

Tests: 45 orchestration backend tests (schemas shape, chat resolution, read-surface
round-trip, unread/mark_read, latest_master_peer) + the tab test suite (8/8:
sessions/messages render, mark_read on open, master send optimistic append, socket
refetch, pairing). typecheck/lint/i18n:check green. Full-stack json_rpc_e2e deferred
to stage 8.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
…tests

Harden the orchestration layer to run unattended, audit logging, and prove the
failure modes with automated tests.

Hardening (ops.rs):
- Every wake cycle awaits scheduler_gate::wait_for_capacity() — a Paused/Throttled
  gate defers the cycle (message stays in the store, cursor untouched), nothing
  dropped.
- invoke_with_runtime: the idempotence cursor advances ONLY on a completed,
  DM-sent cycle, so a provider error mid-graph leaves no outbound DM and the next
  trigger resumes with no duplicate (dm_sent latch + deterministic cycle_id keep
  store writes idempotent).
- record_last_error surfaces failures for orchestration.status (never a body).

Observability:
- orchestration.status now exposes ingest_cursor_lag (pending wake work) + last_error
  alongside steering directive + last tick (store::ingest_cursor_lag).
- Nodes already log entry/exit with session_id/cycle_id/tick_id correlation ids.

Tests:
- provider_error_mid_graph_sends_no_dm_and_a_later_cycle_does_not_double_send
- malformed_envelope_flood_all_fall_back_to_master_without_panic
- orchestration_logs_never_reference_message_bodies (source-scan leak guard:
  no plaintext/body/seed in any log line)
- read-surface round-trip + latest_master_peer (stage 7 data logic)
48 orchestration + 28 about_app tests green.

Docs:
- gitbooks/developing/architecture/orchestration.md (full narrative: wake graph,
  steering loop, RPC/UI, run-unattended guarantees).
- about_app: Session Orchestration capability (Intelligence, Beta).

Deferred to CI infra follow-up: the full tests/json_rpc_e2e.rs harness wiring +
mock tiny.place relay, the WDIO Linux lane, and the coverage-gate lane. The loop
is covered hermetically at the domain level (full-cycle e2e, ingest->graph->store,
review->steering->next-cycle) plus the failure-mode suite above.

Claude-Session: https://claude.ai/code/session_01MjTiUcPjbqXskr9fC1eLKq
@senamakel senamakel requested a review from a team July 3, 2026 04:59
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a subconscious orchestration layer: a checkpointed wake graph coordinating front-end triage and reasoning agents, persisted compressed history/world-diff/steering directives, a debounced wake/review runtime sending signal DMs, a new JSON-RPC read surface with socket broadcast, and a reworked renderer orchestration tab with client, hook, and translations.

Changes

Subconscious Orchestration Feature

Layer / File(s) Summary
Config and capability/agent registration
src/openhuman/config/schema/orchestration.rs, src/openhuman/about_app/catalog_data.rs, src/openhuman/agent_registry/agents/loader.rs, src/openhuman/tools/mod.rs, src/openhuman/tools/ops.rs
Extends OrchestrationConfig with tuning fields and effective_evict_threshold(), adds a session_orchestration capability entry, registers frontend_agent/reasoning_agent builtins, and wires the new decision tools into the tool registry.
Wake graph core
src/openhuman/orchestration/graph/*.rs
Defines OrchestrationState, compression budget/truncation, world-diff helpers, and the compiled wake graph (build_orchestration_graph, run_orchestration_graph, topology), with mechanics/ordering/eviction tests.
Front-end/reasoning agents and decision tools
src/openhuman/orchestration/frontend_agent/*, .../reasoning_agent/*, .../tools.rs, .../types.rs
Adds two-pass frontend_agent and steering-aware reasoning_agent (toml/graph/prompt), task-local steering scope, ReplyToChannelTool/DeferToOrchestratorTool, and ChatKind::from_str.
Persistence store and steering logic
src/openhuman/orchestration/store.rs, .../steering.rs
Adds schema/queries for sessions, compressed history, world diff, KV cursors, and steering directive parsing/prompt building.
Wake/review runtime and wiring
src/openhuman/orchestration/ops.rs, .../bus.rs, src/openhuman/subconscious/engine.rs, src/core/jsonrpc.rs, src/openhuman/orchestration/mod.rs
Implements debounced wake scheduling, idempotent cursor advancement, review-driven steering synthesis, the production runtime, socket broadcast bus, wake subscriber, and subconscious tick integration.
JSON-RPC schemas and socket bridge
src/openhuman/orchestration/schemas.rs, src/core/all.rs, src/core/socketio.rs, src/openhuman/tinyagents/topology.rs, src/openhuman/tinyplace/mod.rs
Adds orchestration controllers (sessions_list, messages_list, send_master_message, mark_read, status), registers them internal-only, broadcasts orchestration:message over sockets, and exposes wake-graph topology.
Renderer client, hook, and UI
app/src/lib/orchestration/orchestrationClient.ts, .../useOrchestrationChats.ts, app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx, *.test.tsx, app/src/lib/i18n/*.ts
Adds a typed RPC client, a session/message/composer hook with socket refetching, a reworked tab UI with separated pairing state and master composer, updated tests, and new translation strings across locales.
Architecture docs
gitbooks/developing/architecture/orchestration.md
Documents the wake cycle, graph mechanics, offline steering loop, RPC/UI surface, guarantees, and config block.

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

Sequence Diagram(s)

sequenceDiagram
  participant Ingest as OrchestrationIngest
  participant Wake as OrchestrationWakeSubscriber
  participant Ops as schedule_wake/invoke_with_runtime
  participant Graph as run_orchestration_graph
  participant Store as OrchestrationStore
  participant Signal as tinyplace signal DM
  Ingest->>Wake: DomainEvent::OrchestrationSessionMessage
  Wake->>Ops: schedule_wake(agent_id, session_id)
  Ops->>Store: seed_state / cursor idempotence check
  Ops->>Graph: run_orchestration_graph(state)
  Graph->>Store: persist compressed_history, world_diff
  Graph->>Signal: send_dm(counterpart, body)
  Graph-->>Ops: dm_sent = true
  Ops->>Store: advance_cursor
Loading
sequenceDiagram
  participant Tab as TinyPlaceOrchestrationTab
  participant Hook as useOrchestrationChats
  participant Client as orchestrationClient
  participant Core as core RPC
  Tab->>Hook: submitComposer(body)
  Hook->>Hook: optimistic append to master chat
  Hook->>Client: sendMasterMessage(body)
  Client->>Core: openhuman.orchestration_send_master_message
  Core-->>Hook: response / PaymentRequiredError
  Hook->>Client: refetch messages/sessions
Loading

Possibly related PRs

  • tinyhumansai/openhuman#4400: Both PRs touch TinyPlaceOrchestrationTab's pairing flow using the same apiClient.orchestrationPairing.* endpoints.
  • tinyhumansai/openhuman#4425: Introduces the DomainEvent::OrchestrationSessionMessage variant consumed by the new wake subscriber added in this PR.

Suggested labels: feature, rust-core, agent, memory

Suggested reviewers: M3gA-Mind, graycyrus

Poem

A rabbit dreams while burrows hum,
A subconscious mind, a wake to come,
Compress the trace, diff the world,
One DM sent, no doubles hurled,
Steering whispers guide the way,
Hop on, brave code, it's launch day! 🐇✨

🚥 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 orchestration split-brain feature and its staged scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 3, 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: e7bf83e386

ℹ️ 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 on lines +231 to +232
.with_update(OrchestrationUpdate::Pass1 { instructions })
.with_goto(["execute"]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve pass-1 replies instead of always executing

When the front-end pass can answer immediately and follows the prompt by calling reply_to_channel, this branch still stores the returned text as Pass1 instructions and unconditionally routes to execute. That makes the quick-reply path unreachable: the reasoning agent receives the intended outbound reply as macro-instructions, can rewrite it, and does unnecessary LLM/tool work before any DM is sent. The front-end result needs to carry which decision tool fired and route reply_to_channel directly to send_dm.

Useful? React with 👍 / 👎.

Comment on lines +406 to +407
let latest = latest_seq(&state);
if !has_new_work(config, agent_id, session_id, latest) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Track Master wake cursors with a monotonic value

For Master messages, classify_message persists every plain DM with seq = 0, but this new idempotence guard uses only latest_seq. After the first successful Master wake advances the cursor to 0, every later Master DM from the same peer also has latest = 0, so this check skips the wake graph and no reply/steering cycle runs. Since schedule_wake only excludes Subconscious messages, Master DMs are intended wake inputs; use a timestamp/relay id or assign a monotonic Master seq before applying this cursor.

Useful? React with 👍 / 👎.

Comment on lines +104 to +105
let latest_seq = messages.iter().map(|m| m.seq).max().unwrap_or(0);
let cycle_id = format!("{session_id}#{latest_seq}");

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 Include agent id in cycle and checkpoint keys

Sessions are stored by (agent_id, session_id), and every peer's Master chat uses the same session_id (master), but this cycle id is derived only from session_id and latest_seq. The compressed-history/world-diff tables key by cycle_id, and the graph checkpoints under orchestration:<session_id>, so two linked agents with the same harness session id—or any two Master peers—can reuse/dedupe each other's rows and resume the wrong checkpointed state. Include the counterpart/agent id in the cycle/thread keys.

Useful? React with 👍 / 👎.

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

🧹 Nitpick comments (5)
src/openhuman/agent_registry/agents/loader.rs (1)

1744-1753: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing tier assertion for reasoning_agent.

reasoning_agent is excluded from other_builtins_default_to_worker_tier, but no test elsewhere pins its actual agent_tier. Unlike frontend_agent (asserted AgentTier::Chat at Line 911), if reasoning_agent's TOML omits agent_tier it silently falls back to the struct default (Worker) with nothing catching the regression.

Consider adding a reasoning_agent_is_registered_on_reasoning_tier... test symmetric to the frontend_agent one to lock its tier and tool surface.

🤖 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 `@src/openhuman/agent_registry/agents/loader.rs` around lines 1744 - 1753, Add
a dedicated tier test for reasoning_agent, since
other_builtins_default_to_worker_tier skips it but nothing currently asserts its
actual tier. Mirror the existing frontend_agent registration test in loader.rs
by locating the reasoning_agent registration path and asserting the expected
AgentTier (so a missing agent_tier in TOML can’t silently fall back to Worker),
and include any tool-surface checks that should stay tied to reasoning_agent.
src/openhuman/orchestration/store.rs (1)

199-249: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

list_recent_messages re-implements map_message_row instead of reusing it.

map_message_row (Lines 237-249) was specifically extracted to be reused across query_map arms, but list_recent_messages (Lines 353-381) duplicates the identical row-mapping closure inline instead of calling it. Any future schema/column change now has to be kept in sync in two places.

♻️ Proposed fix
     let rows = stmt
-        .query_map(params![agent_id, session_id, limit], |row| {
-            let chat_kind: String = row.get(3)?;
-            Ok(OrchestrationMessage {
-                id: row.get(0)?,
-                agent_id: row.get(1)?,
-                session_id: row.get(2)?,
-                chat_kind: crate::openhuman::orchestration::types::ChatKind::from_str(&chat_kind),
-                role: row.get(4)?,
-                body: row.get(5)?,
-                timestamp: row.get(6)?,
-                seq: row.get(7)?,
-            })
-        })?
+        .query_map(params![agent_id, session_id, limit], map_message_row)?
         .collect::<std::result::Result<Vec<_>, _>>()?;

Also applies to: 353-381

🤖 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 `@src/openhuman/orchestration/store.rs` around lines 199 - 249,
`list_recent_messages` is duplicating the same row-to-message mapping logic
already centralized in `map_message_row`, which creates a second place to
maintain the schema mapping. Update `list_recent_messages` to reuse
`map_message_row` for its `query_map` call instead of an inline closure, keeping
the mapping logic in one place and aligned with `list_messages_by_session`.
src/openhuman/orchestration/types.rs (1)

131-139: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider implementing std::str::FromStr instead of an inherent from_str.

Naming an inherent method from_str shadows the standard trait method; clippy's should_implement_trait lint commonly flags this pattern. Since this variant is infallible, either rename it (e.g., parse_kind) or implement FromStr with type Err = Infallible to satisfy the trait shape and enable .parse().

♻️ Option: implement `FromStr`
-impl ChatKind {
-    pub fn as_str(&self) -> &'static str {
+impl std::str::FromStr for ChatKind {
+    type Err = std::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(match s {
+            "session" => ChatKind::Session,
+            "subconscious" => ChatKind::Subconscious,
+            _ => ChatKind::Master,
+        })
+    }
+}
+
+impl ChatKind {
+    pub fn as_str(&self) -> &'static str {
         match self {
             ChatKind::Master => "master",
             ChatKind::Subconscious => "subconscious",
             ChatKind::Session => "session",
         }
     }
-
-    /// Parse the persisted string form back into a [`ChatKind`]. Unknown values
-    /// fall back to [`ChatKind::Master`] (the safe, non-session default).
-    pub fn from_str(s: &str) -> Self {
-        match s {
-            "session" => ChatKind::Session,
-            "subconscious" => ChatKind::Subconscious,
-            _ => ChatKind::Master,
-        }
-    }
 }

Since this is speculative on clippy lint configuration in CI, please confirm whether clippy is run with should_implement_trait enabled (default in clippy) before deciding priority.

🤖 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 `@src/openhuman/orchestration/types.rs` around lines 131 - 139, The inherent
ChatKind::from_str method is shadowing the standard parsing trait and may
trigger clippy’s should_implement_trait lint. Update the parsing API in
src/openhuman/orchestration/types.rs by either renaming the method to something
non-conflicting like parse_kind, or implementing std::str::FromStr for ChatKind
with an infallible error type so callers can use the standard .parse() path.
Check whether clippy is enabled with should_implement_trait in CI before
choosing the preferred fix.
app/src/lib/orchestration/orchestrationClient.ts (1)

77-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor type inconsistency: chatKind typed as string instead of OrchestrationChatKind.

SessionSummary.chatKind and OrchestrationMessage.chatKind use the OrchestrationChatKind union, but OrchestrationMessageEvent.chatKind (the socket payload) is a plain string. Since these appear to represent the same domain concept, tightening the type would give consumers safer narrowing.

♻️ Suggested type tightening
 export interface OrchestrationMessageEvent {
   agentId: string;
   sessionId: string;
-  chatKind: string;
+  chatKind: OrchestrationChatKind;
 }
🤖 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/lib/orchestration/orchestrationClient.ts` around lines 77 - 81, The
`OrchestrationMessageEvent` payload currently uses a generic `string` for
`chatKind`, which is inconsistent with `SessionSummary.chatKind` and
`OrchestrationMessage.chatKind`. Update the `OrchestrationMessageEvent`
interface in `orchestrationClient.ts` to use the existing
`OrchestrationChatKind` union so the socket payload matches the same domain
type. Make sure any references that consume `OrchestrationMessageEvent` still
compile with the tighter `chatKind` type.
app/src/components/intelligence/TinyPlaceOrchestrationTab.test.tsx (1)

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

Socket mock leaks across tests.

getSocketMock.mockReturnValue(socket as never) (line 269) overrides the shared mock's return value with a test-local socket object. vi.clearAllMocks() in beforeEach only clears call history, not mockReturnValue/mockImplementation, so every test that runs after this one in the same file will keep receiving this local socket instead of the shared module-level socket declared in the socketService mock (lines 36-39). It's currently harmless because no later test asserts on socket calls, but it's a latent test-isolation hazard for future additions.

🔧 Suggested fix
   it('refetches when an orchestration:message socket event fires', async () => {
     let handler: ((payload: unknown) => void) | undefined;
     const socket = {
       on: vi.fn((event: string, cb: (payload: unknown) => void) => {
         if (event === 'orchestration:message') handler = cb;
       }),
       off: vi.fn(),
     };
     getSocketMock.mockReturnValue(socket as never);

     render(<TinyPlaceOrchestrationTab />);

     await waitFor(() => expect(sessionsListMock).toHaveBeenCalled());
     const initialCalls = sessionsListMock.mock.calls.length;
     expect(handler).toBeDefined();

     handler?.({ agentId: '`@worker-alpha`', sessionId: 'master', chatKind: 'master' });

     await waitFor(() => expect(sessionsListMock.mock.calls.length).toBeGreaterThan(initialCalls));
+
+    // Restore the default shared socket so later tests aren't affected.
+    getSocketMock.mockReturnValue(defaultSocket as never);
   });
🤖 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/intelligence/TinyPlaceOrchestrationTab.test.tsx` around
lines 261 - 279, The test is overriding the shared getSocketMock return value
with a local socket, which can leak into later tests because vi.clearAllMocks()
does not reset mock implementations. Update the orchestration message test in
TinyPlaceOrchestrationTab.test.tsx to avoid permanently changing getSocketMock,
and instead use the shared socket mock from the socketService setup or
restore/reset the mock implementation after the test. Keep the event handler
assertion and refetch trigger logic the same, but ensure the mock state is
isolated per test.
🤖 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/lib/orchestration/useOrchestrationChats.ts`:
- Around line 177-200: The shared messagesState updates in loadMessages are not
scoped to the active chat, so stale responses can overwrite the UI for a
different selection. Update loadMessages in useOrchestrationChats to capture the
chatKey being loaded and only apply setMessagesByChat/setMessagesState when that
chat is still the currently selected one (and mountedRef.current is true). Apply
the same guard to the loading/ok/error branches referenced by the related state
writes so out-of-order responses from an old chat cannot affect the active
chat’s messagesState.
- Line 280: The fire-and-forget `loadSessions()` calls in
`useOrchestrationChats` can reject without being handled, which risks unhandled
promise rejections. Update both call sites (the `sendMaster` success path and
the socket message handler) to either wrap `loadSessions` in local try/catch or
append a `.catch` that swallows/logs the error similarly to `refreshStatus`, so
`orchestrationClient.sessionsList()` failures remain best-effort and do not
bubble globally.
- Around line 248-257: `selectChat` in `useOrchestrationChats` currently returns
early when the requested chat matches `selectedIdRef.current`, which prevents
retrying a failed message load for the active chat. Add a dedicated reload path
such as `retryMessages` to `UseOrchestrationChatsResult` that always re-invokes
`loadMessages` and `markRead` for the current `selected.id`, and update
`TinyPlaceOrchestrationTab`’s messages-error retry button to call that new
method instead of `selectChat(selected.id)`.
- Around line 313-332: The orchestration message listeners are attached only
when getSocket() is already available, so this effect can miss the first
connection from socketService.connect(...). Update the useEffect in
useOrchestrationChats to subscribe through the socket service’s queued listener
mechanism or make it rerun when the socket instance becomes available, and keep
the existing handler logic for orchestration:message/orchestration_message
intact.

In `@gitbooks/developing/architecture/orchestration.md`:
- Around line 16-31: The architecture diagram is an unlabeled fenced code block,
which triggers the markdownlint fenced-code-language warning. Update the
markdown fence in the orchestration documentation to include an appropriate
language tag such as text so the block passes lint. Keep the diagram content
unchanged and ensure the fix is applied to the specific fenced block showing the
Claude Code / Codex session flow.

In `@src/openhuman/config/schema/orchestration.rs`:
- Around line 65-69: The orchestration config field subagent_concurrency is
defined in the schema but never used, so the reasoning execute node ignores the
documented concurrency cap. Thread this value from the config struct into the
reasoning execute path and use it where sub-agents are spawned or scheduled.
Update the execute node logic to read subagent_concurrency from the
orchestration config instead of relying on a hardcoded limit, keeping
default_subagent_concurrency as the fallback source.

In `@src/openhuman/orchestration/schemas.rs`:
- Around line 67-76: The messages_list schema is missing the optional limit
input even though handle_messages_list supports it. Update the ControllerSchema
entry for messages_list to include an optional u64 limit alongside chat and
before, matching the handler’s default/capped pagination behavior. Use the
existing required_str and optional_str pattern in orchestration_messages_list so
the schema reflects the actual function signature.

In `@src/openhuman/orchestration/store.rs`:
- Around line 527-544: `list_unreviewed_compressed` currently pages only by
`created_at`, so rows sharing the same timestamp can be skipped when the review
cursor advances. Update the compressed-history scan to use a composite cursor
with `created_at` plus a unique tie-breaker such as `cycle_id`, and make the
query order by both fields consistently. Also adjust the cursor advancement
logic around `set_review_cursor` so it records both parts of the composite
position and resumes safely without missing same-timestamp rows.
- Around line 199-233: The paging logic in list_messages_by_session currently
uses only a timestamp cursor even though the results are ordered by timestamp
and seq, which can skip messages that share the same timestamp. Update the
cursor contract in the RPC schema and caller to pass both timestamp and seq, and
change the query/filter in list_messages_by_session to compare the composite
(timestamp, seq) boundary consistently with the existing ORDER BY timestamp
DESC, seq DESC.

---

Nitpick comments:
In `@app/src/components/intelligence/TinyPlaceOrchestrationTab.test.tsx`:
- Around line 261-279: The test is overriding the shared getSocketMock return
value with a local socket, which can leak into later tests because
vi.clearAllMocks() does not reset mock implementations. Update the orchestration
message test in TinyPlaceOrchestrationTab.test.tsx to avoid permanently changing
getSocketMock, and instead use the shared socket mock from the socketService
setup or restore/reset the mock implementation after the test. Keep the event
handler assertion and refetch trigger logic the same, but ensure the mock state
is isolated per test.

In `@app/src/lib/orchestration/orchestrationClient.ts`:
- Around line 77-81: The `OrchestrationMessageEvent` payload currently uses a
generic `string` for `chatKind`, which is inconsistent with
`SessionSummary.chatKind` and `OrchestrationMessage.chatKind`. Update the
`OrchestrationMessageEvent` interface in `orchestrationClient.ts` to use the
existing `OrchestrationChatKind` union so the socket payload matches the same
domain type. Make sure any references that consume `OrchestrationMessageEvent`
still compile with the tighter `chatKind` type.

In `@src/openhuman/agent_registry/agents/loader.rs`:
- Around line 1744-1753: Add a dedicated tier test for reasoning_agent, since
other_builtins_default_to_worker_tier skips it but nothing currently asserts its
actual tier. Mirror the existing frontend_agent registration test in loader.rs
by locating the reasoning_agent registration path and asserting the expected
AgentTier (so a missing agent_tier in TOML can’t silently fall back to Worker),
and include any tool-surface checks that should stay tied to reasoning_agent.

In `@src/openhuman/orchestration/store.rs`:
- Around line 199-249: `list_recent_messages` is duplicating the same
row-to-message mapping logic already centralized in `map_message_row`, which
creates a second place to maintain the schema mapping. Update
`list_recent_messages` to reuse `map_message_row` for its `query_map` call
instead of an inline closure, keeping the mapping logic in one place and aligned
with `list_messages_by_session`.

In `@src/openhuman/orchestration/types.rs`:
- Around line 131-139: The inherent ChatKind::from_str method is shadowing the
standard parsing trait and may trigger clippy’s should_implement_trait lint.
Update the parsing API in src/openhuman/orchestration/types.rs by either
renaming the method to something non-conflicting like parse_kind, or
implementing std::str::FromStr for ChatKind with an infallible error type so
callers can use the standard .parse() path. Check whether clippy is enabled with
should_implement_trait in CI before choosing the preferred fix.
🪄 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: df562305-69be-4081-801b-a290c83310a9

📥 Commits

Reviewing files that changed from the base of the PR and between 0f6f023 and e7bf83e.

📒 Files selected for processing (53)
  • app/src/components/intelligence/TinyPlaceOrchestrationTab.test.tsx
  • app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx
  • 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/lib/orchestration/orchestrationClient.ts
  • app/src/lib/orchestration/useOrchestrationChats.ts
  • gitbooks/developing/architecture/orchestration.md
  • src/core/all.rs
  • src/core/jsonrpc.rs
  • src/core/socketio.rs
  • src/openhuman/about_app/catalog_data.rs
  • src/openhuman/agent_registry/agents/loader.rs
  • src/openhuman/config/schema/orchestration.rs
  • src/openhuman/orchestration/bus.rs
  • src/openhuman/orchestration/frontend_agent/agent.toml
  • src/openhuman/orchestration/frontend_agent/graph.rs
  • src/openhuman/orchestration/frontend_agent/mod.rs
  • src/openhuman/orchestration/frontend_agent/prompt.md
  • src/openhuman/orchestration/frontend_agent/prompt.rs
  • src/openhuman/orchestration/graph/compress.rs
  • src/openhuman/orchestration/graph/mod.rs
  • src/openhuman/orchestration/graph/state.rs
  • src/openhuman/orchestration/graph/tests.rs
  • src/openhuman/orchestration/graph/world_diff.rs
  • src/openhuman/orchestration/mod.rs
  • src/openhuman/orchestration/ops.rs
  • src/openhuman/orchestration/reasoning_agent/agent.toml
  • src/openhuman/orchestration/reasoning_agent/graph.rs
  • src/openhuman/orchestration/reasoning_agent/mod.rs
  • src/openhuman/orchestration/reasoning_agent/prompt.md
  • src/openhuman/orchestration/reasoning_agent/prompt.rs
  • src/openhuman/orchestration/schemas.rs
  • src/openhuman/orchestration/steering.rs
  • src/openhuman/orchestration/store.rs
  • src/openhuman/orchestration/tools.rs
  • src/openhuman/orchestration/types.rs
  • src/openhuman/subconscious/engine.rs
  • src/openhuman/tinyagents/topology.rs
  • src/openhuman/tinyplace/mod.rs
  • src/openhuman/tools/mod.rs
  • src/openhuman/tools/ops.rs

Comment on lines +177 to +200
const loadMessages = useCallback(async (chatKey: string) => {
setMessagesState({ status: 'loading' });
try {
const result = await orchestrationClient.messagesList({
chat: chatKey,
limit: MESSAGE_LIMIT,
});
if (!mountedRef.current) return;
setMessagesByChat(prev => ({
...prev,
[chatKey]: sortMessages(result.messages.map(mapMessage)),
}));
setMessagesState({ status: 'ok' });
} catch (error) {
if (!mountedRef.current) return;
if (error instanceof PaymentRequiredError) {
setSessionsState({ status: 'payment_required' });
setMessagesState({ status: 'idle' });
return;
}
const message = error instanceof Error ? error.message : String(error);
setMessagesState({ status: 'error', message });
}
}, []);

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 | 🏗️ Heavy lift

Race condition: shared messagesState isn't scoped per chat.

loadMessages unconditionally writes messagesState (loading/ok/error) regardless of whether chatKey is still the selected chat when the response arrives. If a user switches chats while a request is in flight, an out-of-order response for the previously selected chat can overwrite the currently displayed chat's state — e.g. a late failure for chat A can stamp an error banner over chat B's successfully-loaded messages, or a late success for A can silently clear a real error for B (this also masks the retry button described below, since the wrong branch renders).

🔒️ Suggested fix: guard state writes by the still-selected chat
   const loadMessages = useCallback(async (chatKey: string) => {
-    setMessagesState({ status: 'loading' });
+    if (chatKey === selectedIdRef.current) setMessagesState({ status: 'loading' });
     try {
       const result = await orchestrationClient.messagesList({
         chat: chatKey,
         limit: MESSAGE_LIMIT,
       });
       if (!mountedRef.current) return;
       setMessagesByChat(prev => ({
         ...prev,
         [chatKey]: sortMessages(result.messages.map(mapMessage)),
       }));
-      setMessagesState({ status: 'ok' });
+      if (chatKey === selectedIdRef.current) setMessagesState({ status: 'ok' });
     } catch (error) {
       if (!mountedRef.current) return;
       if (error instanceof PaymentRequiredError) {
         setSessionsState({ status: 'payment_required' });
-        setMessagesState({ status: 'idle' });
+        if (chatKey === selectedIdRef.current) setMessagesState({ status: 'idle' });
         return;
       }
-      const message = error instanceof Error ? error.message : String(error);
-      setMessagesState({ status: 'error', message });
+      if (chatKey === selectedIdRef.current) {
+        const message = error instanceof Error ? error.message : String(error);
+        setMessagesState({ status: 'error', message });
+      }
     }
   }, []);

Also applies to: 211-215, 230-246

🤖 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/lib/orchestration/useOrchestrationChats.ts` around lines 177 - 200,
The shared messagesState updates in loadMessages are not scoped to the active
chat, so stale responses can overwrite the UI for a different selection. Update
loadMessages in useOrchestrationChats to capture the chatKey being loaded and
only apply setMessagesByChat/setMessagesState when that chat is still the
currently selected one (and mountedRef.current is true). Apply the same guard to
the loading/ok/error branches referenced by the related state writes so
out-of-order responses from an old chat cannot affect the active chat’s
messagesState.

Comment on lines +248 to +257
const selectChat = useCallback(
(chatKey: string) => {
if (chatKey === selectedIdRef.current) return;
setSelectedId(chatKey);
setMasterError(null);
void loadMessages(chatKey);
void markRead(chatKey);
},
[loadMessages, markRead]
);

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

selectChat no-ops on the current chat, breaking the message-error retry button.

selectChat early-returns when chatKey === selectedIdRef.current. TinyPlaceOrchestrationTab's messages-error retry button calls selectChat(selected.id) — which is always the currently selected chat id — so the retry action is a permanent no-op: loadMessages/markRead never re-fire and the user has no way to recover from a message-load failure without navigating away and back.

🐛 Proposed fix: expose a dedicated reload path
   const selectChat = useCallback(
     (chatKey: string) => {
       if (chatKey === selectedIdRef.current) return;
       setSelectedId(chatKey);
       setMasterError(null);
       void loadMessages(chatKey);
       void markRead(chatKey);
     },
     [loadMessages, markRead]
   );
+
+  const retryMessages = useCallback(() => {
+    void loadMessages(selectedIdRef.current);
+  }, [loadMessages]);

Then expose retryMessages in UseOrchestrationChatsResult and have the Tab's messages-error retry button call it instead of selectChat(selected.id).

🤖 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/lib/orchestration/useOrchestrationChats.ts` around lines 248 - 257,
`selectChat` in `useOrchestrationChats` currently returns early when the
requested chat matches `selectedIdRef.current`, which prevents retrying a failed
message load for the active chat. Add a dedicated reload path such as
`retryMessages` to `UseOrchestrationChatsResult` that always re-invokes
`loadMessages` and `markRead` for the current `selected.id`, and update
`TinyPlaceOrchestrationTab`’s messages-error retry button to call that new
method instead of `selectChat(selected.id)`.

if (!mountedRef.current) return true;
// Reconcile against the authoritative server state.
void loadMessages(MASTER_CHAT_KEY);
void loadSessions();

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 | 🟡 Minor | ⚡ Quick win

Unhandled promise rejection risk: void loadSessions() has no .catch.

Unlike refreshStatus (which swallows its own errors), loadSessions (lines 211-215) has no internal try/catch. It's called fire-and-forget via void loadSessions(); both in sendMaster's success branch (line 280) and in the socket message handler (line 320). If orchestrationClient.sessionsList() rejects at either call site, it becomes an unhandled promise rejection (console noise / potential global error-handler / Sentry noise) instead of being surfaced gracefully like the rest of the file's best-effort calls.

🔧 Suggested fix
-        void loadMessages(MASTER_CHAT_KEY);
-        void loadSessions();
+        void loadMessages(MASTER_CHAT_KEY);
+        void loadSessions().catch(() => {});

(and similarly at the socket-handler call site)

Also applies to: 320-320

🤖 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/lib/orchestration/useOrchestrationChats.ts` at line 280, The
fire-and-forget `loadSessions()` calls in `useOrchestrationChats` can reject
without being handled, which risks unhandled promise rejections. Update both
call sites (the `sendMaster` success path and the socket message handler) to
either wrap `loadSessions` in local try/catch or append a `.catch` that
swallows/logs the error similarly to `refreshStatus`, so
`orchestrationClient.sessionsList()` failures remain best-effort and do not
bubble globally.

Comment on lines +313 to +332
useEffect(() => {
const socket = socketService.getSocket();
if (!socket) return;
const handler = (payload: unknown) => {
const event = payload as OrchestrationMessageEvent | null;
if (!event || typeof event !== 'object') return;
const affected = event.chatKind === 'session' ? event.sessionId : event.chatKind;
void loadSessions();
void refreshStatus();
if (affected && affected === selectedIdRef.current) {
void loadMessages(affected);
}
};
socket.on('orchestration:message', handler);
socket.on('orchestration_message', handler);
return () => {
socket.off('orchestration:message', handler);
socket.off('orchestration_message', handler);
};
}, [loadSessions, loadMessages, refreshStatus]);

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "getSocket" -A15 app/src/services/socketService.ts

Repository: tinyhumansai/openhuman

Length of output: 5290


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== socketService connect/getSocket usage =="
rg -n "socketService\.(connect|getSocket|disconnect|onSocket|offSocket)|getSocket\(\)" app/src -g '!**/*.test.*'

echo
echo "== socketService.ts outline =="
ast-grep outline app/src/services/socketService.ts --view expanded

echo
echo "== useOrchestrationChats.ts outline =="
ast-grep outline app/src/lib/orchestration/useOrchestrationChats.ts --view expanded

Repository: tinyhumansai/openhuman

Length of output: 4948


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '150,260p' app/src/services/socketService.ts
echo
sed -n '260,360p' app/src/services/socketService.ts
echo
sed -n '1,220p' app/src/lib/orchestration/useOrchestrationChats.ts

Repository: tinyhumansai/openhuman

Length of output: 16370


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== socketService.ts connect logic =="
sed -n '150,240p' app/src/services/socketService.ts

echo
echo "== socketService.ts connection listeners =="
sed -n '240,360p' app/src/services/socketService.ts

echo
echo "== socketService.ts pending listener mechanics =="
sed -n '360,520p' app/src/services/socketService.ts

echo
echo "== useOrchestrationChats.ts relevant effect and socket access =="
rg -n "socketService|getSocket|orchestration:message|orchestration_message|useEffect" app/src/lib/orchestration/useOrchestrationChats.ts -n -A25 -B10

Repository: tinyhumansai/openhuman

Length of output: 20843


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== socketService.connect call sites =="
rg -n "socketService\.connect\(|\.connect\(" app/src -g '!**/*.test.*' | sed -n '1,200p'

echo
echo "== app bootstrap / providers =="
rg -n "socketService|SocketService|useOrchestrationChats|OrchestrationChats|connect\(" app/src/main.* app/src/App.* app/src/**/providers* app/src/**/Provider* app/src/**/index.* -g '!**/*.test.*' | sed -n '1,240p'

Repository: tinyhumansai/openhuman

Length of output: 1818


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== useOrchestrationChats effect vicinity =="
sed -n '280,360p' app/src/lib/orchestration/useOrchestrationChats.ts

echo
echo "== socketService on/addListener behavior =="
rg -n "pendingListeners|listenerMap|on\(|off\(|emitPendingListeners|queue" app/src/services/socketService.ts -A20 -B20

echo
echo "== any explicit readiness signal or subscribe-to-connect API =="
rg -n "backend.*connected|socket.*connected|setBackend\\(|isConnected\\(|getSocket\\(|socketReady|ready.*socket" app/src -g '!**/*.test.*' | sed -n '1,240p'

Repository: tinyhumansai/openhuman

Length of output: 32412


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== SocketProvider.tsx =="
sed -n '1,220p' app/src/providers/SocketProvider.tsx

echo
echo "== useOrchestrationChats consumers =="
rg -n "useOrchestrationChats\\(" app/src -g '!**/*.test.*'

echo
echo "== orchestration-related provider/tree references =="
rg -n "Orchestration|TinyPlace|Brain tab|orchestration chats" app/src -g '!**/*.test.*'

Repository: tinyhumansai/openhuman

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '150,220p' app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx
echo
sed -n '300,360p' app/src/pages/Brain.tsx

Repository: tinyhumansai/openhuman

Length of output: 4909


Subscribe after socket creation. socketService.connect(...) is async and getSocket() can be null when this effect runs, so the orchestration:message handlers never attach for that render. Use the service’s queued listener path or rerun when the socket instance becomes available.

🤖 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/lib/orchestration/useOrchestrationChats.ts` around lines 313 - 332,
The orchestration message listeners are attached only when getSocket() is
already available, so this effect can miss the first connection from
socketService.connect(...). Update the useEffect in useOrchestrationChats to
subscribe through the socket service’s queued listener mechanism or make it
rerun when the socket instance becomes available, and keep the existing handler
logic for orchestration:message/orchestration_message intact.

Comment on lines +16 to +31
```
Claude Code / Codex session
└─ tinyplace harness wrapper — tails the session JSONL → SessionEnvelopeV1
└─ Signal E2E DM → owner agent's tiny.place inbox [tagged sessionId, source, role]
└─ ingest (decrypt-once → classify → persist → ack) orchestration/ingest.rs
└─ OrchestrationSessionMessage event → debounced wake
└─ THE WAKE GRAPH (one tinyagents CompiledGraph) orchestration/graph/
normalize → frontend(1) → execute → compress → world_diff
▲ │
└───────────────────────────────────┘
└─(channel_response)─► send_dm ─► context_guard ─► done
└─ subconscious tick (offline, cron/heartbeat) — reviews compressed history +
cumulative world diff → emits a steering directive that later cycles inject
UI: Brain → Orchestration tab (orchestration.* RPC + orchestration:message socket)
```

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 | 🟡 Minor | ⚡ Quick win

Add a fence language here.

This code block triggers the markdownlint fenced-code-language warning. Mark it as text (or another appropriate language) so the docs pass lint.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 16-16: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@gitbooks/developing/architecture/orchestration.md` around lines 16 - 31, The
architecture diagram is an unlabeled fenced code block, which triggers the
markdownlint fenced-code-language warning. Update the markdown fence in the
orchestration documentation to include an appropriate language tag such as text
so the block passes lint. Keep the diagram content unchanged and ensure the fix
is applied to the specific fenced block showing the Claude Code / Codex session
flow.

Source: Linters/SAST tools

Comment on lines +65 to +69
/// Maximum concurrent execution sub-agents the reasoning `execute` node may
/// spawn per cycle. Default: `2`.
#[serde(default = "default_subagent_concurrency")]
pub subagent_concurrency: u32,
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'subagent_concurrency' --type=rust

Repository: tinyhumansai/openhuman

Length of output: 160


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files 'src/openhuman/**' | sed -n '1,200p'

echo "== search for concurrency-related config uses =="
rg -n --hidden --glob '!target' --glob '!node_modules' \
  'subagent_concurrency|default_subagent_concurrency|max_supersteps|context_evict_threshold|message_window|concurrent.*sub-agent|spawn.*sub-agent|reasoning_agent|execute node|execute\(' src/openhuman

echo "== search for execute/reasoning domain files =="
fd -a 'reasoning|execute|orchestration' src/openhuman

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the orchestration config file and nearby domain files.
sed -n '1,220p' src/openhuman/config/schema/orchestration.rs

echo "== outline candidate files =="
for f in $(fd -a 'orchestration|reasoning|execute' src/openhuman); do
  echo "--- $f ---"
  wc -l "$f"
done

Repository: tinyhumansai/openhuman

Length of output: 3219


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant file names =="
fd -a 'orchestration\.rs|reasoning|execute|state|graph' src/openhuman

echo "== references to orchestration config fields =="
rg -n --hidden --glob '!target' --glob '!node_modules' \
  'message_window|max_supersteps|context_evict_threshold|subagent_concurrency|seed_state|run_orchestration_graph|default_subagent_concurrency' src/openhuman

echo "== inspect orchestration config file =="
sed -n '1,220p' src/openhuman/config/schema/orchestration.rs

Repository: tinyhumansai/openhuman

Length of output: 12191


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== orchestration graph outline =="
ast-grep outline src/openhuman/orchestration/graph/mod.rs --view expanded | sed -n '1,220p'

echo "== reasoning agent graph outline =="
ast-grep outline src/openhuman/orchestration/reasoning_agent/graph.rs --view expanded | sed -n '1,220p'

echo "== targeted searches =="
rg -n --hidden --glob '!target' \
  'subagent_concurrency|spawn|parallel|concurrent|execute node|reasoning_agent|ExecuteOutcome' \
  src/openhuman/orchestration/graph/mod.rs \
  src/openhuman/orchestration/reasoning_agent/graph.rs

Repository: tinyhumansai/openhuman

Length of output: 2874


Wire subagent_concurrency into the reasoning execute path. The config field is currently unused, so the documented cap has no effect.

🤖 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 `@src/openhuman/config/schema/orchestration.rs` around lines 65 - 69, The
orchestration config field subagent_concurrency is defined in the schema but
never used, so the reasoning execute node ignores the documented concurrency
cap. Thread this value from the config struct into the reasoning execute path
and use it where sub-agents are spawned or scheduled. Update the execute node
logic to read subagent_concurrency from the orchestration config instead of
relying on a hardcoded limit, keeping default_subagent_concurrency as the
fallback source.

Comment on lines +67 to +76
"orchestration_messages_list" => ControllerSchema {
namespace: "orchestration",
function: "messages_list",
description: "List messages for a chat: \"master\", \"subconscious\", or a harness session id.",
inputs: vec![
required_str("chat", "Chat key: \"master\" | \"subconscious\" | <sessionId>."),
optional_str("before", "Exclusive ISO timestamp to page backwards from."),
],
outputs: vec![json_output("result", "{ messages: OrchestrationMessage[] }.")],
},

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the numeric TypeSchema variant available for an integer field.
rg -nP -C2 'enum TypeSchema' src/core

Repository: tinyhumansai/openhuman

Length of output: 411


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- TypeSchema ---'
sed -n '83,130p' src/core/mod.rs

echo '--- orchestration schemas around messages_list ---'
sed -n '60,90p' src/openhuman/orchestration/schemas.rs

echo '--- handle_messages_list ---'
sed -n '240,275p' src/openhuman/orchestration/schemas.rs

echo '--- optional_* helpers in orchestration schemas ---'
rg -n "fn optional_|fn required_|optional_int|optional_str|required_str|json_output" src/openhuman/orchestration/schemas.rs

echo '--- orchestration client messagesList ---'
rg -n "messagesList|limit" src -g '*orchestrationClient*' -g '*orchestration*'

Repository: tinyhumansai/openhuman

Length of output: 6108


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- helper definitions ---'
sed -n '402,440p' src/openhuman/orchestration/schemas.rs

echo '--- search for orchestrationClient/messagesList in repo ---'
rg -n "orchestrationClient|messagesList|messages_list" src -g '*ts' -g '*tsx' -g '*js' -g '*jsx'

Repository: tinyhumansai/openhuman

Length of output: 1277


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "fn optional_(u64|i64|int)|fn required_(u64|i64|int)|TypeSchema::(U64|I64)" src/openhuman src/core

Repository: tinyhumansai/openhuman

Length of output: 26221


Add limit to messages_list schema handle_messages_list already accepts an optional limit (default 100, capped at 500), so the schema should declare it too as an optional u64.

🤖 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 `@src/openhuman/orchestration/schemas.rs` around lines 67 - 76, The
messages_list schema is missing the optional limit input even though
handle_messages_list supports it. Update the ControllerSchema entry for
messages_list to include an optional u64 limit alongside chat and before,
matching the handler’s default/capped pagination behavior. Use the existing
required_str and optional_str pattern in orchestration_messages_list so the
schema reflects the actual function signature.

Comment on lines +199 to +233
/// List messages for a chat keyed by `session_id` alone (so the pinned `master` /
/// `subconscious` windows aggregate across peers). Newest `limit` returned in
/// chronological order; `before` (exclusive timestamp) pages backwards.
pub fn list_messages_by_session(
conn: &Connection,
session_id: &str,
limit: u32,
before: Option<&str>,
) -> Result<Vec<OrchestrationMessage>> {
let rows = match before {
Some(before) => {
let mut stmt = conn.prepare(
"SELECT id, agent_id, session_id, chat_kind, role, body, timestamp, seq
FROM messages WHERE session_id = ?1 AND timestamp < ?2
ORDER BY timestamp DESC, seq DESC LIMIT ?3",
)?;
let rows = stmt
.query_map(params![session_id, before, limit], map_message_row)?
.collect::<std::result::Result<Vec<_>, _>>()?;
rows
}
None => {
let mut stmt = conn.prepare(
"SELECT id, agent_id, session_id, chat_kind, role, body, timestamp, seq
FROM messages WHERE session_id = ?1
ORDER BY timestamp DESC, seq DESC LIMIT ?2",
)?;
let rows = stmt
.query_map(params![session_id, limit], map_message_row)?
.collect::<std::result::Result<Vec<_>, _>>()?;
rows
}
};
Ok(rows.into_iter().rev().collect())
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '160,280p' src/openhuman/orchestration/store.rs

echo
echo "== search callers =="
rg -n "list_messages_by_session|before" src/openhuman -g '!**/target/**'

echo
echo "== related schema references =="
rg -n "session_id.*before|before.*session_id|timestamp.*seq|chat_kind" src/openhuman -g '!**/target/**'

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files 'src/openhuman/**' | rg 'orchestration|message|schema|rpc'

echo
echo "== search message insert / timestamp generation =="
rg -n "timestamp|seq|insert.*messages|INSERT INTO messages|list_messages_by_session|before" src/openhuman -g '!**/target/**'

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== orchestration store tests around list_messages_by_session =="
sed -n '760,845p' src/openhuman/orchestration/store.rs

echo
echo "== orchestration schema cursor description =="
sed -n '60,90p' src/openhuman/orchestration/schemas.rs

echo
echo "== message insert/update paths =="
rg -n "INSERT INTO messages|UPDATE messages|timestamp =|seq =" src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 5528


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== message table schema and insert path =="
sed -n '1,170p' src/openhuman/orchestration/store.rs

echo
echo "== surrounding insert_message implementation =="
sed -n '170,240p' src/openhuman/orchestration/store.rs

echo
echo "== test message helper =="
sed -n '845,930p' src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 10037


Use a composite (timestamp, seq) cursor for paging. The query already sorts by (timestamp DESC, seq DESC), but before filters only on timestamp, so messages that share the boundary timestamp can be skipped. Update the RPC schema/caller to pass both values.

🤖 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 `@src/openhuman/orchestration/store.rs` around lines 199 - 233, The paging
logic in list_messages_by_session currently uses only a timestamp cursor even
though the results are ordered by timestamp and seq, which can skip messages
that share the same timestamp. Update the cursor contract in the RPC schema and
caller to pass both timestamp and seq, and change the query/filter in
list_messages_by_session to compare the composite (timestamp, seq) boundary
consistently with the existing ORDER BY timestamp DESC, seq DESC.

Comment on lines +527 to +544
/// Compressed-history rows not yet reviewed (created_at > cursor), oldest-first,
/// bounded. Returns `(created_at, text)`.
pub fn list_unreviewed_compressed(
conn: &Connection,
since_created_at: &str,
limit: u32,
) -> Result<Vec<(String, String)>> {
let mut stmt = conn.prepare(
"SELECT created_at, text FROM compressed_history
WHERE created_at > ?1 ORDER BY created_at ASC LIMIT ?2",
)?;
let rows = stmt
.query_map(params![since_created_at, limit], |r| {
Ok((r.get::<_, String>(0)?, r.get::<_, String>(1)?))
})?
.collect::<std::result::Result<Vec<_>, _>>()?;
Ok(rows)
}

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail
printf '\n## Files\n'
git ls-files 'src/openhuman/orchestration/store.rs' 'src/openhuman/**/store.rs' 'src/openhuman/**/mod.rs' | sed 's#^`#-` #'

printf '\n## Search related symbols\n'
rg -n "list_unreviewed_compressed|set_review_cursor|review cursor|compressed_history|created_at" src/openhuman/orchestration/store.rs src/openhuman -g '!**/target/**'

printf '\n## store.rs around relevant lines\n'
sed -n '1,260p' src/openhuman/orchestration/store.rs
printf '\n--- middle ---\n'
sed -n '260,620p' src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

set -euo pipefail
printf '\n## Schema/search for compressed_history\n'
rg -n "CREATE TABLE.*compressed_history|compressed_history" src/openhuman -g '!**/target/**'

printf '\n## Search for insert into compressed_history\n'
rg -n "INSERT INTO compressed_history|compressed_history" src/openhuman -g '!**/target/**'

printf '\n## Search for created_at generation format\n'
rg -n "created_at|strftime|now\\(|Utc::now|SystemTime|timestamp" src/openhuman -g '!**/target/**'

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

set -euo pipefail
sed -n '1,120p' src/openhuman/orchestration/store.rs
printf '\n---\n'
sed -n '380,560p' src/openhuman/orchestration/store.rs
printf '\n---\n'
sed -n '180,270p' src/openhuman/orchestration/ops.rs
printf '\n---\n'
sed -n '760,790p' src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 16063


🏁 Script executed:

set -euo pipefail
sed -n '800,860p' src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 2416


🏁 Script executed:

set -euo pipefail
printf '## src/openhuman/orchestration/store.rs\n'
sed -n '1,90p' src/openhuman/orchestration/store.rs
printf '\n## src/openhuman/orchestration/store.rs (compressed_history + cursor)\n'
sed -n '380,560p' src/openhuman/orchestration/store.rs
printf '\n## src/openhuman/orchestration/ops.rs (use of compressed history)\n'
sed -n '184,260p' src/openhuman/orchestration/ops.rs
printf '\n## tests around compressed history\n'
sed -n '760,860p' src/openhuman/orchestration/store.rs

Repository: tinyhumansai/openhuman

Length of output: 17191


🏁 Script executed:

set -euo pipefail
rg -n -C 4 "insert_compressed\\(|created_at: .*to_rfc3339|to_rfc3339\\(\\)" src/openhuman/orchestration/ops.rs src/openhuman/orchestration/store.rs
printf '\n--- around compressed write path ---\n'
sed -n '620,720p' src/openhuman/orchestration/ops.rs

Repository: tinyhumansai/openhuman

Length of output: 13380


Use a composite review cursor for compressed history. list_unreviewed_compressed pages only on created_at; if two rows land on the same timestamp, the later one can be skipped when set_review_cursor advances. Order and cursor by created_at plus a unique tie-breaker like cycle_id to make the scan safe.

🤖 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 `@src/openhuman/orchestration/store.rs` around lines 527 - 544,
`list_unreviewed_compressed` currently pages only by `created_at`, so rows
sharing the same timestamp can be skipped when the review cursor advances.
Update the compressed-history scan to use a composite cursor with `created_at`
plus a unique tie-breaker such as `cycle_id`, and make the query order by both
fields consistently. Also adjust the cursor advancement logic around
`set_review_cursor` so it records both parts of the composite position and
resumes safely without missing same-timestamp rows.

@sanil-23

sanil-23 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Heads-up on the red CI: Rust Core Coverage / PR CI Gate isn't a coverage-threshold miss — the coverage job crashes with exit 101 (13738 passed; 2 failed) before diff-cover runs, so no report is produced.

Root cause: frontend_agent and reasoning_agent are added to BUILTINS (agent_registry/agents/loader.rs) but not to RESOURCE_CATALOG, so two MCP tests panic:

  • mcp_server::resources::tests::catalog_mirrors_builtins
  • mcp_server::resources::tests::read_resource_returns_content_for_each_subagent

One-commit fix (register both in RESOURCE_CATALOG → their orchestration/<agent>/prompt.md) verified locally: cargo test --lib mcp_server::resources 9 pass, openhuman::orchestration 48 pass, cargo check --lib 0 errors. Since I can't push to your fork branch, it's on #4431 (single commit fix(orchestration): register frontend_agent/reasoning_agent in MCP resource catalog) — feel free to cherry-pick it onto this branch to turn CI green here.

Left the two P1 findings (graph/mod.rs:232 quick-reply routing; ops.rs:407 Master seq=0 cursor) untouched — they're logic bugs the current tests pass despite, so they need your context.

@senamakel senamakel merged commit d6f178f into tinyhumansai:main Jul 3, 2026
17 of 23 checks passed
sanil-23 added a commit to sanil-23/openhuman that referenced this pull request Jul 3, 2026
…e-id seam note

Addresses @M3gA-Mind review:
- store.rs: CREATE UNIQUE INDEX IF NOT EXISTS under the existing name is a
  SQLite no-op on DBs that already have the non-unique index (tinyhumansai#4430), so
  uniqueness never took on already-created stores. Drop the legacy index,
  de-dupe any pre-existing race rows (keep earliest per key so the UNIQUE build
  can't fail), and create the unique index under a new name — all idempotent on
  execute_batch. Adds a test simulating a legacy DB → migration → dedupe +
  duplicate-seq rejection.
- state.rs: document the cycle_id format-change migration seam (an in-flight
  cycle at the upgrade boundary may append one extra timeline entry; Beta-gated,
  not corruption).
senamakel added a commit to senamakel/openhuman that referenced this pull request Jul 3, 2026
…o tinyagents migration

Resolves the conflict in tinyagents/topology.rs (kept both upstream's new
orchestration:wake graph and our branch's delegation/workflow_runs/subagent/
researcher/spawn_parallel topologies) and the semantic breaks where upstream's
tinyhumansai#4430 depended on symbols this branch changed:

- agent_registry/agents/loader.rs: wrap the new frontend_agent/reasoning_agent
  graph_fn entries in Some(...) — our 08.4 work made graph_fn Option<fn()->AgentGraph>.
- orchestration/{graph/mod.rs,ops.rs,graph/state.rs}: port the wake graph off the
  retired SqlRunLedgerCheckpointer (deleted in 04.3) to the crate SqliteCheckpointer
  at a dedicated orchestration_checkpoints.db, mirroring agent_orchestration/delegation.rs.

Merged tree compiles clean; 607 tests green across the touched areas.

Claude-Session: https://claude.ai/code/session_0137dT9i1vLjeUQZ3mj8ZAct
sanil-23 added a commit to sanil-23/openhuman that referenced this pull request Jul 3, 2026
…e-id seam note

Addresses @M3gA-Mind review:
- store.rs: CREATE UNIQUE INDEX IF NOT EXISTS under the existing name is a
  SQLite no-op on DBs that already have the non-unique index (tinyhumansai#4430), so
  uniqueness never took on already-created stores. Drop the legacy index,
  de-dupe any pre-existing race rows (keep earliest per key so the UNIQUE build
  can't fail), and create the unique index under a new name — all idempotent on
  execute_batch. Adds a test simulating a legacy DB → migration → dedupe +
  duplicate-seq rejection.
- state.rs: document the cycle_id format-change migration seam (an in-flight
  cycle at the upgrade boundary may append one extra timeline entry; Beta-gated,
  not corruption).
sanil-23 added a commit to sanil-23/openhuman that referenced this pull request Jul 3, 2026
…tinyagents migration + versioned world-diff migration

Rebased onto current main (c43f796) which merged tinyhumansai#4399 (finish TinyAgents
migration) after tinyhumansai#4430 — leaving main red (Rust Quality) from two semantic
conflicts this repairs:
- agent_registry loader: BuiltinAgent.graph_fn is now Option<fn()->AgentGraph>;
  wrap frontend_agent/reasoning_agent in Some(...) (E0308).
- orchestration graph: tinyhumansai#4399 retired SqlRunLedgerCheckpointer for the tinyagents
  crate SqliteCheckpointer (graph_checkpoints.db). Migrate graph/mod.rs + the
  ops resume test to SqliteCheckpointer::open, mirroring delegation.rs (E0432).

Also addresses CodeRabbit on the world-diff unique index: move it into a
user_version-gated one-time migrate() (was CREATE UNIQUE INDEX IF NOT EXISTS —
a no-op on already-created stores), de-dupe legacy race rows, and reconcile
terminal_state so it can't point at a deleted duplicate's mutation. Test extended
with distinct mutations + stale terminal_state + user_version assertions.
senamakel added a commit to senamakel/openhuman that referenced this pull request Jul 3, 2026
…ansai#4430 squash-merge

The TinyAgents migration (tinyhumansai#4249) squash-merged on top of tinyhumansai#4430's subconscious
orchestration layer, but the pre-integration merge state landed: tinyhumansai#4430's wake
graph still references SqlRunLedgerCheckpointer (deleted by the migration in
04.3) and the new frontend_agent/reasoning_agent registrations pass a bare
graph_fn while the migration made that field Option<fn() -> AgentGraph>. main
does not compile (E0432 unresolved import + E0308 mismatched types).

Restore the fixes that never reached main:
- agent_registry/agents/loader.rs: wrap the two orchestration graph_fn entries
  in Some(...).
- orchestration/{graph/mod.rs, ops.rs test, graph/state.rs doc}: port the wake
  graph off the retired SqlRunLedgerCheckpointer to the crate SqliteCheckpointer
  at a dedicated orchestration_checkpoints.db, mirroring agent_orchestration/
  delegation.rs.

main + this fix compiles clean.

Claude-Session: https://claude.ai/code/session_0137dT9i1vLjeUQZ3mj8ZAct
sanil-23 added a commit to sanil-23/openhuman that referenced this pull request Jul 3, 2026
…ce mock

tinyhumansai#4399 raised RUNTIME_SNAPSHOT_TTL 2s -> 10s to fix a rebuild-stampede perf bug,
but app_state_snapshot_degrades_runtime_service_status_failures ages the cache
out with a 2.1s sleep — fine for the old 2s TTL, now < the 10s one, so the test
reads a stale cached snapshot from a prior test and never sees the injected
'forced status failure' (asserts service degrades to Unknown). Deterministic;
only surfaced now because main (with tinyhumansai#4399) doesn't compile until tinyhumansai#4431 repairs
the tinyhumansai#4399/tinyhumansai#4430 conflict, so this is the first branch to actually run it.

Fix: when OPENHUMAN_SERVICE_MOCK is active (a test-only env hook production
service status already honors), never serve from or write to the process-global
runtime cache — the mock's state changes between calls, so caching masks the
injected value and poisons later non-mocked reads. Full
config_auth_app_state_connectivity_e2e binary: 50 passed.
senamakel added a commit to senamakel/openhuman that referenced this pull request Jul 3, 2026
With the build restored, two pre-existing failures from the tinyhumansai#4249/tinyhumansai#4430 merge
seam now run:

- mcp_server/resources.rs: tinyhumansai#4430 added frontend_agent + reasoning_agent to the
  agent BUILTINS but not to RESOURCE_CATALOG, so catalog_mirrors_builtins and
  read_resource_returns_content_for_each_subagent panicked. Add both entries
  (using each agent's prompt.md).
- app_state/ops.rs: the tinyhumansai#4249 profiling fix raised RUNTIME_SNAPSHOT_TTL to 10s,
  breaking app_state_snapshot_degrades_runtime_service_status_failures, which
  ages the process-global runtime cache out with a 2100ms sleep. Revert the TTL
  to 2s — the single-flight gate is the real stampede cure; the TTL only sets
  how often a coalesced rebuild runs, so 2s keeps status fresh and honors the
  test's age-out contract with no perf regression.

Verified: mcp_server::resources 9/9, app_state::ops 17/17, and the e2e
app_state_snapshot_degrades... 1/1 against the mock backend.

Claude-Session: https://claude.ai/code/session_0137dT9i1vLjeUQZ3mj8ZAct
sanil-23 added a commit to sanil-23/openhuman that referenced this pull request Jul 3, 2026
…n review fixes

Rebased onto current main (8aab529), which already carries the tinyhumansai#4399/tinyhumansai#4430
compile reconciliation (graph_fn Some, SqliteCheckpointer migration, MCP
catalog) via tinyhumansai#4433 — so this is slimmed to the fixes main still lacks:

- app_state: bypass the runtime-snapshot cache when OPENHUMAN_SERVICE_MOCK is
  active. tinyhumansai#4399 raised RUNTIME_SNAPSHOT_TTL 2s->10s, so the mock-service e2e
  (which ages the cache with a 2.1s sleep) reads a stale snapshot and never sees
  the injected failure. Bypassing read+write under the mock fixes it (full
  config_auth_app_state_connectivity_e2e binary: 50 passed).
- orchestration/ops: split steering out of seed_state into apply_cycle_steering,
  invoked only after the has_new_work guard, so no-op wakes don't consume a cycle
  tick and prematurely expire steering (CodeRabbit).
- orchestration/store: user_version-gated world-diff migration — drop legacy
  non-unique index, de-dupe race rows, unique index, reconcile terminal_state
  (M3gA-Mind + CodeRabbit) + test.
- orchestration/graph/state: agent-scoped cycle_id (avoid cross-peer collision)
  + migration-seam note (Codex + M3gA-Mind).
- orchestration/schemas: ingest-health MAX(last_message_at) excludes pinned
  master/subconscious windows (CodeRabbit).
- frontend: orchestration socket listeners via socketService.on/off (queues
  through startup/reconnect) + messages Retry -> refresh() (CodeRabbit/Codex).
- docs: orchestration.md fenced-block language (markdownlint).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants