fix(web): count only training events for discrimination and split user-stop from validated range
Three collected events with a reserved holdout were stalling because the discriminator door counted holdout. Public selection_allowed still had snapshot fallbacks, and health only proved the image SHA. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,9 +8,11 @@ from scripts.rectification.candidate_contrast import (
|
||||
MIN_DISCRIMINATOR_DOMAINS,
|
||||
MIN_DISCRIMINATOR_EVENTS,
|
||||
SIGNATURE_LAYERS,
|
||||
discriminator_gate_open,
|
||||
distinguish_contract_errors,
|
||||
feature_signature,
|
||||
select_signature_representatives,
|
||||
training_scoreable_stats,
|
||||
)
|
||||
from scripts.rectification.event_probes import (
|
||||
candidate_contrast_opportunities,
|
||||
@@ -90,6 +92,7 @@ def _gate_events() -> list[dict]:
|
||||
{"id": "e1", "domain": "education", "event_kind": "education_start", "date": "2014-09-01", "precision": "month"},
|
||||
{"id": "e2", "domain": "education", "event_kind": "education_completion", "date": "2017-06-01", "precision": "month"},
|
||||
{"id": "e3", "domain": "career", "event_kind": "career_entry", "date": "2018-07-01", "precision": "month"},
|
||||
{"id": "e4", "domain": "relationship", "event_kind": "relationship_start", "date": "2021-08-01", "precision": "month"},
|
||||
]
|
||||
|
||||
|
||||
@@ -190,6 +193,45 @@ class DiscriminatorContractTest(unittest.TestCase):
|
||||
self.assertGreaterEqual(MIN_DISCRIMINATOR_EVENTS, 3)
|
||||
self.assertGreaterEqual(MIN_DISCRIMINATOR_DOMAINS, 2)
|
||||
|
||||
def test_training_gate_needs_four_events_when_one_is_holdout(self) -> None:
|
||||
two = _gate_events()[:2]
|
||||
three = _gate_events()[:3]
|
||||
four = _gate_events()
|
||||
self.assertFalse(discriminator_gate_open(two))
|
||||
self.assertFalse(discriminator_gate_open(three))
|
||||
two_count, _, _ = training_scoreable_stats(two)
|
||||
three_count, three_domains, _ = training_scoreable_stats(three)
|
||||
four_count, four_domains, _ = training_scoreable_stats(four)
|
||||
self.assertLess(two_count, MIN_DISCRIMINATOR_EVENTS)
|
||||
self.assertLess(three_count, MIN_DISCRIMINATOR_EVENTS)
|
||||
self.assertGreaterEqual(four_count, MIN_DISCRIMINATOR_EVENTS)
|
||||
self.assertGreaterEqual(four_domains, MIN_DISCRIMINATOR_DOMAINS)
|
||||
built = {
|
||||
"static_contexts": [
|
||||
_context("05:13", d4_asc=0, sun_house=4, sun_varga_sign=3),
|
||||
_context("05:40", d4_asc=1, sun_house=10, sun_varga_sign=9),
|
||||
]
|
||||
}
|
||||
three_probes = discriminating_event_probes(
|
||||
{"birth_date": "1997-08-08", "events": three},
|
||||
built,
|
||||
scan=window_scan(built),
|
||||
candidate_times=["05:13", "05:40"],
|
||||
representative_time="05:13",
|
||||
today=date(2026, 8, 22),
|
||||
)
|
||||
four_probes = discriminating_event_probes(
|
||||
{"birth_date": "1997-08-08", "events": four},
|
||||
built,
|
||||
scan=window_scan(built),
|
||||
candidate_times=["05:13", "05:40"],
|
||||
representative_time="05:13",
|
||||
today=date(2026, 8, 22),
|
||||
)
|
||||
self.assertEqual(three_probes, [])
|
||||
self.assertTrue(four_probes)
|
||||
self.assertGreater(three_domains, 0)
|
||||
|
||||
def test_signature_clusters_are_not_three_adjacent_minutes(self) -> None:
|
||||
rows = [
|
||||
{"time": "05:13", "score": 20},
|
||||
@@ -286,6 +328,10 @@ class DiscriminatorContractTest(unittest.TestCase):
|
||||
"05:00": {"points": 100, "rule_ids": []},
|
||||
"05:20": {"points": 0, "rule_ids": []},
|
||||
},
|
||||
"e4": {
|
||||
"05:00": {"points": 4, "rule_ids": []},
|
||||
"05:20": {"points": 1, "rule_ids": []},
|
||||
},
|
||||
},
|
||||
"missing_layers": [],
|
||||
}
|
||||
@@ -311,9 +357,15 @@ class DiscriminatorContractTest(unittest.TestCase):
|
||||
}
|
||||
rows = score_from_matrix(request, built)
|
||||
by_time = {row["time"]: row for row in rows}
|
||||
self.assertEqual(by_time["05:00"]["score"], 20)
|
||||
training_ids = {event["id"] for event in events} - holdout
|
||||
expected = sum(
|
||||
built["matrix"][event_id]["05:00"]["points"]
|
||||
for event_id in training_ids
|
||||
if event_id in built["matrix"]
|
||||
)
|
||||
self.assertEqual(by_time["05:00"]["score"], expected)
|
||||
self.assertFalse(any(item["event_id"] == holdout_id for item in by_time["05:00"]["evidence"]))
|
||||
self.assertIn(holdout_id, built["matrix"])
|
||||
self.assertIn(holdout_id, {event["id"] for event in events})
|
||||
|
||||
probes = discriminating_event_probes(
|
||||
_request(events=events),
|
||||
|
||||
@@ -48,6 +48,15 @@ def _request(*, extra_events=()):
|
||||
"date_start": "2015-06-01",
|
||||
"date_end": "2015-06-01",
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-4000-8000-000000000010",
|
||||
"domain": "career",
|
||||
"summary": "职责变化",
|
||||
"event_kind": "career_change",
|
||||
"precision": "day",
|
||||
"date_start": "2019-04-01",
|
||||
"date_end": "2019-04-01",
|
||||
},
|
||||
*extra_events,
|
||||
]
|
||||
return {"events": events}
|
||||
|
||||
@@ -102,6 +102,14 @@ def _gate_events() -> list[dict]:
|
||||
"date": "2018-07-01",
|
||||
"precision": "month",
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-4000-8000-000000000014",
|
||||
"domain": "relationship",
|
||||
"event_kind": "relationship_start",
|
||||
"summary": "相识",
|
||||
"date": "2021-08-01",
|
||||
"precision": "month",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ def request_events() -> dict:
|
||||
{"id": "00000000-0000-4000-8000-000000000001", "domain": "career", "summary": "入职", "event_kind": "career_entry", "precision": "day", "date_start": "2016-09-15", "date_end": "2016-09-15"},
|
||||
{"id": "00000000-0000-4000-8000-000000000002", "domain": "relationship", "summary": "开始一段关系", "event_kind": "relationship_start", "precision": "day", "date_start": "2018-03-01", "date_end": "2018-03-01"},
|
||||
{"id": "00000000-0000-4000-8000-000000000003", "domain": "education", "summary": "毕业", "event_kind": "education_completion", "precision": "day", "date_start": "2015-06-01", "date_end": "2015-06-01"},
|
||||
]
|
||||
{"id": "00000000-0000-4000-8000-000000000004", "domain": "family", "summary": "家人变化", "event_kind": "family_event", "precision": "day", "date_start": "2020-01-01", "date_end": "2020-01-01"},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +264,7 @@ class RefinementPacketTest(unittest.TestCase):
|
||||
self.assertNotIn("points", str(packet["event_dasha_ledger"]))
|
||||
self.assertEqual(packet["lagna_contrast"]["intervals"][0]["lagna"], "金牛座")
|
||||
self.assertTrue(packet["nakshatra_boundary"]["near_boundary"])
|
||||
self.assertEqual(packet["oos_blind_prompts"][0]["domain"], "family")
|
||||
self.assertEqual(packet["oos_blind_prompts"][0]["domain"], "finance")
|
||||
self.assertFalse(packet["oos_blind_prompts"][0]["used_for_scoring"])
|
||||
self.assertFalse(packet["confirmation_allowed"])
|
||||
encoded = str(packet["window_scan"])
|
||||
|
||||
@@ -417,10 +417,11 @@ class RectificationV5ServicesTest(unittest.TestCase):
|
||||
event(1, "education", "education_start"),
|
||||
event(2, "career", "promotion", precision="month"),
|
||||
event(3, "finance", "finance_gain"),
|
||||
event(5, "family", "family_event"),
|
||||
event(4, "other", "other", precision="year"),
|
||||
]
|
||||
normalized = normalize_rectification_request(body, today=date(2026, 7, 28))
|
||||
scored_ids = [item["id"] for item in normalized["events"][:3]]
|
||||
scored_ids = [item["id"] for item in normalized["events"] if item["domain"] != "other"]
|
||||
built = {
|
||||
"candidate_times": ["05:13", "05:14", "05:15"],
|
||||
"matrix": {
|
||||
@@ -495,7 +496,7 @@ class RectificationV5ServicesTest(unittest.TestCase):
|
||||
self.assertEqual(receipt["representative_time"], "05:13")
|
||||
|
||||
entries = first["execution_ledger"]
|
||||
background = next(item for item in entries if item.get("event_id") == normalized["events"][3]["id"])
|
||||
background = next(item for item in entries if item.get("event_id") == normalized["events"][4]["id"])
|
||||
self.assertEqual(background["status"], "retained_not_scored")
|
||||
executed = next(item for item in entries if item.get("event_id") == normalized["events"][0]["id"])
|
||||
self.assertEqual(executed["technique_layers"], ["vim_md_domain_house"])
|
||||
@@ -592,6 +593,7 @@ class RectificationV5ServicesTest(unittest.TestCase):
|
||||
event(1, "career", "career_entry"),
|
||||
event(2, "career", "promotion"),
|
||||
event(3, "education", "education_start"),
|
||||
event(4, "family", "family_event"),
|
||||
]
|
||||
normalized = normalize_rectification_request(body, today=date(2026, 7, 28))
|
||||
built = {
|
||||
|
||||
Reference in New Issue
Block a user