fix(rectification): show question stems and unblock adopt after occupation
Choice legends and spoken collect prompts were hidden after BUG-461, and occupation still blocked canAdopt once dated coverage was done. Restore visible stems and stop polling extra collects when adopt is allowed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -78,6 +78,29 @@ function openingRangeFromDossier(dossier: {
|
||||
return openingRangeFromCandidateRange(dossier.case?.candidateRange ?? null);
|
||||
}
|
||||
|
||||
function shouldSkipFollowupPersist(input: {
|
||||
canAdopt: boolean;
|
||||
nextAction: string;
|
||||
}): boolean {
|
||||
return input.canAdopt
|
||||
&& input.nextAction !== "ask_fact_collection"
|
||||
&& input.nextAction !== "ask_candidate_discriminator"
|
||||
&& input.nextAction !== "ask_holdout_validation";
|
||||
}
|
||||
|
||||
function adoptHostNarration(input: {
|
||||
credibleRange?: readonly [string, string] | null;
|
||||
representativeTime?: string | null;
|
||||
openingRange: readonly [string, string] | null;
|
||||
receipt: Readonly<Record<string, unknown>> | null | undefined;
|
||||
}): string {
|
||||
return withProspectiveWindows(deliveryAdoptNarration({
|
||||
credibleRange: input.credibleRange,
|
||||
representativeTime: input.representativeTime,
|
||||
openingRange: input.openingRange,
|
||||
}), input.receipt);
|
||||
}
|
||||
|
||||
export type ApplyChoiceCommand = Readonly<{
|
||||
userId: string;
|
||||
caseId: string;
|
||||
@@ -316,6 +339,21 @@ export async function persistNextInterviewAfterChoice(input: {
|
||||
nextAction: ReturnType<typeof publicNextAction>;
|
||||
birthDate?: string | null;
|
||||
}): Promise<{ hostNarration: string; choiceReady: boolean; persisted?: boolean }> {
|
||||
if (shouldSkipFollowupPersist({
|
||||
canAdopt: input.nextAction.can_adopt,
|
||||
nextAction: input.nextAction.type,
|
||||
})) {
|
||||
return {
|
||||
hostNarration: adoptHostNarration({
|
||||
credibleRange: input.nextAction.credible_range,
|
||||
representativeTime: input.nextAction.representative_time,
|
||||
openingRange: openingRangeFromDossier(input.dossier),
|
||||
receipt: input.dossier.latestResult?.decisionReceipt,
|
||||
}),
|
||||
choiceReady: false,
|
||||
persisted: false,
|
||||
};
|
||||
}
|
||||
const latest = input.dossier.latestResult
|
||||
? {
|
||||
...input.dossier.latestResult,
|
||||
@@ -553,20 +591,16 @@ export async function persistNextInterviewIfIdle(input: {
|
||||
birthDate = null;
|
||||
}
|
||||
const decision = decideFromDossier(dossier, { birthDate });
|
||||
if (
|
||||
decision.canAdopt
|
||||
&& decision.nextAction !== "ask_fact_collection"
|
||||
&& decision.nextAction !== "ask_candidate_discriminator"
|
||||
&& decision.nextAction !== "ask_holdout_validation"
|
||||
) {
|
||||
if (shouldSkipFollowupPersist(decision)) {
|
||||
return {
|
||||
persisted: false,
|
||||
choiceReady: false,
|
||||
hostNarration: withProspectiveWindows(deliveryAdoptNarration({
|
||||
hostNarration: adoptHostNarration({
|
||||
credibleRange: decision.credibleRange,
|
||||
representativeTime: decision.representativeTime,
|
||||
openingRange: openingRangeFromDossier(dossier),
|
||||
}), dossier.latestResult?.decisionReceipt),
|
||||
receipt: dossier.latestResult?.decisionReceipt,
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (isNonConvergingRangeOffer(decision)) {
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
* Finance/health score if volunteered; they are not method-layer rotation.
|
||||
* Method coverage finishes before repeating a precision-stage ask.
|
||||
* Appearance and marks are skipped_by_policy. Horary does not block offering
|
||||
* time cards. Occupation still blocks adopt and confirmation until a note
|
||||
* exists, but once the training gate is open it must not also block yearless
|
||||
* varga cards. Career evidence plus a closed occupation collect focus covers
|
||||
* occupation without depending on the model picking domain=occupation.
|
||||
* time cards. Occupation is a method-layer note, not an adopt gate: dated
|
||||
* dasha/D9/D10/relatives coverage plus the engine ceiling can offer
|
||||
* representative cards while occupation remains uncovered. Yearless-to-collect
|
||||
* conversion still waits until occupation is covered, so that note can be
|
||||
* asked later without blocking adopt. Career evidence
|
||||
* plus a closed occupation collect focus still covers the occupation method
|
||||
* without depending on the model picking domain=occupation.
|
||||
* Method coverage asks for dated events in natural language.
|
||||
* Known-event quality probes (exam went badly for a year already
|
||||
* in the ledger) are not reverse-inference cards. Dasha existence
|
||||
@@ -205,7 +208,6 @@ const BLOCKING_COVERAGE_IDS = new Set<MethodFollowupId>([
|
||||
"d9_relationship",
|
||||
"d10_career",
|
||||
"relatives",
|
||||
"occupation",
|
||||
]);
|
||||
|
||||
function isConfirmedDated(item: MethodFollowupEvidence): boolean {
|
||||
@@ -1685,7 +1687,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
source: "method_coverage",
|
||||
});
|
||||
}
|
||||
if (!next && dashaCovered && coverageComplete) {
|
||||
if (!next && dashaCovered && coverageComplete && occupationCovered) {
|
||||
const allowLowGainDiscriminator = !coverageComplete || !candidatesSeparated;
|
||||
const yearless = yearlessDiscriminators[0];
|
||||
if (yearless && (allowLowGainDiscriminator || yearless.score >= 0.08)) {
|
||||
|
||||
@@ -33,9 +33,10 @@ export function dossierHasNonemptyAssistantBody(
|
||||
/**
|
||||
* Whether to append the server-owned focus prompt as its own assistant turn.
|
||||
*
|
||||
* Structured only: action, focus kind/intent, and whether this turn already
|
||||
* has a nonempty assistant body. Never inspect the body text to decide
|
||||
* “whether it already asked”.
|
||||
* Structured only: focus kind/intent, and whether this turn already has a
|
||||
* nonempty assistant body. Never inspect the body text to decide
|
||||
* “whether it already asked”. Collect prompts live in the question slot,
|
||||
* so a second assistant turn is only written when this turn has no body.
|
||||
*/
|
||||
export function shouldPersistFocusPromptTurn(input: {
|
||||
action: RectificationRouteAction;
|
||||
@@ -45,7 +46,7 @@ export function shouldPersistFocusPromptTurn(input: {
|
||||
}): boolean {
|
||||
const collect = input.questionKind === "collect_spoken"
|
||||
|| input.questionIntent === "collect_method_evidence";
|
||||
return !(input.action === "opening" && collect && input.assistantBodyPresent);
|
||||
return !(collect && input.assistantBodyPresent);
|
||||
}
|
||||
|
||||
export async function finalizeSuccessfulTurnExit(input: {
|
||||
|
||||
Reference in New Issue
Block a user