Files
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

3.7 KiB
Raw Permalink Blame History

Quality Loop v1 — Edit-Outcome Feedback into Mode Selection

Status: experimental (GL #494) Owner: core engine Consumers: auto_mode_resolver, ctx_edit, ctx_metrics

Problem

BounceTracker and path_mode_memory close the feedback loop for re-read bounces (compressed read → full re-read), but an edit that fails because the file was last read in a compressed mode taught the system nothing: the agent quoted an old_string from a map/signatures rendering whose body was never in context, the edit missed, and the next read of a similar file was compressed exactly the same way.

Signals

Edit outcomes are recorded by ctx_edit (both the MCP tool and the in-process tools::ctx_edit::handle path) via core::edit_quality::record_edit_outcome, keyed by the mode of the last lean-ctx read of that file (session cache last_mode). Only two outcomes carry signal:

Outcome Condition Recorded as
Success replacement applied (CacheEffect::Invalidate) success for (ext, last_mode)
Compression-correlated failure old_string not found (auto-escalation CacheEffect::StoreFull, or plain miss after a full read as baseline) failure for (ext, last_mode)

Explicitly not recorded (no compression signal): create=true, empty or identical old_string/new_string, preimage/TOCTOU mismatches, missing files, already-applied edits, and files never read through lean-ctx (last_mode empty).

Feedback rules

1. Per-path one-shot escalation

A compression-correlated failure (last mode ≠ full) arms a pending escalation for that path. The next mode=auto resolution of the same path returns full (resolver source: edit_fail_escalation), then the escalation is consumed. Pending escalations expire after 1 hour.

This complements the immediate in-response escalation that ctx_edit already appends (full content in the error message): the in-response copy serves the retry, the pending escalation serves the next independent read.

2. Per-(extension × mode) risky penalty

Aggregated per (file extension, read mode) pair with hysteresis:

fail_rate = fails / (fails + successes)

enter risky:  fails >= 2  AND  fail_rate >= 0.25
exit  risky:  fail_rate < 0.15

While a pair is risky, mode=auto resolutions that would pick that mode for that file type return full instead (resolver source: edit_quality_penalty). The two thresholds prevent flapping: a single lucky edit cannot immediately re-enable a mode that keeps breaking edits.

The penalty is per extension, never global: rs|map being risky does not affect py|map or rs|signatures.

Persistence

~/.lean-ctx/edit_quality.json (respects LEAN_CTX_DATA_DIR), atomic tmp+rename writes, flushed every 10 recordings and on server shutdown.

Bounds:

Limit Value
Pair decay (no failure) 30 days
Escalation TTL 1 hour
Max pairs 200 (oldest-failure evicted)
Max pending escalations 100 (oldest evicted)

Observability

ctx_metrics prints an Edit quality (compression-correlated) section: per pair fails/successes/fail-rate, the [risky -> full] marker, plus served and pending escalation counts. Auto-mode resolutions show up in the existing Auto-mode sources line as edit_fail_escalation and edit_quality_penalty.

Invariants

  • Recording an outcome never blocks an edit: store access is lock-guarded and failures to lock are silently skipped.
  • The penalty only ever escalates toward full; it never picks a lossier mode than the resolver would have chosen.
  • No regression of bounce semantics: BounceTracker / path_mode_memory remain independent signals evaluated before the quality loop's penalty.