fix(v1): de-flake the live E2E suite - #2267
Merged
Merged
Conversation
- openclaw: make reasoning replay opt-in (sampling.reasoning_effort), never a model-name guess. OpenClaw redacts Prime's dotted encrypted_content in its persisted transcript (fails its opaque-token allowlist), so resumed sessions deterministically 400 replaying the mangled token. - chat wire: replay an empty assistant completion as content "" instead of null - strict providers reject null content without tool calls (422). - echo-tool fixture: score the stamped TOOL result (the tool really ran) instead of the assistant's verbatim relay (model obedience). - e2e conftest: retry HarnessError'd rollouts too (empty agent turns, agent-timeout stalls); deterministic failures still fail all attempts.
Contributor
ApprovabilityVerdict: Approved de73918 This PR contains defensive bugfixes for E2E test flakiness: handling null content for strict API providers, narrowing reasoning detection to explicit opt-in, and updating test retry/validation logic. All changes have clear intent, limited scope, and low risk. You can customize Macroscope's approvability policy. Learn more. |
A strong instruction-follower reads the scenario's imperative text
("Call the `echo_back` tool ...") as its own instructions and opens the
conversation by emitting the task's answer format directly - the
assistant never hears the request, no tool ever runs, and the episode
scores 0. Frame the scenario as what the USER wants the ASSISTANT to do
and forbid the user seat from producing the task's output itself.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Five targeted fixes for the remaining live-E2E failures on
main(post #2262). Each was reproduced and diagnosed locally against the real endpoint before fixing.1.
test_acp_resume_with_tool[openclaw-acp-in-docker]— deterministic upstream 400 on resumeRoot cause (captured the exact rejected
/responsesbody locally): withreasoning: true, OpenClaw requestsinclude: ["reasoning.encrypted_content"]and replays reasoning items from its persisted transcript on session resume. Prime's gateway emitsencrypted_contentin a dotted<fernet>.<base64-metadata>format, which fails OpenClaw's opaque-replay-token allowlist (/^[A-Za-z0-9+/_-]+={0,2}$/— no dot), so OpenClaw's secret redaction masks the persisted token togAAAAA…iA==.<metadata>(head6…tail4). The resumed session replays the mangled token → gateway 400 "Invalid request" → every resumed OpenClaw rollout dies. (Live sessions replay from memory, unredacted — which is why only resume broke.) OpenClaw even has a strip-encrypted-content retry, but it only matchesinvalid_encrypted_content/thinking_signature_invaliderror codes; the gateway's genericinvalid_requestnever triggers it.Fix: OpenClaw
reasoningnow follows the explicit sampling config (reasoning_effort), never a model-name guess. The old heuristic force-enabled reasoning replay forgpt-5*/o*models, which is exactly the broken path on the default (Prime) endpoint.Upstream follow-ups worth filing (out of scope here):
encrypted_contentbreaks agents that allowlist OpenAI's dot-free token shape; the opaque 400 also defeats agents' own strip-and-retry fallbacks.encrypted_contentfields.Validated: failing 5/5 before (3 CI runs + 2 local), passing 4/4 locally after.
2.
test_env_id_user_sim_with_tools— 422 modeThe CI model occasionally returns a fully-empty completion; it records as
content=Noneandmessage_to_wirereplays it as"content": nullin the next segment's initial messages — strict providers reject the request (content is required unless an assistant message includes tool_calls). Empty completions now replay as"".3.
test_env_id_user_sim_with_tools— score-0 modeLocal transcript: the tool ran and returned
hello world [ok-7f3], but the sim-user paraphrased away the "reply with exactly what it returns" requirement, so the assistant dropped the stamp and the reward scored 0. Theecho-tool-v1reward now scores the stamped tool result — per the fixture's own contract ("reward 1.0 only if the model actually called the tool — trivial when the infra works, impossible when it doesn't") — instead of grading whether the model parrots the stamp verbatim.Validated: failing 4/4 CI runs before; passing 3/3 locally after (2 targeted runs +
test_toolplacement).4.
test_env_id_user_sim_with_tools— task-leak modeLocal transcript: the sim-user (a strong instruction-follower) reads the scenario's imperative text ("Call the
echo_backtool … reply inside<answer></answer>tags") as its own instructions and opens the conversation with<answer>hello world</answer>itself — the assistant is never asked to do anything, no tool ever runs (zero TOOL messages, so 3.'s reward fix can't save it), the sim-user closes with###DONE###, and the episode scores 0.Fix: harden the
user-simPERSONA — frame the scenario as what you want the ASSISTANT to do for you, and add an explicit rule that the user seat never performs the task itself (no tool calls, answers, or output formats; it asks the assistant instead).Validated: failing 2/2 locally before (with fixes 1–3 already in-tree); passing 3/3 after, sibling
test_env_id_user_simstill green.5.
test_single_turn/test_agentic[rlm-*],test_tool_state— unretried harness flakesRLM occasionally ends a turn with zero output (
ACP agent produced no visible reply, survives #2262's grace period — the model genuinely emits nothing), andtest_tool_stateoccasionally stalls into its rollout budget (agent timeout). Both record asHarnessError, which the e2e retry include didn't cover (onlyProviderError). The conftest now retriesHarnessErrorrollouts too; deterministic harness bugs still fail all three attempts.Validation
uv run pytest tests/v1 -m "not e2e"— all passeduv run pytest tests/ -m "not e2e"— all passedtest_env_id_user_sim_with_tools×3 +test_env_id_user_sim×1 — all passeduv run ruff check .,ty check verifiers(3.13),uv run pre-commit run --all-files— passedNote
Medium Risk
Production paths change OpenClaw reasoning defaults, chat serialization, and user-sim behavior—not just tests—though changes are narrow and aimed at known flake/failure modes.
Overview
Targets five live-E2E failure modes with small behavioral fixes in harness, dialect, env, and test defaults.
OpenClaw resume:
reasoningon the intercept model is now driven only bysampling.reasoning_effort(notgpt-5/o*name heuristics), avoiding persisted encrypted-reasoning replay that 400s on session resume.Chat wire:
message_to_wiresendscontent: ""instead ofnullfor assistant turns with no text and no tool calls, so strict providers accept the next request.User-sim: The sim-user
PERSONAframes the scenario as what the assistant should do and forbids the user seat from performing tools, answers, or formatted output itself—fixing cases where the user “completed” the task before the assistant ran tools.Echo-tool fixture: The
echoedreward checks stamped text in tool messages (viacontent_text), not whether the assistant parroted the stamp.E2E defaults: Per-seat retries in
conftestnow includeHarnessErroralongsideProviderError(still max 2 retries).Reviewed by Cursor Bugbot for commit de73918. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix flaky live E2E tests by correcting reward logic, retry config, and assistant message handling
HarnessErrorto the retry list alongsideProviderErrorin_eval_config, so transient harness failures no longer fail seats permanently.echoedreward inEchoToolTaskto check tool messages (not assistant messages) for the expected phrase and token, requiring actual tool execution.contentto an empty string instead ofnullwhen there are no tool calls inmessage_to_wire, improving provider compatibility.OpenClawHarnessto enable reasoning only whensampling.reasoning_effortis explicitly set, removing the model-name heuristic.echoedreward scores will change for any rollout where the assistant relayed the phrase without invoking the tool.Macroscope summarized de73918.