Spaces:
Sleeping
Sleeping
| """Pure schedule math: duration shrinkage, slip, completion rates, EV score. | |
| Server-owned — LLM must never invent these statistics. | |
| P1 scope lock (do not expand): | |
| - EV stays exactly: | |
| EV = P(done)*U + γ*I + η*Fun − λt*d_hat − λm*cost − λf*FSE | |
| - No PERMA, no ωE_i, no δ_i, no H=S+C+V in code. | |
| - Hedonic δ is not a v1 term; learn later via would_repeat + falling fun. | |
| - Seligman = operators on a trigger day: raise λ_f and η; only P0 overrides. | |
| - Escape (porn/court/rerun binge) ≠ explore/restore_fun. | |
| - Family contact is often FSE load, not a pillar to maximize. | |
| """ | |
| from __future__ import annotations | |
| from collections import defaultdict | |
| from typing import Any | |
| # Default planned minutes by kind when no samples exist yet. | |
| PRIOR_DEFAULT_MIN: dict[str, float] = { | |
| "earn_ship": 45, | |
| "admin_spain": 30, | |
| "body_care": 20, | |
| "move_out": 15, | |
| "boundary": 10, | |
| "food_out": 45, | |
| "stabilize": 15, | |
| "explore": 25, | |
| "restore_fun": 30, | |
| "sleep_window": 45, | |
| "other": 30, | |
| } | |
| # Escape / FSE tags — never treat as fun or explore intent. | |
| ESCAPE_FSE_TAGS = frozenset( | |
| {"urge", "corn", "court", "rerun", "daydream", "bully", "shame", "family"} | |
| ) | |
| def is_strong_feedback(fb: dict[str, Any]) -> bool: | |
| """Strong iff done|partial with actual_min, quality, and fun present.""" | |
| did = fb.get("did") | |
| return ( | |
| did in ("done", "partial") | |
| and fb.get("actual_min") is not None | |
| and fb.get("quality") is not None | |
| and fb.get("fun") is not None | |
| ) | |
| def d_hat( | |
| mean_actual: float | None, | |
| n: int, | |
| prior_default: float, | |
| *, | |
| m: float = 3.0, | |
| ) -> float: | |
| """Shrinkage duration estimate: (n/(n+m))*mean + (m/(n+m))*prior.""" | |
| if n <= 0 or mean_actual is None: | |
| return float(prior_default) | |
| weight = n / (n + m) | |
| return weight * float(mean_actual) + (1.0 - weight) * float(prior_default) | |
| def p_done_rate(n_done: int, n: int, *, alpha: float = 1.0, beta: float = 1.0) -> float: | |
| """Smoothed completion rate (N_done + α) / (N + α + β).""" | |
| return (n_done + alpha) / (n + alpha + beta) if (n + alpha + beta) else 0.5 | |
| def mean_or_none(values: list[float]) -> float | None: | |
| return sum(values) / len(values) if values else None | |
| def recompute_priors( | |
| feedback: list[dict[str, Any]], | |
| blocks_by_id: dict[str, dict[str, Any]], | |
| *, | |
| shrink_k: float = 3.0, | |
| ) -> dict[str, dict[str, Any]]: | |
| """Rebuild per-kind priors from strong feedback samples. | |
| EV ranking (documented for schedule generators / OR prompts): | |
| EV ≈ P_done * U + γ * I + η * Fun_bar - λt * d_hat - λm * cost - λf * fse_load | |
| High I when n_k is low or variance is high (explore kinds). | |
| """ | |
| by_kind: dict[str, list[dict[str, Any]]] = defaultdict(list) | |
| for fb in feedback: | |
| if not (fb.get("strong") or is_strong_feedback(fb)): | |
| continue | |
| block = blocks_by_id.get(str(fb.get("block_id") or "")) | |
| kind = (block or {}).get("kind") or fb.get("kind") or "other" | |
| by_kind[str(kind)].append(fb) | |
| out: dict[str, dict[str, Any]] = {} | |
| for kind, samples in by_kind.items(): | |
| actuals = [float(s["actual_min"]) for s in samples if s.get("actual_min") is not None] | |
| qualities = [float(s["quality"]) for s in samples if s.get("quality") is not None] | |
| funs = [float(s["fun"]) for s in samples if s.get("fun") is not None] | |
| energies = [ | |
| float(s["energy_after"]) | |
| for s in samples | |
| if s.get("energy_after") is not None | |
| ] | |
| slips: list[float] = [] | |
| for s in samples: | |
| block = blocks_by_id.get(str(s.get("block_id") or "")) | |
| planned = (block or {}).get("planned_min") | |
| if planned is not None and s.get("actual_min") is not None: | |
| slips.append(float(s["actual_min"]) - float(planned)) | |
| n = len(samples) | |
| n_done = sum(1 for s in samples if s.get("did") == "done") | |
| mean_actual = mean_or_none(actuals) | |
| prior = PRIOR_DEFAULT_MIN.get(kind, 30.0) | |
| repeats = [ | |
| 1.0 if s.get("would_repeat") == "yes" else 0.0 | |
| for s in samples | |
| if s.get("would_repeat") in ("yes", "no", "maybe") | |
| ] | |
| out[kind] = { | |
| "kind": kind, | |
| "n": n, | |
| "mean_actual": mean_actual, | |
| "d_hat": d_hat(mean_actual, n, prior, m=shrink_k), | |
| "mean_quality": mean_or_none(qualities), | |
| "mean_fun": mean_or_none(funs), | |
| "mean_energy": mean_or_none(energies), | |
| "p_done": p_done_rate(n_done, n), | |
| "mean_slip": mean_or_none(slips), | |
| "repeat_score": mean_or_none(repeats) or 0.0, | |
| } | |
| # Ensure defaults exist for known kinds with no samples. | |
| for kind, prior in PRIOR_DEFAULT_MIN.items(): | |
| if kind not in out: | |
| out[kind] = { | |
| "kind": kind, | |
| "n": 0, | |
| "mean_actual": None, | |
| "d_hat": float(prior), | |
| "mean_quality": None, | |
| "mean_fun": None, | |
| "mean_energy": None, | |
| "p_done": 0.5, | |
| "mean_slip": None, | |
| "repeat_score": 0.0, | |
| } | |
| return out | |
| def minutes_between(start: str, end: str) -> int: | |
| """Compute end-start in minutes for HH:MM strings.""" | |
| sh, sm = map(int, start.split(":")) | |
| eh, em = map(int, end.split(":")) | |
| return (eh * 60 + em) - (sh * 60 + sm) | |
| def parse_hhmm(value: str) -> int: | |
| h, m = map(int, value.split(":")) | |
| return h * 60 + m | |
| def overlaps(a_start: str, a_end: str, b_start: str, b_end: str) -> bool: | |
| a0, a1 = parse_hhmm(a_start), parse_hhmm(a_end) | |
| b0, b1 = parse_hhmm(b_start), parse_hhmm(b_end) | |
| return a0 < b1 and b0 < a1 | |
| def validate_blocks( | |
| blocks: list[dict[str, Any]], | |
| *, | |
| max_blocks: int = 7, | |
| previous_p0: list[dict[str, Any]] | None = None, | |
| allow_p0_move: bool = False, | |
| must_include_explore_or_restore: bool = False, | |
| capacity_hint: float | None = None, | |
| hard_explore: bool = False, | |
| ) -> tuple[list[str], list[str]]: | |
| """Return (errors, warnings). Empty errors means valid.""" | |
| errors: list[str] = [] | |
| warnings: list[str] = [] | |
| if len(blocks) > max_blocks: | |
| errors.append(f"max_blocks exceeded ({len(blocks)} > {max_blocks})") | |
| for block in blocks: | |
| start = str(block.get("start") or "") | |
| end = str(block.get("end") or "") | |
| try: | |
| span = minutes_between(start, end) | |
| except Exception: # noqa: BLE001 | |
| errors.append(f"invalid time on block {block.get('id')}") | |
| continue | |
| if span <= 0: | |
| errors.append(f"end must be after start for {block.get('id')}") | |
| planned = int(block.get("planned_min") or 0) | |
| if planned and abs(planned - span) > 1: | |
| errors.append( | |
| f"planned_min mismatch for {block.get('id')}: {planned} vs {span}" | |
| ) | |
| for i, a in enumerate(blocks): | |
| for b in blocks[i + 1 :]: | |
| if overlaps( | |
| str(a.get("start")), | |
| str(a.get("end")), | |
| str(b.get("start")), | |
| str(b.get("end")), | |
| ): | |
| errors.append( | |
| f"overlap between {a.get('id')} and {b.get('id')}" | |
| ) | |
| if previous_p0 and not allow_p0_move: | |
| prev = { | |
| str(b.get("id")): b | |
| for b in previous_p0 | |
| if b.get("priority") == "P0" or b.get("locked") | |
| } | |
| for block in blocks: | |
| bid = str(block.get("id") or "") | |
| if bid in prev: | |
| old = prev[bid] | |
| if old.get("start") != block.get("start") or old.get("end") != block.get( | |
| "end" | |
| ): | |
| errors.append(f"P0/locked block {bid} cannot be moved") | |
| if ( | |
| must_include_explore_or_restore | |
| and blocks | |
| and capacity_hint is not None | |
| and capacity_hint >= 0.4 | |
| ): | |
| has_explore = any( | |
| b.get("intent") in ("explore", "restore_fun") for b in blocks | |
| ) | |
| if not has_explore: | |
| msg = "all-grind plan: add explore or restore_fun when capacity allows" | |
| if hard_explore: | |
| errors.append(msg) | |
| else: | |
| warnings.append(msg) | |
| return errors, warnings | |
| def ev_score( | |
| *, | |
| p_done: float, | |
| utility: float, | |
| information: float = 0.0, | |
| fun: float = 0.0, | |
| d_hat_min: float = 30.0, | |
| cost: float = 0.0, | |
| fse: float = 0.0, | |
| gamma: float = 0.25, | |
| eta: float = 0.35, | |
| lambda_t: float = 0.01, | |
| lambda_m: float = 0.15, | |
| lambda_f: float = 0.4, | |
| raise_eta: bool = False, | |
| raise_lambda_f: bool = False, | |
| ) -> float: | |
| """Locked EV formula (operators may raise η / λ_f; no δ / H / PERMA terms).""" | |
| eta_eff = eta * (1.35 if raise_eta else 1.0) | |
| lf_eff = lambda_f * (1.4 if raise_lambda_f else 1.0) | |
| return ( | |
| p_done * utility | |
| + gamma * information | |
| + eta_eff * fun | |
| - lambda_t * d_hat_min | |
| - lambda_m * cost | |
| - lf_eff * fse | |
| ) | |
| def capacity_hint( | |
| *, | |
| risk_1h_score: float, | |
| triggers_yesterday: list[str], | |
| yesterday_trigger: bool | None = None, | |
| last_hour_high: bool | None = None, | |
| ) -> float: | |
| """Soft capacity 0..1. Trigger day / last-hour FSE cut C_today; P0 still allowed. | |
| On trigger days, callers should also raise λ_f and η in ranking/reschedule | |
| prompts (operators only — EV formula unchanged). | |
| """ | |
| y_trig = ( | |
| bool(yesterday_trigger) | |
| if yesterday_trigger is not None | |
| else len(triggers_yesterday) > 0 | |
| ) | |
| hour_high = ( | |
| bool(last_hour_high) | |
| if last_hour_high is not None | |
| else risk_1h_score >= 1.0 | |
| ) | |
| penalty = min( | |
| 0.65, | |
| 0.15 * risk_1h_score | |
| + 0.08 * len(triggers_yesterday) | |
| + (0.12 if y_trig else 0.0) | |
| + (0.15 if hour_high else 0.0), | |
| ) | |
| return max(0.25, 1.0 - penalty) | |
| def trigger_operators( | |
| *, | |
| risk_1h_tags: list[str], | |
| triggers_yesterday: list[str], | |
| ) -> dict[str, Any]: | |
| """Seligman-as-operators payload for reschedule / agent context (not new math).""" | |
| escape_hit = bool(ESCAPE_FSE_TAGS & set(risk_1h_tags + triggers_yesterday)) | |
| trigger_day = len(triggers_yesterday) > 0 or escape_hit | |
| return { | |
| "trigger_day": trigger_day, | |
| "raise_lambda_f": trigger_day, | |
| "raise_eta": trigger_day, | |
| "p0_only_overrides": True, | |
| "escape_is_not_explore": True, | |
| "fun_must_yield_data_or_skill": True, | |
| "no_family_relationship_optimization": True, | |
| "ev_formula_locked": True, | |
| } | |
| def plan_health( | |
| blocks: list[dict[str, Any]], | |
| feedback: list[dict[str, Any]], | |
| ) -> dict[str, Any]: | |
| """Health ≈ (strong_fb/planned) * p0_done_rate * explore_flag.""" | |
| planned = [b for b in blocks if b.get("status") != "cancelled"] | |
| planned_count = max(1, len(planned)) | |
| fb_by_block = {str(f.get("block_id")): f for f in feedback} | |
| strong = sum( | |
| 1 | |
| for b in planned | |
| if is_strong_feedback(fb_by_block.get(str(b.get("id")), {})) | |
| or fb_by_block.get(str(b.get("id")), {}).get("strong") | |
| ) | |
| p0 = [b for b in planned if b.get("priority") == "P0"] | |
| p0_done = sum( | |
| 1 | |
| for b in p0 | |
| if fb_by_block.get(str(b.get("id")), {}).get("did") == "done" | |
| or b.get("status") == "done" | |
| ) | |
| p0_rate = (p0_done / len(p0)) if p0 else 1.0 | |
| explore_done = any( | |
| b.get("intent") in ("explore", "restore_fun") | |
| and ( | |
| b.get("status") in ("done", "partial") | |
| or fb_by_block.get(str(b.get("id")), {}).get("did") in ("done", "partial") | |
| ) | |
| for b in planned | |
| ) | |
| score = (strong / planned_count) * p0_rate * (1.0 if explore_done else 0.0) | |
| return { | |
| "score": round(score, 3), | |
| "strong_feedback_count": strong, | |
| "planned_count": len(planned), | |
| "p0_done_rate": round(p0_rate, 3), | |
| "explore_or_restore_done": explore_done, | |
| } | |
| def priors_markdown(priors: dict[str, dict[str, Any]]) -> str: | |
| """Compact SERVER_PRIORS table for LLM prompts.""" | |
| lines = [ | |
| "SERVER_PRIORS (do not invent numbers)", | |
| "kind | n | d_hat | p_done | fun_bar | repeat", | |
| ] | |
| for kind in sorted(priors.keys()): | |
| row = priors[kind] | |
| fun = row.get("mean_fun") | |
| fun_s = f"{fun:.2f}" if isinstance(fun, (int, float)) else "n/a" | |
| lines.append( | |
| f"{kind} | {row.get('n', 0)} | {row.get('d_hat', 0):.0f} | " | |
| f"{row.get('p_done', 0):.2f} | {fun_s} | {row.get('repeat_score', 0):.2f}" | |
| ) | |
| return "\n".join(lines) | |