Skip to content

exact-match always collapses internal whitespace, and trim: false does not turn it off #9

Description

@royalpinto007

Desired outcome

exact-match can do a genuinely exact comparison, or its documentation stops implying that it can.

Why it matters

normalize() in src/scorers/util.ts collapses internal whitespace unconditionally:

export function normalize(text: string, opts: { caseSensitive?: boolean; trim?: boolean } = {}): string {
  let out = text;
  if (opts.trim !== false) out = out.trim();
  if (!opts.caseSensitive) out = out.toLowerCase();
  return out.replace(/\s+/g, " ");
}

The trim option only controls the leading and trailing trim. The final replace(/\s+/g, " ") always runs, so every run of whitespace, including newlines and tabs, becomes a single space no matter what the caller passes.

exactMatchScorer in src/scorers/exact-match.ts documents itself as:

Passes when the output equals the expected value. Supports case-insensitive and whitespace-normalized comparison via options.

  • trim: default true

That reads as if whitespace normalization is opt-out, and caseSensitive: true, trim: false looks like the way to get a byte-exact comparison. It is not. A scorer checking that a model emitted a specific multi-line block, indented code, or a two-space separator will pass on output whose formatting is completely different. For a scorer literally named exact-match, that is a surprising silent pass, and silent passes are the failure mode an eval gate exists to prevent.

The same applies to contains and not-contains in src/scorers/contains.ts, which normalize both haystack and needles, so a banned-phrase check cannot be written against exact spacing.

Steps

  1. Add a collapseWhitespace option to normalize() (default true, preserving today's behaviour) and apply the replace only when it is set.
  2. Thread it through exactMatchScorer from spec.collapseWhitespace, so { caseSensitive: true, trim: false, collapseWhitespace: false } is a true byte comparison.
  3. Update the doc comments on normalize and exactMatchScorer, and the scorer table in README.md, to say plainly that whitespace is collapsed by default.
  4. Add tests in tests/scorers.test.ts for output differing from expected only in internal whitespace, once with the option on and once off.

Claiming this

Comment below to claim it. A reply usually comes within a day.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions