Files
Kigi-CLI/crates/codegen/kigi-pager-pty-harness/src/scroll_matrix/invariants.rs
T
ZacharyZhang-NY d6c20fc13f M0: compilable skeleton — Kigi 0.1.0 fork surgery
Hard fork of xai-org/grok-build (Apache-2.0) re-targeted as Kigi, an
unofficial Kimi Code CLI community build.

Rename & identity
- 72 xai-*/xai-grok-* crates -> kigi-* (explicit: xai-grok-pager-bin ->
  kigi-bin [binary `kigi`], xai-grok-pager -> kigi-tui; rest mechanical);
  ptyctl, ptyctl-cli, third_party/ unchanged; proto package
  xai.grok.tools.v1 -> kigi.tools.v1
- Config home ~/.kigi (KIGI_SHARE_DIR override), env prefix GROK_* ->
  KIGI_*, `kigi --version` carries the unofficial-community-build notice
- clap identity, help text, startup banner, prompt templates rebranded
  (templates re-encrypted)

Deletions (PRD removal list #5/#6/#7/#9/#10)
- voice input (xai-grok-voice) and all TUI wiring
- telemetry: Mixpanel client, external OTel stream, Sentry, OTLP layers,
  trace/GCS/S3 upload queues (kigi-file-utils halved), workspace upload
  module & dc_log, heap-profile uploader, auth-diagnostics uploader,
  session-analytics halves of feedback; local zero-egress observability
  preserved in new kigi-log crate (unified log, --debug firehose,
  subsystem file logs, opt-in instrumentation)
- announcements (crate, remote-settings fields, TUI surfaces)
- plugin marketplace (crate, sources/browse/CTA/extensions-modal tab);
  direct plugin install/uninstall/update via kigi-agent git_install kept
- relay/gateway/assets endpoints and features (agent relay, headless
  relay transport, gateway bridge, LeaderEnvUrls); leader IPC socket now
  ~/.kigi/leader.sock + KIGI_LEADER_SOCKET, no ws-url derivation
- functional types rehomed instead of deleted: PermissionMode ->
  kigi-config-types, McpInitStrategy -> kigi-mcp, PrCreationSource ->
  session signals, TerminalDiagnostics -> kigi-pager-render, agent_id ->
  shell util

Endpoints
- kigi-env rewritten: single production KigiEndpoints {coding_api_base_url
  https://api.kimi.com/coding/v1 (KIGI_CODE_BASE_URL), oauth_host
  https://auth.kimi.com (KIGI_OAUTH_HOST), update_base_url (GitHub
  Releases API), upgrade_page_url}; GrokBuildEnvironment enum deleted

Toolchain & workspace hygiene
- Rust 1.97.0 pinned; edition 2024; full cargo update; git2 hoisted to
  workspace at 0.21 (Option->Result API migration), quick-xml 0.41
- Root Cargo.toml hand-maintained (PRD §8.1): version 0.1.0 inherited by
  all members, members sorted, unused deps pruned
- cargo-deny advisories gate (deny.toml with documented transitive
  exceptions); CI workflow (check/clippy/fmt/deny/test, macOS+Linux)
- cross-crate test seams re-gated behind `test-support` cargo feature;
  insta snapshot baselines renamed to the kigi_tui prefix
- clippy --workspace --all-targets: zero warnings; fmt clean

Fixes surfaced by the port
- updater probe/installer divergence (bin/kigi vs bin/grok symlink set)
- idle model-metadata refresh dead under KIGI_CODE_BASE_URL override
  (new is_effective_coding_endpoint_url, loopback+override aware)
- macOS symlinked-TMPDIR fixture canonicalization (foreign_sessions,
  fast-worktree); RSS measurement tests serialized via serial_test

Docs & legal (Apache §4)
- NOTICE added (upstream attribution + change statement); THIRD-PARTY
  notices sustained; kigi-tools ported-code notices extended; README,
  CONTRIBUTING, SECURITY, AGENTS.md rewritten

Out of scope for M0 (tracked): Kimi auth/inference (M1), search/fetch,
command parity, config import (M2), Computer Hub excision & final
brand-token sweep (M2), distribution & self-update rewrite (M3).
2026-07-17 05:31:01 -04:00

801 lines
32 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! The invariant suite: predicates over grouped `KIGI_SCROLL_LOG` streams.
//!
//! Stall-safety: every timing predicate reads the RECORDER's clock
//! (`ts_ms`, `ms_since_prev_flush`, `avg_interval_ms`), never the test
//! process's — CI load can stretch host-side gesture delays but can only
//! ever *widen* the producer-measured spacings, so no invariant here can
//! false-fail on a loaded machine.
//!
//! Two invariants are declared here but checked by the A13 matrix runner,
//! not this module: [`InvariantId::Screen`] (the viewport visibly
//! moved/clamped — needs `PtyHarness` marker positions) and
//! [`InvariantId::Quiet`] (no repaint churn after finalize — needs the
//! harness frame watermark). They exist in the id enum so cells can declare
//! them and the runner can route by [`InvariantId::is_log_side`];
//! [`check_log_invariant`] panics if asked to evaluate them.
use super::cells::ExpectedProfile;
use super::gestures::{
ACCEL_MIN_INTERVAL_MS, MIN_LINES_PER_WHEEL_STREAM, REDRAW_CADENCE_MS, TRACKPAD_ACCEL_MAX,
};
use super::log::{ScrollLogLine, StreamGroup};
/// Float slack for f32-serialized fields (accel/speed/carry comparisons).
const F32_TOLERANCE: f64 = 0.01;
/// Invariant identifier; `as_str` is the design's I-* vocabulary.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum InvariantId {
/// I-ORD: `ts_ms` is non-decreasing across the capture (flip
/// boundaries legitimately share a timestamp).
Ord,
/// I-CAP: every record's `|flushed| ≤ cap` — the A4 teleport guard.
Cap,
/// I-DROP-EQ: finalize carries `dropped == backlog_after` (the producer
/// constructs it that way; a mismatch is producer drift).
DropEq,
/// I-CADENCE: intra-stream flush spacings ≥ `REDRAW_CADENCE_MS 1` —
/// the A2 busy-spin guard. Skips `promotion`-triggered records (they
/// flush immediately by design) and `finalize` records (the finalize
/// flush deliberately ignores the cadence gate — `finalize_stream_at`
/// in `mouse.rs` — and a flip finalize can land mid-slot; a gap
/// finalize is ≥80ms anyway, so nothing real is lost). The design
/// sketch listed only the promotion skip; the finalize skip is the
/// code-verified correction.
Cadence,
/// I-CONS-W: forced-wheel totals are exact —
/// `|applied+dropped| == trunc(events × wheel_lpt/ept × speed)` ±1,
/// with the `MIN_LINES_PER_WHEEL_STREAM` substitution when the raw
/// pricing truncates to zero. Wheel pricing never includes carry.
ConsW,
/// I-CONS-A: auto/trackpad totals are bounded —
/// per-event pricing lies in `[min(wheel_lpt/ept, tp_lpt/3),
/// max(wheel_lpt/ept, ACCEL_MAX × tp_lpt/3)] × speed` (trackpad divisor
/// is the normalized 3, accel ceiling 3.0 = `trackpad_accel_max`;
/// effective accel tops at 2.5 so the bound is loose-but-sound). Checks
/// the finalize's `desired` within `[lo, hi]` and the delivered
/// `|applied+dropped| ≤ hi`; ±1 slack absorbs carry/trunc.
ConsA,
/// I-ACCEL: `1.0 ≤ accel ≤ 3.0` on every record, and `avg_interval_ms`,
/// when present, is ≥ `ACCEL_MIN_INTERVAL_MS` (6). The G5 clause: even
/// ghostty-style 4ms duplicate reports must never drag the average
/// under 6 — the producer excludes sub-6ms intervals from the window,
/// so a lower value means that artifact guard regressed.
Accel,
/// I-CARRY: `|carry| < 1.0` everywhere (only sub-line remainders ride
/// across streams), and a wheel-kind finalize zeroes it — the NEXT
/// `stream_start` must echo `carry == 0`. The log carries no direction,
/// but the machine zeroes carry at wheel finalize and resets it on
/// direction change, so the next-start check holds for both same- and
/// opposite-direction successors (direction-agnostic strengthening of
/// the design's same-direction phrasing).
Carry,
/// I-CFG: the `stream_start` config echo matches the cell's expected
/// profile (mode/ept/wheel_lpt/trackpad_lpt/invert/speed) — the env →
/// profile plumbing witness.
Cfg,
/// I-MUX-NO-OVER: delivered total per stream ≤ `events × speed + 1` —
/// the conservative remuxed profile (ept=1/wheel_lpt=1) prices at most
/// one line per event. Attach only to accel-free gestures (>20ms
/// spacing — exactly 20ms still interpolates to 1.6× in the accel band;
/// G9's 55ms clears it): a fast trackpad-classified mux stream may
/// legitimately exceed it via accel.
MuxNoOver,
/// I-SMOOTH-COAST: per stream, `Σ|flushed|` over flush-bearing records
/// with `events_since_flush == 0` ≤ cap — motion delivered after input
/// stopped is at most one capped catch-up. The jerk's coast-drain +
/// finalize re-price burst exceeds it (xfail until A13's decel fix).
SmoothCoast,
/// I-NO-DROP: every finalize has `dropped == 0`. Attach to gestures the
/// cap can keep up with; floods legitimately drop.
NoDrop,
/// I-SCREEN (harness-side, A13): viewport marker delta matches the
/// gesture — moved on scroll, clamped at the bottom pin (G7).
Screen,
/// I-QUIET (harness-side, A13): frame watermark stays put after the
/// last finalize — no post-gesture repaint churn (A2's symptom).
Quiet,
}
impl InvariantId {
/// Design vocabulary label.
pub fn as_str(self) -> &'static str {
match self {
InvariantId::Ord => "I-ORD",
InvariantId::Cap => "I-CAP",
InvariantId::DropEq => "I-DROP-EQ",
InvariantId::Cadence => "I-CADENCE",
InvariantId::ConsW => "I-CONS-W",
InvariantId::ConsA => "I-CONS-A",
InvariantId::Accel => "I-ACCEL",
InvariantId::Carry => "I-CARRY",
InvariantId::Cfg => "I-CFG",
InvariantId::MuxNoOver => "I-MUX-NO-OVER",
InvariantId::SmoothCoast => "I-SMOOTH-COAST",
InvariantId::NoDrop => "I-NO-DROP",
InvariantId::Screen => "I-SCREEN",
InvariantId::Quiet => "I-QUIET",
}
}
/// Whether [`check_log_invariant`] can evaluate this id from the log
/// alone. `false` = harness-side (screen/frame state), owned by the
/// A13 runner.
pub fn is_log_side(self) -> bool {
!matches!(self, InvariantId::Screen | InvariantId::Quiet)
}
}
/// Verdict of one invariant over one cell's captured streams.
#[derive(Clone, Debug, PartialEq)]
pub enum InvariantResult {
Pass,
Violated { detail: String },
}
impl InvariantResult {
pub fn is_pass(&self) -> bool {
matches!(self, InvariantResult::Pass)
}
}
fn violated(detail: String) -> InvariantResult {
InvariantResult::Violated { detail }
}
/// All records of all groups, in capture order.
fn records<'a>(groups: &'a [StreamGroup<'a>]) -> impl Iterator<Item = &'a ScrollLogLine> {
groups.iter().flat_map(|g| {
std::iter::once(g.start)
.chain(g.flushes.iter().copied())
.chain(g.finalize)
})
}
/// Signed delivered total of a finalized stream: applied + discarded.
fn delivered(finalize: &ScrollLogLine) -> i64 {
finalize.applied_total + finalize.dropped.unwrap_or(0)
}
/// Evaluate one log-side invariant. Panics on harness-side ids
/// ([`InvariantId::is_log_side`] == false) — routing those here is a
/// runner bug, not a cell verdict.
pub fn check_log_invariant(
id: InvariantId,
expected: &ExpectedProfile,
groups: &[StreamGroup<'_>],
) -> InvariantResult {
match id {
InvariantId::Ord => check_ord(groups),
InvariantId::Cap => check_cap(groups),
InvariantId::DropEq => check_drop_eq(groups),
InvariantId::Cadence => check_cadence(groups),
InvariantId::ConsW => check_cons_w(expected, groups),
InvariantId::ConsA => check_cons_a(expected, groups),
InvariantId::Accel => check_accel(groups),
InvariantId::Carry => check_carry(groups),
InvariantId::Cfg => check_cfg(expected, groups),
InvariantId::MuxNoOver => check_mux_no_over(expected, groups),
InvariantId::SmoothCoast => check_smooth_coast(groups),
InvariantId::NoDrop => check_no_drop(groups),
InvariantId::Screen | InvariantId::Quiet => panic!(
"{} is harness-side (needs PtyHarness screen/frame state); the A13 matrix \
runner checks it — route by InvariantId::is_log_side",
id.as_str()
),
}
}
fn check_ord(groups: &[StreamGroup<'_>]) -> InvariantResult {
let mut prev = f64::NEG_INFINITY;
for rec in records(groups) {
if rec.ts_ms < prev {
return violated(format!(
"ts_ms went backwards: {} after {prev} ({} record)",
rec.ts_ms, rec.evt
));
}
prev = rec.ts_ms;
}
InvariantResult::Pass
}
fn check_cap(groups: &[StreamGroup<'_>]) -> InvariantResult {
for rec in records(groups) {
if rec.flushed.abs() > rec.cap {
return violated(format!(
"flushed {} exceeds cap {} at ts_ms={} (trigger {})",
rec.flushed, rec.cap, rec.ts_ms, rec.trigger
));
}
}
InvariantResult::Pass
}
fn check_drop_eq(groups: &[StreamGroup<'_>]) -> InvariantResult {
for group in groups {
let Some(fin) = group.finalize else { continue };
match fin.dropped {
Some(dropped) if dropped == fin.backlog_after => {}
Some(dropped) => {
return violated(format!(
"finalize at ts_ms={} has dropped={dropped} but backlog_after={}",
fin.ts_ms, fin.backlog_after
));
}
None => {
return violated(format!("finalize at ts_ms={} lacks dropped", fin.ts_ms));
}
}
}
InvariantResult::Pass
}
fn check_cadence(groups: &[StreamGroup<'_>]) -> InvariantResult {
// A stream's first flush-bearing record is skipped: its spacing is
// global (measured from the previous stream — see
// `intra_stream_flush_spacings_ms`).
let floor = (REDRAW_CADENCE_MS - 1) as f64;
for group in groups {
for rec in group.flush_bearing().skip(1) {
if rec.trigger == "promotion" || rec.trigger == "finalize" {
continue;
}
if let Some(spacing) = rec.ms_since_prev_flush
&& spacing < floor
{
return violated(format!(
"{}ms flush spacing < {floor}ms at ts_ms={} (trigger {})",
spacing, rec.ts_ms, rec.trigger
));
}
}
}
InvariantResult::Pass
}
fn check_cons_w(expected: &ExpectedProfile, groups: &[StreamGroup<'_>]) -> InvariantResult {
if expected.mode != "wheel" {
return violated(format!(
"I-CONS-W attached to a mode={} cell (needs forced wheel)",
expected.mode
));
}
let rate = f64::from(expected.wheel_lpt) / f64::from(expected.ept.max(1));
for group in groups {
let Some(fin) = group.finalize else { continue };
let raw = (fin.events_total as f64 * rate * f64::from(expected.speed)).trunc() as i64;
let want = if fin.events_total > 0 {
raw.max(MIN_LINES_PER_WHEEL_STREAM)
} else {
0
};
let got = delivered(fin).abs();
if (got - want).abs() > 1 {
return violated(format!(
"wheel stream at ts_ms={}: delivered {got} lines for {} events, expected {want}±1",
fin.ts_ms, fin.events_total
));
}
}
InvariantResult::Pass
}
fn check_cons_a(expected: &ExpectedProfile, groups: &[StreamGroup<'_>]) -> InvariantResult {
if expected.mode == "wheel" {
return violated("I-CONS-A attached to a forced-wheel cell (use I-CONS-W)".into());
}
let wheel_rate = f64::from(expected.wheel_lpt) / f64::from(expected.ept.max(1));
let tp_rate = f64::from(expected.trackpad_lpt) / 3.0;
// Forced trackpad never prices via the wheel table.
let (min_rate, max_rate) = if expected.mode == "trackpad" {
(tp_rate, TRACKPAD_ACCEL_MAX * tp_rate)
} else {
(
wheel_rate.min(tp_rate),
wheel_rate.max(TRACKPAD_ACCEL_MAX * tp_rate),
)
};
for group in groups {
let Some(fin) = group.finalize else { continue };
let events = fin.events_total as f64;
let speed = f64::from(expected.speed);
let lo = events * min_rate * speed - 1.0;
let hi = events * max_rate * speed + 1.0;
let desired = f64::from(fin.desired).abs();
if desired < lo || desired > hi {
return violated(format!(
"stream at ts_ms={}: |desired|={desired:.2} outside [{lo:.2}, {hi:.2}] \
for {} events",
fin.ts_ms, fin.events_total
));
}
let got = delivered(fin).abs() as f64;
if got > hi {
return violated(format!(
"stream at ts_ms={}: delivered {got} lines > bound {hi:.2} for {} events",
fin.ts_ms, fin.events_total
));
}
}
InvariantResult::Pass
}
fn check_accel(groups: &[StreamGroup<'_>]) -> InvariantResult {
for rec in records(groups) {
let accel = f64::from(rec.accel);
if !(1.0 - F32_TOLERANCE..=TRACKPAD_ACCEL_MAX + F32_TOLERANCE).contains(&accel) {
return violated(format!(
"accel {accel} outside [1.0, {TRACKPAD_ACCEL_MAX}] at ts_ms={}",
rec.ts_ms
));
}
if let Some(avg) = rec.avg_interval_ms
&& avg < ACCEL_MIN_INTERVAL_MS - F32_TOLERANCE
{
return violated(format!(
"avg_interval_ms {avg} < 6 at ts_ms={} — sub-6ms batching artifacts \
(ghostty dups) leaked into the interval window",
rec.ts_ms
));
}
}
InvariantResult::Pass
}
fn check_carry(groups: &[StreamGroup<'_>]) -> InvariantResult {
for rec in records(groups) {
if f64::from(rec.carry).abs() >= 1.0 {
return violated(format!(
"|carry| {} ≥ 1.0 at ts_ms={} — whole lines leaked across streams",
rec.carry, rec.ts_ms
));
}
}
for pair in groups.windows(2) {
let Some(fin) = pair[0].finalize else {
continue;
};
if fin.kind == "wheel" && f64::from(pair[1].start.carry).abs() > F32_TOLERANCE {
return violated(format!(
"stream_start at ts_ms={} carries {} after a wheel finalize (must be 0)",
pair[1].start.ts_ms, pair[1].start.carry
));
}
}
InvariantResult::Pass
}
fn check_cfg(expected: &ExpectedProfile, groups: &[StreamGroup<'_>]) -> InvariantResult {
for group in groups {
let start = group.start;
let echo = (
start.mode.as_deref(),
start.ept,
start.wheel_lpt,
start.trackpad_lpt,
start.invert,
);
let want = (
Some(expected.mode),
Some(expected.ept),
Some(expected.wheel_lpt),
Some(expected.trackpad_lpt),
Some(expected.invert),
);
let speed_ok = start
.speed
.is_some_and(|s| (f64::from(s) - f64::from(expected.speed)).abs() <= F32_TOLERANCE);
if echo != want || !speed_ok {
return violated(format!(
"config echo at ts_ms={} is {:?} speed={:?}, cell expects \
mode={} ept={} wheel_lpt={} trackpad_lpt={} invert={} speed={}",
start.ts_ms,
echo,
start.speed,
expected.mode,
expected.ept,
expected.wheel_lpt,
expected.trackpad_lpt,
expected.invert,
expected.speed,
));
}
}
InvariantResult::Pass
}
fn check_mux_no_over(expected: &ExpectedProfile, groups: &[StreamGroup<'_>]) -> InvariantResult {
for group in groups {
let Some(fin) = group.finalize else { continue };
let bound = fin.events_total as f64 * f64::from(expected.speed) + 1.0;
let got = delivered(fin).abs() as f64;
if got > bound {
return violated(format!(
"remuxed stream at ts_ms={}: delivered {got} lines for {} events \
(> {bound:.2} — over-scroll on the conservative mux profile)",
fin.ts_ms, fin.events_total
));
}
}
InvariantResult::Pass
}
fn check_smooth_coast(groups: &[StreamGroup<'_>]) -> InvariantResult {
for group in groups {
let coast: i64 = group
.flush_bearing()
.filter(|rec| rec.events_since_flush == 0)
.map(|rec| rec.flushed.abs())
.sum();
let cap = group
.flush_bearing()
.map(|rec| rec.cap)
.max()
.unwrap_or(i64::MAX);
if coast > cap {
return violated(format!(
"stream at ts_ms={}: {coast} coast lines (flushes with no new events) \
> cap {cap} — post-input motion beyond one capped catch-up (the jerk)",
group.start.ts_ms
));
}
}
InvariantResult::Pass
}
fn check_no_drop(groups: &[StreamGroup<'_>]) -> InvariantResult {
for group in groups {
let Some(fin) = group.finalize else { continue };
let dropped = fin.dropped.unwrap_or(0);
if dropped != 0 {
return violated(format!(
"finalize at ts_ms={} dropped {dropped} lines",
fin.ts_ms
));
}
}
InvariantResult::Pass
}
#[cfg(test)]
mod tests {
use super::super::log::{group_streams, parse_jsonl_str};
use super::*;
// ── JSONL fixture builders ─────────────────────────────────────────
// Raw strings through parse_jsonl_str so every fixture also exercises
// the wire schema (same stance as log.rs's producer-shaped constants).
const C1: ExpectedProfile = ExpectedProfile {
mode: "auto",
ept: 3,
wheel_lpt: 3,
trackpad_lpt: 3,
invert: false,
speed: 1.0,
};
const C1_WHEEL: ExpectedProfile = ExpectedProfile {
mode: "wheel",
..C1
};
// Floats are formatted with `{:?}` so whole values keep their decimal
// point (`32.0`, not `32`) — the mutation `.replace()`s below match on
// that spelling, and it mirrors serde_json's f64 output for round
// numbers.
fn start(ts: f64, carry: f32, mode: &str, speed: f32) -> String {
format!(
r#"{{"ts_ms":{ts:?},"evt":"stream_start","trigger":"event","kind":"unknown","events_total":0,"events_since_flush":0,"accel":1.0,"desired":0.0,"applied_total":0,"flushed":0,"backlog_after":0,"carry":{carry:?},"cap":25,"mode":"{mode}","ept":3,"wheel_lpt":3,"trackpad_lpt":3,"invert":false,"speed":{speed:?},"viewport_height":50}}"#
)
}
#[allow(clippy::too_many_arguments)]
fn row(
evt: &str,
ts: f64,
trigger: &str,
kind: &str,
events: (u64, u64),
accel_avg: (f32, Option<f64>),
lines: (f32, i64, i64, i64), // desired, applied_total, flushed, backlog_after
msf: Option<f64>,
dropped: Option<i64>,
) -> String {
let avg = accel_avg
.1
.map_or(String::new(), |v| format!(r#""avg_interval_ms":{v:?},"#));
let msf = msf.map_or(String::new(), |v| {
format!(r#","ms_since_prev_flush":{v:?}"#)
});
let dropped = dropped.map_or(String::new(), |v| format!(r#","dropped":{v}"#));
format!(
r#"{{"ts_ms":{ts:?},"evt":"{evt}","trigger":"{trigger}","kind":"{kind}","events_total":{},"events_since_flush":{},{avg}"accel":{:?},"desired":{:?},"applied_total":{},"flushed":{},"backlog_after":{},"carry":0.0,"cap":25{msf}{dropped}}}"#,
events.0, events.1, accel_avg.0, lines.0, lines.1, lines.2, lines.3,
)
}
fn check(id: InvariantId, expected: &ExpectedProfile, jsonl: &[String]) -> InvariantResult {
let raw = jsonl.join("\n");
let records = parse_jsonl_str(&raw).expect("fixture must parse");
let groups = group_streams(&records).expect("fixture must group");
check_log_invariant(id, expected, &groups)
}
fn assert_violated(result: InvariantResult, needle: &str) {
match result {
InvariantResult::Violated { detail } => {
assert!(
detail.contains(needle),
"detail {detail:?} lacks {needle:?}"
);
}
InvariantResult::Pass => panic!("expected violation mentioning {needle:?}"),
}
}
/// Canonical clean capture: a trackpad stream (sub-line carry out), a
/// wheel stream (carry zeroed), a third stream echoing that zero.
/// One record per line (rustfmt::skip) — reads like the JSONL it builds.
#[rustfmt::skip]
fn canonical() -> Vec<String> {
vec![
start(0.0, 0.0, "auto", 1.0),
row("flush", 16.0, "event", "trackpad", (6, 6), (1.0, Some(10.0)), (6.4, 6, 6, 0), None, None),
row("flush", 32.0, "tick", "trackpad", (9, 3), (1.0, Some(10.0)), (9.4, 9, 3, 0), Some(16.0), None),
row("finalize", 120.0, "finalize", "trackpad", (9, 0), (1.0, Some(10.0)), (9.4, 9, 0, 0), Some(88.0), Some(0)),
start(500.0, 0.4, "auto", 1.0),
row("flush", 505.0, "promotion", "wheel", (3, 3), (1.0, None), (3.0, 3, 3, 0), Some(385.0), None),
row("finalize", 600.0, "finalize", "wheel", (3, 0), (1.0, None), (3.0, 3, 0, 0), Some(95.0), Some(0)),
start(700.0, 0.0, "auto", 1.0),
row("flush", 716.0, "event", "unknown", (6, 6), (1.0, Some(8.0)), (6.2, 6, 6, 0), Some(116.0), None),
row("finalize", 800.0, "finalize", "trackpad", (6, 0), (1.0, Some(8.0)), (6.2, 6, 0, 0), Some(84.0), Some(0)),
]
}
/// The real G4 signature: coast drain + finalize re-price burst with a
/// drop — mid-stream priced as unknown (~1 line/event), re-priced ×2.5
/// at the trackpad finalize, backlog beyond one capped flush discarded.
#[rustfmt::skip]
fn jerk() -> Vec<String> {
vec![
start(0.0, 0.0, "auto", 1.0),
row("flush", 16.0, "event", "unknown", (40, 40), (2.5, Some(6.0)), (40.0, 25, 25, 15), None, None),
row("flush", 32.0, "tick", "unknown", (66, 26), (2.5, Some(6.0)), (66.0, 50, 25, 16), Some(16.0), None),
row("flush", 48.0, "tick", "unknown", (66, 0), (2.5, Some(6.0)), (66.0, 66, 16, 0), Some(16.0), None),
row("finalize", 146.0, "finalize", "trackpad", (66, 0), (2.5, Some(6.0)), (165.0, 91, 25, 74), Some(98.0), Some(74)),
]
}
#[test]
fn every_log_side_invariant_passes_on_the_canonical_capture() {
// All log-side ids except I-CONS-W, which requires a forced-wheel
// profile and has its own pass fixture.
let fixture = canonical();
for id in [
InvariantId::Ord,
InvariantId::Cap,
InvariantId::DropEq,
InvariantId::Cadence,
InvariantId::ConsA,
InvariantId::Accel,
InvariantId::Carry,
InvariantId::Cfg,
InvariantId::MuxNoOver,
InvariantId::SmoothCoast,
InvariantId::NoDrop,
] {
let result = check(id, &C1, &fixture);
assert!(result.is_pass(), "{} on canonical: {result:?}", id.as_str());
}
}
#[test]
fn ord_rejects_backwards_timestamps() {
let mut fixture = canonical();
fixture[2] = fixture[2].replace(r#""ts_ms":32.0"#, r#""ts_ms":12.0"#);
assert_violated(check(InvariantId::Ord, &C1, &fixture), "backwards");
}
/// A4 teleport: one flush delivering more than the per-flush cap.
#[test]
fn cap_rejects_over_cap_flush() {
let mut fixture = canonical();
fixture[1] = fixture[1].replace(r#""flushed":6"#, r#""flushed":40"#);
assert_violated(check(InvariantId::Cap, &C1, &fixture), "exceeds cap");
}
#[test]
fn drop_eq_rejects_mismatched_finalize_accounting() {
let mut fixture = canonical();
fixture[3] = fixture[3].replace(r#""backlog_after":0,"#, r#""backlog_after":9,"#);
fixture[3] = fixture[3].replace(r#""dropped":0"#, r#""dropped":5"#);
assert_violated(check(InvariantId::DropEq, &C1, &fixture), "dropped=5");
}
/// A2 busy-spin: an 8ms tick-flush spacing violates; the same spacing on
/// a promotion-triggered record is skipped (promotion flushes bypass the
/// cadence gate by design), as are finalize records (flip finalizes).
#[test]
fn cadence_rejects_sub_16ms_spacing_but_skips_promotion_and_finalize() {
let mut fixture = canonical();
fixture[2] = fixture[2].replace(
r#""ms_since_prev_flush":16.0"#,
r#""ms_since_prev_flush":8.0"#,
);
assert_violated(check(InvariantId::Cadence, &C1, &fixture), "8ms");
let mut skipped = canonical();
skipped[2] = skipped[2]
.replace(r#""trigger":"tick""#, r#""trigger":"promotion""#)
.replace(
r#""ms_since_prev_flush":16.0"#,
r#""ms_since_prev_flush":8.0"#,
);
// Flip-style finalize 8ms after the previous flush: also skipped.
skipped[3] = skipped[3].replace(
r#""ms_since_prev_flush":88.0"#,
r#""ms_since_prev_flush":8.0"#,
);
assert!(check(InvariantId::Cadence, &C1, &skipped).is_pass());
}
/// A3 under-travel: a forced-wheel stream delivering two lines short.
#[test]
fn cons_w_exact_totals_with_min_lines_substitution() {
// 6 events × (3/3) × 1.0 = 6 lines, delivered exactly; a second
// 1-event stream prices to 1.0 → still ≥ the MIN_LINES floor.
#[rustfmt::skip]
let pass = vec![
start(0.0, 0.0, "wheel", 1.0),
row("flush", 16.0, "event", "wheel", (6, 6), (1.0, None), (6.0, 6, 6, 0), None, None),
row("finalize", 100.0, "finalize", "wheel", (6, 0), (1.0, None), (6.0, 6, 0, 0), Some(84.0), Some(0)),
start(300.0, 0.0, "wheel", 1.0),
row("finalize", 400.0, "finalize", "wheel", (1, 1), (1.0, None), (1.0, 1, 1, 0), Some(300.0), Some(0)),
];
assert!(check(InvariantId::ConsW, &C1_WHEEL, &pass).is_pass());
let mut short = pass.clone();
short[1] = short[1].replace(
r#""applied_total":6,"flushed":6"#,
r#""applied_total":4,"flushed":4"#,
);
short[2] = short[2].replace(r#""applied_total":6"#, r#""applied_total":4"#);
assert_violated(check(InvariantId::ConsW, &C1_WHEEL, &short), "expected 6±1");
// Attached to a non-wheel cell = cell-table bug, not a pass.
assert_violated(check(InvariantId::ConsW, &C1, &pass), "needs forced wheel");
}
#[test]
fn cons_a_bounds_auto_totals() {
// 3 events on the C1 profile can never desire 100 lines
// (hi = 3 × max(1, 3×1) × 1 + 1 = 10).
let mut fixture = canonical();
fixture[6] = fixture[6].replace(r#""desired":3.0"#, r#""desired":100.0"#);
assert_violated(check(InvariantId::ConsA, &C1, &fixture), "outside");
assert_violated(
check(InvariantId::ConsA, &C1_WHEEL, &canonical()),
"use I-CONS-W",
);
}
/// G5 clause: a sub-6ms average means ghostty-style duplicate reports
/// leaked into the interval window; out-of-range accel is the same
/// regression on the multiplier side.
#[test]
fn accel_rejects_out_of_band_multiplier_and_sub_6ms_average() {
let mut fixture = canonical();
fixture[1] = fixture[1].replace(r#""accel":1.0"#, r#""accel":4.5"#);
assert_violated(check(InvariantId::Accel, &C1, &fixture), "accel 4.5");
let mut dup = canonical();
dup[1] = dup[1].replace(r#""avg_interval_ms":10.0"#, r#""avg_interval_ms":3.0"#);
assert_violated(check(InvariantId::Accel, &C1, &dup), "interval window");
}
#[test]
fn carry_rejects_whole_line_carry_and_nonzero_start_after_wheel_finalize() {
let mut fixture = canonical();
fixture[4] = start(500.0, 1.4, "auto", 1.0);
assert_violated(check(InvariantId::Carry, &C1, &fixture), "≥ 1.0");
// Wheel finalize (stream 2) must zero the carry into stream 3.
let mut leak = canonical();
leak[7] = start(700.0, 0.4, "auto", 1.0);
assert_violated(check(InvariantId::Carry, &C1, &leak), "wheel finalize");
}
#[test]
fn cfg_rejects_echo_profile_mismatch() {
assert!(check(InvariantId::Cfg, &C1, &canonical()).is_pass());
let mut fixture = canonical();
fixture[0] = start(0.0, 0.0, "auto", 6.0); // speed echo ≠ expected 1.0
assert_violated(check(InvariantId::Cfg, &C1, &fixture), "speed");
let expected_wheel = ExpectedProfile {
mode: "wheel",
..C1
};
assert_violated(
check(InvariantId::Cfg, &expected_wheel, &canonical()),
"mode",
);
}
/// A4-class over-scroll on the conservative remuxed profile: more
/// delivered lines than events at speed 1.0.
#[test]
fn mux_no_over_rejects_over_delivery() {
let mut fixture = canonical();
fixture[3] = fixture[3].replace(r#""applied_total":9"#, r#""applied_total":20"#);
// Keep DropEq-independent: only this invariant is under test.
assert_violated(check(InvariantId::MuxNoOver, &C1, &fixture), "over-scroll");
}
/// The jerk fixture violates exactly the two xfail invariants of
/// `c1_auto_g4_jerk_xfail` — and nothing else in the core suite, which
/// is what confines the expected failure to those rows.
#[test]
fn jerk_shape_violates_smooth_coast_and_no_drop_only() {
let fixture = jerk();
assert_violated(check(InvariantId::SmoothCoast, &C1, &fixture), "coast");
assert_violated(check(InvariantId::NoDrop, &C1, &fixture), "dropped 74");
for id in [
InvariantId::Ord,
InvariantId::Cap,
InvariantId::DropEq,
InvariantId::Cadence,
InvariantId::ConsA,
InvariantId::Accel,
InvariantId::Carry,
InvariantId::Cfg,
] {
let result = check(id, &C1, &fixture);
assert!(result.is_pass(), "{} on jerk: {result:?}", id.as_str());
}
}
/// One capped catch-up flush after input stops is legitimate (that is
/// the finalize contract) — coast ≤ cap passes.
#[test]
fn smooth_coast_allows_a_single_capped_catchup() {
#[rustfmt::skip]
let fixture = vec![
start(0.0, 0.0, "auto", 1.0),
row("flush", 16.0, "event", "unknown", (30, 30), (1.0, Some(6.0)), (30.0, 25, 25, 5), None, None),
row("finalize", 100.0, "finalize", "trackpad", (30, 0), (1.0, Some(6.0)), (30.0, 30, 5, 0), Some(84.0), Some(0)),
];
assert!(check(InvariantId::SmoothCoast, &C1, &fixture).is_pass());
assert!(check(InvariantId::NoDrop, &C1, &fixture).is_pass());
}
#[test]
#[should_panic(expected = "harness-side")]
fn harness_side_ids_panic_in_the_log_checker() {
let _ = check_log_invariant(InvariantId::Screen, &C1, &[]);
}
#[test]
fn log_side_partition_matches_the_a13_split() {
for id in [InvariantId::Screen, InvariantId::Quiet] {
assert!(!id.is_log_side(), "{}", id.as_str());
}
for id in [
InvariantId::Ord,
InvariantId::Cap,
InvariantId::DropEq,
InvariantId::Cadence,
InvariantId::ConsW,
InvariantId::ConsA,
InvariantId::Accel,
InvariantId::Carry,
InvariantId::Cfg,
InvariantId::MuxNoOver,
InvariantId::SmoothCoast,
InvariantId::NoDrop,
] {
assert!(id.is_log_side(), "{}", id.as_str());
}
}
}