feat(projection): add complete observation day gate (issue #94)

This commit is contained in:
xavierk
2026-09-18 15:23:59 +05:30
parent 95cca2e115
commit b76067104b
6 changed files with 461 additions and 1 deletions
+49
View File
@@ -483,6 +483,31 @@ def _build_pu_context_line(conn, rate, days, clock_now):
return "Percentage Used: %d%%" % pu
# ---------------------------------------------------------------------------
# Complete observation day gate (issue #94)
# ---------------------------------------------------------------------------
def _has_complete_local_day(conn):
"""Check if at least one complete local observation day exists.
A complete local day is a full midnight-to-midnight calendar day
within a monitoring period that has usable observation evidence.
This is the prerequisite for showing an endurance outlook.
"""
row = conn.execute(
"SELECT 1 FROM local_days WHERE complete = 1 LIMIT 1"
).fetchone()
return row is not None
def _count_complete_local_days(conn):
"""Count the number of complete local observation days."""
row = conn.execute(
"SELECT COUNT(*) FROM local_days WHERE complete = 1"
).fetchone()
return row[0] if row else 0
# ---------------------------------------------------------------------------
# Main projection function
# ---------------------------------------------------------------------------
@@ -499,6 +524,30 @@ def compute_projection(conn, clock_now):
tier, baseline, baseline_label, baseline_facts = _resolve_baseline(conn, current_segment)
facts.extend(baseline_facts)
# --- Complete observation day gate (issue #94) ---
# An endurance outlook requires at least one complete local
# midnight-to-midnight calendar day with usable observation evidence.
has_complete_day = _has_complete_local_day(conn)
if not has_complete_day:
facts.append("waiting for a full local observation day")
return ProjectionResult(
confidence_state=ConfidenceState.UNSUPPORTED,
contributing_facts=facts,
headline_remaining_seconds=None,
scenario_range=None,
pu_context_line="Percentage Used: unknown" if _get_latest_pu(conn) is None else "Percentage Used: %d%%" % (_get_latest_pu(conn) or 0),
disclosure_text=list(DISCLOSURES),
baseline_tier=tier,
baseline_label=baseline_label,
regime_days=None,
habit_change_fact=None,
warming_fact=None,
staleness_fact=None,
degraded_identity_fact=None,
zero_rate_fact=None,
qualifying_days_progress=None,
)
segment_days = _get_days_in_segment(conn, current_segment["opened_at"]) if current_segment else _get_all_days(conn)
all_days = _get_all_days(conn)