/**
 * The manifest bridge — which arm did this run belong to, according to the RUN
 * rather than according to the experimenter.
 *
 * Before 9.41.0 an arm label was bookkeeping: the consumer set a variable to
 * `'rerank'`, built an agent it believed re-ranked, and nothing in the library
 * could contradict it. `agentfootprint.agent.run_configured` names the adapters
 * and strategies a run is about to use, so the belief became checkable — and
 * {@link ArmFacets} is deliberately spelled in that event's own vocabulary so
 * the check is a field-by-field comparison and not a translation layer.
 *
 * Two directions, both here:
 *  - **verify** — `checkArmApplied(arm, manifest)`: the arm said `retrieval:
 *    'rerank'`; did the run agree? A contradiction costs the arm its verdict
 *    (`compare.ts`), because a difference measured between two arms that were
 *    secretly one configuration is not evidence about either.
 *  - **classify** — `matchArm(arms, manifest)`: hand it a recorded run's
 *    manifest and it says which declared arm that run belongs to. This is the
 *    door for grouping runs a study already made, offline, out of saved
 *    recordings.
 *
 * ## Absence is a contradiction, not a wildcard
 *
 * The manifest's own rule is that an absent field means "not configured", never
 * a guessed default. So an arm declaring `window: 'tokenBudget'` against a
 * manifest with no `window` is a MISMATCH, reported with `observed` absent. The
 * alternative — treating absence as "could be anything" — would let a run with
 * no window stage pass as the token-budget arm, which is exactly the mis-wiring
 * this file exists to catch.
 */
import type { RunManifestLike } from '../../recorders/observability/recordedManifest.js';
import type { ArmFacetMismatch, ArmFacets, StrategyArm } from './types.js';
/**
 * Project a manifest onto the arm-facet vocabulary — the inverse of what an arm
 * declares. Memory rows collapse to the FIRST one; a study varying retrieval
 * across several mounted memories should declare `memory.id` and read the rows
 * itself rather than trust a projection to pick.
 */
export declare function armFacetsFromManifest(manifest: RunManifestLike): ArmFacets;
/**
 * A stable label for a set of facets — sorted `key=value`, so two runs of one
 * configuration produce the same string whatever order the fields were written
 * in. Useful as a grouping key for N recorded runs.
 */
export declare function armLabel(facets: ArmFacets): string;
/**
 * Compare one arm's DECLARED facets against a run's manifest. Empty result =
 * the run agreed with everything the arm claimed.
 *
 * Only declared facets are compared. An arm is a claim about the facets it
 * names and says nothing about the rest — checking undeclared fields would fail
 * every arm for differing from the manifest in ways it never claimed.
 */
export declare function checkArmApplied(arm: StrategyArm, manifest: RunManifestLike): readonly ArmFacetMismatch[];
/**
 * Which declared arm does this run belong to? The offline door: group N
 * recorded runs into arms by what each run's own manifest says.
 *
 * Rules, all conservative:
 * - only arms that DECLARE facets are candidates (an arm naming nothing matches
 *   every run and would swallow the whole study);
 * - a candidate matches when the manifest contradicts none of its facets;
 * - the MOST SPECIFIC match wins (most declared facets), and a tie returns
 *   `undefined` — two arms fitting one run equally well is an ambiguity, and
 *   guessing which the experimenter meant is exactly the bookkeeping this
 *   function replaces.
 */
export declare function matchArm(arms: readonly StrategyArm[], manifest: RunManifestLike): StrategyArm | undefined;
//# sourceMappingURL=manifest.d.ts.map