feat(rectification): 出卡加精度门槛,补经历改成系统点名
Independent Staging Quality Gate / validate (push) Failing after 6m28s
Independent Staging Quality Gate / publish (push) Skipped

宽度超过 10 分钟或头名并列时不再出交付卡,改为按大运边界逐条问、
用类型芯片和年/月选择器录入。跳过的线换问法再问一次;答「这类事
都没有过」的不再问。用户说「没有了」仍立刻给目前范围。Skill 10.0.27。

BUG-740~743
This commit is contained in:
jesse-ux
2026-09-16 18:35:27 +08:00
parent 317e9f1886
commit cfb41daf3d
75 changed files with 4763 additions and 383 deletions
@@ -231,6 +231,10 @@ export type DecideRectificationInput = Readonly<{
windowWidenSuggested?: boolean;
refreshExhausted?: boolean;
targetedCollectExhausted?: boolean;
/** D1: width ≤ 10, top-two display gap > 3, not an exact first-place tie. */
precisionGateMet?: boolean;
/** Guided window / skip-retry / uncovered-domain pool is empty. */
guidedCollectExhausted?: boolean;
/** Opening search window from `case.candidateRange`. Omit in helper/unit paths. */
openingCandidateRange?: readonly [string, string] | null;
/** Unasked D9/D10 style questions remain. */
@@ -359,6 +363,16 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
&& !probe
&& input.targetedCollectExhausted !== false
) {
if (!mayDeliverOnPrecision(input)) {
return collect(
separation,
holdout,
range,
probe,
waitToNarrowCapability(rangeDeliveryCapability),
stopClass.reason,
);
}
return deliverRange(
input,
separation,
@@ -372,7 +386,7 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
if (coverageBlocks) {
const engineOffers = input.engineCeiling.acceptanceAllowed
|| input.engineCeiling.proposeAllowed;
const narrowingOpen = stillNeedNarrowing(input);
const narrowingOpen = stillNeedNarrowing(input) && !mayDeliverOnPrecision(input);
if (
stopClass?.kind !== "keep_collecting"
&& input.trainingGateOpen !== false
@@ -406,17 +420,37 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
return holdoutValidation(separation, range, capability);
}
// coverageBlocks already collected when the training gate is closed.
// Dated-pool empty is not delivery until refresh and targeted collect are
// exhausted (BUG-654). Personality still does not occupy this slot.
// Uncovered collect lines keep collecting only while D1 is unmet
// (BUG-654 + precision gate). 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)) {
if (stillNeedNarrowing(input) && !mayDeliverOnPrecision(input)) {
return collect(separation, holdout, range, probe, waitToNarrowCapability(capability), stopReason);
}
if (stopClass?.kind === "exhausted") {
if (!mayDeliverOnPrecision(input)) {
return collect(
separation,
holdout,
range,
probe,
waitToNarrowCapability(rangeDeliveryCapability),
stopReason,
);
}
return deliverRange(input, separation, holdout, range, "exhausted", rangeDeliveryCapability, stopClass.reason);
}
if (rangeDeliveryCapability.canAdopt && input.methodCoverageAll) {
if (!mayDeliverOnPrecision(input)) {
return collect(
separation,
holdout,
range,
probe,
waitToNarrowCapability(rangeDeliveryCapability),
"probe_pool_exhausted",
);
}
return finish("adopt_representative", {
input,
separation,
@@ -427,9 +461,29 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
stopReason: "probe_pool_exhausted",
});
}
if (!mayDeliverOnPrecision(input)) {
return collect(
separation,
holdout,
range,
probe,
waitToNarrowCapability(rangeDeliveryCapability),
stopReason,
);
}
return deliverRange(input, separation, holdout, range, "offer", rangeDeliveryCapability);
}
if (stopClass?.kind === "exhausted") {
if (!mayDeliverOnPrecision(input)) {
return collect(
separation,
holdout,
range,
probe,
waitToNarrowCapability(rangeDeliveryCapability),
stopReason,
);
}
return deliverRange(input, separation, holdout, range, "exhausted", rangeDeliveryCapability, stopClass.reason);
}
if (input.accepted) {
@@ -445,7 +499,7 @@ export function decideRectification(input: DecideRectificationInput): Rectificat
capability: rangeDeliveryCapability,
});
}
if (input.datedMethodCollectOpen === true && !input.userStopped) {
if (input.datedMethodCollectOpen === true && !input.userStopped && !mayDeliverOnPrecision(input)) {
return collect(separation, holdout, range, null, capability, stopReason);
}
if (confirmationAllowed) {
@@ -588,6 +642,20 @@ function stillNeedNarrowing(input: DecideRectificationInput): boolean {
return input.refreshExhausted === false || input.targetedCollectExhausted === false;
}
/**
* Exhausted / offer delivery is blocked until D1, the user stops, or the
* guided pool is empty. Omitted flags keep the helper/unit path delivering.
*/
export function mayDeliverOnPrecision(input: DecideRectificationInput): boolean {
if (input.userStopped === true) return true;
if (input.guidedCollectExhausted === true) return true;
if (input.precisionGateMet === true) return true;
if (input.precisionGateMet === undefined && input.guidedCollectExhausted === undefined) {
return true;
}
return false;
}
export function shouldHoldForTieBreak(
input: Pick<
DecideRectificationInput,