fix(rectification): refresh remaining probes and targeted collect before delivering range (BUG-653/654)
Independent Staging Quality Gate / validate (push) Successful in 13m54s
Independent Staging Quality Gate / publish (push) Successful in 10m50s

Dated-choice exhaustion is not convergence. Refresh probes from remaining
active candidates, then ask a targeted collect, then deliver. Skill 10.0.24.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-11 18:28:39 +08:00
co-authored by Cursor
parent 9941c34d4b
commit 6c9a089620
58 changed files with 2109 additions and 295 deletions
@@ -190,6 +190,10 @@ export function buildInferenceState(input: {
representative_time: top?.time ?? null,
credible_range: unionStillValidRange(candidates),
holdout_passed: holdoutPassed,
...(typeof previous?.refresh_count === "number" ? { refresh_count: previous.refresh_count } : {}),
...(typeof previous?.refresh_answer_count === "number"
? { refresh_answer_count: previous.refresh_answer_count }
: {}),
...(transitions ? { transitions } : {}),
};
const decision = evaluateConvergence({ ...draft, holdout_passed: holdoutPassed });
@@ -141,7 +141,7 @@ export function publicCanAdopt(decision: Pick<RectificationDecision, "canAdopt"
}
/**
* Delivery copy (`这次给出的范围` / representative-candidate close) is only
* Delivery copy (`目前范围` / representative-candidate close) is only
* allowed when the public adopt flag is on, or the session is explicitly
* offering a selectable range. Internal `canAdopt` during collect is not enough.
*/
@@ -210,6 +210,8 @@ export type DecideRectificationInput = Readonly<{
caseStage?: "minute" | "block_scan";
blockScanDeclined?: boolean;
windowWidenSuggested?: boolean;
refreshExhausted?: boolean;
targetedCollectExhausted?: boolean;
}>;
function classifyStop(
@@ -318,16 +320,25 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
if (coverageBlocks) {
const engineOffers = input.engineCeiling.acceptanceAllowed
|| input.engineCeiling.proposeAllowed;
const narrowingOpen = stillNeedNarrowing(input);
if (
stopClass?.kind !== "keep_collecting"
&& input.trainingGateOpen !== false
&& separation.ranked.length > 0
&& !probe
&& engineOffers
&& !narrowingOpen
) {
return offerRangeWithoutAdopt(separation, holdout, range, capability);
}
return collect(separation, holdout, range, probe, capability, stopReason);
return collect(
separation,
holdout,
range,
probe,
narrowingOpen ? waitToNarrowCapability(capability) : capability,
stopReason,
);
}
if (stopClass?.kind === "keep_collecting") {
return collect(separation, holdout, range, probe, capability, stopClass.reason);
@@ -343,7 +354,13 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
return holdoutValidation(separation, range, capability);
}
// coverageBlocks already collected when the training gate is closed.
// An open leftover collect must not block S3 delivery (BUG-651).
// Dated-pool empty is not delivery until refresh and targeted collect are
// exhausted (BUG-654). Personality still does not occupy this slot.
// Omitted flags mean the helper/unit path: do not wait. Production
// decideFromDossier always passes explicit booleans.
if (stillNeedNarrowing(input)) {
return collect(separation, holdout, range, probe, waitToNarrowCapability(capability), stopReason);
}
if (stopClass?.kind === "exhausted") {
return completeWithRange(separation, holdout, range, "exhausted", capability, stopClass.reason);
}
@@ -506,6 +523,20 @@ function askWindowWiden(
};
}
function stillNeedNarrowing(input: DecideRectificationInput): boolean {
return input.refreshExhausted === false || input.targetedCollectExhausted === false;
}
function waitToNarrowCapability(capability: DeliveryCapability): DeliveryCapability {
return {
...capability,
canAdopt: false,
selectionAllowed: false,
proposeAllowed: false,
canConfirmExactMinute: false,
};
}
function collect(
separation: CandidateSeparation,
holdout: HoldoutValidationStatus,
@@ -143,6 +143,8 @@ export type InferenceState = Readonly<{
representative_time: string | null;
credible_range: readonly [string, string] | null;
holdout_passed?: boolean | null;
refresh_count?: number;
refresh_answer_count?: number;
transitions?: readonly Readonly<{
layer: string;
at: string;