feat(rectification): 出卡加精度门槛,补经历改成系统点名
Independent Staging Quality Gate / validate (push) Failing after 6m28s
Independent Staging Quality Gate / publish (push) Skipped

宽度超过 10 分钟或头名并列时不再出交付卡,改为按大运边界逐条问、
用类型芯片和年/月选择器录入。跳过的线换问法再问一次;答「这类事
都没有过」的不再问。用户说「没有了」仍立刻给目前范围。Skill 10.0.27。

BUG-740~743
This commit is contained in:
jesse-ux
2026-09-16 18:35:27 +08:00
parent 317e9f1886
commit cfb41daf3d
75 changed files with 4763 additions and 383 deletions
+88
View File
@@ -0,0 +1,88 @@
from __future__ import annotations
import unittest
from datetime import date
from scripts.rectification.event_probes import GUIDED_COLLECT_LIMIT, guided_collect_windows
from tests.test_rectification_event_probes import _context, _gate_events, _multi_layer_window_built, _request
class GuidedCollectWindowsTests(unittest.TestCase):
def test_twenty_minute_window_emits_at_least_one_real_dasha_window(self) -> None:
built = _multi_layer_window_built()
rows = guided_collect_windows(
_request(),
built,
candidate_times=["04:47", "04:48", "05:00", "05:06", "05:07"],
today=date(2026, 8, 22),
)
self.assertGreaterEqual(len(rows), 1)
self.assertLessEqual(len(rows), GUIDED_COLLECT_LIMIT)
for row in rows:
self.assertIn("year", row)
self.assertIn("month_lo", row)
self.assertIn("month_hi", row)
self.assertIn("domain", row)
self.assertIn("split", row)
self.assertGreaterEqual(row["month_lo"], 1)
self.assertLessEqual(row["month_hi"], 12)
self.assertGreaterEqual(row["month_hi"], row["month_lo"])
self.assertGreaterEqual(row["split"]["left"], 1)
self.assertGreaterEqual(row["split"]["right"], 1)
def test_declined_domains_are_removed(self) -> None:
built = _multi_layer_window_built()
times = ["04:47", "04:48", "05:00", "05:06", "05:07"]
full = guided_collect_windows(_request(), built, candidate_times=times, today=date(2026, 8, 22))
if not full:
self.skipTest("fixture produced no guided windows")
target = str(full[0]["domain"])
blocked = guided_collect_windows(
_request(declined_domains=[target]),
built,
candidate_times=times,
today=date(2026, 8, 22),
)
self.assertFalse(any(row["domain"] == target for row in blocked))
def test_split_balance_sorts_before_year_distance(self) -> None:
built = {
"static_contexts": [
_context("04:47", d4_asc=0, sun_house=4, sun_varga_sign=3, moon=80.0, d9_asc=1, d10_asc=1),
_context("04:48", d4_asc=1, sun_house=10, sun_varga_sign=9, moon=140.0, d9_asc=2, d10_asc=2),
_context("05:06", d4_asc=1, sun_house=10, sun_varga_sign=9, moon=200.0, d9_asc=3, d10_asc=3),
],
}
rows = guided_collect_windows(
_request(events=_gate_events()),
built,
candidate_times=["04:47", "04:48", "05:06"],
today=date(2026, 8, 22),
)
if len(rows) < 2:
self.skipTest("fixture produced fewer than two windows")
balances = [abs(row["split"]["left"] - row["split"]["right"]) for row in rows]
self.assertEqual(balances, sorted(balances))
def test_cross_year_split_emits_separate_rows(self) -> None:
built = {
"static_contexts": [
_context("04:50", d4_asc=0, sun_house=4, sun_varga_sign=3, moon=10.0, d9_asc=0, d10_asc=0),
_context("05:10", d4_asc=6, sun_house=10, sun_varga_sign=9, moon=190.0, d9_asc=6, d10_asc=6),
],
}
rows = guided_collect_windows(
_request(),
built,
candidate_times=["04:50", "05:10"],
today=date(2026, 8, 22),
)
grouped: dict[tuple[str, int], list[int]] = {}
for row in rows:
grouped.setdefault((row["domain"], row["year"]), []).append(row["month_lo"])
self.assertTrue(rows, "expected real dasha windows from distant moons")
if __name__ == "__main__":
unittest.main()