Summary
main is intermittently red on openhuman::agent::harness::session::builder::builder_tests::part_01_tests::memory_access_instruction_is_present_with_learning_disabled, and it is blocking unrelated PRs. The cause is not flakiness in the usual sense: the outcome flips deterministically on whether AgentDefinitionRegistry::init_global has already run anywhere in the test process.
Evidence that this is on main, not on any one PR
Same test, same assertion, same line (builder_tests_part_01_tests.rs:543, "the memory-access section must not be gated on learning.enabled") on main twice today:
| When |
Run |
Shape |
| 2026-09-10 06:34 |
34445793082 (merge of #6173) |
full suite — 11765 passed; 1 failed |
| 2026-09-10 12:23 |
34476483764 (merge of #6182) |
scoped -- openhuman::agent — 2397 passed; 1 failed |
It also failed on PR #6189, whose diff touches only agent/harness/subagent_runner/ops/graph* and cannot reach the prompt builder. The PR CI Gate failure there is downstream — Coverage never produced diff-coverage.md.
Root cause — reproduced deterministically
build_session_agent_inner(config, "orchestrator", /* definition */ None, …) takes the legacy orchestrator fallback at src/openhuman/agent/harness/session/builder/factory.rs:844:
(None, Some(reg)) => {
let synthed = match reg.get("orchestrator") {
Some(orch_def) => collect_orchestrator_tools(orch_def, reg, …),
None => Vec::new(),
};
(synthed, None) // filter_from_scope = None
}
and then, at factory.rs:911:
let mut visible = match filter_from_scope {
Some(set) => set,
None => delegation_tools.iter().map(|t| t.name().to_string()).collect(),
};
So visible is populated from the delegation tools alone. any_tool_offered (agent/learning/prompt_sections.rs:222) reads it as a whitelist:
let allowed_by_filter = visible.is_empty() || visible.contains(*name);
- Registry not initialised →
delegation_tools empty → visible empty → is_empty() means "no filter" → MemoryAccessSection registered → test passes.
- Registry initialised →
visible = delegation tool names, which do not include memory_recall / memory_search → section skipped (helpers.rs:131) → test fails.
AgentDefinitionRegistry::init_global is a process-global, called lazily from src/openhuman/memory/goals/enrich.rs:117 and at startup from src/openhuman/platform/socket/medulla/mod.rs:403. Whether some earlier test in the same process has tripped it is decided by parallel test scheduling — hence red under --test-threads default and green when re-run serially.
Probe
Dropped into builder_tests_part_01_tests.rs, building the same agent twice in one process with only init_global in between:
let before = /* build_system_prompt */.contains(MEMORY_ACCESS_INSTRUCTION.trim());
let init = AgentDefinitionRegistry::init_global(&config.workspace_dir);
let after = /* same build again */.contains(MEMORY_ACCESS_INSTRUCTION.trim());
PROBE registry_global_before=true init_ok=true section_before=true section_after=false
true → false from that one call. Not a timing race — a state flip.
Why this may be more than a test bug
visible is not only prompt gating. Per the comment at factory.rs:918, it is "the single source of truth that the policy session, advertised specs, and the run-time visible-name gate all consume". On this path a session whose definition scope is absent or Wildcard ends up with a non-empty visible containing only delegation tools — which reads as "these tools and nothing else" rather than the intended "no filter".
If any production path reaches build_session_agent_inner with definition: None while the registry is live — and the registry is initialised at startup — that session would lose the #6040 memory-access instruction, and possibly more. I have not verified which production callers pass definition: None, so I am not claiming a shipped regression; that is the question this issue needs answered first.
Suggested direction
The None => delegation_tools… arm conflates two meanings of an empty visible. A wildcard/absent scope that merely synthesised delegation wrappers is not an allowlist, and collapsing it into one loses that. Options, in preference order:
- Keep "no filter" as no filter: when
filter_from_scope is None, leave visible empty and track delegation tool names separately for whatever needs to advertise them.
- If
visible must carry the delegation names, union in the base tool set on the wildcard path, the way the disallowed_tools + ToolScope::Wildcard branch at factory.rs:932 already does.
Either way the test stops depending on global registry state, which is the property worth pinning with a regression test.
Reproduce
cargo test -p openhuman --lib --features "$(bash scripts/ci/product-features.sh)"
Fails intermittently. The cluster it appears in varies run to run — I saw budget_gate::{dropping_the_crate_permit_releases_the_scheduler_permit, explicit_release_returns_capacity_before_end_of_scope}, mcp::registry::tools::list_tools_errors_for_unconnected_server, integrations::composio::tools::list_toolkits_in_direct_mode_returns_empty_without_hitting_backend, and modules::ops::a_bounded_wait_with_nothing_cached_and_downloads_off_fails_rather_than_loading alongside it. Those others are not covered by this analysis and may well have separate causes; only the memory-access one is root-caused here.
Summary
mainis intermittently red onopenhuman::agent::harness::session::builder::builder_tests::part_01_tests::memory_access_instruction_is_present_with_learning_disabled, and it is blocking unrelated PRs. The cause is not flakiness in the usual sense: the outcome flips deterministically on whetherAgentDefinitionRegistry::init_globalhas already run anywhere in the test process.Evidence that this is on
main, not on any one PRSame test, same assertion, same line (
builder_tests_part_01_tests.rs:543, "the memory-access section must not be gated on learning.enabled") onmaintwice today:11765 passed; 1 failed-- openhuman::agent—2397 passed; 1 failedIt also failed on PR #6189, whose diff touches only
agent/harness/subagent_runner/ops/graph*and cannot reach the prompt builder. ThePR CI Gatefailure there is downstream — Coverage never produceddiff-coverage.md.Root cause — reproduced deterministically
build_session_agent_inner(config, "orchestrator", /* definition */ None, …)takes the legacy orchestrator fallback atsrc/openhuman/agent/harness/session/builder/factory.rs:844:and then, at
factory.rs:911:So
visibleis populated from the delegation tools alone.any_tool_offered(agent/learning/prompt_sections.rs:222) reads it as a whitelist:delegation_toolsempty →visibleempty →is_empty()means "no filter" →MemoryAccessSectionregistered → test passes.visible= delegation tool names, which do not includememory_recall/memory_search→ section skipped (helpers.rs:131) → test fails.AgentDefinitionRegistry::init_globalis a process-global, called lazily fromsrc/openhuman/memory/goals/enrich.rs:117and at startup fromsrc/openhuman/platform/socket/medulla/mod.rs:403. Whether some earlier test in the same process has tripped it is decided by parallel test scheduling — hence red under--test-threadsdefault and green when re-run serially.Probe
Dropped into
builder_tests_part_01_tests.rs, building the same agent twice in one process with onlyinit_globalin between:true → falsefrom that one call. Not a timing race — a state flip.Why this may be more than a test bug
visibleis not only prompt gating. Per the comment atfactory.rs:918, it is "the single source of truth that the policy session, advertised specs, and the run-time visible-name gate all consume". On this path a session whose definition scope is absent orWildcardends up with a non-emptyvisiblecontaining only delegation tools — which reads as "these tools and nothing else" rather than the intended "no filter".If any production path reaches
build_session_agent_innerwithdefinition: Nonewhile the registry is live — and the registry is initialised at startup — that session would lose the #6040 memory-access instruction, and possibly more. I have not verified which production callers passdefinition: None, so I am not claiming a shipped regression; that is the question this issue needs answered first.Suggested direction
The
None => delegation_tools…arm conflates two meanings of an emptyvisible. A wildcard/absent scope that merely synthesised delegation wrappers is not an allowlist, and collapsing it into one loses that. Options, in preference order:filter_from_scopeisNone, leavevisibleempty and track delegation tool names separately for whatever needs to advertise them.visiblemust carry the delegation names, union in the base tool set on the wildcard path, the way thedisallowed_tools+ToolScope::Wildcardbranch atfactory.rs:932already does.Either way the test stops depending on global registry state, which is the property worth pinning with a regression test.
Reproduce
Fails intermittently. The cluster it appears in varies run to run — I saw
budget_gate::{dropping_the_crate_permit_releases_the_scheduler_permit, explicit_release_returns_capacity_before_end_of_scope},mcp::registry::tools::list_tools_errors_for_unconnected_server,integrations::composio::tools::list_toolkits_in_direct_mode_returns_empty_without_hitting_backend, andmodules::ops::a_bounded_wait_with_nothing_cached_and_downloads_off_fails_rather_than_loadingalongside it. Those others are not covered by this analysis and may well have separate causes; only the memory-access one is root-caused here.