Skip to content

fix(core): harden the eval harness from live A/B and BEAM runs - #1416

Open
phernandez wants to merge 10 commits into
mainfrom
1398-eval-test-fixes
Open

fix(core): harden the eval harness from live A/B and BEAM runs#1416
phernandez wants to merge 10 commits into
mainfrom
1398-eval-test-fixes

Conversation

@phernandez

Copy link
Copy Markdown
Member

Why

Live testing of the #1398 eval stack — five real-model A/B runs and a full BEAM 100K pass — against merged main. Every commit on this branch was bought by a real failure; the runs that followed each fix validated it. Fixes #1400's follow-through and produces the tracker's first quotable numbers.

What changed (12 commits, in failure order)

BEAM live-data drift (all caught by the deliberate fail-fasts):

  • event_ordering chat-id groups mix ints with int-lists ([116, …, [136, 138]]) — flatten one level, deeper still fails
  • Probe-marker variants ->-> 2,22, 24 and ->-> 1,5) — final pattern covers the complete surveyed population (2,199 markers, five shapes, survey in the comment); the ) verified as generator junk; unknown ->-> content still fails fast

Agent-task harness correctness:

  • Task projects were never indexed: project add registers only, status reported ready vacuously, and all 24 tasks of run 3 saw empty projects (masked by the scripted smoke, whose canned answers never consult the index) — explicit reindex --full --search before settle
  • Grader permalink comparison: live DBs store project-prefixed permalinks; answer-set graders and the RelationResolves SQL both now match the task's own prefix while foreign prefixes still fail (cross-project leakage keeps failing, verified against live run DBs)
  • State-graded tasks reindex (whose completion includes forward-reference relation resolution) before grading
  • at-at- double project prefix removed

Model-endpoint integration (Anthropic compat, verified live):

  • --model-header Name=value (identity-linked keys need anthropic-workspace-id); values ride only in the model-factory closure, structurally excluded from run artifacts
  • --model-temperature with omit (Claude 5 rejects the parameter); recorded in the run config for provenance
  • openai-compat errors include the response body — the next rejection names itself

CLI: plain-slice footer no longer visually concatenates onto unterminated content (stdout stays byte-exact for pipes).

What the validated runs produced

  • BEAM 100K baseline (run 4dedb8c85318): bm-local vs mem0-local at retrieval parity (R@10 0.657 vs 0.648 answerable) with half the latency (379 ms vs 746 ms); QA macro 0.498 vs 0.513; BM's only meaningful per-ability deficits are temporal reasoning (−7.2pp) and contradiction resolution (−6.6pp) — exactly SPEC-82 and SPEC-89, now recorded pre-implementation as measurable deltas.
  • A/B runs 4–5 (Sonnet 5): rich 10–11/12 @ ~80k tokens/completed; posix 5/12 — with nearly every failure on either surface being the wrong-project addressing gap (Project-qualified paths: projects as mount points in the tool namespace #1415), not retrieval capability. Where scope is handled, posix matches rich at 26–32% fewer tokens (manual chain: 23.1k both runs, 11 tokens apart).

Product issues driven by these runs

#1414 (index-on-add + readiness contract + refuse-on-never-indexed), #1415 (project-qualified paths — round-trip asymmetry evidence), plus tracker findings on #1398.

🤖 Generated with Claude Code

https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 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-09-01T18:55:38.266929Z 65de3a4 New commits
ℹ️ 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.

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

ℹ️ 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 benchmarks/src/basic_memory_benchmarks/agent_tasks/models.py

@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: 628b027058

ℹ️ 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 benchmarks/src/basic_memory_benchmarks/agent_tasks/grading.py
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 628b027058

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

phernandez and others added 10 commits September 1, 2026 13:51
An unterminated slice concatenated the stderr footer onto the final
stdout line in terminals and merged captures. Lead with the newline on
stderr when content lacks one; stdout stays byte-exact for pipes.

Found during live smoke testing on the 1398 eval branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
The live 100K tier mixes ints with one level of int-list groups in
event_ordering source_chat_ids ([116, ..., [136, 138]]) when a single
event's evidence spans chats — a shape the fail-fast loader rejected.
Flatten one level of int lists into the union; anything deeper or
non-int still fails fast. Fixture and tests carry the live shape.

Found by the loader's own schema guard during the first real dataset
fetch on the 1398 eval branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
The live 100K tier carries a third marker variant: '->-> 2,22, 24' —
an id list with a space after a comma. The pattern now matches an int
followed by comma-separated ints or N/A with optional spaces, staying
narrow so unknown '->->'-bearing content still trips the fail-fast
instead of being silently stripped. Fixture and tests carry all three
observed variants.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
Surveyed every marker in the live 100K tier (2,199 across five shapes)
and closed the last gap: six markers carry a trailing ')' that is
generator junk (zero opening parens in every affected message). The
pattern now covers the complete observed population while unknown
'->->' content still fails fast; comment records the survey.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
Anthropic's OpenAI-compat endpoint rejects identity-linked API keys
without an anthropic-workspace-id header, which the first live A/B run
hit as an opaque 400 on all 24 tasks. Add a repeatable --model-header
Name=value option that rides only in the model-factory closure — never
in AgentTasksConfig, so header values can never leak into run
artifacts — and include the response body in openai-compat errors so
the next rejection names itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
Claude 5 models reject the temperature parameter outright ('temperature
is deprecated for this model'), which the second live A/B hit on all 24
tasks — named precisely by the new error-body reporting. Add
--model-temperature (number, or 'omit' to drop the parameter), default
unchanged at 0 so local openai-compat servers stay pinned; the choice is
recorded in the run config for provenance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
project add registers a project but does not index it, so the DB stayed
empty, status reported ready vacuously (zero pending work was ever
queued), and every retrieval tool saw an empty project — the first
real-model A/B ran 24 tasks against nothing. Run an explicit
reindex --full --search after registration, before the settle wait. The
scripted smoke masked this because canned answers never consult the
index.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
Three fixes from the first real-model A/B run:

- Answer-set graders now strip the task's OWN project prefix from
  answer-extracted permalinks (agents faithfully quote tool output,
  which is project-prefixed); a different project's prefix still fails,
  so cross-project leakage keeps failing. Six of the run's failures
  were this comparison artifact.
- State-graded tasks run reindex --search (whose completion includes
  forward-reference relation resolution) before settling and grading;
  the rich curate-connect 'write was verified correct by argument
  fingerprint but grading saw 0 resolved relations' race is closed.
- Task project names no longer double the at- prefix.

Also diagnosed, agent-side by design (measured behavior, no harness
change): agents sometimes omit the project argument and the warm MCP
session routes calls to the previously named project — including
writes, with the agent then 'verifying' in the wrong project.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
Live-run DBs store entity permalinks project-prefixed
('at-<run>-<task>/notes/...'), so RelationResolves' relative-permalink
SQL could never match — curate-connect was ungradeable on every run for
every agent. Match both forms for the source and strip the task's own
project prefix from resolved targets before comparison; a target under
a different project's prefix still fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>
A programmatic caller constructing AgentTasksConfig and calling
run_agent_tasks directly got the factory's default temperature while
manifest.json recorded the configured value — a silent provenance lie in
an artifact whose whole job is provenance. The CLI was unaffected because
it pre-binds temperature into its factory.

The default is now a None sentinel rather than the function itself, so
the branch reads the module attribute at call time; an injected factory
still owns its own configuration and is called unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp
Signed-off-by: phernandez <paul@basicmachines.co>

@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: 65de3a498e

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

# missing header, quota) — without it the operator sees only
# a bare status code.
if isinstance(exc, httpx.HTTPStatusError):
error_body = exc.response.text[:300]

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 Redact response bodies before saving task errors

When an OpenAI-compatible gateway includes request headers or other sensitive request details in a 4xx/5xx response, these raw 300 characters are appended to LLMRunnerError; the driver then writes that text to per-task-agent.jsonl and summary.md, and publish copies the entire run into the public results bundle. This can therefore persist the sensitive values accepted through --model-header, despite the new interface promising they never enter run artifacts; retain a safe status/error summary or redact secrets before propagating the body.

AGENTS.md reference: benchmarks/AGENTS.md:L8-L11

Useful? React with 👍 / 👎.

temperature: float | None = None
else:
try:
temperature = float(model_temperature)

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 Reject non-finite model temperatures

When --model-temperature is nan, inf, or -inf, float() accepts it and the config validation also permits it, but httpx rejects the resulting request body with ValueError: Out of range float values are not JSON compliant. That exception is not one of _post's handled transport failures, so the whole benchmark aborts after setup instead of producing an explicit errored task and provenance artifacts; validate that the parsed value is finite before constructing the config.

AGENTS.md reference: benchmarks/AGENTS.md:L93-L98

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BEAM benchmark integration in the benchmarks package

1 participant