Skip to content

feat(flows): completed_with_warnings run status (run honesty)#4587

Merged
graycyrus merged 3 commits into
tinyhumansai:mainfrom
graycyrus:feat/flows-run-honesty
Jul 6, 2026
Merged

feat(flows): completed_with_warnings run status (run honesty)#4587
graycyrus merged 3 commits into
tinyhumansai:mainfrom
graycyrus:feat/flows-run-honesty

Conversation

@graycyrus

@graycyrus graycyrus commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Problem

A flow run whose =-bindings resolved to null (Slack channel/text, summarize input) reported green "Completed" — a hollow run shown as success. The observer already records per-step diagnostics; the terminal status derivation just ignored them (it was derived solely from pending approvals).

Fix

flows_run/flows_resume now derive status from the settled steps:

  • any step status == errorfailed
  • any step with null-resolution diagnosticscompleted_with_warnings (amber)
  • else completed

Precedence: pending_approval > failed > completed_with_warnings > completed. Single settle_steps read (no extra DB hit).

Frontend: FlowRunStatus union + inspector status maps (amber badge, non-pulsing dot) + TERMINAL poller set + i18n (14 locales). Also fills the pre-existing cancelled gap in the TS union/maps.

Independent of #4586

Reads diagnostics the observer already writes on main. (Trivial ops.rs rebase if #4586 lands first.)

Verification

cargo flows:: 279 pass (4 new degrade_completed_status tests) · typecheck/eslint clean · vitest 167 pass · i18n:check 0 drift. Validated by a live run: a null-binding run now surfaces amber instead of a false green.

Summary by CodeRabbit

  • New Features
    • Added support for the new run status “Completed with warnings” across the app.
    • Updated status styling and indicators (including run details, list rows, and status pills) to recognize both “Completed with warnings” and “Cancelled”.
    • Added localized UI text for “Completed with warnings” in multiple languages.
  • Bug Fixes
    • Runs that complete with warnings now stop polling when they reach a terminal state.
    • Cancellation and terminal handling now treat “Completed with warnings” correctly, preserving the warning outcome.

…reported as success

A run whose =-bindings resolved to null (or whose nodes errored) reported green
"Completed". The observer already records per-step diagnostics; the status
derivation just ignored them. Now flows_run/flows_resume derive status from the
settled steps: any step error → "failed", any null-resolution diagnostic →
"completed_with_warnings" (amber), else "completed". Precedence:
pending_approval > failed > completed_with_warnings > completed.

Frontend: FlowRunStatus union + status maps (amber badge, non-pulsing dot) +
TERMINAL poller set + i18n (14 locales); also fills the pre-existing 'cancelled'
gap in the TS union/maps.

cargo flows:: 279 pass (4 new degrade_completed_status tests); typecheck/eslint
clean; vitest 167 pass; i18n:check 0 drift.
@graycyrus graycyrus requested a review from a team July 6, 2026 15:37
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0251d36a-b5de-410b-b81c-1d7bbeed0e12

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9a1d8 and 22aaf5c.

📒 Files selected for processing (2)
  • src/openhuman/flows/ops.rs
  • src/openhuman/flows/ops_tests.rs

📝 Walkthrough

Walkthrough

This PR adds completed_with_warnings and cancelled flow run statuses. The backend derives and preserves the warning status from settled steps, the API and poller treat the new statuses as terminal, the UI renders them, and translations are added for the warning label.

Changes

Flow run status extension

Layer / File(s) Summary
Backend status derivation and terminal checks
src/openhuman/flows/ops.rs, src/openhuman/flows/ops_tests.rs, src/openhuman/flows/types.rs
Derives failed, completed_with_warnings, or completed from settled steps, treats completed_with_warnings as terminal for cancel flow, and updates docs/tests for the new terminal states.
API type and poller terminal states
app/src/services/api/flowsApi.ts, app/src/hooks/useFlowRunPoller.ts, app/src/hooks/__tests__/useFlowRunPoller.test.ts
Extends the exported status union and poller terminal set to include completed_with_warnings and cancelled, with tests covering polling stop behavior.
Drawer status rendering
app/src/components/flows/FlowRunInspectorDrawer.tsx, app/src/components/flows/FlowRunsDrawer.test.tsx
Adds status styling and labels for completed_with_warnings and cancelled, and verifies the drawer renders the warning status text.
Locale strings
app/src/lib/i18n/*.ts
Adds flowRuns.status.completed_with_warnings entries across the supported locale catalogs.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: feature, rust-core

Poem

A rabbit hops जहां warnings glow,
“Completed with warnings” now in tow. 🐰
Polls stop, labels sing,
Cancelled runs don’t ping,
And every locale joins the show.

🚥 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 identifies the main change: adding the new completed_with_warnings flow run status.
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.

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

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return "failed";
}
if steps.iter().any(|s| !s.diagnostics.is_empty()) {
"completed_with_warnings"

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 Treat warning completions as terminal everywhere

When a run gets this new completed_with_warnings status, flows_cancel_run still only treats completed | failed | cancelled as terminal (src/openhuman/flows/ops.rs:1424). That means a settled warning run can later be passed to openhuman.flows_cancel_run, which will fall through and overwrite the run row and flow summary as cancelled, corrupting the history/status for an already-finished run. Please include this new status in the terminal guard before emitting it here.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed and fixed in 22aaf5cflows_cancel_run's terminal-status guard now includes completed_with_warnings alongside completed/failed/cancelled, matching FlowRun::status's doc contract that already listed it as terminal. Added a regression test (flows_cancel_run_of_a_completed_with_warnings_run_errors) that forces a settled warning row and asserts cancel is rejected with 'already terminal' and the row's status is untouched. Good catch.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 6, 2026
…_run (addresses @chatgpt-codex-connector on src/openhuman/flows/ops.rs:1629)

flows_cancel_run's terminal-status guard only recognized
completed/failed/cancelled, so a settled completed_with_warnings run (run
honesty, PR2) would fall through the "not in flight" cancel path and get
overwritten as cancelled, silently discarding the warning status it already
recorded. Add completed_with_warnings to the guard, matching the type-level
contract in FlowRun::status's doc comment that already listed it as
terminal. Adds a regression test.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

1070-1084: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the duplicated terminal-status computation.

The 6-line block computing settled/status and calling finish_flow_run_row is now byte-for-byte duplicated between flows_run and flows_resume. A shared helper (e.g. fn finalize_terminal_status(settled: &[FlowRunStep], pending_approvals: &[String]) -> &'static str) would keep the precedence rule in one place, reducing the risk of the two call sites drifting (as already happened with the error field above).

Also applies to: 1273-1287

🤖 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/flows/ops.rs` around lines 1070 - 1084, The terminal-status
computation is duplicated in both flows_run and flows_resume, so extract the
shared logic into a helper near the existing
settle_steps/degrade_completed_status flow. Add a small helper keyed off
settle_steps, degrade_completed_status, and the pending_approvals precedence so
both call sites use the same status selection and finish_flow_run_row arguments,
keeping the rule in one place and preventing drift.
🤖 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/flows/ops.rs`:
- Around line 1070-1084: Populate FlowRun.error when
degrade_completed_status(&settled) returns a failed status in
ops::finish_flow_run_row path. In the code that builds status from
settle_steps/config and then calls store::record_run and finish_flow_run_row,
capture the failure details from settled or the step error and pass them through
so failed runs are recorded with a non-empty error instead of None. Update the
flows_run/flows_resume flow to preserve the error detail whenever status is
"failed", using the existing settle_steps, degrade_completed_status, and
finish_flow_run_row symbols to locate the change.

---

Nitpick comments:
In `@src/openhuman/flows/ops.rs`:
- Around line 1070-1084: The terminal-status computation is duplicated in both
flows_run and flows_resume, so extract the shared logic into a helper near the
existing settle_steps/degrade_completed_status flow. Add a small helper keyed
off settle_steps, degrade_completed_status, and the pending_approvals precedence
so both call sites use the same status selection and finish_flow_run_row
arguments, keeping the rule in one place and preventing drift.
🪄 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: fa2d8f24-d0a5-4304-98d3-4439542b6b18

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd28e2 and 1c9a1d8.

📒 Files selected for processing (22)
  • app/src/components/flows/FlowRunInspectorDrawer.tsx
  • app/src/components/flows/FlowRunsDrawer.test.tsx
  • app/src/hooks/__tests__/useFlowRunPoller.test.ts
  • app/src/hooks/useFlowRunPoller.ts
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • app/src/services/api/flowsApi.ts
  • src/openhuman/flows/ops.rs
  • src/openhuman/flows/ops_tests.rs
  • src/openhuman/flows/types.rs

Comment on lines +1070 to 1084
let settled = settle_steps(config, &thread_id, &outcome.output);
let status = if !outcome.pending_approvals.is_empty() {
"pending_approval"
} else {
degrade_completed_status(&settled)
};
store::record_run(config, flow_id, status).map_err(|e| e.to_string())?;
finish_flow_run_row(
config,
&thread_id,
status,
&settle_steps(config, &thread_id, &outcome.output),
&settled,
&outcome.pending_approvals,
None,
);

@coderabbitai coderabbitai Bot Jul 6, 2026

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
set -euo pipefail

# Locate the relevant symbols and surrounding code.
rg -n "degrade_completed_status|finish_flow_run_row|FlowRun::error|error: None|pending_approval|status == \"failed\"" src/openhuman -S

# Show concise outlines of the main file and types file.
ast-grep outline src/openhuman/flows/ops.rs --view expanded || true
ast-grep outline src/openhuman/flows/types.rs --view expanded || true

# Show the relevant line ranges with context.
for f in src/openhuman/flows/ops.rs src/openhuman/flows/types.rs; do
  echo "==== $f ===="
  wc -l "$f"
done

# Print the relevant snippets around likely line numbers if present.
sed -n '1000,1125p' src/openhuman/flows/ops.rs
echo "==== types excerpt ===="
sed -n '1,260p' src/openhuman/flows/types.rs

# Search for tests around degraded failed path and finish_flow_run_row.
rg -n "degraded|failed.*error|finish_flow_run_row|pending_approval|FlowRunStep|step error|step.*failed" src/openhuman -g '*test*' -g '*.rs' -S

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== finish_flow_run_row and surrounding call sites =="
sed -n '1510,1565p' src/openhuman/flows/ops.rs
echo
echo "== degrade_completed_status =="
sed -n '1624,1648p' src/openhuman/flows/ops.rs
echo
echo "== relevant tests around degrade_completed_status =="
sed -n '1659,1715p' src/openhuman/flows/ops_tests.rs
echo
echo "== run persistence schema / row mapping =="
sed -n '430,560p' src/openhuman/flows/store.rs
echo
echo "== flow run type contract =="
sed -n '190,232p' src/openhuman/flows/types.rs

Repository: tinyhumansai/openhuman

Length of output: 13429


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ops_tests degraded status block =="
sed -n '1668,1710p' src/openhuman/flows/ops_tests.rs

echo "== finish_flow_run_row definition =="
sed -n '1517,1545p' src/openhuman/flows/ops.rs

echo "== any tests asserting FlowRun.error on failed statuses =="
rg -n 'error.*failed|failed.*error|FlowRun .*error|status: "failed"|status == "failed"' src/openhuman/flows/ops_tests.rs src/openhuman/flows/store_tests.rs -S

Repository: tinyhumansai/openhuman

Length of output: 2979


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== flows_resume settle path =="
sed -n '1238,1288p' src/openhuman/flows/ops.rs
echo
echo "== failed run test =="
sed -n '270,330p' src/openhuman/flows/ops_tests.rs

Repository: tinyhumansai/openhuman

Length of output: 4273


Populate FlowRun.error for degraded failures. Both flows_run and flows_resume persist status: "failed" with error: None when degrade_completed_status(&settled) trips on a step error. That leaves failed rows inconsistent with FlowRun::error’s contract and strips the only failure detail from run history.

🤖 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/flows/ops.rs` around lines 1070 - 1084, Populate FlowRun.error
when degrade_completed_status(&settled) returns a failed status in
ops::finish_flow_run_row path. In the code that builds status from
settle_steps/config and then calls store::record_run and finish_flow_run_row,
capture the failure details from settled or the step error and pass them through
so failed runs are recorded with a non-empty error instead of None. Update the
flows_run/flows_resume flow to preserve the error detail whenever status is
"failed", using the existing settle_steps, degrade_completed_status, and
finish_flow_run_row symbols to locate the change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed and fixed in e1ed6e4. Added failed_step_error_summary(), which names the node(s) whose step settled with status == "error" (the only detail available — the engine's ExecutionStep doesn't carry a message for a step failing under on_error: "continue""/"route", only a run-future Err does, and that path already populated error). Folded it into finalize_terminal_status(), shared by flows_run/flows_resume, which also resolves the nitpick below (the duplicated 6-line terminal-status block) in the same change — one place now owns both the status precedence and the error population, so they can't drift again. Added regression tests: failed_step_error_summary_*, finalize_terminal_status_*, and an end-to-end flows_run_populates_error_when_a_continue_policy_node_errors using an on_error: "continue" node.

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.

@graycyrus, thanks for the detailed writeup — this looks like a clean fix. Consolidating the precedence + error-population logic into finalize_terminal_status() is exactly right; it removes the duplication between flows_run/flows_resume and closes the gap where a "failed" row could persist with error: None. Good call using node-name attribution in failed_step_error_summary() given the engine doesn't carry a message for continue/route-policy step failures. Appreciate the added regression coverage too.


🧠 Learnings used
Learnt from: sanil-23
Repo: tinyhumansai/openhuman PR: 416
File: src/openhuman/memory/relex.rs:441-464
Timestamp: 2026-04-07T15:49:51.275Z
Learning: When using the `ort` Rust crate v2.x with the `load-dynamic` feature enabled, don’t require individual execution-provider feature flags (e.g., `directml`, `coreml`, `cuda`) alongside `load-dynamic` to get EP registration code. The `ort` crate already compiles EP registration via `#[cfg(any(feature = "load-dynamic", feature = "<ep_name>"))]` guards, and adding per-EP feature flags can pull in static-linking dependencies that conflict with the dynamic loading approach. At runtime, EP availability is determined by what the dynamically loaded ONNX Runtime library (`onnxruntime.dll`/`.so`/`.dylib`) supports; ort docs indicate providers like `directml`/`xnnpack`/`coreml` are available in builds when the platform supports them.

Learnt from: sanil-23
Repo: tinyhumansai/openhuman PR: 416
File: src/openhuman/memory/relex.rs:441-464
Timestamp: 2026-04-07T15:49:51.275Z
Learning: When integrating the `ort` Rust crate v2.x with the `load-dynamic` feature enabled, do NOT also require/enable individual provider EP Cargo features like `directml`, `coreml`, or `cuda`. In `ort` v2.x, EP registration for providers (e.g., DirectML, CoreML, CUDA, etc.) is already compiled in under source-level `#[cfg(any(feature = "load-dynamic", feature = "<provider>"))]` guards, such as in `ep/directml.rs`. Adding provider feature flags alongside `load-dynamic` can pull in static-linking dependencies that conflict with the dynamic-loading approach. Provider availability should be treated as runtime-determined by what the loaded `onnxruntime` library (`onnxruntime.dll`/`libonnxruntime.so`/`libonnxruntime.dylib`) actually supports.

Learnt from: oxoxDev
Repo: tinyhumansai/openhuman PR: 571
File: src/openhuman/local_ai/service/whisper_engine.rs:69-80
Timestamp: 2026-04-14T19:59:04.826Z
Learning: When reviewing Rust code in this repo that uses the upstream `whisper-rs` crate (v0.16.0), do not report `WhisperContextParameters::use_gpu(...)` or `WhisperContextParameters::flash_attn(...)` as missing/invalid APIs. These builder-style methods exist upstream and return `&mut Self`; they are not limited to `WhisperVadContextParams`.

Learnt from: graycyrus
Repo: tinyhumansai/openhuman PR: 1078
File: src/openhuman/agent/agents/welcome/prompt.rs:24-24
Timestamp: 2026-05-01T13:41:00.958Z
Learning: For Rust code under `src/openhuman/**/*.rs`, use `snake_case` for local variables (not `camelCase`). If a local variable name is written in `camelCase`, treat it as a style/lint issue because it will trigger Rust’s `non_snake_case` warning (and related clippy linting, if enabled). Avoid suggesting `camelCase` for any Rust local variable names in this repository.

Learnt from: senamakel
Repo: tinyhumansai/openhuman PR: 1173
File: tests/agent_memory_loader_public.rs:88-88
Timestamp: 2026-05-04T06:50:47.877Z
Learning: In this repository, the general camelCase naming guideline should not be applied to Rust source files. For all .rs files, Rust function (and related) names should use snake_case, and snake_case Rust function names should not be flagged—even for async test functions annotated with attributes like #[tokio::test]. This is consistent with Rust’s non_snake_case lint behavior.

Learnt from: sanil-23
Repo: tinyhumansai/openhuman PR: 3775
File: src/openhuman/inference/openai_oauth/flow_tests.rs:605-638
Timestamp: 2026-06-19T04:39:51.616Z
Learning: When reviewing path usage in the `tinyhumansai/openhuman` Rust code (especially auth/session storage), don’t flag a “path-mismatch” concern for `AuthService::from_config` just because it doesn’t use `workspace_dir`. `AuthService::from_config` resolves its state directory via `state_dir_from_config(config)`, which returns `config_path.parent()` (see `src/openhuman/credentials/core.rs:119-124`). In tests that use `test_config(&tmp)` (where `config_path = tmp.path().join("config.toml")`), creating `AuthProfilesStore::new(tmp.path(), false)` writes into the same directory that `AuthService::from_config` will read (the config parent directory).

Learnt from: senamakel
Repo: tinyhumansai/openhuman PR: 4087
File: src/openhuman/thread_goals/ops.rs:41-47
Timestamp: 2026-06-25T07:34:02.244Z
Learning: In this repo, controller/RPC response shapes follow an established asymmetric convention: (1) read handlers should return the bare serialized value (no `{ result, logs }` envelope), and (2) mutation handlers should return an envelope shaped like `{ result, logs }`. When reviewing Rust RPC controller implementations in `src/openhuman/**/ops.rs`, follow this convention. For the thread-goals surface specifically, do not flag `thread_goals_get` returning a bare `GoalEnvelope` if the frontend/API helper (`app/src/services/api/threadGoalApi.ts`) and existing E2E helpers already `unwrap()`/accept both bare and envelope shapes.

…pe terminal-status logic (addresses @coderabbitai on src/openhuman/flows/ops.rs:1084)

flows_run/flows_resume persisted status: "failed" with error: None whenever
degrade_completed_status degraded a settled run (a node under an
on_error:"continue"/"route" policy errors but the run future still returns
Ok) — leaving the row inconsistent with FlowRun::error's own doc contract
("Error message when status == \"failed\"") and losing the only failure
detail in run history.

Add failed_step_error_summary(), which names the node(s) whose step settled
with status "error" (the engine's ExecutionStep carries no message of its
own for this case — only a run-future Err, which already has its own
message, does). Fold it into a new finalize_terminal_status() shared by both
call sites, which also resolves CodeRabbit's nitpick that the two call sites'
6-line terminal-status block was byte-for-byte duplicated (and had already
drifted once, on this very error-population gap).
@graycyrus graycyrus merged commit f88197a into tinyhumansai:main Jul 6, 2026
13 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