fix(rectification): split D4/D5 stages and recast after adopt
Independent Staging Quality Gate / validate (push) Successful in 9m19s
Independent Staging Quality Gate / publish (push) Failing after 7m45s

Keep family on D12+D7 instead of mixing it into D4, score D5 on education, and show a natal recast plus technique audit after adopt without unique-minute claims.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-20 09:11:54 +08:00
co-authored by Cursor
parent b1b4f5fac9
commit a93a3cc1a9
40 changed files with 1195 additions and 66 deletions
@@ -255,6 +255,9 @@ test("D9 differ becomes an internal ask theme without sign labels", () => {
assert.deepEqual(observations, [
{ layer: "d9", candidates_differ: true, ask_theme: "relationship_style" },
{ layer: "d10", candidates_differ: false, ask_theme: null },
{ layer: "d4", candidates_differ: false, ask_theme: null },
{ layer: "d5", candidates_differ: false, ask_theme: null },
{ layer: "d7", candidates_differ: false, ask_theme: null },
{ layer: "d12", candidates_differ: false, ask_theme: null },
]);
assert.doesNotMatch(JSON.stringify({ scan, observations }), FORBIDDEN_LABELS);
@@ -501,9 +504,9 @@ test("rescore failure does not fail the evidence write", async () => {
assert.ok(result.rescore.error_code);
});
test("public tool surface stays at 13 and new cases bind 10.0.4", () => {
test("public tool surface stays at 13 and new cases bind 10.0.5", () => {
assert.equal(PUBLIC_RECTIFICATION_TOOLS.length, 13);
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.4");
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
const deprecated = resolveExactSkillPackage(
"jyotish-birth-time-rectification",
"10.0.2",
@@ -569,6 +572,41 @@ test("precision stage lagna_frame asks another dated event instead of rotating d
assert.doesNotMatch(JSON.stringify(plan), FORBIDDEN_LABELS);
});
test("precision stage d4 asks home change not family, and d5 asks education", () => {
const d4 = buildMethodFollowupPlan({
evidence: [
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
],
precisionStage: "d4_refine",
});
assert.equal(d4.next_followup?.source, "precision_stage");
assert.equal(d4.next_followup?.method_id, "d4_home");
assert.equal(d4.next_followup?.domain, "relocation");
assert.equal(d4.next_followup?.ask_theme, "home_change");
assert.doesNotMatch(d4.next_followup?.user_prompt_hint ?? "", /家人/);
const legacyTheme = buildMethodFollowupPlan({
evidence: d4.next_followup ? [
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
] : [],
precisionStage: "theme_refine",
});
assert.equal(legacyTheme.next_followup?.ask_theme, "home_change");
const d5 = buildMethodFollowupPlan({
evidence: [
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
],
precisionStage: "d5_refine",
});
assert.equal(d5.next_followup?.method_id, "d5_education");
assert.equal(d5.next_followup?.domain, "education");
assert.doesNotMatch(JSON.stringify(d4), FORBIDDEN_LABELS);
});
test("accepted representative time hands off to consultation", () => {
const plan = buildMethodFollowupPlan({
evidence: [{