BUG-1142: distinguish focuses wrote the planner domain verbatim, and health_pressure is not in the focus table's target_domain check. The write failed inside a swallowed retry and the session went straight to delivery although tap cards remained. Every focus write now goes through focusTargetDomain (persistableFocusDomain, BUG-672), and focus-to-probe matching uses sameCollectDomain. BUG-1143: segmentOrderEnabledFor turns segment-gain probe order on by default when the scanned window is at most 21 minutes, where the 77-case persisted replay gained head hits with no lost truth segment. RECTIFICATION_SEGMENT_ORDER =off disables it; =on keeps the 61-minute research envelope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
502 lines
19 KiB
TypeScript
502 lines
19 KiB
TypeScript
/**
|
|
* Single candidate-score persist path for compare, stop, idle, and window change.
|
|
*
|
|
* Stop / idle keep previous answers. Block-scan choice and window widen still
|
|
* write a fresh inference_state, but with an empty answer ledger.
|
|
*/
|
|
import { shouldForceMinuteAfterSubBlocks } from "./block-scan.ts";
|
|
import { segmentOrderEnabledFor } from "../core/segment-probe-order.ts";
|
|
import { scanCaseSegments } from "./segment-scan.ts";
|
|
import { targetChartsForDomain } from "../core/segment-summary.ts";
|
|
import { buildProductCaseInferenceState } from "./product-inference.ts";
|
|
import { productDeliveryForDomain } from "./product-delivery.ts";
|
|
import { candidateSetId } from "../core/build-state.ts";
|
|
import {
|
|
buildCandidateContrastPacket,
|
|
conflictProbesFromContrast,
|
|
datedDomainsFromEvidence,
|
|
inspectDiscriminatorProbes,
|
|
mentionedVargaKeysFromLedgerEvidence,
|
|
volunteeredDomainsFromEvidence,
|
|
} from "../core/candidate-contrast-packet.ts";
|
|
import { readVedastroMinuteSensitiveStatus } from "./confirmation-gate.ts";
|
|
import {
|
|
askedDiscriminatorKeys,
|
|
askedSemanticKeysForEngine,
|
|
authoritativeCandidateProjection,
|
|
previousInferenceFromReceipt,
|
|
} from "./inference-adapter.ts";
|
|
import { columnTimesForSlowCompare } from "./column-times-for-compare.ts";
|
|
import { refinementFromDecisionReceipt } from "./refinement-packet.ts";
|
|
import { declinedDomainNames } from "./collection-question-pool.ts";
|
|
import { blockScanRequestExtras } from "./search-window.ts";
|
|
import {
|
|
cachedEngineScoreIsReusable,
|
|
executedMethodsFromLedger,
|
|
mergeVedastroValidateIntoReceipt,
|
|
readV9EngineScoringIdentity,
|
|
scoringIdentityIsTrusted,
|
|
scoringIdentityMatches,
|
|
runV9BlockScan,
|
|
runV9CandidateScore,
|
|
runV9VedastroValidate,
|
|
toEngineEvents,
|
|
type V9EngineScoreResult,
|
|
} from "./engine-client.ts";
|
|
import { windowScanFromDecisionReceipt, type WindowScan } from "./varga-observations.ts";
|
|
import {
|
|
candidateRangeFingerprint,
|
|
ensureV9DatedWindow,
|
|
evidenceLedgerFingerprint,
|
|
loadV9CaseCompute,
|
|
loadV9CaseDossier,
|
|
persistV9Candidate,
|
|
refreshV9VedastroValidation,
|
|
RectificationToolServiceError,
|
|
scorableEvidence,
|
|
setV9CaseStage,
|
|
writeV9BlockScan,
|
|
type AccountingClient,
|
|
type V9CaseDossier,
|
|
type V9PersistedCandidate,
|
|
} from "./tool-service.ts";
|
|
|
|
export type ScorePersistTimings = Readonly<{
|
|
engine_compare_ms: number;
|
|
vedastro_validate_ms: number;
|
|
persist_ms: number;
|
|
}>;
|
|
|
|
export type ScorePersistResult = Readonly<{
|
|
readOnly?: boolean;
|
|
persisted: V9PersistedCandidate | Readonly<{
|
|
resultId: string;
|
|
cached: boolean;
|
|
candidates: readonly [];
|
|
overallConfidence: "low";
|
|
selectionAllowed: false;
|
|
confirmationAllowed: false;
|
|
representativeTime: null;
|
|
algorithmVersion: string;
|
|
eventContractVersion: string;
|
|
policyVersion: string | null;
|
|
decisionReceipt: Readonly<Record<string, unknown>>;
|
|
executionLedger: readonly [];
|
|
}>;
|
|
score: V9EngineScoreResult;
|
|
dossier: V9CaseDossier;
|
|
windowScan: WindowScan | null;
|
|
decisionReceipt: Readonly<Record<string, unknown>>;
|
|
timings: ScorePersistTimings;
|
|
}>;
|
|
|
|
export async function persistBlockScanPayload(input: {
|
|
accounting: AccountingClient;
|
|
userId: string;
|
|
caseId: string;
|
|
evidenceFingerprint: string;
|
|
rangeFingerprint?: string;
|
|
scan: Awaited<ReturnType<typeof runV9BlockScan>>;
|
|
previousRounds?: number;
|
|
}): Promise<void> {
|
|
const isSub = input.scan.blocks.some((block) => (
|
|
block.period === "sub_1" || block.period === "sub_2" || block.period === "sub_3"
|
|
));
|
|
await writeV9BlockScan(input.accounting, input.userId, input.caseId, {
|
|
evidence_ledger_fingerprint: input.evidenceFingerprint,
|
|
algorithm_version: input.scan.algorithmVersion,
|
|
decision_policy_version: input.scan.policyVersion,
|
|
candidate_range_fingerprint: input.rangeFingerprint ?? null,
|
|
minute_step: input.scan.minuteStep,
|
|
rounds: isSub ? (input.previousRounds ?? 0) + 1 : 0,
|
|
blocks: input.scan.blocks,
|
|
});
|
|
}
|
|
|
|
async function persistableReceipt(
|
|
score: V9EngineScoreResult,
|
|
input: {
|
|
baselineBirthSnapshot: Readonly<Record<string, unknown>>;
|
|
candidateRange: { start_time: string; end_time: string };
|
|
events: ReturnType<typeof toEngineEvents>;
|
|
},
|
|
): Promise<Record<string, unknown>> {
|
|
const base = score.windowScan
|
|
? { ...score.decisionReceipt, window_scan: score.windowScan }
|
|
: { ...score.decisionReceipt };
|
|
const ranked = [...score.candidates].sort((left, right) => left.rank - right.rank);
|
|
const primary = ranked[0]?.time;
|
|
const runnerUp = ranked[1]?.time;
|
|
if (!score.selectionAllowed || !primary || !runnerUp || primary === runnerUp) return base;
|
|
const validation = await runV9VedastroValidate({
|
|
...input,
|
|
candidateTimes: [primary, runnerUp],
|
|
});
|
|
return mergeVedastroValidateIntoReceipt(base, validation);
|
|
}
|
|
|
|
function emptyBlockScanScore(
|
|
candidateRange: { start_time: string; end_time: string },
|
|
algorithmVersion: string,
|
|
engineResultId = "",
|
|
): V9EngineScoreResult {
|
|
return {
|
|
engineResultId,
|
|
algorithmVersion,
|
|
eventContractVersion: "",
|
|
policyVersion: "",
|
|
candidateRange,
|
|
candidates: [],
|
|
overallConfidence: "low",
|
|
marginPercent: null,
|
|
acceptanceAllowed: false,
|
|
selectionAllowed: false,
|
|
proposeAllowed: false,
|
|
confirmationAllowed: false,
|
|
representativeCandidateId: null,
|
|
representativeTime: null,
|
|
decisionReceipt: {},
|
|
executionLedger: [],
|
|
executedMethods: [],
|
|
windowScan: null,
|
|
};
|
|
}
|
|
|
|
export async function scoreAndPersistCurrentEvidence(input: {
|
|
accounting: AccountingClient;
|
|
userId: string;
|
|
caseId: string;
|
|
keepAnswers?: boolean;
|
|
}): Promise<ScorePersistResult> {
|
|
const keepAnswers = input.keepAnswers !== false;
|
|
const dossier = await loadV9CaseDossier(input.accounting, input.userId, input.caseId);
|
|
const scorable = scorableEvidence(dossier.evidence);
|
|
if (scorable.length === 0) {
|
|
throw new RectificationToolServiceError("no_scorable_evidence");
|
|
}
|
|
let candidateRange = dossier.case.candidateRange;
|
|
if (!candidateRange) throw new RectificationToolServiceError("case_range_missing");
|
|
const compute = await loadV9CaseCompute(input.accounting, input.userId, input.caseId);
|
|
const liveIdentity = await readV9EngineScoringIdentity();
|
|
if (scoringIdentityIsTrusted(liveIdentity) && liveIdentity.algorithmVersion === "rectification-v5-matrix-scoring-9" && !candidateRange.candidate_intervals) {
|
|
candidateRange = await ensureV9DatedWindow(input.accounting, input.userId, input.caseId);
|
|
}
|
|
if (candidateRange.midnight_side_pending === true && scoringIdentityIsTrusted(liveIdentity)) {
|
|
throw new RectificationToolServiceError("midnight_side_pending");
|
|
}
|
|
const evidenceFingerprint = evidenceLedgerFingerprint(dossier.evidence);
|
|
const rangeFingerprint = candidateRangeFingerprint(candidateRange, compute.baselineProfileFingerprint);
|
|
const readOnly = !scoringIdentityIsTrusted(liveIdentity);
|
|
if (readOnly && !(dossier.case.stage === "block_scan" ? dossier.case.blockScan : dossier.latestResult)) {
|
|
throw new RectificationToolServiceError("engine_identity_unavailable");
|
|
}
|
|
if (
|
|
!readOnly
|
|
&& dossier.case.stage === "block_scan"
|
|
&& shouldForceMinuteAfterSubBlocks(dossier.case.blockScan)
|
|
) {
|
|
await setV9CaseStage(input.accounting, input.userId, input.caseId, "minute");
|
|
return scoreAndPersistCurrentEvidence(input);
|
|
}
|
|
if (dossier.case.stage === "block_scan") {
|
|
const cachedPayload = dossier.case.blockScan;
|
|
const cached = cachedEngineScoreIsReusable(cachedPayload, {
|
|
evidenceLedgerFingerprint: evidenceFingerprint, candidateRangeFingerprint: rangeFingerprint,
|
|
}, liveIdentity);
|
|
if (!cached && !readOnly) {
|
|
const events = toEngineEvents(scorable);
|
|
const extras = blockScanRequestExtras(candidateRange);
|
|
const scoreStarted = Date.now();
|
|
const scan = await runV9BlockScan({
|
|
baselineBirthSnapshot: compute.baselineBirthSnapshot,
|
|
candidateRange,
|
|
events,
|
|
...extras,
|
|
});
|
|
const engineCompareMs = Date.now() - scoreStarted;
|
|
const persistStarted = Date.now();
|
|
await persistBlockScanPayload({
|
|
accounting: input.accounting,
|
|
userId: input.userId,
|
|
caseId: input.caseId,
|
|
evidenceFingerprint,
|
|
rangeFingerprint,
|
|
scan,
|
|
previousRounds: cachedPayload?.rounds ?? 0,
|
|
});
|
|
const reloaded = await loadV9CaseDossier(input.accounting, input.userId, input.caseId);
|
|
return {
|
|
readOnly: !scoringIdentityMatches(scan, liveIdentity),
|
|
persisted: {
|
|
resultId: scan.resultId ?? "",
|
|
cached: false,
|
|
candidates: [],
|
|
overallConfidence: "low",
|
|
selectionAllowed: false,
|
|
confirmationAllowed: false,
|
|
representativeTime: null,
|
|
algorithmVersion: scan.algorithmVersion,
|
|
eventContractVersion: "",
|
|
policyVersion: scan.policyVersion,
|
|
decisionReceipt: {},
|
|
executionLedger: [],
|
|
},
|
|
score: emptyBlockScanScore(candidateRange, scan.algorithmVersion, scan.resultId ?? ""),
|
|
dossier: reloaded,
|
|
windowScan: null,
|
|
decisionReceipt: {},
|
|
timings: {
|
|
engine_compare_ms: engineCompareMs,
|
|
vedastro_validate_ms: 0,
|
|
persist_ms: Date.now() - persistStarted,
|
|
},
|
|
};
|
|
}
|
|
return {
|
|
readOnly,
|
|
persisted: {
|
|
resultId: "",
|
|
cached,
|
|
candidates: [],
|
|
overallConfidence: "low",
|
|
selectionAllowed: false,
|
|
confirmationAllowed: false,
|
|
representativeTime: null,
|
|
algorithmVersion: cachedPayload?.algorithmVersion ?? "",
|
|
eventContractVersion: "",
|
|
policyVersion: cachedPayload?.policyVersion ?? null,
|
|
decisionReceipt: {},
|
|
executionLedger: [],
|
|
},
|
|
score: emptyBlockScanScore(candidateRange, cachedPayload?.algorithmVersion ?? ""),
|
|
dossier,
|
|
windowScan: null,
|
|
decisionReceipt: {},
|
|
timings: {
|
|
engine_compare_ms: 0,
|
|
vedastro_validate_ms: 0,
|
|
persist_ms: 0,
|
|
},
|
|
};
|
|
}
|
|
const events = toEngineEvents(scorable);
|
|
const previousReceipt = keepAnswers ? dossier.latestResult?.decisionReceipt : null;
|
|
const askedProbeKeys = keepAnswers
|
|
? askedSemanticKeysForEngine(previousReceipt, dossier.evidence)
|
|
: [];
|
|
const latest = dossier.latestResult;
|
|
if (
|
|
latest
|
|
&& (readOnly || (keepAnswers && cachedEngineScoreIsReusable(
|
|
latest,
|
|
{ evidenceLedgerFingerprint: evidenceFingerprint, candidateRangeFingerprint: rangeFingerprint },
|
|
liveIdentity,
|
|
)))
|
|
) {
|
|
const ledger = latest.executionLedger ?? [];
|
|
const windowScan = windowScanFromDecisionReceipt(latest.decisionReceipt);
|
|
let decisionReceipt = latest.decisionReceipt ?? {};
|
|
const candidateProjection = authoritativeCandidateProjection(latest);
|
|
const candidates = candidateProjection.fromInference ? candidateProjection.candidates : latest.candidates;
|
|
const representativeTime = candidateProjection.fromInference
|
|
? candidateProjection.representativeTime
|
|
: latest.representativeTime;
|
|
const ranked = [...candidates].sort((left, right) => left.rank - right.rank);
|
|
const primary = ranked[0]?.time;
|
|
const runnerUp = ranked[1]?.time;
|
|
let vedastroMs = 0;
|
|
let persistMs = 0;
|
|
if (
|
|
!readOnly
|
|
&& latest.selectionAllowed
|
|
&& primary
|
|
&& runnerUp
|
|
&& primary !== runnerUp
|
|
&& readVedastroMinuteSensitiveStatus(decisionReceipt) !== "passed"
|
|
) {
|
|
const vedastroStarted = Date.now();
|
|
const validation = await runV9VedastroValidate({
|
|
baselineBirthSnapshot: compute.baselineBirthSnapshot,
|
|
candidateRange,
|
|
events,
|
|
candidateTimes: [primary, runnerUp],
|
|
});
|
|
vedastroMs = Date.now() - vedastroStarted;
|
|
const persistStarted = Date.now();
|
|
decisionReceipt = await refreshV9VedastroValidation(input.accounting, input.userId, input.caseId, {
|
|
resultId: latest.resultId,
|
|
evidenceFingerprint,
|
|
rangeFingerprint,
|
|
validation: {
|
|
status: validation.status,
|
|
search_events_primary_supports_local_winner: validation.searchEventsSupportsLocalWinner,
|
|
can_confirm_exact_minute: validation.canConfirmExactMinute,
|
|
failure: validation.failure,
|
|
},
|
|
minuteSensitiveStatus: validation.minuteSensitiveStatus,
|
|
});
|
|
persistMs = Date.now() - persistStarted;
|
|
}
|
|
return {
|
|
readOnly,
|
|
persisted: {
|
|
resultId: latest.resultId,
|
|
cached: !readOnly,
|
|
candidates,
|
|
overallConfidence: latest.overallConfidence,
|
|
selectionAllowed: !readOnly && candidateProjection.consistent && latest.selectionAllowed,
|
|
confirmationAllowed: !readOnly && latest.confirmationAllowed,
|
|
representativeTime,
|
|
algorithmVersion: latest.algorithmVersion,
|
|
eventContractVersion: latest.eventContractVersion,
|
|
policyVersion: latest.policyVersion,
|
|
decisionReceipt,
|
|
executionLedger: ledger,
|
|
},
|
|
score: {
|
|
engineResultId: latest.resultId,
|
|
algorithmVersion: latest.algorithmVersion ?? "",
|
|
eventContractVersion: latest.eventContractVersion ?? "",
|
|
policyVersion: latest.policyVersion ?? "",
|
|
candidateRange,
|
|
candidates,
|
|
overallConfidence: latest.overallConfidence,
|
|
marginPercent: null,
|
|
acceptanceAllowed: !readOnly && latest.selectionAllowed,
|
|
selectionAllowed: !readOnly && candidateProjection.consistent && latest.selectionAllowed,
|
|
proposeAllowed: !readOnly && latest.selectionAllowed,
|
|
confirmationAllowed: !readOnly && latest.confirmationAllowed,
|
|
representativeCandidateId: null,
|
|
representativeTime,
|
|
decisionReceipt,
|
|
executionLedger: ledger,
|
|
executedMethods: executedMethodsFromLedger(ledger),
|
|
windowScan,
|
|
},
|
|
dossier,
|
|
windowScan,
|
|
decisionReceipt,
|
|
timings: {
|
|
engine_compare_ms: 0,
|
|
vedastro_validate_ms: vedastroMs,
|
|
persist_ms: persistMs,
|
|
},
|
|
};
|
|
}
|
|
const scoreStarted = Date.now();
|
|
const latestReceipt = dossier.latestResult?.decisionReceipt;
|
|
const previousCompareMs = typeof latestReceipt?.column_compare_ms === "number"
|
|
? latestReceipt.column_compare_ms
|
|
: null;
|
|
const previousInference = previousInferenceFromReceipt(latestReceipt);
|
|
const columnTimes = columnTimesForSlowCompare({
|
|
previousColumnCompareMs: previousCompareMs,
|
|
activeTimes: previousInference?.candidates
|
|
.filter((candidate) => candidate.status === "active")
|
|
.map((candidate) => candidate.time) ?? [],
|
|
});
|
|
const score = await runV9CandidateScore({
|
|
baselineBirthSnapshot: compute.baselineBirthSnapshot,
|
|
candidateRange,
|
|
events,
|
|
askedProbeKeys,
|
|
declinedDomains: declinedDomainNames(dossier.conversationSummary.declinedSkippedTopics),
|
|
columnTimes,
|
|
});
|
|
const engineCompareMs = Date.now() - scoreStarted;
|
|
const vedastroStarted = Date.now();
|
|
const responseReadOnly = !scoringIdentityMatches(score, liveIdentity);
|
|
const receipt = responseReadOnly ? score.decisionReceipt : await persistableReceipt(score, {
|
|
baselineBirthSnapshot: compute.baselineBirthSnapshot,
|
|
candidateRange,
|
|
events,
|
|
});
|
|
const vedastroMs = Date.now() - vedastroStarted;
|
|
const refinement = refinementFromDecisionReceipt(receipt);
|
|
const windowScan = windowScanFromDecisionReceipt(receipt);
|
|
const scoredCandidateSetId = candidateSetId(
|
|
candidateRange.start_time,
|
|
candidateRange.end_time,
|
|
score.candidates.map((item) => item.time),
|
|
score.candidates,
|
|
);
|
|
const askedKeys = keepAnswers
|
|
? askedDiscriminatorKeys(previousReceipt, dossier.evidence)
|
|
: [];
|
|
const contrastPacket = buildCandidateContrastPacket({
|
|
candidateSetVersion: scoredCandidateSetId,
|
|
calculationResultId: score.engineResultId,
|
|
engineProbes: refinement.discriminating_event_probes,
|
|
vargaDifferences: [
|
|
...(windowScan?.d9_candidates_differ && windowScan.d9_sign_names.length >= 2
|
|
? [{ layer: "d9" as const, signs: windowScan.d9_sign_names }]
|
|
: []),
|
|
...(windowScan?.d10_candidates_differ && windowScan.d10_sign_names.length >= 2
|
|
? [{ layer: "d10" as const, signs: windowScan.d10_sign_names }]
|
|
: []),
|
|
],
|
|
candidateTimes: score.candidates.map((item) => item.time),
|
|
transitions: windowScan?.transitions ?? [],
|
|
askedKeys,
|
|
volunteeredDomains: volunteeredDomainsFromEvidence(dossier.evidence),
|
|
providedDomains: datedDomainsFromEvidence(dossier.evidence),
|
|
});
|
|
// A failed optional scan must not destroy the frozen scoring result. Candidate
|
|
// signatures can still support a partial summary, never a full-window claim.
|
|
const productDomain = dossier.case.rectificationDomain;
|
|
const segmentTargets = productDomain ? targetChartsForDomain(productDomain) : undefined;
|
|
const segmentMinutes = segmentTargets
|
|
? await scanCaseSegments({ snapshot: compute.baselineBirthSnapshot, range: candidateRange, targets: segmentTargets })
|
|
.catch(() => undefined)
|
|
: undefined;
|
|
const inference = buildProductCaseInferenceState({
|
|
segmentMinutes, segmentTargets, segmentScanComplete: Boolean(segmentMinutes),
|
|
segmentOrderEnabled: segmentOrderEnabledFor(segmentMinutes?.length, process.env.RECTIFICATION_SEGMENT_ORDER),
|
|
range: candidateRange,
|
|
candidates: score.candidates,
|
|
evidence: scorable,
|
|
probes: refinement.discriminating_event_probes,
|
|
extraProbes: conflictProbesFromContrast(contrastPacket),
|
|
previous: keepAnswers ? previousInferenceFromReceipt(previousReceipt ?? null) : null,
|
|
transitionTimes: windowScan?.transitions.filter((item) => !item.segment_start).map((item) => item.at) ?? [],
|
|
transitions: windowScan?.transitions ?? [],
|
|
}, productDomain);
|
|
const decisionReceipt = {
|
|
...receipt,
|
|
...(productDomain ? { product_delivery: productDeliveryForDomain(productDomain) } : {}),
|
|
inference_state: inference,
|
|
dropped_probes: inspectDiscriminatorProbes(contrastPacket, {
|
|
askedKeys,
|
|
mentionedKeys: mentionedVargaKeysFromLedgerEvidence(dossier.evidence),
|
|
birthDate: String(compute.baselineBirthSnapshot.birth_date ?? "") || null,
|
|
}).dropped,
|
|
};
|
|
const persistStarted = Date.now();
|
|
const persisted = await persistV9Candidate(input.accounting, input.userId, input.caseId, {
|
|
engineResultId: score.engineResultId,
|
|
algorithmVersion: score.algorithmVersion,
|
|
evidenceFingerprint,
|
|
rangeFingerprint,
|
|
skillVersion: dossier.case.skillVersion,
|
|
eventContractVersion: score.eventContractVersion,
|
|
policyVersion: score.policyVersion,
|
|
candidateRange,
|
|
candidates: score.candidates,
|
|
decisionReceipt,
|
|
executionLedger: score.executionLedger,
|
|
});
|
|
return {
|
|
readOnly: responseReadOnly,
|
|
persisted: responseReadOnly ? { ...persisted, selectionAllowed: false, confirmationAllowed: false } : persisted,
|
|
score: responseReadOnly ? { ...score, selectionAllowed: false, confirmationAllowed: false, acceptanceAllowed: false, proposeAllowed: false } : score,
|
|
dossier,
|
|
windowScan: score.windowScan,
|
|
decisionReceipt,
|
|
timings: {
|
|
engine_compare_ms: engineCompareMs,
|
|
vedastro_validate_ms: vedastroMs,
|
|
persist_ms: Date.now() - persistStarted,
|
|
},
|
|
};
|
|
}
|