Skip to content

feat: add eval for fallback strategy selection before invocation #77

Description

@martinfrancois

Problem

The Optional capture workflow missed a fallback refactor on an adjacent absence API: a nullable/absent strategy was selected and then invoked. The reusable lesson is to choose between interchangeable strategy objects first and invoke the common operation once. This must not turn a broader ThreadLocal-to-ScopedValue migration into generic Optional advice.

Area

Evals or scoring

Describe the solution you want

Add a Java 25 reference eval for an existing ScopedValue<Function<...>> or equivalent owning container where absence selects a cheap prebuilt fallback strategy. Teach the skill to use the owning container's fallback operation and invoke the selected strategy once.

Code before the prompt was executed

private static final ThreadLocal<Function<String, String>> LOOKUP = new ThreadLocal<>();

static String get(String name) {
    Function<String, String> lookup = LOOKUP.get();
    return lookup == null ? System.getProperty(name) : lookup.apply(name);
}

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 only changes that clearly reduce code, complexity, duplication, or maintenance risk.
  • Preserve observable behavior, ordering, failure semantics, null handling, concurrency, security, and relevant performance characteristics.
  • Add focused regression tests for each affected boundary.

The prompt should have activated Optional/absence capture because it asks the agent to replace nullable fallback control flow with an owning JDK API.

Later prompt that exposed the issue

A maintainer later asked whether the Optionals capture issue had been created and requested a durable trigger improvement for cases like this.

Prompt-produced code before maintainer correction

private static final Function<String, String> SYSTEM_LOOKUP = System::getProperty;
private static final ScopedValue<Function<String, String>> LOOKUP = ScopedValue.newInstance();

static String get(String name) {
    return LOOKUP.orElse(SYSTEM_LOOKUP).apply(name);
}

The implementation is preferred, but the adjacent absence/fallback lesson was not captured.

Why the prompt-produced code is weak

The code is not weak; the capture process is. The current workflow focuses on java.util.Optional syntax and misses fallback/default refactors expressed by other owning APIs, despite the Optional skill's broader nullable/fallback trigger. The useful lesson is the higher-order selection shape, not the concurrency-container migration.

Behavior-equivalence analysis

ScopedValue.orElse selects the bound lookup or the already-constructed system lookup. Eager fallback evaluation is harmless because the fallback strategy is a prebuilt constant. The selected function may itself return null; that result must remain valid. A null override is deliberately normalized to and bound as the system strategy so it masks an outer binding. Tests must cover bound, unbound, nested masking, exceptional restoration, null override, and null function result.

Maintainer-preferred code

private static final Function<String, String> SYSTEM_LOOKUP = System::getProperty;
private static final ScopedValue<Function<String, String>> LOOKUP = ScopedValue.newInstance();

static String get(String name) {
    return LOOKUP.orElse(SYSTEM_LOOKUP).apply(name);
}

Why the replacement is better

The code selects one strategy with the owning fallback API and invokes the common operation once. It removes duplicated invocation/null branching without introducing an Optional wrapper.

Desired eval behavior

  • Reward activation during the original nullable/fallback API-audit prompt.
  • Reward selecting a strategy first, then invoking once.
  • Reward direct use of the owning container rather than wrapping it in Optional.
  • Reward orElse only for a cheap, prebuilt fallback; require lazy handling when construction or side effects are non-trivial and the API supports it.
  • Reward keeping the broader ThreadLocal/ScopedValue migration out of the generic Optional lesson.

Anti-patterns the eval should reject

  • Wrapping ScopedValue in Optional.
  • Calling get() while unbound.
  • Duplicating .apply(name) in both branches.
  • Failing to mask an outer binding for an explicit null override.
  • Claiming a general ThreadLocal-to-ScopedValue rewrite from this example.

Suggested eval name

scoped-value-fallback-strategy

Examples

Use the minimal Java 25 strategy selection above. Start with a natural baseline reference eval; add ScopedValue to activation metadata only if the evidence shows the skill otherwise does not activate.

Alternatives considered

Issues #71, #74, and #76 cover domain selection, constant selection, and binding a present Optional value. None covers a higher-order fallback strategy on an adjacent owning container.

Current workaround

Manually apply the Optional skill's absence/fallback principles to other JDK containers and capture the lesson separately.

Additional context

No user-facing contract change is intended. ScopedValue.orElse should be documented only as an adjacent Java 25 API if the final runtime example remains ScopedValue-based.

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.

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