feat(rectification): expand dated dasha_boundary probe supply
Independent Staging Quality Gate / validate (push) Successful in 12m41s
Independent Staging Quality Gate / publish (push) Successful in 9m33s

Distinguish-stage reverse-verify questions were exhausting after 1–3
dated probes. Union boundary windows across representative pairs, keep
multiple years per domain, raise the public cap, and allow activation
fallback without relaxing MIN_BOUNDARY_DAYS or scoring.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-30 11:46:30 +08:00
parent e8fa1ce4ea
commit 04b2ccdbe2
3 changed files with 530 additions and 102 deletions
+258 -101
View File
@@ -42,7 +42,22 @@ from scripts.rectification.probe_question_contract import (
)
from scripts.rectification.refinement_packet import match_level
MAX_PROBES = 3
# Public discriminator list. Four to six domains typically compete; 8 lets about
# three domains keep two years plus a couple of activation fallbacks without
# flooding the ask layer, which still ranks globally by information_gain.
MAX_PROBES = 8
# Collection still asks at most three missing-domain age-band questions.
MAX_COLLECTION_PROBES = 3
# N: keep the top scored probes per domain (boundary years, plus at most one
# activation if the domain is still under this cap).
MAX_PROBES_PER_DOMAIN = 3
# K: per-domain evaluation budget of unique (year, month) windows.
# N <= K. Endpoints and evenly spaced months are tried first (at most K).
# If those K miss every discriminator, scan the remainder until the first
# hit so a lone month is not dropped; do not keep scanning to fill N.
# Shrink K if runtime more than doubles; do not drop multi-pair union.
# MAX_PROBES is the published cap after a global information_gain sort.
MAX_BOUNDARY_CANDIDATES_PER_DOMAIN = 8
MIN_BOUNDARY_DAYS = 45
LEVEL_RANK = {"none": 0, "weak": 1, "medium": 2, "strong": 3}
LEVEL_P = {"none": 0.15, "weak": 0.35, "medium": 0.62, "strong": 0.82}
@@ -284,59 +299,6 @@ def _remaining_contexts(built: dict[str, Any], candidate_times: Sequence[str]) -
return remaining
def _pick_representatives(
built: dict[str, Any],
scan: dict[str, Any],
candidate_times: Sequence[str],
representative_time: str | None,
) -> tuple[dict[str, Any], dict[str, Any]] | None:
contexts = _static_contexts(built)
by_time = {_context_time(item): item for item in contexts}
times = [str(_context_time(item)) for item in contexts]
remaining: list[str] = []
for raw in candidate_times:
time = str(raw or "")[:5]
if len(time) >= 5 and time in by_time and time not in remaining:
remaining.append(time)
if len(remaining) >= 2:
remaining_set = set(remaining)
for transition in scan.get("transitions") or []:
if not isinstance(transition, dict):
continue
layer = transition.get("layer")
at = str(transition.get("at") or "")[:5]
if layer not in SCORING_LAYERS or at not in by_time or at not in remaining_set:
continue
left = None
for time in remaining:
if _clock(time) < _clock(at):
left = time
if left and left != at:
return by_time[left], by_time[at]
return by_time[remaining[0]], by_time[remaining[-1]]
for transition in scan.get("transitions") or []:
if not isinstance(transition, dict):
continue
layer = transition.get("layer")
at = str(transition.get("at") or "")[:5]
if layer not in SCORING_LAYERS or at not in by_time:
continue
index = times.index(at)
left = times[index - 1] if index > 0 else at
if left != at:
return by_time[left], by_time[at]
picked: list[str] = []
for raw in [*candidate_times, representative_time]:
time = str(raw or "")[:5]
if len(time) >= 5 and time in by_time and time not in picked:
picked.append(time)
if len(picked) >= 2:
return by_time[picked[0]], by_time[picked[-1]]
if len(times) >= 2:
return by_time[times[0]], by_time[times[-1]]
return None
def _scoreable(context: dict[str, Any]) -> bool:
chart = context.get("chart")
planets = context.get("planet_longitudes")
@@ -480,6 +442,196 @@ def _boundary_years(left: list[int], right: list[int]) -> set[int]:
return {item.year for item in _boundary_windows(left, right)}
def _representative_pairs(
reps: Sequence[dict[str, Any]],
) -> list[tuple[dict[str, Any], dict[str, Any]]]:
ordered = sorted(
[item for item in reps if _scoreable(item) and _context_time(item)],
key=lambda item: _clock(str(_context_time(item))),
)
if len(ordered) < 2:
return []
pairs: list[tuple[dict[str, Any], dict[str, Any]]] = []
seen: set[tuple[str, str]] = set()
def add(left: dict[str, Any], right: dict[str, Any]) -> None:
left_time = str(_context_time(left) or "")
right_time = str(_context_time(right) or "")
if not left_time or not right_time or left_time == right_time:
return
key = (left_time, right_time) if left_time < right_time else (right_time, left_time)
if key in seen:
return
seen.add(key)
pairs.append((left, right))
for index in range(len(ordered) - 1):
add(ordered[index], ordered[index + 1])
if len(ordered) > 2:
add(ordered[0], ordered[-1])
return pairs
def _vim_cache_key(birth_date: str, moon: float, lo: int, hi: int) -> tuple[Any, ...]:
return (birth_date, round(float(moon), 6), lo, hi)
def _narayana_cache_key(
ascendant_index: int,
planet_longitudes: dict[str, Any],
birth_date: str,
lo: int,
hi: int,
) -> tuple[Any, ...]:
planet_key = tuple(
sorted(
(str(name), round(float(lon), 6))
for name, lon in planet_longitudes.items()
if isinstance(lon, (int, float))
)
)
return (int(ascendant_index), planet_key, birth_date, lo, hi)
def _union_boundary_dates(
reps: Sequence[dict[str, Any]],
*,
birth_date: str,
lo: int,
hi: int,
) -> list[date]:
vim_cache: dict[tuple[Any, ...], list[date]] = {}
narayana_cache: dict[tuple[Any, ...], list[date] | None] = {}
dates_by_key: dict[tuple[int, int], date] = {}
for left, right in _representative_pairs(reps):
left_moon = float(left["planet_longitudes"]["Moon"])
right_moon = float(right["planet_longitudes"]["Moon"])
left_vim_key = _vim_cache_key(birth_date, left_moon, lo, hi)
right_vim_key = _vim_cache_key(birth_date, right_moon, lo, hi)
if left_vim_key not in vim_cache:
vim_cache[left_vim_key] = _vim_start_dates(birth_date, left_moon, lo, hi)
if right_vim_key not in vim_cache:
vim_cache[right_vim_key] = _vim_start_dates(birth_date, right_moon, lo, hi)
windows = list(_boundary_windows(vim_cache[left_vim_key], vim_cache[right_vim_key]))
left_nara_key = _narayana_cache_key(
int(left["ascendant_index"]),
left["planet_longitudes"],
birth_date,
lo,
hi,
)
right_nara_key = _narayana_cache_key(
int(right["ascendant_index"]),
right["planet_longitudes"],
birth_date,
lo,
hi,
)
if left_nara_key not in narayana_cache:
narayana_cache[left_nara_key] = _narayana_start_dates(
int(left["ascendant_index"]),
left["planet_longitudes"],
birth_date,
lo,
hi,
)
if right_nara_key not in narayana_cache:
narayana_cache[right_nara_key] = _narayana_start_dates(
int(right["ascendant_index"]),
right["planet_longitudes"],
birth_date,
lo,
hi,
)
left_narayana = narayana_cache[left_nara_key]
right_narayana = narayana_cache[right_nara_key]
if left_narayana is not None and right_narayana is not None:
windows.extend(_boundary_windows(left_narayana, right_narayana))
for item in windows:
dates_by_key.setdefault((item.year, item.month), item)
return sorted(dates_by_key.values(), key=lambda item: (item.year, item.month))
def _bounded_candidate_dates(dates: Sequence[date], limit: int) -> list[date]:
items = list(dates)
if limit <= 0 or len(items) <= limit:
return items
if limit == 1:
return items[:1]
picked: list[date] = []
seen: set[tuple[int, int]] = set()
last_index = len(items) - 1
for step in range(limit):
index = (step * last_index + (limit - 1) // 2) // (limit - 1)
item = items[index]
key = (item.year, item.month)
if key in seen:
continue
seen.add(key)
picked.append(item)
if len(picked) < limit:
for item in items:
key = (item.year, item.month)
if key in seen:
continue
seen.add(key)
picked.append(item)
if len(picked) >= limit:
break
return picked
def _evaluation_order(dates: Sequence[date], limit: int) -> list[date]:
sampled = _bounded_candidate_dates(dates, limit)
sampled_keys = {(item.year, item.month) for item in sampled}
remainder = [item for item in dates if (item.year, item.month) not in sampled_keys]
return sampled + remainder
def _probe_sort_key(row: dict[str, Any]) -> tuple[float, str]:
return (-float(row.get("information_gain") or 0), str(row.get("semantic_key") or ""))
def _best_probe_per_year(rows: Sequence[dict[str, Any]]) -> list[dict[str, Any]]:
by_year: dict[int, dict[str, Any]] = {}
for row in sorted(rows, key=_probe_sort_key):
year = int(row["year"])
if year not in by_year:
by_year[year] = row
return list(by_year.values())
def _try_activation_probe(
*,
reps: Sequence[dict[str, Any]],
birth_date: str,
birth_year: int,
domain: str,
now: date,
blocked_years: set[int],
holdout_keys: set[str],
clusters: Sequence[dict[str, Any]],
set_version: str,
) -> dict[str, Any] | None:
midpoint = _age_band_year(birth_year, domain, now)
if midpoint is None or midpoint in blocked_years or f"{domain}:{midpoint}" in holdout_keys:
return None
found = _evaluate_contexts(
reps,
birth_date=birth_date,
domain=domain,
year=midpoint,
source="dasha_activation",
clusters=clusters,
set_version=set_version,
)
if found is None or distinguish_contract_errors(found):
return None
if not isinstance(found.get("year"), int) or int(found["year"]) <= 0:
return None
return found
def _score_year(
context: dict[str, Any],
*,
@@ -906,7 +1058,7 @@ def evidence_collection_probes(
),
event_family=str(DOMAIN_CATALOG[domain]["event_family"]),
))
if len(rows) >= MAX_PROBES:
if len(rows) >= MAX_COLLECTION_PROBES:
break
return rows
@@ -984,27 +1136,7 @@ def discriminating_event_probes(
if not domains:
return []
lo, hi = birth_year + 5, min(now.year, birth_year + 80)
left, right = reps[0], reps[-1]
left_moon = float(left["planet_longitudes"]["Moon"])
right_moon = float(right["planet_longitudes"]["Moon"])
vim_windows = _boundary_windows(
_vim_start_dates(birth_date, left_moon, lo, hi),
_vim_start_dates(birth_date, right_moon, lo, hi),
)
left_narayana = _narayana_start_dates(int(left["ascendant_index"]), left["planet_longitudes"], birth_date, lo, hi)
right_narayana = _narayana_start_dates(int(right["ascendant_index"]), right["planet_longitudes"], birth_date, lo, hi)
narayana_windows: list[date] = []
if left_narayana is not None and right_narayana is not None:
narayana_windows = _boundary_windows(left_narayana, right_narayana)
boundary_dates: list[date] = []
seen_windows: set[tuple[int, int]] = set()
for item in [*vim_windows, *narayana_windows]:
key = (item.year, item.month)
if key in seen_windows:
continue
seen_windows.add(key)
boundary_dates.append(item)
boundary_dates.sort()
boundary_dates = _union_boundary_dates(reps, birth_date=birth_date, lo=lo, hi=hi)
probes: list[dict[str, Any]] = []
for domain in domains:
if domain not in DOMAIN_CATALOG:
@@ -1012,14 +1144,20 @@ def discriminating_event_probes(
known_years = _event_years(events, domain)
blocked_years = _existence_blocked_years(domain, known_years)
domain_lo = _domain_year_floor(birth_year, domain, lo)
boundary = [item for item in boundary_dates if domain_lo <= item.year <= hi]
best = None
for at in boundary:
if at.year in blocked_years:
continue
if f"{domain}:{at.year}" in holdout_keys:
continue
found = _evaluate_contexts(
eligible = [
item
for item in boundary_dates
if domain_lo <= item.year <= hi
and item.year not in blocked_years
and f"{domain}:{item.year}" not in holdout_keys
]
found: list[dict[str, Any]] = []
evaluated = 0
sample_size = min(MAX_BOUNDARY_CANDIDATES_PER_DOMAIN, len(eligible))
for at in _evaluation_order(eligible, MAX_BOUNDARY_CANDIDATES_PER_DOMAIN):
if evaluated >= sample_size and found:
break
row = _evaluate_contexts(
reps,
birth_date=birth_date,
domain=domain,
@@ -1029,25 +1167,42 @@ def discriminating_event_probes(
clusters=clusters,
set_version=set_version,
)
if found is None:
evaluated += 1
if row is None or distinguish_contract_errors(row):
continue
if best is None or float(found["information_gain"]) > float(best["information_gain"]):
best = found
if best is None:
midpoint = _age_band_year(birth_year, domain, now)
if midpoint is not None and midpoint not in blocked_years and f"{domain}:{midpoint}" not in holdout_keys:
best = _evaluate_contexts(
reps,
birth_date=birth_date,
domain=domain,
year=midpoint,
source="dasha_activation",
clusters=clusters,
set_version=set_version,
if not isinstance(row.get("year"), int) or int(row["year"]) <= 0:
continue
found.append(row)
if evaluated > sample_size:
break
kept = _best_probe_per_year(found)[:MAX_PROBES_PER_DOMAIN]
if len(kept) < MAX_PROBES_PER_DOMAIN:
activation = _try_activation_probe(
reps=reps,
birth_date=birth_date,
birth_year=birth_year,
domain=domain,
now=now,
blocked_years=blocked_years,
holdout_keys=set(holdout_keys),
clusters=clusters,
set_version=set_version,
)
if activation is not None:
activation_key = (
str(activation["domain"]),
int(activation["year"]),
int(activation.get("month") or 0),
str(activation["source"]),
)
if best and not distinguish_contract_errors(best):
probes.append(best)
probes.sort(key=lambda row: (-float(row.get("information_gain") or 0), str(row.get("semantic_key") or "")))
existing = {
(str(row["domain"]), int(row["year"]), int(row.get("month") or 0), str(row["source"]))
for row in kept
}
if activation_key not in existing:
kept.append(activation)
probes.extend(kept)
probes.sort(key=_probe_sort_key)
public: list[dict[str, Any]] = []
seen: set[tuple[str, int, int, str]] = set()
for row in probes:
@@ -1055,6 +1210,8 @@ def discriminating_event_probes(
continue
if distinguish_contract_errors(row):
continue
if not isinstance(row.get("year"), int) or int(row["year"]) <= 0:
continue
key = (str(row["domain"]), int(row["year"]), int(row.get("month") or 0), str(row["source"]))
encoded = str(row)
if key in seen or "points" in encoded: