fix(rectification): hold time cards until propose gate and interview stop

Keep representative-time cards off while method coverage is still open.
New cases bind Skill 10.0.9; existing 10.0.8 packages stay hashed.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-20 15:18:17 +08:00
parent 3bf93fdbb6
commit 7dc97a49ee
31 changed files with 1024 additions and 113 deletions
+2
View File
@@ -84,6 +84,7 @@ def score_candidates(request: RectificationRequest) -> dict[str, Any]:
"display_allowed": decision_receipt["display_allowed"],
"selection_allowed": decision_receipt["selection_allowed"],
"acceptance_allowed": decision_receipt["acceptance_allowed"],
"propose_allowed": decision_receipt["propose_allowed"],
"confirmation_allowed": decision_receipt["confirmation_allowed"],
"representative_candidate_id": representative["candidate_id"] if representative else None,
"representative_time": representative["time"] if representative else None,
@@ -111,6 +112,7 @@ def diagnostics(request: RectificationRequest) -> dict[str, Any]:
"display_allowed": scored["display_allowed"],
"selection_allowed": scored["selection_allowed"],
"acceptance_allowed": scored["acceptance_allowed"],
"propose_allowed": scored["propose_allowed"],
"confirmation_allowed": scored["confirmation_allowed"],
"representative_candidate_id": scored["representative_candidate_id"],
"representative_time": scored["representative_time"],
+25 -5
View File
@@ -33,6 +33,7 @@ MIN_ACCEPTANCE_DOMAINS = 2
MIN_DATE_QUALITY_MEAN = Decimal("0.65")
MIN_DIAGNOSTIC_RETENTION = Decimal("0.75")
MIN_ACCEPTANCE_MARGIN_PERCENT = Decimal("10")
POLICY_SKIPPED_LAYERS = frozenset({"KP_cusps"})
_BAD_DATE_RELIABILITY = frozenset({"low", "uncertain", "unreliable"})
_CLEAR_DATE_CONFLICT = frozenset({"", "none", "resolved", "no_conflict"})
@@ -271,7 +272,7 @@ def build_technique_audit(
rows.append({
"technique": "KP 宫头",
"status": "blocked",
"note": "KP 宫头本轮未计算",
"note": "KP 宫头政策跳过,不参与提出门或确认门",
})
rows.extend((
vedastro_audit_row(vedastro_status),
@@ -335,6 +336,14 @@ def _gate(passed: bool, **details: Any) -> dict[str, Any]:
return {"passed": passed, **details}
def _actionable_missing_layers(layers: Any) -> list[str]:
return sorted({
str(layer)
for layer in (layers or [])
if str(layer) not in POLICY_SKIPPED_LAYERS
})
def _date_quality(events: Sequence[dict[str, Any]]) -> dict[str, Any]:
weights = [_decimal(precision_weight(str(event["precision"]))) for event in events]
total = sum(weights, Decimal(0))
@@ -405,9 +414,16 @@ def build_decision_receipt(
top_tied_count = candidate_decisions[0]["tied_minute_count"] if candidate_decisions else 0
unique_top = _gate(top_tied_count == 1, tied_minute_count=top_tied_count)
diagnostic_quality = _diagnostic_quality(diagnostics)
skipped_layers = sorted(
str(layer)
for layer in (built.get("missing_layers") or [])
if str(layer) in POLICY_SKIPPED_LAYERS
)
actionable_missing_layers = _actionable_missing_layers(built.get("missing_layers"))
required_layers = _gate(
not built.get("missing_layers"),
missing_layers=sorted(built.get("missing_layers") or []),
not actionable_missing_layers,
missing_layers=actionable_missing_layers,
skipped_by_policy=skipped_layers,
)
# Adoption is the session result when a representative time exists.
@@ -472,15 +488,18 @@ def build_decision_receipt(
confirmation_reasons.append("insufficient_confirmation_margin")
if not adjacent_passed:
confirmation_reasons.append("adjacent_minutes_indistinguishable")
engine_granted = all((
propose_allowed = all((
acceptance_allowed,
unique_top["passed"],
diagnostic_quality["passed"],
required_layers["passed"],
confirmation_event_quality,
confirmation_domain_quality,
confirmation_margin,
adjacent_passed,
))
engine_granted = all((
propose_allowed,
confirmation_margin,
not dasha_conflict,
))
if not engine_granted:
@@ -506,6 +525,7 @@ def build_decision_receipt(
"display_allowed": bool(candidate_decisions),
"selection_allowed": acceptance_allowed,
"acceptance_allowed": acceptance_allowed,
"propose_allowed": propose_allowed,
"confirmation_allowed": False,
"accept_allowed": acceptance_allowed,
"confirm_allowed": False,