fix(rectification): deliver range cards on tied first place instead of falling back to collect (BUG-680/681/682)
Refresh persist failures no longer count as attempts. tied_first completes with a range before stillNeedNarrowing. Delivery narration and cards share DELIVERY_OUTCOMES. The question gap gets a delivered terminal so the unavailable copy does not appear after a range is given.
This commit is contained in:
@@ -130,12 +130,25 @@ export const ADOPT_OUTCOMES: ReadonlySet<DecisionSessionOutcome> = new Set([
|
||||
"validated_range",
|
||||
]);
|
||||
|
||||
/** Range-delivery card and delivery copy share this set. ADOPT_OUTCOMES stays the adopt gate. */
|
||||
export const DELIVERY_OUTCOMES: ReadonlySet<DecisionSessionOutcome> = new Set([
|
||||
...ADOPT_OUTCOMES,
|
||||
"completed_with_range",
|
||||
"provisional_range",
|
||||
]);
|
||||
|
||||
export function sessionOutcomeAllowsAdopt(
|
||||
outcome: DecisionSessionOutcome | string | null | undefined,
|
||||
): outcome is DecisionSessionOutcome {
|
||||
return typeof outcome === "string" && ADOPT_OUTCOMES.has(outcome as DecisionSessionOutcome);
|
||||
}
|
||||
|
||||
export function sessionOutcomeAllowsDelivery(
|
||||
outcome: DecisionSessionOutcome | string | null | undefined,
|
||||
): outcome is DecisionSessionOutcome {
|
||||
return typeof outcome === "string" && DELIVERY_OUTCOMES.has(outcome as DecisionSessionOutcome);
|
||||
}
|
||||
|
||||
export function publicCanAdopt(decision: Pick<RectificationDecision, "canAdopt" | "sessionOutcome">): boolean {
|
||||
return decision.canAdopt && sessionOutcomeAllowsAdopt(decision.sessionOutcome);
|
||||
}
|
||||
@@ -151,7 +164,8 @@ export function deliveryNarrationAllowed(
|
||||
): boolean {
|
||||
if (publicCanAdopt(decision)) return true;
|
||||
const action = nextAction ?? decision.nextAction;
|
||||
return decision.selectionAllowed === true && action === "offer_provisional_range";
|
||||
if (decision.selectionAllowed === true && action === "offer_provisional_range") return true;
|
||||
return decision.selectionAllowed === true && sessionOutcomeAllowsDelivery(decision.sessionOutcome);
|
||||
}
|
||||
|
||||
export type CompletionStatus =
|
||||
@@ -317,6 +331,14 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
|
||||
}
|
||||
return collect(separation, holdout, range, probe, capability, stopReason);
|
||||
}
|
||||
if (
|
||||
stopClass?.kind === "exhausted"
|
||||
&& stopClass.reason === "tied_first"
|
||||
&& input.trainingGateOpen !== false
|
||||
&& separation.ranked.length > 0
|
||||
) {
|
||||
return completeWithRange(separation, holdout, range, "exhausted", capability, stopClass.reason);
|
||||
}
|
||||
if (coverageBlocks) {
|
||||
const engineOffers = input.engineCeiling.acceptanceAllowed
|
||||
|| input.engineCeiling.proposeAllowed;
|
||||
|
||||
Reference in New Issue
Block a user