Adds W1-T: an observational telemetry leaf for idle_tick's learning flywheel,
modeled on core.cognition.leeway (the B4 precedent). Never gates, refuses,
or alters trace_hash.
New core/cognition/backpressure.py:
BackpressureRecord(pending_proposals, candidate_backlog, cap, headroom,
contemplated_this_tick, created_this_tick, at_fixed_point, did_work)
build_backpressure_record(...) — pure function, resolves ADR-0161 cap from
env (CORE_HITL_PENDING_CAP or 256), derives headroom = max(0, cap-pending),
at_fixed_point = (candidate_backlog==0 and created_this_tick==0).
chat/runtime.py:
IdleTickResult gains backpressure: BackpressureRecord | None = None (always
set on a completed tick).
idle_tick builds the record from counts already computed (pending_proposals,
candidate_backlog, contemplated_count, created, did_work) — no new
computation, no serving-path change.
Appends one JSONL line per tick to engine_state/idle_telemetry.jsonl
(best-effort, never crashes the continuous life; accumulates across all
generations so history survives reboot independently of the checkpoint).
tests/test_idle_backpressure_telemetry.py (16 tests):
- field derivation: headroom, cap, at_fixed_point (holds + bites)
- cap resolution: default 256, env override, invalid env fallback
- firewall proof: trace_hash of a served turn is byte-identical whether
idle_tick ran before it or not (the load-bearing invariant)
- integration: record fields on a fresh runtime; telemetry written to
engine_state dir; history accumulates across ticks
All 16 tests pass. ADR-0161 cap and queue_full control logic untouched.
277 lines
9.1 KiB
Python
277 lines
9.1 KiB
Python
"""W1-T — Idle backpressure telemetry tests.
|
|
|
|
Three classes of tests per the brief:
|
|
1. Record fields match the tick's actual counts (unit coverage).
|
|
2. ``trace_hash`` of a served turn is byte-identical with and without the
|
|
backpressure telemetry code active — the load-bearing firewall proof.
|
|
3. ``headroom``/``at_fixed_point`` semantics for backlog-growing vs draining
|
|
ticks.
|
|
|
|
Each numeric predicate has a *_holds test (expected value) and a *_bites test
|
|
(mutation that trips it), per CLAUDE.md schema-as-proof discipline.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
from core.cognition.backpressure import (
|
|
BackpressureRecord,
|
|
_DEFAULT_PENDING_CAP,
|
|
_resolve_cap,
|
|
build_backpressure_record,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Unit tests — build_backpressure_record field derivation
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_fields_match_input_counts():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=10,
|
|
candidate_backlog=5,
|
|
contemplated_this_tick=3,
|
|
created_this_tick=2,
|
|
did_work=True,
|
|
)
|
|
assert rec.pending_proposals == 10
|
|
assert rec.candidate_backlog == 5
|
|
assert rec.contemplated_this_tick == 3
|
|
assert rec.created_this_tick == 2
|
|
assert rec.did_work is True
|
|
|
|
|
|
def test_headroom_derived_from_cap_minus_pending():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=50,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.cap == _DEFAULT_PENDING_CAP # 256 by default
|
|
assert rec.headroom == _DEFAULT_PENDING_CAP - 50
|
|
|
|
|
|
def test_headroom_zero_at_cap_holds():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=_DEFAULT_PENDING_CAP,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.headroom == 0
|
|
|
|
|
|
def test_headroom_clamped_at_zero_when_over_cap():
|
|
# Should not go negative even if somehow over cap.
|
|
rec = build_backpressure_record(
|
|
pending_proposals=_DEFAULT_PENDING_CAP + 10,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.headroom == 0
|
|
|
|
|
|
def test_headroom_zero_bites():
|
|
# A tick with fewer proposals than cap must have positive headroom.
|
|
rec = build_backpressure_record(
|
|
pending_proposals=_DEFAULT_PENDING_CAP - 1,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.headroom > 0, "headroom must be positive when below the cap"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# at_fixed_point semantics
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_at_fixed_point_when_backlog_empty_and_no_creations():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=0,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.at_fixed_point is True
|
|
|
|
|
|
def test_at_fixed_point_false_when_backlog_nonempty():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=0,
|
|
candidate_backlog=3, # candidates still waiting
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.at_fixed_point is False
|
|
|
|
|
|
def test_at_fixed_point_false_when_proposals_created_this_tick():
|
|
rec = build_backpressure_record(
|
|
pending_proposals=2,
|
|
candidate_backlog=0, # backlog now empty...
|
|
contemplated_this_tick=5,
|
|
created_this_tick=2, # ...but this tick created proposals
|
|
did_work=True,
|
|
)
|
|
assert rec.at_fixed_point is False
|
|
|
|
|
|
def test_at_fixed_point_bites_on_nonempty_backlog():
|
|
# at_fixed_point must NOT be True when there are pending candidates.
|
|
rec = build_backpressure_record(
|
|
pending_proposals=0,
|
|
candidate_backlog=1,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert not rec.at_fixed_point, "at_fixed_point must be False with non-empty backlog"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cap resolution
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_default_cap_is_256():
|
|
assert _resolve_cap() == 256
|
|
|
|
|
|
def test_cap_env_override():
|
|
with patch.dict(os.environ, {"CORE_HITL_PENDING_CAP": "64"}):
|
|
rec = build_backpressure_record(
|
|
pending_proposals=0,
|
|
candidate_backlog=0,
|
|
contemplated_this_tick=0,
|
|
created_this_tick=0,
|
|
did_work=False,
|
|
)
|
|
assert rec.cap == 64
|
|
assert rec.headroom == 64
|
|
|
|
|
|
def test_cap_env_invalid_falls_back_to_default():
|
|
with patch.dict(os.environ, {"CORE_HITL_PENDING_CAP": "not_a_number"}):
|
|
assert _resolve_cap() == _DEFAULT_PENDING_CAP
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Firewall proof: idle_tick's backpressure telemetry must not change trace_hash
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_trace_hash_byte_identical_with_backpressure_active(tmp_path: Path):
|
|
"""The serving trace_hash is byte-identical whether idle_tick runs before
|
|
the turn or not.
|
|
|
|
Uses a fresh runtime with default config (all learning passes disabled)
|
|
so idle_tick is a pure no-op except for building the BackpressureRecord.
|
|
If backpressure building or telemetry writing introduces any side effect
|
|
on the serving field state, the trace_hashes will diverge.
|
|
"""
|
|
from chat.runtime import ChatRuntime
|
|
from core.cognition.pipeline import CognitiveTurnPipeline
|
|
from core.config import RuntimeConfig
|
|
|
|
text = "what is truth"
|
|
|
|
# Baseline: fresh runtime, single turn (no idle_tick).
|
|
rt_a = ChatRuntime(
|
|
config=RuntimeConfig(), engine_state_path=tmp_path / "a"
|
|
)
|
|
pipe_a = CognitiveTurnPipeline(runtime=rt_a)
|
|
hash_a = pipe_a.run(text).trace_hash
|
|
|
|
# Firewall: fresh runtime, idle_tick first, THEN same turn.
|
|
# With default config, idle_tick does no learning (all passes off,
|
|
# empty backlog), so the field state entering pipe_b.run is identical.
|
|
rt_b = ChatRuntime(
|
|
config=RuntimeConfig(), engine_state_path=tmp_path / "b"
|
|
)
|
|
pipe_b = CognitiveTurnPipeline(runtime=rt_b)
|
|
tick_result = rt_b.idle_tick()
|
|
|
|
# idle_tick must have built a backpressure record (the new code path).
|
|
assert tick_result.backpressure is not None
|
|
assert isinstance(tick_result.backpressure, BackpressureRecord)
|
|
|
|
hash_b = pipe_b.run(text).trace_hash
|
|
|
|
assert hash_a == hash_b, (
|
|
"Backpressure telemetry in idle_tick must not change the serving trace_hash.\n"
|
|
f" without idle_tick: {hash_a}\n"
|
|
f" with idle_tick: {hash_b}"
|
|
)
|
|
|
|
|
|
def test_idle_tick_backpressure_record_fields_on_fresh_runtime(tmp_path: Path):
|
|
"""On a fresh runtime with no candidates, backpressure reflects zeros."""
|
|
from chat.runtime import ChatRuntime
|
|
from core.config import RuntimeConfig
|
|
|
|
rt = ChatRuntime(config=RuntimeConfig(), engine_state_path=tmp_path / "rt")
|
|
result = rt.idle_tick()
|
|
|
|
bp = result.backpressure
|
|
assert bp is not None
|
|
assert bp.candidate_backlog == 0
|
|
assert bp.pending_proposals == 0
|
|
assert bp.contemplated_this_tick == 0
|
|
assert bp.created_this_tick == 0
|
|
assert bp.did_work is False
|
|
assert bp.at_fixed_point is True
|
|
assert bp.headroom == bp.cap # headroom == cap when pending == 0
|
|
|
|
|
|
def test_idle_telemetry_written_to_engine_state_dir(tmp_path: Path):
|
|
"""One JSONL line is appended to idle_telemetry.jsonl per idle_tick call."""
|
|
from chat.runtime import ChatRuntime
|
|
from core.config import RuntimeConfig
|
|
|
|
engine_dir = tmp_path / "es"
|
|
rt = ChatRuntime(config=RuntimeConfig(), engine_state_path=engine_dir)
|
|
rt.idle_tick()
|
|
|
|
telem = engine_dir / "idle_telemetry.jsonl"
|
|
assert telem.exists(), "idle_telemetry.jsonl must be created in engine_state dir"
|
|
lines = [l for l in telem.read_text(encoding="utf-8").splitlines() if l.strip()]
|
|
assert len(lines) == 1
|
|
|
|
record = json.loads(lines[0])
|
|
assert "pending_proposals" in record
|
|
assert "candidate_backlog" in record
|
|
assert "cap" in record
|
|
assert "headroom" in record
|
|
assert "at_fixed_point" in record
|
|
assert "did_work" in record
|
|
|
|
|
|
def test_idle_telemetry_accumulates_across_ticks(tmp_path: Path):
|
|
"""Each idle_tick appends a new line — history accumulates."""
|
|
from chat.runtime import ChatRuntime
|
|
from core.config import RuntimeConfig
|
|
|
|
engine_dir = tmp_path / "es"
|
|
rt = ChatRuntime(config=RuntimeConfig(), engine_state_path=engine_dir)
|
|
rt.idle_tick()
|
|
rt.idle_tick()
|
|
rt.idle_tick()
|
|
|
|
telem = engine_dir / "idle_telemetry.jsonl"
|
|
lines = [l for l in telem.read_text(encoding="utf-8").splitlines() if l.strip()]
|
|
assert len(lines) == 3, "each idle_tick must append exactly one line"
|