Skip to content

feat: add eval for replacing identity string reductions with joining #62

Description

@martinfrancois

Problem

A broad Java API-reuse audit correctly replaced an identity-based string reduction with
Collectors.joining(), but the Java Streams skill and its eval-capture workflow did not activate
for that transformation. The implementation needs no correction; the missing behavior is automatic
recognition and capture of this reusable boundary.

Issue #60 covers a conditional delimiter reducer whose empty-string sentinel can collide with an
empty mapped value. This case is distinct: the source is the identity reduction
.reduce("", String::concat), the destination has no delimiter, and the material
behavior-equivalence risk is null handling.

Area

Evals or scoring

Describe the solution you want

Add a reference eval that recognizes an ordered Stream<String> identity concatenation and prefers
Collectors.joining() after proving that mapped values are non-null.

Code before the prompt was executed

Assume renderRow either returns a non-null HTML row or throws while rendering it.

return rows.stream()
        .map(Renderer::renderRow)
        .reduce("", String::concat);

Prompt that caused the implementation

The original prompt required a complete Java-source API-reuse audit:

  • Audit every tracked Java source for worthwhile replacements with the Java standard library or a
    directly declared dependency.
  • Implement replacements only when they clearly reduce code, complexity, duplication, or
    maintenance risk.
  • Consult exact-version official documentation and preserve ordering, exceptions, null handling,
    concurrency, security, and relevant performance characteristics.
  • Add focused regression coverage for behavior-sensitive boundaries.

This prompt should have activated the Java Streams skill and the eval-capture workflow for the
identity string reduction.

Later prompt that exposed the issue

A maintainer later asked:

Did you already create an issue with the streams capture skill here? If not, tweak the skill so
you'll remember to capture things like this next time and please create an issue on the skill repo
for this change.

Prompt-produced or reviewed code

return rows.stream()
        .map(Renderer::renderRow)
        .collect(Collectors.joining());

The code is already preferred. The miss is skill activation and eval capture, not the implementation
choice.

What the skill missed

The skill states that Collectors.joining() is the intent-encoding collector for concatenated text,
but it did not cause the broad audit to capture .reduce("", String::concat) as a distinct
reusable source pattern. The eval-capture workflow also stopped after capturing the related
delimiter-reducer case in #60.

Behavior-equivalence analysis

  • Empty input returns "" in both forms.
  • One or many non-null mapped strings produce the same concatenation in encounter order, including
    when an individual mapped string is empty.
  • Mapping and rendering exceptions propagate from the same terminal traversal.
  • String::concat is associative with "" as its identity, so ordered parallel reduction does not
    change the selected result; joining() also preserves encounter order.
  • Null handling is not equivalent in the general case. String.concat(null) throws
    NullPointerException, while StringJoiner.add(null), which backs joining(), appends the four
    characters "null". The replacement is correct only when the mapper or source contract proves
    non-null elements or when changed null behavior is explicitly intended.

The eval MUST cover empty input, one element, several elements, empty mapped strings, a null
counterexample, encounter order, and an exception thrown by the mapper.

Maintainer-preferred code

return rows.stream()
        .map(Renderer::renderRow)
        .collect(Collectors.joining());

Why the replacement is better

The collector names the requested result directly and owns string accumulation instead of expressing
concatenation through a generic immutable reduction. The justification is intent and accumulation
ownership; the eval MUST NOT promise a speedup without measurement.

Desired eval behavior

  • Reward recognizing .reduce("", String::concat) and an equivalent
    .reduce("", (left, right) -> left.concat(right)) source shape.
  • Reward Collectors.joining() only after proving compatible null behavior.
  • Reward preserving empty-input behavior, encounter order, mapped empty strings, and exception
    propagation.
  • Reward activating the Java Streams skill and eval capture during the original broad audit, even
    when the prompt does not name streams.
  • Reward distinguishing this identity-concatenation boundary from feat: add eval for replacing delimiter reductions with joining #60's conditional delimiter and
    sentinel-collision boundary.
  • Reward stating that the reviewed code was already correct when only activation or capture was
    missed.

Anti-patterns the eval should reject

  • Rewriting every string reduction mechanically without checking null behavior.
  • Treating joining() and String::concat as null-equivalent.
  • Adding an unnecessary delimiter, intermediate collection, or custom collector.
  • Claiming that the already-preferred implementation needs a product-code correction.
  • Claiming an unmeasured performance improvement as the correctness rationale.

Suggested eval name

identity-string-reduce-to-joining

Examples

The before/after pair above is the minimal eval. Include a negative fixture whose mapped stream
contains null; the preferred answer MUST retain the original reduction or require an explicit
null-behavior decision for that fixture.

Alternatives considered

Updating #60 alone would merge two different equivalence boundaries. Its custom delimiter reducer
depends on proving that an empty accumulator sentinel cannot collide with data. This issue instead
depends on the identity-concatenation shape and the String.concat versus StringJoiner.add null
contract. The evals MAY share general joining guidance, but they MUST score those constraints
separately.

Current workaround

Repository-local capture guidance explicitly enumerates identity string reductions during broad
audits and requires a separate capture when their constraints differ from delimiter reductions.

Additional context

No user-facing product contract changes. The requested change is skill activation and eval coverage.

AI Assistance

  • AI-assisted issue
  • I confirm I understand and reviewed this request

AI prompts / session logs (optional)

Prepared with Codex assistance from a maintainer review of a behavior-preserving Java API-reuse
audit. The exact later prompt is quoted above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions