Orchestrata Ultimate › Gates › freshness-guard
Gate: freshness-guard
At a glance
| Purpose | "Detect and refresh every stale-data class the 2026-08-04 run history hit (Mohamed ruling: 'no staleness, every run is fresh')" — module docstring of scripts/freshness_guard.py. |
| Where it runs | scripts/run_tests.py::_main, step 0, before basetemp pruning, affected resolution, infra and the safety gates. So it runs inside the pre-push hook and inside deploy/ship.sh's verify, which both call run_tests.py. |
| Trigger | Every run_tests.py invocation unless --skip-freshness is passed. A tree with no scripts/freshness_guard.py prints ⚠ freshness_guard.py not found — skipping freshness guard. |
| Exact command | python scripts/freshness_guard.py (detect and refresh) · python scripts/freshness_guard.py --check (detect only). The runner calls it as [sys.executable, scripts/freshness_guard.py] with timeout=900. |
| Blocks | Refresh mode: exit 1 when a refresh failed → run_tests.py returns _abort("freshness"). --check: exit 1 when anything is stale. |
| Ruling / ADR | The 2026-08-04 ruling quoted in the docstring and in run_tests.py step 0. No RUL page names this script (rulings Enforcement lists, 2026-10-23). |
What it checks
Six checks, run in this order (CHECKS in scripts/freshness_guard.py, read with
the AST toolkit). Each is a (detect, refresh) pair and returns (stale, ok).
| # | Output name | Detects | Refreshes | Founding incident (docstring) |
|---|---|---|---|---|
| 1 | ast-runtime-merge |
plans/ast-ultimate.json has zero runtime_calls entries while plans/runtime-callgraph.json exists |
build_runtime_callgraph.py reaugment in place |
A bare ast-sync dropped every runtime_calls field; derive_rtm fell 1055 → 575 |
| 2 | prolog-kbs |
trace_intel's STRUCTURAL_FACTS / TRACEABILITY_FACTS or .claude/run/codebase_kb/facts.pl missing or older than the snapshot's mtime |
trace_intel.ensure_kb(no_refresh=False), then scripts/code_intel.py reindex (timeout 600 s) only when the code_intel KB was stale |
Stale structural facts made derive_rtm abort |
| 3 | durations-sink |
A record in reports/test-durations.ndjson older than 7 days or naming a deleted test file |
Compact in place | The sink grew to 267 MB / 1.78M lines; ~4.4 s per runner start |
| 4 | observer-registry |
A $XDG_RUNTIME_DIR/orchestrata/pytest-sessions/*.json with status=running whose pid is dead |
Mark it status=killed ("never faked to finished") |
"11 running" with zero live pids |
| 5 | packer-cache |
.cache/test_durations.json keys for modules that no longer exist |
Drop them | Dead entries skewed bin packing |
| 6 | runtime-capture |
plans/runtime-callgraph.json older than 7 days |
Report only — schedule an instrumented run with a per-batch ORCH_RCG_DIR, never a global PYTEST_ADDOPTS |
A global PYTEST_ADDOPTS leaked into nested pytest and broke 6 modules on 2026-08-04 |
Real output, from the passing push of 2026-10-22 (push-item3-retry3.log lines 7–12):
[freshness] ast-runtime-merge: FRESH — runtime_calls present
[freshness] prolog-kbs: FRESH — all KBs newer than snapshot
[freshness] durations-sink: FRESH — 714 records, all current
[freshness] observer-registry: FRESH — no dead-pid running sessions
[freshness] packer-cache: FRESH — 9 entries, all current
[freshness] runtime-capture: FRESH — 0.2 days old
Other statuses the checks print: STALE, REFRESHED, REFRESH-FAILED, SKIP
(for example prolog-kbs: SKIP no snapshot).
Why a run can spend minutes here
Check 2 delegates to scripts/trace_intel.py::ensure_kb, which (read with the AST
toolkit) re-runs extract when the traceability facts are stale, calls
_refresh_snapshot (runs REPO_ROOT/.venv/bin/ast-sync --output-dir .cache/ast
when the source tree is newer than the live snapshot; its docstring measured
"~12s warm"), and reindexes the structural KB from the active snapshot
(.cache/ast/… when present, else plans/ast-ultimate.json).
The coordinator's notes of 2026-10-22 record a "run_tests.py trace_intel
preflight" of 180–234 s after any edit, which killed every 300 s VERIFY that
day. run_tests.py itself has no trace_intel reference (AST source of the
module); freshness_guard.py:153 is a call site of ensure_kb. So that preflight
cost is this guard's check 2. The split of the 180–234 s between extract, ast-sync
and reindex is not measured.
Known gap
IMPROVEMENT-LOG finding F3 (2026-10-22): run_tests.py --affected resolves
import closures from plans/ast-ultimate.json, and after the commit discipline
restored that file to its committed version (which lacked
core/threading/failure_detail.py) the run refused, "and the runner's freshness
guard refreshed the Prolog KBs without noticing the snapshot is missing a src/
file". That matches the code: check 2 compares KB mtimes with the snapshot's
mtime; none of the six checks compares the committed snapshot's module set with
the source tree.
Typical failures and how to fix them
| Symptom | Cause | Fix |
|---|---|---|
Run aborts at stage freshness |
A refresh step exited non-zero (for example prolog-kbs: REFRESH-FAILED <stderr tail> from code_intel.py reindex) |
Run python scripts/freshness_guard.py alone and read the failing line; fix that artifact's generator |
| A 300 s VERIFY budget is gone before tests start | Check 2 rebuilding the trace_intel KBs after an edit (above) | Warm the KBs before a timed run (run the guard once), or budget for it in the brief, as better-briefs memory records |
runtime-capture: STALE |
Capture older than 7 days | Report only; schedule an instrumented suite run. Not a failure |
--affected refuses "outside the serialized import closure" although the guard printed FRESH |
F3: the snapshot lacks a new src/ file |
Re-serialize the snapshot before the run; do not restore plans/ast-ultimate.json between measuring and running (D14 in the IMPROVEMENT-LOG) |