Skip to content

Add OpenHuman host profile to memory eval - #252

Merged
senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:issue-251-openhuman-eval
Oct 10, 2026
Merged

senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:issue-251-openhuman-eval

Conversation

@senamakel

@senamakel senamakel commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Add the first OpenHuman host eval profile to memory_eval. Scripted turns now use OpenHuman's recall policy, 1500 ms pre-turn deadline, continued background task after a timeout, and bounded logged tool-result lines. Pre-turn probes obey the same deadline. A JSON-scripted 500-turn loop guard measures pack growth and repeated lines and fails if an injected <memory-context> tag reaches stored items. Reports include p99 and timeout rate. The eval script can reuse its existing Docker image when Docker Hub is unavailable.

This is a scoped part of #251. The live model step, memory tool, source/import paths, larger JSON scenario suite, leakage audit, fuzzing, and engine guide remain in that issue.

Related issue

Refs #251

API or behavior changes

None to the library API. The memory_eval example gains --host openhuman and --loop-guard; scripts/memory-eval.sh gains REUSE_IMAGE=1.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --all-targets --all-features
  • cargo test --all-features --quiet
  • bash -n scripts/memory-eval.sh
  • 500-turn reference loop guard: 500 nonempty packs, 0 timeouts, 0 stored context tags
  • Full CortexDB mock eval: 12 scenarios, 41/52 recall pack hits, 40/52 synthesis pack hits, 0/175 pre-turn timeouts
  • Three OpenRouter/CortexDB tool_heavy repeats: 0/6 recall pack hits in each, 5/6 synthesis pack hits in each, 10–12/19 pre-turn timeouts; CortexDB model cost $0.012–$0.050 per run

The live repeats expose a latency gap against the proposed <1% timeout gate. They are a six-probe scenario, not an estimate of the full suite. Each run used --enrich-wait 90 and the existing --llm answer model.

Tests

Added eval unit coverage for logged tool-result formatting, pack tag isolation in stored turns, and combined scripted/probe timeout arithmetic. The full 500-turn behavior is covered by the executable eval; no transport-fault injection was added in this slice.

Documentation

Updated docs/evals/README.md and added docs/evals/openhuman-host.md with the host parity table, commands, measured results, and the remaining #251 work.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Summary by CodeRabbit

  • New Features

    • Added an OpenHuman evaluation mode with configurable host selection and a loop-guard option for testing recall over extended sessions.
    • Evaluation reports now include pre-turn timeout counts, p99 latency, and additional recall and duplicate-content metrics.
    • Added an option to reuse a locally built evaluation image.
  • Documentation

    • Added guidance for running the OpenHuman evaluation profile and using the new options.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 11 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Changes requested
Priority: high
Reviewed head: 61bfc4082c88
Updated: 1791647048 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 6 Active findings 11
Tests 2 Noted findings 0
Documentation 2 Resolved findings 0
Configuration 1 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

  • high · critique · Return the empty pack without awaiting the timed-out task — When `pre_turn_dated` exceeds `PRE_TURN_TIMEOUT`, this branch immediately awaits the spawned task to completion before returning. That means a slow recall operation still blocks th (crates/tinymemory\-integrations/examples/memory\_eval/main\.rs:813)
  • medium · critique · Reconcile the probe count with the reported hit rates — This row says the run covered 53 probes, but both recall and synthesis results use a denominator of 52, with no explanation for the omitted probe. That makes the documented coverag (docs/evals/openhuman\-host\.md:50)
  • medium · critique · Count timeouts only for pre-turn probes — The denominator below counts only probes whose `via` starts with `pre_turn`, but this numerator counts every timed-out probe. If a non-pre-turn probe times out, it increases the nu (crates/tinymemory\-integrations/examples/memory\_eval/kpi\.rs:461)
  • medium · critique · Reserve the turn index before allowing timed-out tasks to overlap — When this timeout branch stores the still-running task and returns, `self.next` is not advanced until the later `post_turn` completes. If the caller starts another `user` call befo (crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs:143)
  • medium · critique · Retain pending tasks when flushing encounters an error — If any drained task returns a `JoinError` or an inner pre-turn error, `?` exits the loop immediately. The remaining `JoinHandle`s have already been removed from `self.pending`; dro (crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs:99)
  • medium · critique · Restrict echoed-item detection to injected pack content — This scans the serialized representation of every stored item, so any legitimate user text, learning, metadata, or other field containing `<memory-context>` is counted as an echoed (crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs:84)
  • medium · critique · Clean up the evaluation namespace on every exit path — After data is stored, any error from `agent.flush()`, `engine.export()`, or the later `forget()` returns immediately through `?`, bypassing the cleanup at the end of the function. (crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs:77)
  • high · security · Detach timed-out pre-turn tasks instead of awaiting them — After `timeout` returns `Err`, the spawned task is still running because the handle was borrowed. Awaiting it here blocks until `pre_turn_dated` completes, so a slow or stuck recal (crates/tinymemory\-integrations/examples/memory\_eval/main\.rs:815)
  • medium · tests · Add a test module for loop_guard's pure helpers — The repo's rules require sibling `<module>_tests.rs` unit tests and ~80% coverage of meaningful behaviour with every behaviour change. `loop_guard.rs` adds pure, easily tested logi (crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs:34)
  • medium · tests · Test the pre-turn timeout and flush path, not only the on-time path — The docs (`openhuman-host.md`) and the code comments claim a timed-out task keeps running and can still log the user turn, and `timed_out: context.is_none()` plus `flush()` exist t (crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs:95)
  • medium · e2e · Drive the new openhuman/loop-guard flags end to end — The new eval flags are the external surface of this change: `--host openhuman` changes the recall policy, prompt wrapping and reply logging, and `--loop-guard` fails the run when s (crates/tinymemory\-integrations/examples/memory\_eval/main\.rs:148)

Before merge

  • Address Return the empty pack without awaiting the timed-out task (crates/tinymemory\-integrations/examples/memory\_eval/main\.rs).
  • Address Detach timed-out pre-turn tasks instead of awaiting them (crates/tinymemory\-integrations/examples/memory\_eval/main\.rs).
Agent review details

critique

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 11 files; 7 findings. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/main\.rs — Return the empty pack without awaiting the timed-out task
  • Evidence: docs/evals/openhuman\-host\.md — Reconcile the probe count with the reported hit rates
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/kpi\.rs — Count timeouts only for pre-turn probes
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs — Reserve the turn index before allowing timed-out tasks to overlap
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs — Retain pending tasks when flushing encounters an error
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs — Restrict echoed-item detection to injected pack content
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs — Clean up the evaluation namespace on every exit path

security

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 9 files; 1 finding. 2 files were not security-reviewed: docs/evals/README.md (prose or tabular data), docs/evals/openhuman-host.md (prose or tabular data). _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/main\.rs — Detach timed-out pre-turn tasks instead of awaiting them

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change adds an OpenHuman host profile (deadline-bounded pre-turns, logged tool results, timeout KPIs) plus a 500-turn loop guard, with new tests for `logged_reply` and the timeout-rate KPI. The tests that exist are behavioural and can fail, but the timeout/flush path of `ScriptedAgent` — the invariant the docs and code comments lean on — is never exercised by a test, and `loop_guard.rs` ships with no test module at all despite the repo's coverage rules. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/loop\_guard\.rs — Add a test module for loop_guard's pure helpers
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/agent\.rs — Test the pre-turn timeout and flush path, not only the on-time path

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The description accurately matches the diff: the OpenHuman host profile (recall policy, 1500 ms deadline, background continuation of timed-out pre-turns, bounded logged tool lines), the JSON-scripted 500-turn loop guard with the `<memory-context>` leakage check, pre-turn p99 and timeout-rate KPIs, `REUSE_IMAGE=1` in the eval script, and the documentation updates are all present and behave as described. The change looks sound to merge. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

e2e

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The pull request adds OpenHuman host mirroring and a loop-guard probe to the memory_eval example. The loop-guard itself is the check for pack echo, and the recorded measured runs show it executed end to end against the reference engine, but nothing in CI or the e2e tree drives the new flags, so the new CLI surface (`--host openhuman`, `--loop-guard`) can regress silently. Otherwise the change looks sound. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/examples/memory\_eval/main\.rs — Drive the new openhuman/loop-guard flags end to end
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.038365
  • Tokens: 545267 input · 32810 output · 48080 cached · 0 embedding
Head State Pass summary
61bfc4082c88 changes requested 11 active finding(s), 0 resolved finding(s) (at 1791647048)

tinysweeper 0.1.0

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T15:47:35.406014Z 61bfc40 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 18a4c2b7-1c1d-40ff-ba9b-befa2609cda5

📥 Commits

Reviewing files that changed from the base of the PR and between f30b9bb and 61bfc40.


📒 Files selected for processing (11)
  • crates/tinymemory-integrations/examples/memory_eval/agent.rs
  • crates/tinymemory-integrations/examples/memory_eval/agent_tests.rs
  • crates/tinymemory-integrations/examples/memory_eval/data/loop_guard.json
  • crates/tinymemory-integrations/examples/memory_eval/kpi.rs
  • crates/tinymemory-integrations/examples/memory_eval/kpi_tests.rs
  • crates/tinymemory-integrations/examples/memory_eval/loop_guard.rs
  • crates/tinymemory-integrations/examples/memory_eval/main.rs
  • crates/tinymemory-integrations/examples/memory_eval/score.rs
  • docs/evals/README.md
  • docs/evals/openhuman-host.md
  • scripts/memory-eval.sh

 ___________________________________________________________________________
< Your code and I are going to be best friends. Very critical best friends. >
 ---------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0384 · 545,267 in / 32,810 out · 48,080 cached (9%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0220 · 289,698 in / 19,410 out · 29,710 cached (10%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0157 · 186,919 in / 9,200 out  · 18,242 cached (10%) · gpt-5.6-luna
tests:       $0.0002 · 16,455 in  / 1,132 out  · 0 cached (0%)       · glm-5.3-flash
description: $0.0001 · 16,323 in  / 359 out    · 0 cached (0%)       · glm-5.3-flash
e2e:         $0.0002 · 18,670 in  / 691 out    · 0 cached (0%)       · glm-5.3-flash

tokio::spawn(async move { memory.pre_turn_dated(pre, false, async { None }).await });
match tokio::time::timeout(PRE_TURN_TIMEOUT, &mut task).await {
Ok(context) => Ok((pack(context??.pack), false, ms(started))),
Err(_) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high critique confident

Return the empty pack without awaiting the timed-out task

When pre_turn_dated exceeds PRE_TURN_TIMEOUT, this branch immediately awaits the spawned task to completion before returning. That means a slow recall operation still blocks the probe and the evaluation cannot continue at the host deadline; the recorded elapsed only measures time until the timeout, so the reported latency also hides the extra wait. The timed-out task should be retained for later cleanup/flush, or otherwise detached while the empty pack is returned at the deadline.

[RULE] deadline-bypass ·

| Run | Scope | Recall / synthesis pack hit | Synthesis model answer | Pre-turn p95 | Timeout rate | CortexDB cost |
| --- | --- | --- | --- | --- | --- | --- |
| `openhuman-cortex-mock` | `tool_heavy,compaction`, 8 probes | 8/8 · 8/8 | no answer model | 48 ms | 0/27 scripted turns | $0.000 |
| `openhuman-cortex-mock-full` | all 12 scenarios, 53 probes | 41/52 · 40/52 | no answer model | 358 ms | 0/175 calls | $0.000 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Reconcile the probe count with the reported hit rates

This row says the run covered 53 probes, but both recall and synthesis results use a denominator of 52, with no explanation for the omitted probe. That makes the documented coverage and hit rates inconsistent and prevents readers from reproducing or trusting the measurement. Make the probe count and denominators agree, or explicitly document why one probe is excluded.

[RULE] inconsistent-metrics ·

Comment on lines +461 to +463
.flat_map(|r| &r.probes)
.filter(|probe| probe.timed_out)
.count();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Count timeouts only for pre-turn probes

The denominator below counts only probes whose via starts with pre_turn, but this numerator counts every timed-out probe. If a non-pre-turn probe times out, it increases the numerator without increasing the denominator, producing an incorrect rate or even a value above 100%. Apply the same via filter when counting timed-out probes.

Suggested change
.flat_map(|r| &r.probes)
.filter(|probe| probe.timed_out)
.count();
.flat_map(|r| &r.probes)
.filter(|probe| probe.via.starts_with("pre_turn") && probe.timed_out)
.count();

[RULE] inconsistent-filtering ·

tokio::spawn(
async move { memory.pre_turn_dated(pre, false, async { None }).await },
);
match tokio::time::timeout(PRE_TURN_TIMEOUT, &mut task).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.

priority medium critique confident

Reserve the turn index before allowing timed-out tasks to overlap

When this timeout branch stores the still-running task and returns, self.next is not advanced until the later post_turn completes. If the caller starts another user call before the pending task finishes, that call constructs another PreTurn with the same turn index and can log concurrently with the first task. The resulting conversation can contain duplicate user-turn indices and assistant logging in the wrong order. Reserve/increment the turn position before launching or accepting an overlapping turn, or serialize subsequent turns until the pending pre-turn has committed.

[RULE] concurrent-turn-ordering ·

/// those tasks running, so their accepted user turns may still land.
pub(crate) async fn flush(&mut self) -> Result<usize, Error> {
let mut logged = 0;
for task in self.pending.drain(..) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique confident

Retain pending tasks when flushing encounters an error

If any drained task returns a JoinError or an inner pre-turn error, ? exits the loop immediately. The remaining JoinHandles have already been removed from self.pending; dropping Tokio join handles detaches those tasks rather than cancelling them, so they can continue writing memory after flush has reported failure and can never be observed by a later flush. Await all tasks while retaining or aggregating errors, or restore unprocessed handles to self.pending before returning.

[RULE] unobserved-background-task ·

runner.run(job).await?;
}
}
agent.flush().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.

priority medium critique likely

Clean up the evaluation namespace on every exit path

After data is stored, any error from agent.flush(), engine.export(), or the later forget() returns immediately through ?, bypassing the cleanup at the end of the function. A failed probe therefore leaves its namespace and items behind, which can pollute subsequent evaluation runs or accumulate indefinitely. Arrange for the forget operation to run in an error-safe cleanup guard or explicitly clean up before propagating each post-store error.

[RULE] cleanup-on-error ·

Ok(context) => Ok((pack(context??.pack), false, ms(started))),
Err(_) => {
let elapsed = ms(started);
task.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.

priority high security confident

Detach timed-out pre-turn tasks instead of awaiting them

After timeout returns Err, the spawned task is still running because the handle was borrowed. Awaiting it here blocks until pre_turn_dated completes, so a slow or stuck recall defeats the documented 1500 ms host deadline and prevents the simulated host from continuing with an empty pack. Drop or otherwise detach the handle after the timeout so the write can finish asynchronously while this function returns at the deadline.

Suggested change
task.await??;
drop(task);

[RULE] timeout-not-enforced ·

pub(crate) echoed_items: usize,
}

fn mean(values: impl Iterator<Item = usize>) -> f64 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Add a test module for loop_guard's pure helpers

The repo's rules require sibling <module>_tests.rs unit tests and ~80% coverage of meaningful behaviour with every behaviour change. loop_guard.rs adds pure, easily tested logic — mean (including its empty-slice guard) and the duplicate-rate closure (including its lines == 0 branch) — plus the echo-scan counting, and none of it is covered; the only verification is the manual run recorded in the docs. Extract rate into a named function next to mean and add loop_guard_tests.rs covering the empty and zero-division branches so a regression in the reported rates fails a test rather than only a future eval run.

[RULE] missing-test-coverage ·

self
}

/// Wait for pre-turn tasks whose host deadline expired. OpenHuman leaves

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Test the pre-turn timeout and flush path, not only the on-time path

The docs (openhuman-host.md) and the code comments claim a timed-out task keeps running and can still log the user turn, and timed_out: context.is_none() plus flush() exist to model that. The new agent_tests.rs only covers the on-time path (assert!(!record.timed_out)); the timeout branch and flush are never executed by any test, so if the pending-task bookkeeping regressed (e.g. flush stopped counting logs, or timed-out turns were dropped instead of logged) nothing would fail. Add a test that forces the 1500 ms deadline to expire — e.g. by using an engine whose pre_turn_dated is delayed beyond PRE_TURN_TIMEOUT (the constant is pub(crate), so a test-shorter deadline is also possible) — and asserts record.timed_out is true and flush() returns the late-logged count.

[RULE] untested-invariant ·

"--json" => parsed.json = Some(value()?),
"--label" => parsed.label = value()?,
"--llm" => parsed.llm = true,
"--host" => parsed.host = value()?,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium e2e likely

Drive the new openhuman/loop-guard flags end to end

The new eval flags are the external surface of this change: --host openhuman changes the recall policy, prompt wrapping and reply logging, and --loop-guard fails the run when stored items contain an injected <memory-context> tag. There is no e2e workflow in the tree and no CI job runs scripts/memory-eval.sh with these flags; the candidate lexical hits in integration/cortexdb/ are unrelated comment text. Coverage relies on unit tests (agent_tests.rs, kpi_tests.rs) plus the manually recorded measured runs in docs/evals/openhuman-host.md. A test would have to run the eval binary through scripts/memory-eval.sh --host openhuman --loop-guard --only none (or cargo run --example memory_eval ... --engine reference --loop-guard) and assert exit status 0 with "echoed_items": 0 in the report, so a regression that re-introduces pack echo or breaks the flag parsing fails a job rather than a documentation table.

[RULE] e2e-uncovered ·

@tinysweeper tinysweeper Bot added the priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. label Oct 10, 2026
@senamakel
senamakel merged commit b98268d into tinyhumansai:main Oct 10, 2026
22 of 25 checks passed

@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: 61bfc4082c

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

loop {
let mut req = ListRequest::new(layout.holistic_filter(), 100);
req.cursor = cursor;
let page = engine.export(req).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.

P1 Badge Wait for turn visibility before auditing the loop guard

On CortexDB, the lifecycle stores used by ScriptedAgent return at WaitFor::Accepted, so flush() only waits for timed-out pre-turn tasks to finish and does not guarantee that those turns (or the latest assistant turns) are listable. Exporting immediately can therefore omit the tail of the 500-turn thread and report echoed_items == 0 even when a not-yet-visible stored item contains the tag; the subsequent filtered forget can race the same writes as well. Count the accepted user/assistant writes and perform the same visibility-settle step used by Eval::settle before exporting.

Useful? React with 👍 / 👎.

Ok(context) => Ok((pack(context??.pack), false, ms(started))),
Err(_) => {
let elapsed = ms(started);
task.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 Continue probes immediately after the host deadline

Whenever a probe's pre-turn exceeds 1500 ms, this await prevents Eval::probe from invoking the answer model or starting the next probe until the memory task actually finishes. That is the opposite of the OpenHuman timeout path being mirrored, which proceeds with an empty pack while the task remains in the background; in the documented live runs where many probes time out, this serializes request load and can skew later timeout results, and a stuck task hangs the eval despite the deadline. Retain or detach the handle and flush it separately instead of awaiting it on this path.

Useful? React with 👍 / 👎.

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

Labels

priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant