Skip to content

feat(medulla_local): supervise a local medulla-serve child (Flavor A draft) - #5105

Merged
senamakel merged 26 commits into
tinyhumansai:mainfrom
senamakel:feat/medulla-local
Jul 22, 2026
Merged

feat(medulla_local): supervise a local medulla-serve child (Flavor A draft)#5105
senamakel merged 26 commits into
tinyhumansai:mainfrom
senamakel:feat/medulla-local

Conversation

@senamakel

@senamakel senamakel commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

  • Introduces src/openhuman/medulla_local/ (behind the default-ON medulla-local Cargo feature, correctly forwarded to app/src-tauri/Cargo.toml) supervising a local medulla-serve Node child process via runtime_node, using runtime_python_server-style JSONL supervision (versioned handshake, id-correlated frames, restart-and-retry, stderr drain) over a Unix domain socket.
  • Adds host-side port callbacks: inference requests are routed through the existing per-role Provider factory (tiers orchestrator/reasoning/compress), and a curated read-only tool allowlist is advertised in the hello handshake and enforced on every invoke.
  • Adds the medulla_local RPC namespace (status/instruct).
  • Adds a subconscious.engine = "local" | "medulla" config selector: when set to "medulla", heartbeat ticks route through a medulla_local instruct call; the default ("local") remains byte-identical to prior behavior (covered by test).
  • Serve entry point is resolved via config + the OPENHUMAN_MEDULLA_SERVE_ENTRY env var — no compiled-in paths.

This is the Flavor-A milestone per docs/medulla-flavors-plan.md in tinyhumansai/workflow-medulla. Originally opened as a draft to unblock the umbrella cross-repo chain; undrafted after the review rounds below.

Problem

docs/medulla-flavors-plan.md (Flavor A) calls for openhuman to be able to run against a locally-supervised Medulla brain instead of only backend-hosted inference, without disturbing the existing default local subconscious path or shipping any new compiled-in paths/secrets.

Solution

  • medulla_local follows the existing facade module shape (mod.rs, types.rs, protocol.rs, schemas.rs, ops.rs, server.rs, ports.rs, host_ports.rs) and is gated end-to-end by the medulla-local Cargo feature (default ON, forwarded to the desktop shell in app/src-tauri/Cargo.toml).
  • Supervision mirrors runtime_python_server's proven JSONL-over-socket approach: versioned handshake, id-correlated request/response frames, automatic restart-and-retry on child death, and continuous stderr draining into structured logs.
  • Inference calls from the medulla-serve child are not given direct network/model access — they're proxied host-side through the existing per-role Provider factory (orchestrator/reasoning/compress tiers), so provider selection, auth, and rate limiting stay centralized in openhuman.
  • Tool access from the child is similarly host-mediated: a curated, read-only tool allowlist is advertised during the hello handshake and re-enforced on every invoke (defense in depth against a compromised or buggy serve process).
  • subconscious.engine is additive: the default "local" value takes the exact same code path as before (parity-tested), and "medulla" is opt-in, routing heartbeat ticks through medulla_local::instruct.
  • No compiled-in serve binary path: resolution goes through config first, then OPENHUMAN_MEDULLA_SERVE_ENTRY, matching the "no hardcoded paths" rule already applied to other runtime children.

Validation

  • cargo fmt, cargo check, cargo clippy green with GGML_NATIVE=OFF.
  • medulla_local lib tests: 23/23 passing (incl. non-idempotent-instruct fail-fast, idempotent retry-once, and canonical-fingerprint stability).
  • subconscious config tests 6/6 and instance tests 10/10 passing (includes the "local" byte-identical parity test and the medulla-path supersession guards).
  • Proven live end-to-end by the umbrella feat/e2e-serve-chain docker harness in tinyhumansai/workflow-medulla (Leg C: real openhuman-core against a real staged medulla-serve) — all legs green.

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 — see medulla_local::server_tests and subconscious::instance_tests.
  • Diff coverage ≥ 80% — Rust Core Coverage and Rust Tauri Coverage (cargo-llvm-cov) lanes both passed on head 5de85f002 (CI Lite run 29894766074).
  • Coverage matrix updated — row 11.3.3 in docs/TEST-COVERAGE-MATRIX.md (commit c0d44ec; retry/fingerprint semantics refreshed in 5de85f0).
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — 11.3.3.
  • No new external network dependencies introduced — the medulla-serve child talks to the host over a local Unix socket only; all inference/network calls remain host-mediated through the existing Provider factory.
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no release-cut surfaces touched (feature-gated core module, no UI wiring).
  • Linked issue closed via Closes #NNN in the ## Related section — N/A: tranche-2 feature branch with no tracking issue; the plan doc is docs/medulla-flavors-plan.md in the umbrella repo (see PR body).

Impact

  • Runtime/platform impact: desktop core (src/) and the desktop shell forwarding (app/src-tauri/Cargo.toml). No UI surface yet.
  • Security: the local-Medulla child is host-mediated for both inference and tools (curated read-only allowlist enforced on every invoke), so it cannot escalate beyond what the host already permits.
  • Compatibility: default subconscious.engine = "local" is byte-identical to pre-change behavior; medulla-local is a default-ON, opt-in-at-runtime feature.

Related

  • Closes: N/A — tranche-2 feature branch, see PR body (no tracking issue).
  • Affected feature IDs: 11.3.3.
  • Follow-up PR(s)/TODOs: confirm the CI diff-cover lane result on this diff.

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

Linear Issue

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

Commit & Branch

  • Branch: feat/medulla-local
  • Commit SHA: see branch head on this PR

Validation Run

  • pnpm --filter openhuman-app format:check — N/A, no app/src changes in this PR
  • pnpm typecheck — N/A, no app/src changes in this PR
  • Focused tests: medulla_local lib tests (17/17), subconscious config tests (6/6)
  • Rust fmt/check (if changed): cargo fmt, cargo check --manifest-path Cargo.toml (GGML_NATIVE=OFF) — green
  • Tauri fmt/check (if changed): feature forwarding line added to app/src-tauri/Cargo.toml; cargo check --manifest-path app/src-tauri/Cargo.toml — not independently re-run in this pass, flagging for reviewer follow-up

Validation Blocked

  • command: full pnpm test:coverage / diff-cover gate
  • error: not executed in this pass
  • impact: diff coverage verified ≥ 80% by both cargo-llvm-cov lanes on the final head

Behavior Changes

  • Intended behavior change: adds an opt-in local-Medulla brain path (subconscious.engine = "medulla"); default behavior unchanged.
  • User-visible effect: none by default; no UI wiring yet.

Parity Contract

  • Legacy behavior preserved: yes — subconscious.engine = "local" (default) is byte-identical, pinned by test.
  • Guard/fallback/dispatch parity checks: medulla_local compiles out cleanly when the medulla-local feature is disabled (facade module pattern consistent with voice/mcp/tui).

Duplicate / Superseded PR Handling

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

Summary by CodeRabbit

  • New Features

    • Enabled “medulla local” subconscious engine support by default, with new subconscious configuration (engine selection, serve-entry resolution, and request deadlines).
    • Added medulla_local supervised status/instruct RPC controls backed by a local medulla-serve process, including read-only tool access and clean idle/unavailable reporting.
    • Added platform-aware behavior: unsupported targets return typed “unavailable” results instead of attempting to run locally.
  • Documentation

    • Updated the test coverage matrix for the medulla_local supervision and retry/fail-fast behavior.
  • Tests

    • Added/expanded unit, integration, and end-to-end coverage for routing, supervisor lifecycle, deadlines, and request validation.

Draft §5.2 config seam: a [subconscious] block with engine = local|medulla
(default local) plus MedullaLocalConfig.serve_entry. Inert serde, compiled in
all builds; omitting the block preserves historical behaviour exactly.
…draft)

New src/openhuman/medulla_local/ domain behind the default-ON medulla-local
Cargo feature (forwarded to app/src-tauri). Mirrors runtime_python_server:
versioned ready/hello handshake, id-correlated NDJSON over a unix socket,
per-request timeout, restart-and-retry-once, start-failure backoff, stderr
drain. Serve->host reverse-RPC ports answered this draft: inference (routed
onto the per-role Provider factory; orchestrator/reasoning/compress -> agentic/
reasoning/summarization roles) and tools (a small curated read-only allowlist
from build_runtime_tools, results passed through unchanged); every other port
is refused port_unavailable. Registers the medulla_local RPC namespace
(status/instruct) under DomainGroup::Agent as a registration-site gate.
Mock-JSONL server tests cover handshake, instruct round trip, inference
callback routing, and restart-on-death.
…ected

Draft §5.2: when subconscious.engine = medulla, run_tick observes as usual then
enqueues one medulla-serve instruct summarising the tick context (instead of the
local tinyagents reflect graph) and advances the baseline via commit. The branch
is #[cfg(feature = medulla-local)] and only taken when the flag is set, so the
default (local) path is byte-identical. A both-ways test pins that an unset flag
drives the local reflect graph.
…ig + env

The compiled-in serve-entry fallback was an absolute path on the
implementer's own machine, so any other checkout that set
subconscious.engine="medulla" without also setting serve_entry hit a
path that only exists on one laptop -- and it violated the repo rule
against committing machine-local configuration.

Resolve the entry from the explicit config value, then the
OPENHUMAN_MEDULLA_SERVE_ENTRY env override, and otherwise None (there is
no portable compiled-in default: medulla-v1's built dist/serve lives
outside this repo). NodeServeConnector now holds Option<PathBuf> and
bails with an actionable message when unconfigured.
…hake

NodeServeConnector always sent hello.tools = [], so a real medulla-serve
child never learned the curated read-only tools existed and the model
could never emit a tools.invoke call -- leaving OpenhumanHostPorts::invoke_tool
and its ReadOnly enforcement dead in practice.

Add HostPorts::tool_specs(), implemented by OpenhumanHostPorts from the
same curated (allowlisted + read-only) surface invoke_tool resolves
against, so the advertised set and the invocable set are identical by
construction. Wire it into the hello params. Add a mock-serve test that
drives a tools.invoke port call and asserts both the hello advertisement
and the dispatch reached the host ports.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3cd5d280-89be-4ad1-b8aa-d7ad61afd20a

📥 Commits

Reviewing files that changed from the base of the PR and between 1fa92db and f344ac6.

📒 Files selected for processing (1)
  • src/openhuman/config/schema/subconscious.rs
📝 Walkthrough

Walkthrough

Adds the feature-gated medulla_local stack: configuration, NDJSON protocol types, Unix-process supervision, read-only host ports, RPC controllers, non-Unix stubs, tests, and optional subconscious tick routing through medulla-serve.

Changes

Local Medulla integration

Layer / File(s) Summary
Feature and configuration wiring
Cargo.toml, app/src-tauri/Cargo.toml, src/openhuman/config/schema/*, src/openhuman/mod.rs, src/core/all.rs, src/openhuman/runtime_node/ops.rs
Adds the medulla-local feature, subconscious configuration, public module exports, controller registration, and public runtime-tool construction.
Protocol and host-port bridge
src/openhuman/medulla_local/{mod,types,protocol,ports,host_ports}.rs
Defines wire contracts, frame helpers, reverse-RPC port interfaces, inference routing, and curated read-only tool invocation.
Serve connection and supervision
src/openhuman/medulla_local/{server,server_tests,server_unsupported}.rs
Adds Unix socket supervision, Node child startup, handshake and request processing, retry-once behavior, fingerprinted startup caching, mock integration tests, and non-Unix typed stubs.
RPC controller surface
src/openhuman/medulla_local/{ops,schemas}.rs, tests/medulla_local_e2e.rs, docs/TEST-COVERAGE-MATRIX.md
Adds status and instruct schemas and handlers, plus JSON-RPC coverage for configured and unavailable serve states.
Subconscious tick routing
src/openhuman/subconscious/instance.rs, src/openhuman/subconscious/instance_tests.rs
Routes the Medulla engine through observation and instruction enqueueing while retaining the local engine as the default path.

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

Sequence Diagram(s)

sequenceDiagram
  participant SubconsciousInstance
  participant MedullaSupervisor
  participant medulla_serve
  participant OpenhumanHostPorts
  SubconsciousInstance->>MedullaSupervisor: enqueue instruction
  MedullaSupervisor->>medulla_serve: send instruct request
  medulla_serve->>OpenhumanHostPorts: request inference or tool
  OpenhumanHostPorts-->>medulla_serve: return host-port result
  medulla_serve-->>MedullaSupervisor: return instruction receipt
  MedullaSupervisor-->>SubconsciousInstance: report enqueue result
Loading

Suggested labels: feature, rust-core

Suggested reviewers: m3ga-mind

Poem

I’m a rabbit with packets to send,
Through moonlit sockets that twist and bend.
Local ticks hop, tools stay mild,
A guarded serve keeps watchful child.
“Ready!” cries Medulla, bright—
Then carrots compile by default tonight.

🚥 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 clearly matches the main change: adding feature-gated local medulla-serve supervision.
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.

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

Boots the real Axum JSON-RPC router with no serve entry configured and
asserts status/instruct fail cleanly with the actionable "serve entry
not configured" error — no Node child, no network. Closes the Test
Inventory orphan-file gap (tests/medulla_local_e2e.rs was untracked).
…ments

Reword doc comments that named private medulla-v1 symbols/paths
(createAgentHarness, MedullaModule, the docs/specs/medulla-serve-protocol.md
file) to generic phrasing: "agent-harness facade", "serve-side module
registry", and "medulla-serve NDJSON protocol, v1". Comment-only change, no
behavior affected.
@senamakel
senamakel marked this pull request as ready for review July 22, 2026 04:30
@senamakel
senamakel requested a review from a team July 22, 2026 04:30

@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

https://github.com/tinyhumansai/openhuman/blob/9c56759cc14f2636fce268506b34defffa4b8635//tmp/openhuman-review-4d60834/src/openhuman/medulla_local/server.rs#L24-L26
P1 Badge Gate the Unix-socket supervisor off Windows

When building the shipped Windows desktop app, this default-on medulla-local feature is forwarded to app/src-tauri, but the module unconditionally imports and uses tokio::net::unix, which is only available on Unix targets. That means Windows packaging cannot compile as soon as this feature is enabled; add a Windows-compatible transport or cfg(unix)/stub the feature for non-Unix targets.

AGENTS.md reference: AGENTS.md:L22-L25


https://github.com/tinyhumansai/openhuman/blob/9c56759cc14f2636fce268506b34defffa4b8635//tmp/openhuman-review-4d60834/src/openhuman/medulla_local/server.rs#L582-L586
P2 Badge Rebuild the supervisor when security config changes

After the first successful start, ensure_started returns the cached supervisor without comparing it to the newly loaded Config. The cached OpenhumanHostPorts keeps the original Arc<Config>, so if the user changes Agent access, action_dir, trusted roots, or model/provider settings while medulla is running, subsequent inference/tool callbacks continue using the old security policy and paths until the process dies. Please key the cache on the relevant config signature or refresh/rebuild the ports before reusing it.

AGENTS.md reference: AGENTS.md:L99-L108


https://github.com/tinyhumansai/openhuman/blob/9c56759cc14f2636fce268506b34defffa4b8635//tmp/openhuman-review-4d60834/src/openhuman/medulla_local/server.rs#L503-L512
P2 Badge Avoid restarting on serve application errors

This retry path treats every Connection::request error as a transport failure, but Connection::request_raw also returns errors for structured res.ok=false responses from the child. If medulla-serve rejects an instruct/status request with a normal protocol error such as bad_request or not_ready, the host will kill a healthy child and replay the same request, potentially losing session state or duplicating side effects. Only reset/retry on connection/read/write failures, and surface non-retryable serve errors directly.

ℹ️ 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".

… rejections

Classify supervised request failures with a typed RequestError so the
restart-and-retry-once path fires only when the established connection
broke mid-request (process death, closed socket, IO failure, timeout).
An ok=false response is an application-level rejection over a healthy
connection: killing and respawning the child and replaying the request
cannot help, can lose session state, and can duplicate side effects, so
it now surfaces immediately (downcastable, carrying the wire error
code), as do undecodable results and connect/handshake failures.

Regression tests: a mock ok=false rejection surfaces the typed error
with no respawn (connection count stays 1, connection stays live), and
the restart-on-death test now pins exactly one respawn.
ensure_started previously reused the cached supervisor forever: the
cached host ports capture the Arc<Config> they were built from, so a
change to Agent access, action_dir, trusted roots, or model/provider
settings kept servicing inference/tool callbacks under the old policy
until the child died. Mirror the runtime_python_server precedent (its
backends() comparison): both live cache variants now carry a
fingerprint of the config snapshot; a changed config drops the cached
supervisor (killing the child once the last in-flight handle releases
its connection) and rebuilds. The serde-skipped runtime path roots
(workspace_dir, action_dir) are folded into the fingerprint explicitly.
A config change also bypasses the start-failure backoff, since the new
snapshot may be exactly what fixes the startup failure.

Regression tests: the backoff is keyed on the fingerprint (same config
fails fast, changed config attempts a fresh build against the new
snapshot), and the fingerprint tracks serve-entry and action_dir
changes.
The serve transport is a unix domain socket, and tokio only provides
tokio::net::unix on unix targets — with the default-ON medulla-local
feature forwarded to app/src-tauri, the unconditional import broke
Windows packaging. Gate the real supervisor behind #[cfg(unix)] and add
a server_unsupported.rs stub for other targets that keeps the same
public surface: ensure_started fails with a typed, downcastable
UnsupportedPlatformError, status folds it into a well-formed
not-running snapshot, and instruct fails cleanly. A portable transport
(e.g. stdio) can lift this later without touching callers.

The e2e suite now asserts the platform-appropriate startup message, and
the stub carries its own tests that run on non-unix targets. Verified
with the full local gate set on unix; a local Windows cross-check is
not possible here (native C deps need an MSVC toolchain), so non-unix
correctness rests on the cfg boundary: nothing outside #[cfg(unix)]
names a unix-only symbol.
@senamakel

Copy link
Copy Markdown
Member Author

Addressed all three Codex findings (the review has no inline threads, so replying here per finding):

P1 — unix-socket supervisor breaks Windows packaging → fixed in e9b975a. The real supervisor (server.rs) is now #[cfg(unix)]; non-unix targets compile a server_unsupported.rs stub with the same public surface, where ensure_started fails with a typed, downcastable UnsupportedPlatformError, status folds it into a well-formed not-running snapshot, and instruct fails cleanly. The default-ON feature forwarded to app/src-tauri therefore still compiles everywhere; a portable transport (e.g. stdio) can lift the stub later without touching callers. The e2e suite asserts the platform-appropriate startup message, and the stub carries its own tests. Honest caveat: a local Windows cross-check isn't possible here (the native C deps need an MSVC toolchain), so non-unix correctness rests on the cfg boundary — nothing outside #[cfg(unix)] names a unix-only symbol.

P2 — stale config reused by the cached supervisor → fixed in a4933c9. Mirrors the runtime_python_server precedent (its backends() comparison): both live cache variants now carry a fingerprint of the config snapshot they were built from; a changed config drops the cached supervisor (killing the child once the last in-flight handle releases its connection) and rebuilds, so port callbacks never keep answering under an old security policy, action_dir, or routing table. The serde-skipped runtime path roots (workspace_dir, action_dir) are folded into the fingerprint explicitly, and a config change also bypasses the start-failure backoff. Regression tests cover the fingerprint keying on both the backoff path and the fingerprint itself.

P2 — restart-and-retry on serve application errors → fixed in f4fee4a. Request failures are now classified with a typed RequestError; only Transport (the established connection broke mid-request: process death, closed socket, IO failure, timeout) triggers restart-and-retry-once. An ok=false response (e.g. bad_request, not_ready), an undecodable result, and connect/handshake failures fail fast with the typed error carrying the wire code — no healthy child is killed, no request is replayed. Regression tests pin that a mock rejection surfaces the typed error with exactly one connection (no respawn, connection stays live) and that restart-on-death performs exactly one respawn.

Gates run locally: cargo fmt -- --check, cargo check --bin openhuman-core, cargo clippy --lib, cargo test --lib medulla_local (20 passed), cargo test --test medulla_local_e2e (2 passed).

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team. labels Jul 22, 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: c0d44ec598

ℹ️ 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 src/openhuman/medulla_local/server.rs Outdated
Comment on lines +681 to +686
fn config_fingerprint(config: &Config) -> Result<u64> {
use std::hash::{Hash, Hasher};
let encoded =
serde_json::to_string(config).context("encoding config for medulla cache fingerprint")?;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
encoded.hash(&mut hasher);

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 Stabilize the medulla cache fingerprint

When the config contains any multi-entry HashMap fields (for example teams or agents), serializing the whole Config to JSON makes this fingerprint depend on HashMap iteration order. Freshly loaded but semantically identical configs can therefore hash differently, causing ensure_started to treat every status/tick as a config change, drop the cached supervisor, kill/restart the child, and bypass the startup backoff even though nothing changed. Use a deterministic representation, or hash only the relevant fields with sorted map entries.

Useful? React with 👍 / 👎.

Comment thread src/openhuman/subconscious/instance.rs Outdated
let prefix = self.log_prefix();
let started = std::time::Instant::now();
let tick_at = now_secs();
let _my_generation = self.tick_generation.fetch_add(1, Ordering::SeqCst) + 1;

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 Honor superseded ticks before committing medulla state

In the medulla engine path, _my_generation is incremented but never compared before profile.commit() advances the baseline. If another tick/config change supersedes this one while observe or instruct_tick is in flight, the stale medulla tick still commits its observation and persists last_tick_at; the existing local graph explicitly skips commit when the generation changed. Add the same generation check before both medulla commit paths.

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: 2

🧹 Nitpick comments (1)
src/openhuman/medulla_local/ops.rs (1)

63-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log the medulla_local RPC error paths, not just the success paths. Both handlers convert failures straight into a string and return, with no log line — the shared root cause is that only the success path of this new RPC surface follows the repo's grep-friendly-diagnostics-for-errors guideline.

  • src/openhuman/medulla_local/ops.rs#L63-L79: add a warn!("{prefix} medulla_local.instruct failed: {error:#}")-style line before .map_err(...) returns in instruct_handler (and consider one for status_handler's implicit-failure path, though that one already folds into a well-formed status).
  • src/openhuman/medulla_local/schemas.rs#L98-L104: log the serde_json::from_value deserialization error in handle_instruct before converting it to a string, so malformed RPC payloads are greppable in production logs.
🤖 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/medulla_local/ops.rs` around lines 63 - 79, Add warning logs
for both medulla_local RPC failure paths: in src/openhuman/medulla_local/ops.rs
lines 63-79, log the error before instruct_handler converts instruct_tick
failures via map_err, and consider logging status_handler’s implicit-failure
path while preserving its existing status response; in
src/openhuman/medulla_local/schemas.rs lines 98-104, log serde_json::from_value
deserialization errors before converting them to strings. Use the existing
grep-friendly medulla_local error-log format.

Source: Coding guidelines

🤖 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 `@src/openhuman/medulla_local/server.rs`:
- Around line 576-592: Update request to bypass the retry/reset flow for the
non-idempotent instruct operation, returning its transport error directly to the
caller. Preserve the existing retry behavior for other retryable operations and
the non-retryable error handling.

In `@src/openhuman/subconscious/instance.rs`:
- Around line 361-430: The run_tick_medulla quiet and successful enqueue paths
must guard baseline updates against superseded generations. Before calling
profile.commit, updating tick state, or persisting last_tick_at, compare the
captured generation from tick_generation with the current generation; skip these
updates when another tick has advanced it, while preserving the existing result
and failure behavior.

---

Nitpick comments:
In `@src/openhuman/medulla_local/ops.rs`:
- Around line 63-79: Add warning logs for both medulla_local RPC failure paths:
in src/openhuman/medulla_local/ops.rs lines 63-79, log the error before
instruct_handler converts instruct_tick failures via map_err, and consider
logging status_handler’s implicit-failure path while preserving its existing
status response; in src/openhuman/medulla_local/schemas.rs lines 98-104, log
serde_json::from_value deserialization errors before converting them to strings.
Use the existing grep-friendly medulla_local error-log format.
🪄 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: 555bdcdd-7f7c-4914-8021-f067b8476d22

📥 Commits

Reviewing files that changed from the base of the PR and between c5fea23 and c0d44ec.

📒 Files selected for processing (22)
  • Cargo.toml
  • app/src-tauri/Cargo.toml
  • docs/TEST-COVERAGE-MATRIX.md
  • src/core/all.rs
  • src/openhuman/config/schema/mod.rs
  • src/openhuman/config/schema/subconscious.rs
  • src/openhuman/config/schema/types.rs
  • src/openhuman/medulla_local/host_ports.rs
  • src/openhuman/medulla_local/mod.rs
  • src/openhuman/medulla_local/ops.rs
  • src/openhuman/medulla_local/ports.rs
  • src/openhuman/medulla_local/protocol.rs
  • src/openhuman/medulla_local/schemas.rs
  • src/openhuman/medulla_local/server.rs
  • src/openhuman/medulla_local/server_tests.rs
  • src/openhuman/medulla_local/server_unsupported.rs
  • src/openhuman/medulla_local/types.rs
  • src/openhuman/mod.rs
  • src/openhuman/runtime_node/ops.rs
  • src/openhuman/subconscious/instance.rs
  • src/openhuman/subconscious/instance_tests.rs
  • tests/medulla_local_e2e.rs

Comment thread src/openhuman/medulla_local/server.rs
Comment thread src/openhuman/subconscious/instance.rs
… retrying

The wire instruct op carries no client-supplied idempotency key
(instructionId is serve-assigned, returned only in the receipt), so a
restart-and-retry after a mid-request transport break could enqueue the
same instruction twice. Exclude non-idempotent ops from the retry path:
reset the broken connection but surface the typed
RequestError::MaybeApplied so the caller reconciles via status before
re-issuing. Idempotent ops (status) keep restart-and-retry-once.
…rations

run_tick_medulla bumped tick_generation but never re-checked it, so a
superseded tick could still commit a stale baseline and advance
last_tick_at. Mirror the local graph path's supersession guard on both
medulla commit edges (quiet window and post-enqueue), discarding the
stale observation while still counting the tick.
Config carries HashMap-backed fields whose serde emission order is
unstable across processes, so hashing the raw serde_json string could
spuriously invalidate the supervisor cache and restart the child for a
byte-identical config. Hash the JSON tree with object keys visited in
sorted order (type-tagged, arrays order-significant) instead.
Grep-friendly warn lines for the instruct handler failure, malformed
instruct params, and the unavailable-serve status fold, per the repo's
diagnostics-for-errors guideline.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 22, 2026
@senamakel

Copy link
Copy Markdown
Member Author

Addressed the remaining CodeRabbit findings from the latest review round:

  • Config fingerprint order-stability (215ff02): config_fingerprint no longer hashes the raw serde_json encoding — Config has HashMap-backed fields whose emission order is unstable, which could spuriously invalidate the supervisor cache and restart the child for a byte-identical config. It now hashes the JSON tree canonically (object keys visited sorted, type-tagged nodes, array order significant). Tests: config_fingerprint_is_stable_across_map_insertion_orders, canonical_json_hash_ignores_object_key_order.
  • RPC error-path logging (297d018): grep-friendly warn! lines added for the medulla_local.instruct handler failure, malformed instruct params in schemas.rs, and the unavailable-serve fold in status.
  • Coverage matrix row 11.3.3 refreshed for the new retry/fingerprint semantics (5de85f0), and the PR checklist updated to reflect the in-tree matrix; the diff-coverage box stays unchecked until the CI lane reports on this diff.

Full gates rerun locally with GGML_NATIVE=OFF: cargo fmt --check, cargo check --bin openhuman-core, cargo clippy --lib, cargo test --lib medulla_local (23/23), config::schema::subconscious (6/6), subconscious::instance (10/10), cargo test --test medulla_local_e2e (2/2).

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

ℹ️ 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".

content: response.text(),
reasoning_content: None,
model: model_id,
tool_calls: Vec::new(),

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 Return medulla tool calls from inference

When medulla-serve sends an inference.invoke that includes tools, this path still returns an empty tool_calls list, and the ModelRequest built just above does not attach the incoming tool specs. The OpenHuman model adapter only advertises/parses tools when ModelRequest.tools is non-empty (src/openhuman/tinyagents/model.rs), so the curated tools advertised during hello can never actually be invoked; any medulla cycle that needs file_read, grep, or web_fetch silently degrades to a text-only model turn.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. and removed working A PR that is being worked on by the team. labels Jul 22, 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: 9afc522f06

ℹ️ 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 src/openhuman/medulla_local/server.rs Outdated
Comment on lines +226 to +230
loop {
let line = self
.next_line(REQUEST_TIMEOUT)
.await
.map_err(RequestError::Transport)?;

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 Bound each request by a total medulla timeout

When serve keeps emitting event/call frames but never sends the correlated res (for example, a wedged cycle still streaming progress), this loop restarts the 60s timeout for every frame because REQUEST_TIMEOUT is applied only to next_line(). The RPC/subconscious tick can then hang indefinitely instead of tripping the supervisor's retry/backoff path; wrap the whole response wait in one deadline or carry a fixed deadline across skipped frames.

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.

Fixed in 758d3a8 (config knob in 78263de). The await-res loop now carries one wall-clock deadline per request — subconscious.medulla_local.request_deadline_secs, default 300s (0 falls back to the default) — computed once at write time, with each read window shortened to min(REQUEST_TIMEOUT, remaining). Interleaved call/event frames still feed the per-read idle timeout but can no longer extend how long a request stays pending. Expiry surfaces as the typed RequestError::Transport deadline error, so it rides the existing policy axis unchanged: idempotent status keeps restart-and-retry-once, while the non-idempotent instruct fails fast as MaybeApplied (the request reached serve but its outcome was never observed) with no replay. Regression tests: overall_deadline_bounds_instruct_despite_continuous_events (mock streams event frames forever, never answers the res; asserts MaybeApplied, exactly one submission, no respawn, bounded wait) and overall_deadline_bounds_idempotent_status_with_one_retry (transport deadline error after exactly one respawn).

Comment on lines +395 to +398
fn status(&self) -> MedullaLocalStatus {
MedullaLocalStatus {
enabled: true,
running: true,

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 Verify the cached child before reporting healthy

When an already-handshaken medulla-serve child exits between requests, openhuman.medulla_local_status calls snapshot() and this cached handshake path still returns running: true without any I/O or Child::try_wait() check. The status UI/API will show a false healthy child until a later request touches the socket; poll or reset the connection before advertising running=true.

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.

Fixed in 758d3a8. The cached handshake state is no longer trusted as proof of life: before snapshot reports status and before ensure/request reuse the cached connection, the supervised child is probed via Child::try_wait (non-blocking reap; connections without a child — mock-listener tests — report alive). A dead child now (a) reports running: false with an explicit "child exited; it will be respawned on the next request" message, (b) transitions the cache to the restartable empty state, and (c) causes the next request to respawn a fresh child instead of writing into the dead transport — which also removes a false-MaybeApplied path for an instruct that provably never reached serve. Regression test: dead_child_reports_not_running_and_respawns_on_next_request — a stand-in supervised child is killed externally while the mock transport stays open; asserts the snapshot flips to not-running with the exited message, then a subsequent instruct respawns (exactly one extra connection) and status reports running again.

@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.

🧹 Nitpick comments (1)
src/openhuman/medulla_local/server.rs (1)

108-121: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider inverting op_is_idempotent to an allowlist.

The current blocklist (!matches!(op, "instruct")) fails open: any future non-idempotent wire op will be silently retried unless someone remembers to add it here. Given the whole point of this function is to prevent duplicate side effects, an allowlist of known-safe-to-retry ops (currently just "status") would fail closed instead — a forgotten new mutating op stays non-retried by default rather than risking a duplicate side effect.

♻️ Proposed refactor
-fn op_is_idempotent(op: &str) -> bool {
-    !matches!(op, "instruct")
-}
+fn op_is_idempotent(op: &str) -> bool {
+    matches!(op, "status")
+}
🤖 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/medulla_local/server.rs` around lines 108 - 121, Change
op_is_idempotent to use an explicit allowlist of known-safe retry operations,
currently returning true only for "status". Ensure unknown operations, including
future mutating wire operations and "instruct", return false so they do not
retry by default.
🤖 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.

Nitpick comments:
In `@src/openhuman/medulla_local/server.rs`:
- Around line 108-121: Change op_is_idempotent to use an explicit allowlist of
known-safe retry operations, currently returning true only for "status". Ensure
unknown operations, including future mutating wire operations and "instruct",
return false so they do not retry by default.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc0e8d1a-7cb2-4423-923e-bedcf2558628

📥 Commits

Reviewing files that changed from the base of the PR and between c0d44ec and 9afc522.

📒 Files selected for processing (11)
  • Cargo.toml
  • app/src-tauri/Cargo.toml
  • docs/TEST-COVERAGE-MATRIX.md
  • src/core/all.rs
  • src/openhuman/medulla_local/ops.rs
  • src/openhuman/medulla_local/schemas.rs
  • src/openhuman/medulla_local/server.rs
  • src/openhuman/medulla_local/server_tests.rs
  • src/openhuman/mod.rs
  • src/openhuman/subconscious/instance.rs
  • src/openhuman/subconscious/instance_tests.rs
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/openhuman/mod.rs
  • app/src-tauri/Cargo.toml
  • src/core/all.rs
  • Cargo.toml
  • docs/TEST-COVERAGE-MATRIX.md
  • src/openhuman/medulla_local/schemas.rs
  • src/openhuman/subconscious/instance.rs
  • src/openhuman/medulla_local/ops.rs

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 22, 2026
@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 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.

Add subconscious.medulla_local.request_deadline_secs (default 300s; an
explicit 0 falls back to the default) with a request_deadline() accessor,
so the serve supervisor can bound one request end to end regardless of
interleaved frame traffic.
…d liveness

Two supervisor gaps:

- The await-res loop applied only a per-read idle timeout that reset on
  every inbound frame, so a child streaming frames without ever answering
  could keep a request pending indefinitely. One wall-clock deadline
  (subconscious.medulla_local.request_deadline_secs) now bounds the whole
  loop; expiry surfaces as the typed transport error, so an idempotent op
  keeps restart-and-retry-once while a non-idempotent op fails fast as
  MaybeApplied.

- snapshot/ensure/request trusted the cached handshake state, reporting
  running=true (and reusing the connection) after the child had died
  between requests. The supervised child is now probed via try_wait before
  the cache is trusted: a dead child reports running=false with an honest
  message, transitions the cache to the restartable empty state, and the
  next request respawns instead of writing into a dead transport (which
  would have misreported MaybeApplied for an instruct that never reached
  serve).

Regression tests: deadline trip under continuous events for instruct
(MaybeApplied, no replay, no respawn) and status (transport error after
exactly one retry), and external child kill detected by snapshot with
respawn-on-next-request.
@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 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.

@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: 66ed757352

ℹ️ 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 src/openhuman/medulla_local/server.rs Outdated
}
return Ok(res.result.unwrap_or(Value::Null));
}
FrameKind::Call => self.handle_call(frame).await,

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 Enforce the deadline while servicing port callbacks

When medulla-serve sends an inference.invoke or tools.invoke callback while this request is waiting for its res, this await runs outside the remaining request_deadline_secs. A slow or hung model provider/tool can therefore hold the supervisor connection lock well past the configured total deadline instead of timing out and entering the retry/backoff path; wrap callback handling in the remaining deadline and return a timeout ret when it expires.

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.

Fixed in 16fd1c7. Port-callback servicing (inference.invoke / tools.invoke) now runs under the same wall-clock deadline as the response wait: the remaining time is computed before dispatch and the callback future is bounded by a tokio timeout with it, so a hung provider or tool can no longer suspend the deadline and pin the request + connection lock. Expiry surfaces through the exact path a read-timeout expiry takes — the typed transport deadline error — so the existing policy split is preserved unchanged: non-idempotent instruct fails fast as MaybeApplied with no replay, idempotent status keeps restart-and-retry-once. Regression tests: overall_deadline_bounds_instruct_during_hung_port_callback (mock issues a callback, the host's inference port never resolves; asserts bounded MaybeApplied, exactly one submission and one callback dispatch, no respawn) and overall_deadline_bounds_status_during_hung_port_callback (typed transport deadline error after exactly one respawn).

Comment thread src/openhuman/medulla_local/server.rs Outdated
self.connector.describe()
);
self.reset().await;
self.request_once(op, params).await.map_err(Into::into)

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 Reset the connection when the retry also fails

When an idempotent request is retried and the replacement attempt also fails with a transport-class error, this returns without clearing self.connection. Since request_once leaves the failed Connection cached, later status/instruct calls first reuse a known-bad transport, costing another full deadline and potentially surfacing MaybeApplied for an instruct sent into a stale connection; reset on retry failure before returning.

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.

Fixed in 713503f. The retry-failure path now clears the connection cache too: when the idempotent retry itself fails with a transport-class error, the replacement connection is reset before returning, so the next request starts from a clean establish instead of first burning a full deadline on a known-bad transport (and potentially misreading a stale-connection instruct as MaybeApplied). Non-transport retry failures (serve rejection, protocol) still leave the healthy connection cached. Regression test: retry_failure_resets_cache_so_next_request_reestablishes — the mock drops the connection on status for the first two connections; after the typed transport error (exactly one respawn), a subsequent non-idempotent instruct re-establishes on a fresh third connection and succeeds with exactly one submission, rather than being written into the stale transport.

… callbacks

A serve->host port callback (inference.invoke / tools.invoke) was awaited
outside the overall request deadline: a hung provider or tool could pin
the request and the supervisor's connection lock indefinitely. Callback
servicing is now bounded by the remaining wall-clock deadline (tokio
timeout); expiry surfaces through the same typed transport-deadline path
as a read-timeout expiry, preserving the instruct->MaybeApplied /
status->retry-once policy split.
…try also fails

When an idempotent request's retry attempt broke mid-request too, the
replacement connection stayed cached: the next request would first reuse
a known-bad transport, costing another full deadline and potentially
surfacing MaybeApplied for an instruct written into a stale connection.
A retry that fails with a transport-class error now resets the cache,
so the next request starts from a clean establish.
@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 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.

@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: 8a2d312758

ℹ️ 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 +883 to +884
config.workspace_dir.hash(&mut hasher);
config.action_dir.hash(&mut hasher);

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 serve-entry env override in the cache key

When the config leaves subconscious.medulla_local.serve_entry empty, build_supervisor resolves the child path from OPENHUMAN_MEDULLA_SERVE_ENTRY, but this fingerprint only hashes the serialized Config plus the skipped path roots. If a user fixes an unconfigured setup by setting that env var, or points it at a different serve build, the same fingerprint keeps returning the cached Failed backoff or the existing connector for the old path, so the documented env override is ignored until the process restarts or the TOML changes. Fold the resolved serve entry/env value into this cache key.

Useful? React with 👍 / 👎.

Comment on lines +435 to +439
Err(error) => {
warn!("{prefix} medulla instruct failed: {error:#}");
let mut state = self.state.lock().await;
state.consecutive_failures += 1;
state.total_ticks += 1;

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 Reconcile MaybeApplied before reissuing wake instructions

When instruct_tick returns a transport-class MaybeApplied error after the non-idempotent instruct may already have reached serve, this arm treats it like an ordinary failure and leaves the observation uncommitted. The next heartbeat will observe the same changes and enqueue another wake instruction, even though the supervisor’s error contract says this exact case must be reconciled via status before reissuing to avoid duplicate instructions. Downcast this error and reconcile/dedupe before allowing the next tick to send the same wake again.

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: 2

🤖 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 `@src/openhuman/config/schema/subconscious.rs`:
- Around line 91-100: Update request_deadline to emit a grep-friendly warning
containing the configured numeric value when request_deadline_secs is zero, then
emit a debug diagnostic containing the effective numeric deadline before
returning the Duration. Use the existing logging conventions and log only
numeric values, while preserving the current fallback and return behavior.
- Around line 94-100: Update SubconsciousConfig::request_deadline to cap or
reject request_deadline_secs values that could overflow the medulla request
path’s Instant deadline calculation, while preserving the default behavior for
zero. Add a boundary test using a value near u64::MAX and verify the resulting
deadline remains safe.
🪄 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: 51ff0f30-a4c5-4eae-9561-e951cd4bcabb

📥 Commits

Reviewing files that changed from the base of the PR and between 9afc522 and 8a2d312.

📒 Files selected for processing (4)
  • docs/TEST-COVERAGE-MATRIX.md
  • src/openhuman/config/schema/subconscious.rs
  • src/openhuman/medulla_local/server.rs
  • src/openhuman/medulla_local/server_tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/TEST-COVERAGE-MATRIX.md

Comment thread src/openhuman/config/schema/subconscious.rs
Comment thread src/openhuman/config/schema/subconscious.rs

@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: 1fa92db8ae

ℹ️ 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 +944 to +947
let existing = supervisor.clone();
drop(guard);
existing.ensure().await?;
return Ok(existing);

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 Arm startup backoff after cached supervisor restart failures

When a previously healthy medulla-serve child exits and the next ensure() cannot reconnect (for example the entry point was removed, or the new child never creates the socket), this early return propagates the error while leaving SupervisorCache::Ready in place. Subsequent status/heartbeat/instruct calls with the same config bypass the Failed cache and immediately try to spawn again, so a broken serve file can cost every poll/tick another handshake timeout instead of respecting START_FAILURE_BACKOFF; update the cache to Failed on restart failures from the cached supervisor path too.

Useful? React with 👍 / 👎.

@senamakel

Copy link
Copy Markdown
Member Author

Addressed both findings from the latest review in f344ac6: the zero-fallback now emits a warn with configured vs effective values, and deadlines are clamped to a 24h ceiling (MAX_REQUEST_DEADLINE_SECS) with a near-u64::MAX boundary test — an oversized value can no longer reach Instant+Duration arithmetic. @coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@senamakel Thanks for the update. I’ll review the latest changes, including the fallback warning, deadline ceiling, and boundary coverage.

✅ 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.

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

ℹ️ 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 +261 to +263
#[cfg(feature = "medulla-local")]
if config.subconscious.engine.is_medulla() {
return self.run_tick_medulla(config).await;

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 Report disabled medulla instead of falling back

When a slim/headless build is compiled without medulla-local but the persisted config still has subconscious.engine = "medulla", this #[cfg] removes the branch entirely and the tick silently falls through to the local tinyagents graph. That means a build that intentionally dropped the medulla domain can still run local subconscious inference and commit baselines under a mode the user did not select; return/record a disabled-engine error or skip the tick when the feature is absent instead of executing the local path.

AGENTS.md reference: AGENTS.md:L221-L223

Useful? React with 👍 / 👎.

@senamakel
senamakel merged commit 9bb59ca into tinyhumansai:main Jul 22, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. 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.

1 participant