Stabilize suggestion acceptance and passive calibration - #7
Conversation
930b34c to
1e29ffc
Compare
There was a problem hiding this comment.
Pull request overview
This PR makes suggestion acceptance deterministic (Tab accepts only the visible completion; boundaries like Space/Enter/punctuation/digits remain typed-word boundaries), adds a fail-isolated passive calibration collector + Phase-A calibration tooling, and introduces privacy-guarded keystroke tracing to diagnose input-path regressions without leaking content by default.
Changes:
- Enforce Tab-only acceptance semantics and harden boundary handling to prevent “display/commit mismatch” and delimiter/preedit races.
- Add passive calibration collection (O1 shim) plus Phase-A harness (logging, validity selection, analysis gate, sweeps/watchdog, reconciliation report) with isolation/guardrails.
- Add keystroke diagnostic tracing (OFF/structural/full) with strict privacy constraints, plus session-scoped ghost rejection memory to suppress repeatedly rejected completions.
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_o1_shim.py | Adds focused tests for the passive calibration collector (DB schema/privacy, kill-switch, failure isolation, adapter integration). |
| tests/test_o1_phasea.py | Adds pytest surface for Phase-A self-tests and key invariants (scope firewall, corpus pinning, guards). |
| tests/conftest.py | Ensures repo root is on sys.path for consistent imports under pytest. |
| smartkey-debug | Adds a small CLI wrapper to launch the keystroke debug tool. |
| shim_report.py | Adds reconciliation reporting that shares the canonical row selector with analysis. |
| phase_a/validity.py | Introduces canonical campaign row selection + exclusion reasons shared across tools. |
| phase_a/sweep.py | Adds daily sweep receipt + watchdog logic for operational gating signals. |
| phase_a/selftest.py | Adds an end-to-end self-test suite for the Phase-A harness and gate reachability. |
| phase_a/paths.py | Adds artifact isolation guardrails and corpus pin verification utilities. |
| phase_a/harness.py | Adds SQLite event logging schema + HMAC context hashing and logger API. |
| phase_a/freqmodel.py | Adds a pure n-gram frequency model used as the measured predictor in Phase-A. |
| phase_a/corpus_replay.py | Adds a corpus-replay driver to generate synthetic calibration events for lab gating. |
| phase_a/constants.py | Defines shared thresholds, scope/firewall lines, and gate constants. |
| phase_a/analyze.py | Adds offline analysis and PASS/FAIL/INCONCLUSIVE gate using isotonic calibration and bucketed scoring. |
| phase_a/init.py | Exposes the Phase-A public surface and documents the measured scope/firewall. |
| ibus/test_smartkey_debug.py | Adds integration and privacy tests for the keystroke trace (OFF/structural/full behavior, guardrails, budgets). |
| ibus/test_rejection_memory_adapter.py | Adds adapter-level tests for session-scoped ghost rejection feedback into core memory. |
| ibus/test_accept_backspace.py | Extends adapter integration tests for backspace forwarding and Tab-only accept/boundary behavior. |
| ibus/smartkey_debug.py | Implements keystroke tracing + CLI with privacy levels, repo-dir refusal, purge/wipe, and deferred flushing. |
| ibus/o1_shim.py | Implements the passive calibration collector with hot-path isolation and background SQLite writing. |
| ibus/main.py | Gates DEBUG logging on SMARTKEY_DEBUG=full to keep structural tracing content-free. |
| crates/smartkey-py/src/lib.rs | Extends PyO3 core surface with O1 snapshot/resolve/abandon + debug state + rejection recording APIs. |
| crates/smartkey-py/Cargo.toml | Bumps PyO3 dependency version for the Python extension. |
| crates/smartkey-core/tests/virtual_typer.rs | Updates tests around BG phonetic mapping expectations (“zdrawej” cases). |
| crates/smartkey-core/src/rejection_memory.rs | Adds bounded, process-local rejection memory with LRU eviction and suppression threshold. |
| crates/smartkey-core/src/o1_shim.rs | Adds Rust-side n-gram-only snapshot implementation with parity tests vs Phase-A model semantics. |
| crates/smartkey-core/src/master_loop.rs | Integrates rejection suppression, ghost attribution, passive calibration plumbing, and debug state wiring. |
| crates/smartkey-core/src/lib.rs | Exposes new o1_shim and rejection_memory modules. |
| crates/smartkey-core/src/keymap.rs | Adjusts BG traditional phonetic mapping and adds targeted regression tests. |
| crates/smartkey-core/src/input.rs | Enforces Tab-only acceptance and removes boundary auto-accept paths; hardens delimiter ordering and ghost behavior. |
| crates/smartkey-core/src/ensemble.rs | Wires engine-level O1 n-gram snapshot helpers for the passive calibration tap. |
| Cargo.lock | Updates dependency lockfile (PyO3/crossbeam/rand). |
| .gitignore | Adds ignore patterns for debug traces and private inputs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Accept the visible ghost completion (shared by Tab and the | ||
| /// Space/Return word-boundary accept). | ||
| /// |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 930b34cc94
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| rows = conn.execute("SELECT sweep_date, watchdog_status FROM sweeps").fetchall() | ||
| swept = {r[0] for r in rows} | ||
| alarm_raised = alarm_file().exists() or any(r[1] == "ALARM" for r in rows) |
There was a problem hiding this comment.
Scope watchdog sweeps to the selected campaign
When real and synthetic data (or two real campaigns) share a DB, this query treats every sweeps row as coverage for the campaign being analyzed. run_sweep(..., synthetic=True) filters its event population but writes an indistinguishable sweep row, and the schema has no run/synthetic field to filter on; therefore synthetic replay sweeps can make a live campaign appear to have zero missed watchdog days and allow a PASS despite no live watchdog execution. Store campaign/scope on sweeps and filter both analysis and watchdog queries by it.
Useful? React with 👍 / 👎.
What changed
!Why
The input path could diverge across clients and, under a stale suggestion race, display or commit text different from the visible candidate. This makes the acceptance contract deterministic and keeps learning/calibration isolated from the typing hot path.
Validation