fix(rectification): close round A/2 tail gaps in tests, CI, and stale-score reuse
Independent Staging Quality Gate / validate (pull_request) Failing after 6m13s
Independent Staging Quality Gate / publish (pull_request) Has been skipped

Window_scan assertions now match the public from_sign/to_sign contract, the
staging quick gate runs the rectification Python suite, and compare-candidates
rescores when stored policy lags the live engine identity.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-01 18:17:33 +08:00
parent 26ea3f06cb
commit c48a965640
9 changed files with 250 additions and 7 deletions
@@ -181,11 +181,9 @@ function engineBase(): string {
return process.env.JYOTISH_API_BASE?.trim() || "http://127.0.0.1:5200";
}
async function postEngine(path: string, body: unknown, timeoutMs = 60_000): Promise<Record<string, unknown>> {
async function readEngineJson(path: string, init: RequestInit, timeoutMs: number): Promise<Record<string, unknown>> {
const response = await fetch(`${engineBase()}${path}`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
...init,
signal: AbortSignal.timeout(timeoutMs),
});
const data = await response.json().catch(() => null);
@@ -201,6 +199,87 @@ async function postEngine(path: string, body: unknown, timeoutMs = 60_000): Prom
return data as Record<string, unknown>;
}
async function postEngine(path: string, body: unknown, timeoutMs = 60_000): Promise<Record<string, unknown>> {
return readEngineJson(path, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
}, timeoutMs);
}
async function getEngine(path: string, timeoutMs = 5_000): Promise<Record<string, unknown>> {
return readEngineJson(path, {
method: "GET",
headers: { accept: "application/json" },
}, timeoutMs);
}
/** Coarse product id is not a scoring identity; never treat it as live algorithm. */
const COARSE_ENGINE_PRODUCT_ID = "rectification-v5";
export type LiveEngineScoringIdentity = Readonly<{
algorithmVersion: string | null;
policyVersion: string | null;
}>;
export function liveEngineScoringIdentityFromEnv(
env: NodeJS.ProcessEnv | Record<string, string | undefined> = process.env,
): LiveEngineScoringIdentity {
const engine = env.RECTIFICATION_ENGINE_VERSION?.trim() || "";
const algorithm = env.RECTIFICATION_ALGORITHM_VERSION?.trim()
|| (engine && engine !== COARSE_ENGINE_PRODUCT_ID ? engine : "");
const policy = env.RECTIFICATION_DECISION_POLICY_VERSION?.trim() || "";
return {
algorithmVersion: algorithm || null,
policyVersion: policy || null,
};
}
export function scoringIdentityFromEnginePayload(
payload: Readonly<Record<string, unknown>> | null | undefined,
): LiveEngineScoringIdentity {
const algorithm = typeof payload?.algorithm_version === "string" ? payload.algorithm_version.trim() : "";
const policy = typeof payload?.decision_policy_version === "string"
? payload.decision_policy_version.trim()
: "";
return {
algorithmVersion: algorithm || null,
policyVersion: policy || null,
};
}
export function cachedEngineScoreIsReusable(
stored: {
evidenceLedgerFingerprint?: string | null;
candidateRangeFingerprint?: string | null;
algorithmVersion?: string | null;
policyVersion?: string | null;
} | null | undefined,
fingerprints: { evidenceLedgerFingerprint: string; candidateRangeFingerprint: string },
live: LiveEngineScoringIdentity,
): boolean {
if (!stored) return false;
if (stored.evidenceLedgerFingerprint !== fingerprints.evidenceLedgerFingerprint) return false;
if (stored.candidateRangeFingerprint !== fingerprints.candidateRangeFingerprint) return false;
if (live.policyVersion && stored.policyVersion && stored.policyVersion !== live.policyVersion) {
return false;
}
if (live.algorithmVersion && stored.algorithmVersion && stored.algorithmVersion !== live.algorithmVersion) {
return false;
}
return true;
}
export async function readV9EngineScoringIdentity(): Promise<LiveEngineScoringIdentity> {
const fromEnv = liveEngineScoringIdentityFromEnv();
if (fromEnv.policyVersion || fromEnv.algorithmVersion) return fromEnv;
try {
return scoringIdentityFromEnginePayload(await getEngine("/api/rectification/v5/versions"));
} catch {
return { algorithmVersion: null, policyVersion: null };
}
}
function readCandidates(
value: unknown,
range: { start_time: string; end_time: string },
@@ -132,6 +132,8 @@ import {
runV9CandidateScore,
runV9Diagnostics,
runV9VedastroValidate,
readV9EngineScoringIdentity,
cachedEngineScoreIsReusable,
toEngineEvents,
v9EngineVersion,
executedMethodsFromLedger,
@@ -830,10 +832,14 @@ export function createRectificationV9Tools(ctx: RectificationV9Context) {
);
const events = toEngineEvents(scorableEvidence(dossier.evidence));
const latest = dossier.latestResult;
const liveIdentity = await readV9EngineScoringIdentity();
if (
latest
&& latest.evidenceLedgerFingerprint === evidenceFingerprint
&& latest.candidateRangeFingerprint === rangeFingerprint
&& cachedEngineScoreIsReusable(
latest,
{ evidenceLedgerFingerprint: evidenceFingerprint, candidateRangeFingerprint: rangeFingerprint },
liveIdentity,
)
) {
const ledger = latest.executionLedger ?? [];
const windowScan = windowScanFromDecisionReceipt(latest.decisionReceipt);