/**
 * assoc() — collapses the `{ run: ctx.runId, …axisValues }` boilerplate
 * every producer would otherwise write at each `ctx.artifactWriter.emit()`
 * call site.
 *
 * Instead of:
 *   ctx.artifactWriter.emit("testOutputs", { run: ctx.runId, mode, task, model }, payload)
 *
 * Producers write:
 *   ctx.artifactWriter.emit("testOutputs", assoc(ctx, { mode, task, model }), payload)
 *
 * The `run` axis is always present because it's derivable from context;
 * every other axis is whatever the producer's local loop variables are.
 * See `docs/work-items/W0050-...json` (Q1 decision) and `tasks/plan.md § Q1`.
 */
import type { AssociationValues, RunId } from "../types/branded-ids.js";
/**
 * Structural subset of `AppContext` needed by `assoc()`. Producers pass
 * their full `ctx` here; tests (and agents writing toy fixtures) can pass
 * a plain `{ runId }` object.
 */
export interface AssocContext {
    readonly runId: RunId;
}
/**
 * Build an `AssociationValues` object with `run` pinned from context and
 * the rest of the axes supplied by the caller.
 *
 * Intentionally does NOT validate that the caller supplied all axes the
 * descriptor requires — that would couple the helper to a specific type
 * and defeat the point. Invalid associations surface at `descriptor.
 * formatEntryKey()` time with a clear error, which is where the contract
 * boundary actually lives.
 */
export declare function assoc(ctx: AssocContext, partial?: Omit<AssociationValues, "run">): AssociationValues;
/**
 * Literacy-mode task descriptions carry a `(gold)` / `(baseline)` suffix that
 * encodes which half of the with-docs / without-docs pair the judgment belongs
 * to. The D0033 artifact axes treat that variant as the `mode` axis — a single
 * promptfoo run of evaluation mode "literacy" produces artifacts whose `mode`
 * axis is "gold" or "baseline". All producers and all readers must agree on
 * this decomposition, or signed-URL lookups 404.
 *
 * This helper is the single source of truth for the split. It's shared between:
 *   - eval's `emit-eval-results.ts` (rawResults, renderedPrompts,
 *     graderPrompts, graderJudgments)
 *   - eval's `upload-test-outputs.ts` (testOutputs)
 *   - core's `slim-report-summary.ts` (slim judgment / failure-mode ids)
 *   - studio's `JudgmentList#testOutputsKeyFor` (hover prefetch keys)
 *
 * Non-literacy modes (mcp-server, agent-harness, …) do not suffix their task
 * descriptions; `splitTaskVariant` returns `variant: null` and the caller
 * falls back to the high-level eval mode. See `resolveVariantMode`.
 *
 * Pure function — safe to call from browser or Node.
 */
export interface TaskVariantSplit {
    /** Task id with any trailing `(gold)` / `(baseline)` suffix stripped. */
    readonly task: string;
    /** Lowercased variant (`"gold"` | `"baseline"`), or `null` when absent. */
    readonly variant: "baseline" | "gold" | null;
}
export declare function splitTaskVariant(taskId: string): TaskVariantSplit;
/**
 * Resolve the `mode` axis value for an artifact association: prefer the
 * per-task variant when present, fall back to the high-level evaluation mode.
 * Mirrors `mode = variant ?? defaultMode` in `slim-report-summary#slimJudgments`.
 */
export declare function resolveVariantMode(taskId: string, defaultMode: string): {
    mode: string;
    task: string;
};
