fix(rectification): bump scoring identity to scoring-10 for functional profile v2; dated contract by generation (BUG-1181)

Functional roles feed the *_functional_*_auxiliary rules, so 57782aea changes
candidate scores for identical input (memoization fixture 12:00: 8.6274 ->
8.4977). Per the "scoring semantics change => bump ALGORITHM_VERSION"
precedent (scoring-7 -> 8 -> 9), the identity moves to scoring-10; policy v3,
input contract v5 and Skill versions are unchanged, history is not relabeled.

Five frontend sites and one SQL guard tested `=== "...scoring-9"` for the
dated candidate-window contract; they now use isDatedScoringAlgorithmVersion /
a generation regex (>= 9). Migration 20261002010000 only recreates
validate_dated_rectification_candidate (one-line guard change).

Memoization golden v2 written by the test's own write_golden; v1 (scoring-8)
frozen by sha256. Real-engine scoring-10 cross-midnight golden added. Research
records re-frozen per ERR-110 (label functional_v2_2026_10_02) and
scripts/functional_benefics.py added to the frozen production identity
(ERR-114: 57782aea changed scores without tripping it).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-10-02 12:31:50 +08:00
co-authored by Claude Opus 5.5
parent 57782aea8a
commit 3733b9787b
25 changed files with 51388 additions and 355 deletions
@@ -31,10 +31,18 @@ const golden = JSON.parse(readFileSync(new URL(
// Historical golden identity stays fixed; it must not be relabeled as the live engine.
const CURRENT = "rectification-v5-matrix-scoring-8";
const PREVIOUS = "rectification-v5-matrix-scoring-7";
const LIVE_CURRENT = "rectification-v5-matrix-scoring-9";
// 原值: LIVE_CURRENT = "rectification-v5-matrix-scoring-9"(liveGolden 同时充当「当前版本」)
// 新值: LIVE_CURRENT = "...-scoring-10";scoring-9 的 dated golden 留作历史(DATED_HISTORICAL),
// 当前版本另有真实引擎生成的 scoring-10 dated golden(currentGolden)
// 原因: 功能吉凶 v2 改变同输入分数,按「打分语义变化必须 bump」升算法身份(BUG-1181)
const LIVE_CURRENT = "rectification-v5-matrix-scoring-10";
const DATED_HISTORICAL = "rectification-v5-matrix-scoring-9";
const liveGolden = JSON.parse(readFileSync(new URL(
"./fixtures/rectification-midnight-date-anchor.delivery.native.json", import.meta.url,
), "utf8"));
const currentGolden = JSON.parse(readFileSync(new URL(
"./fixtures/rectification-midnight-date-anchor.delivery.scoring-10.native.json", import.meta.url,
), "utf8"));
const envKeys = [
"RECTIFICATION_ENGINE_VERSION", "RECTIFICATION_ALGORITHM_VERSION",
"RECTIFICATION_DECISION_POLICY_VERSION",
@@ -61,15 +69,18 @@ test("receipt default matches the cross-midnight native scoring version without
assert.equal(golden.score.algorithm_version, CURRENT);
assert.equal(golden.versions.algorithm_version, CURRENT);
const python = readFileSync(new URL("../../scripts/rectification/scoring_service.py", import.meta.url), "utf8");
assert.match(python, /ALGORITHM_VERSION = "rectification-v5-matrix-scoring-9"/);
assert.equal(liveGolden.response.algorithm_version, LIVE_CURRENT);
assert.match(python, /ALGORITHM_VERSION = "rectification-v5-matrix-scoring-10"/);
assert.equal(liveGolden.response.algorithm_version, DATED_HISTORICAL);
assert.equal(currentGolden.response.algorithm_version, LIVE_CURRENT);
const fingerprints = { evidenceLedgerFingerprint: "e".repeat(64), candidateRangeFingerprint: "c".repeat(64) };
const live = {
algorithmVersion: liveGolden.response.algorithm_version,
policyVersion: liveGolden.response.decision_policy_version,
algorithmVersion: currentGolden.response.algorithm_version,
policyVersion: currentGolden.response.decision_policy_version,
};
const historical = { ...fingerprints, algorithmVersion: CURRENT, policyVersion: golden.versions.decision_policy_version };
assert.equal(cachedEngineScoreIsReusable(historical, fingerprints, live), false);
// BUG-1181: a scoring-9 cache (old functional grouping) is not current under scoring-10.
assert.equal(cachedEngineScoreIsReusable({ ...historical, algorithmVersion: DATED_HISTORICAL }, fingerprints, live), false);
assert.equal(cachedEngineScoreIsReusable({ ...historical, algorithmVersion: LIVE_CURRENT }, fingerprints, live), true);
assert.equal(historical.algorithmVersion, CURRENT, "checking live identity never relabels history");
// A receipt default must not become an environment override for cache identity.