Skip to content

Add eval for extracting nested catalog stream lambdas #57

Description

@martinfrancois

Problem

A catalog-driven feature added two nested stream pipelines inside Optional.map and
Optional.flatMap lambdas. The code was correct, but each lambda began another stream pipeline
that continued across lines. The Streams skill should activate during the original feature prompt
and recommend named collection helpers so the outer Optional flow remains readable glue.

This example targets Java 25.

Code before the prompt was executed

Before model-specific effort choices and descriptions existed, the value object only looked up one
default effort per model:

Optional<String> reasoningEffortForModel(String model) {
    if (blank(model)) {
        return Optional.empty();
    }
    return Optional.ofNullable(reasoningEffortsByModel.get(model.strip()));
}

There was no nested collection transformation or description lookup.

Prompt that caused the implementation

Issue #539 was clarified as follows: do not merely add one hard-coded reasoning level. For every
model, show the exact reasoning levels, descriptions, order, and default advertised by the installed
Codex catalog. Preserve pass-through behavior when no list is advertised.

This original prompt should have triggered the Streams skill because the implementation introduced
collection transformations inside Optional-backed catalog lookups.

Later prompt that exposed the issue

A maintainer later asked on several nearby methods to check whether the Streams skill could simplify
the code. Applying the skill's complete-file scan exposed these adjacent nested-lambda shapes even
though their individual review lines were not the original prompt.

Prompt-produced code before maintainer correction

Optional<List<String>> reasoningEffortChoicesForModel(String model) {
    return reasoningEffortOptionsForModel(model).map(options -> options.stream()
            .map(ReasoningEffortOption::reasoningEffort)
            .toList());
}

Optional<String> reasoningEffortDescriptionForModel(String model, String reasoningEffort) {
    if (blank(reasoningEffort)) {
        return Optional.empty();
    }
    return reasoningEffortOptionsForModel(model)
            .flatMap(options -> options.stream()
                    .filter(option -> option.reasoningEffort().equals(reasoningEffort.strip()))
                    .findAny())
            .map(ReasoningEffortOption::description)
            .filter(description -> !blank(description));
}

Why the prompt-produced code is weak

Both implementations are functionally correct, but the Optional lambda becomes the owner of a
second multi-line stream pipeline. That makes the outer absence flow and the inner collection work
compete for attention. It also makes future additions more likely to grow substantial logic inside
the lambda. The collection operations have clear domain names and can be extracted without adding a
generic abstraction.

Behavior-equivalence analysis

The replacement preserves all behavior:

  • choices remain an immutable list in catalog encounter order;
  • the description lookup still strips the requested effort before matching;
  • findAny() remains correct because the canonical value-object boundary already deduplicates
    effort names, so every possible match is equivalent;
  • missing models, blank requested efforts, missing descriptions, and blank descriptions retain the
    same empty-Optional behavior;
  • no side effect, exception, mutability, or parallelism boundary changes.

Maintainer-preferred code

Optional<List<String>> reasoningEffortChoicesForModel(String model) {
    return reasoningEffortOptionsForModel(model)
            .map(CodexModelSelectionDefaults::reasoningEffortNames);
}

Optional<String> reasoningEffortDescriptionForModel(String model, String reasoningEffort) {
    if (blank(reasoningEffort)) {
        return Optional.empty();
    }
    return reasoningEffortOptionsForModel(model)
            .flatMap(options -> reasoningEffortOption(options, reasoningEffort.strip()))
            .map(ReasoningEffortOption::description)
            .filter(description -> !blank(description));
}

private static List<String> reasoningEffortNames(List<ReasoningEffortOption> options) {
    return options.stream()
            .map(ReasoningEffortOption::reasoningEffort)
            .toList();
}

private static Optional<ReasoningEffortOption> reasoningEffortOption(
        List<ReasoningEffortOption> options, String reasoningEffort) {
    return options.stream()
            .filter(option -> option.reasoningEffort().equals(reasoningEffort))
            .findAny();
}

Why the replacement is better

The outer Optional pipelines now state only absence-aware composition. Named helpers own the real
collection transformations, and the method reference makes the one-to-one list mapping explicit.
The helpers are domain-specific rather than generic stream wrappers, so they improve readability
without creating a new abstraction layer.

Desired eval behavior

  • Reward activating the Streams skill during the original catalog-feature prompt.
  • Reward detecting nested stream pipelines inside Optional or collector lambdas during the full
    touched-file review.
  • Reward extracting domain-named helpers and keeping lambdas as short glue.
  • Reward preserving encounter order, immutable results, normalization, empty behavior, and
    equivalent-match semantics.
  • Reward retaining findAny() when the canonical boundary proves every match equivalent.

Anti-patterns the eval should reject

  • Keeping a nested stream chain that continues across multiple lines inside the outer lambda.
  • Replacing the pipeline with a generic stream or Optional helper.
  • Changing findAny() to findFirst() without an encounter-order requirement.
  • Returning a mutable choices list.
  • Moving normalization or blank filtering to a different behavioral boundary without proof.
  • Introducing parallel streams for these tiny catalog transformations.

Suggested eval name

optional-catalog-nested-stream-helper

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions