Coverage for little_loops / learning_tests / gate.py: 31%
16 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-06-26 17:38 -0500
« prev ^ index » next coverage.py v7.12.0, created at 2026-06-26 17:38 -0500
1"""Shared gate utilities for learning-test staleness checks (ENH-2208).
3Exposes ``is_record_stale()`` and ``format_nudge_message()`` as standalone
4importable helpers consumed by the discoverability gate hook, the install
5learning gate hook (ENH-2212), and downstream sprint/release gates
6(ENH-2209, ENH-2210, ENH-2214, ENH-2217).
7"""
9from __future__ import annotations
11import datetime
12from typing import TYPE_CHECKING
14if TYPE_CHECKING:
15 from little_loops.learning_tests import LearnTestRecord
18def format_nudge_message(pkg: str, stale: bool = False) -> str:
19 """Return a nudge message for a package with no proven or stale learning test.
21 Args:
22 pkg: The package name (already normalized).
23 stale: If True, the record exists but is stale; otherwise it is absent.
24 """
25 if stale:
26 body = f'Learning test for "{pkg}" is stale.'
27 else:
28 body = f'No learning test for "{pkg}".'
29 return f'[ll: new dependency] {body} Consider: /ll:explore-api "{pkg}"'
32def is_record_stale(record: LearnTestRecord, stale_after_days: int) -> bool:
33 """Return True if the record's proof date exceeds the staleness threshold.
35 Args:
36 record: A LearnTestRecord with a ``date`` field (ISO 8601: YYYY-MM-DD).
37 stale_after_days: Age threshold in days. Clamped to minimum 1 to
38 prevent ``stale_after_days=0`` from being a footgun that passes
39 all records whose date is exactly today.
41 Returns:
42 True if age in days exceeds the threshold; False if fresh or unparseable.
43 """
44 threshold = max(1, stale_after_days)
45 try:
46 record_date = datetime.date.fromisoformat(record.date)
47 except (ValueError, TypeError, AttributeError):
48 return False
49 age_days = (datetime.date.today() - record_date).days
50 return age_days > threshold