项目文件夹

文件
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

94 行
3.7 KiB
Markdown

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# 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.