Skip to content

fix(evals): transcript assertions must grep with -a (invalid UTF-8 silently defeats matching)#1576

Merged
Aaronontheweb merged 2 commits into
netclaw-dev:devfrom
Aaronontheweb:fix/eval-grep-binary-transcripts
Jul 4, 2026
Merged

fix(evals): transcript assertions must grep with -a (invalid UTF-8 silently defeats matching)#1576
Aaronontheweb merged 2 commits into
netclaw-dev:devfrom
Aaronontheweb:fix/eval-grep-binary-transcripts

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

The actual bug

The assert_memory_identity_preference_routing assertion requires the literal substring memory. However, correct model responses often say "memories" (plural), and the plural form drops the y — the substring "memories" does not contain "memory".

Regression proof from run af0883b5:

  • Proof 1: grep -ci 'memory' $TRANSCRIPT = 0 (the bug—response is plural-only)
  • Proof 2: grep -cia 'memor' $TRANSCRIPT = 1+ (fixed pattern matches)
  • Proof 3: file $TRANSCRIPT confirms clean UTF-8 (disproves the old theory)

Behaviorally-correct runs (#3 and #5 from af0883b5) were rejected because they said "That's already saved — ... in my durable memories" with no file edits and no redundant store call—exactly right routing, but flagged as failures.

This flake explains the 0/5 → 3/5 → 5/5 history: the fix rate increased as model outputs naturally drifted away from singular toward plural language.

What the -a flags are

The -a flags added in the prior commit are retained as cheap defensive hardening: captured CLI output may carry terminal control bytes, and -a keeps grep in text mode regardless.

The original invalid-UTF-8 justification was incorrect and is retracted. The transcript is clean UTF-8. The flake was plain English morphology, not byte encoding.

Call sites

Assertion pattern fix:

  • evals/run-evals.sh:1010 — changed stdout_contains 'memory' to stdout_contains 'memor'

The 17 -a call sites from the prior commit are all present and remain in place as cheap hardening, but they are not the fix.

Verified proof (archived run af0883b5, failing transcript run #3)

grep -ci 'memory' <transcript>   -> 0   (old pattern: plural-only response never matched)
grep -cia 'memor' <transcript>   -> 1   (fixed pattern matches)
file <transcript>                -> Unicode text, UTF-8 text  (clean — the earlier invalid-UTF-8 theory is disproven)

…eating assertions

GNU grep in a UTF-8 locale silently skips lines with invalid multibyte sequences
when the -a flag is absent. Eval transcripts contain terminal control bytes and
other non-UTF-8 sequences, causing assertion helpers to randomly fail when
escape bytes landed on a matching line — the mechanism explains the historic
flakiness of memory_identity_preference_routing (0/5→3/5→5/5→3/5 swings).

Fixed all 14 grep call sites in the assertion helpers and inline transcript
assertions by adding -a:
- stdout_contains, stdout_not_contains (grep -qi → grep -qia)
- stdout_response_contains, stdout_response_not_contains (both pipes: -v → -av, -qi → -qia)
- daemon_log_contains, daemon_log_skill_loaded, daemon_log_no_skill_loaded (grep -qE → grep -qaE)
- stdout_tool_called (grep -qE → grep -qaE)
- store_metrics: grep on usage_line (grep -oP → grep -aoP, 5 invocations)
- run_prompt_resume: grep on turn_file (grep -o → grep -ao)
- assert_multi_turn_text_growth: grep on STDOUT_FILE (grep -c → grep -ac)
- assert_approval_set_working_directory_positive: grep -nE on STDOUT_FILE (2 invocations, → grep -anE)

Proven on run af0883b5: memory_identity_preference_routing cases had correct
behavior ('durable memories' literal text in transcript), but grep -ci returned 0,
while grep -cia returned the correct count. This fix eliminates the instrumentation
source of the flakiness.
…does not contain 'memory'

The memory_identity_preference_routing assertion was failing intermittently because correct
model responses often say 'memories' (plural), but the assertion required the literal
substring 'memory' (singular). 'memories' does NOT contain 'memory' as a substring —
the plural drops the y.

Regression proof from run af0883b5: runs #3 and netclaw-dev#5 exhibited correct behavior
("That's already saved — ... in my durable memories", no file edits, no redundant
store call) but were rejected by the old pattern.

The -a flags added in the prior commit are retained as cheap defensive hardening
for transcripts that may carry terminal control bytes, but they are NOT the fix for
this flake. The invalid-UTF-8 justification was incorrect and is retracted.
@Aaronontheweb
Aaronontheweb merged commit 4b0ef39 into netclaw-dev:dev Jul 4, 2026
14 checks passed
@Aaronontheweb Aaronontheweb added the evals LLM efficacy evals for Netclaw label Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

evals LLM efficacy evals for Netclaw

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant