Lesson Trust Semantics¶
MisakaNet 的信任模型和证据等级
一句话定位¶
MisakaNet is a Git-backed failure-memory layer for AI coding agents.
不是通用记忆系统,不是 Agent runtime,不是向量数据库。 是专注、轻量、可审计的失败恢复知识层。
反 RAG 立场¶
MisakaNet is NOT a RAG system.
| RAG 系统 | MisakaNet |
|---|---|
| 向量嵌入 + 语义搜索 | BM25 关键词搜索 |
| 需要嵌入模型 | 纯标准库(无第三方包) |
| 云服务 | 本地运行 |
| 黑盒检索 | 可审计的搜索结果 |
为什么选择 BM25 而不是 RAG?
- 纯标准库(无第三方包): 无需安装嵌入模型(通常 2GB+)
- 可审计: 搜索结果完全可预测
- 本地运行: 无需云服务,无需网络
- 快速: 毫秒级响应
- 足够好: 对于 failure recovery,关键词搜索已经足够
信任级别¶
MisakaNet uses three trust levels for lessons. These terms are used consistently across README, site, and generated data.
Definitions¶
| Term | Meaning | Quality gate |
|---|---|---|
| indexed | In the search index. May be draft, published, or contrib. | quality_scorer ≥ 0 |
| published | Approved and visible. Passes quality gate. | quality_scorer ≥ 75 |
| verified | Fact-checked against original source material. Rare. | manual review + source link |
Usage¶
- README / public site: Use "indexed" when counting total lessons.
- ✅ "249 indexed failure-recovery lessons"
-
❌ "249 verified failure lessons" (unless all 249 have been fact-checked)
-
Lesson frontmatter:
statususes one ofactive,archived,draft,published,stale,superseded. That set is not a convention — it is the onescripts/lesson_gate.pyenforces (VALID_STATUS), the onescripts/queue_lesson.py --statusoffers, and the onelessons/TEMPLATE.mddocuments. Adding a status means changingVALID_STATUS, not just a doc. - Only
publishedis indexed:is_published_status()is a strict comparison, so the other five are excluded from the sitemap and from search weighting. They still get a page, rendered with a "not published" banner — never silently treated as published. -
publishedmeans it passed the quality gate, not that it was manually verified. -
Contrib lessons: Start as
draft, becomepublishedafter quality_scorer ≥ 75. -
Core lessons: Are
publishedby default (maintainer-curated).
Why this matters¶
Claiming "verified" when lessons are only "indexed" erodes trust when a lesson turns out to be wrong. Use "indexed" for scale claims, "verified" only for fact-checked content.
Evidence levels E0–E4 (Issue #786)¶
status answers "is this published?". evidence_level answers the harder question: how reliable is this lesson? Without it, a contributor's self-reported guess and a CI-verified fix are indistinguishable in search results.
| Level | Meaning | How it is achieved | Weight |
|---|---|---|---|
| E0 | Contributor self-reported | Default on intake | 0.00 |
| E1 | Maintainer reviewed | A maintainer accepted the intake | 0.25 |
| E2 | Local smoke reproduced | Maintainer or CI reproduced the fix | 0.50 |
| E3 | Sandbox / CI verified recovery | Automated verification in CI | 0.75 |
| E4 | Reused by distinct clients (observed) | Two or more distinct clients actually retrieved the lesson (COUNT(DISTINCT client_hint) over search_signals) |
1.00 |
Rules¶
- Default is E0. A missing, empty, malformed, or unknown
evidence_levelreads as E0 everywhere — evidence is never assumed.scripts/queue_lesson.pywrites"evidence_level": "E0"on new lessons. - One step at a time. Promotion is E0 → E1 → E2 → E3 → E4; skipping levels means the intermediate evidence was never produced.
-
Evidence is not writing quality. A beautifully written but unreproduced lesson is still E0.
-
E4 is the one rung nobody can write, vote, or merge a lesson into. It reads an observation from the transport layer, so it is the only level not produced by editing a file.
scripts/infer_evidence_level.pytherefore never infers it (see below), and theE3 → E4row above is the only way up.
Promotion rules¶
| From | To | What has to happen |
|---|---|---|
| E0 | E1 | A maintainer reviews the lesson and accepts it (review) |
| E1 | E2 | Someone reproduces the failure and the fix locally (reproduce) |
| E2 | E3 | CI or a sandbox run verifies the recovery automatically (CI verify) |
| E3 | E4 | Two or more distinct clients are observed retrieving the lesson (observed reuse) |
To promote a lesson through E1–E3, edit evidence_level in its frontmatter in the same PR that carries the evidence (review comment, reproduction log, or CI run link). E4 is not edited into a file: it is counted from search_signals by the worker, and a lesson that declares E4 in frontmatter without that observation is claiming something no file can establish.
What the corpus actually looks like¶
backlog-and-growth-2026-09-20.md §3.9 asked for this distribution before any talk of an
"E0/E1 downgrade after six months without reuse" mechanism — a downgrade rule written without the
number is a guess. Generated by python3 scripts/evidence_distribution.py; --check FILE fails
when the committed table stops matching the corpus, so it cannot rot the way a hand-written figure does.
| Level | Lessons | Share |
|---|---|---|
| E0 | 62 | 6.7% |
| E1 (declared) | 443 | 47.8% |
| E2 (declared) | 92 | 9.9% |
| E3 (declared) | 16 | 1.7% |
| E4 (declared) | 0 | 0.0% |
- Total lessons: 926
- At E0 in total (declared + default): 375 (40.5%) — of which 313 declare no level at all
- At E4 (observed reuse by two or more distinct clients): 0
Three things this says that the definitions above do not:
- Most lessons never declare a level — the count is the "declare no level at all" figure in the block above, and it is generated, not typed. They read as E0 by the default rule, not by a decision. That is the honest reading of "evidence is never assumed" — and it means the E0 population is mostly unwritten, not unevidenced.
- No lesson has ever reached E4. The top of the scale rests on an observation — two or more
distinct clients actually retrieving the lesson — and nothing has met it. It is also not
reachable by declaring it: on 2026-10-17 the two lesson pages that carried an
E4badge were found to have been inferred from their own prose (scripts/infer_evidence_level.pymatchedverified by/cross-node confirmationin the body), which is the declaration this rung excludes. That branch was removed; the two lessons declare no level and therefore readE0by the default rule above. Any reuse narrative the project tells should be read against that zero. - E3 is a two-digit count and a low single-digit share (the row in the block above). CI-verified recovery is rare, so a "promote on CI evidence" push has a small denominator to work with.
me_events: live reuse signals (tool-level semantics)¶
misakanet_me_events aggregates a lesson's live reuse evidence — observed retrieval by distinct clients, regression-benchmark citations, helpful votes, and a lesson's own declared provenance. It uses the E-level vocabulary as signal strength, not as the frontmatter promotion chain:
- E4 in the tool comes only from an observation:
search_signalsshows two or more distinctclient_hintvalues actually retrieved the lesson.client_hintis the salted hash of the caller'sclient_id/X-MisakaNet-Client, written by the worker from the request on every completed search — nothing the lesson body says can raise it, and one client retrieving the lesson forty times is still one client (COUNT(DISTINCT client_hint)). It is never conferred by counting lower signals — since 2026-10-16 a helpful vote cannot reach it at any count, and since 2026-10-17 neither can averified by:line in the lesson's own prose. - Anonymous callers do not count. A caller with no
client_idwrites noclient_hint, so the observed count under-counts. That is the correct direction for a trust signal: it can be wrong by staying silent, but it cannot be inflated by editing a lesson. Do not "fix" the undercount with a User-Agent fallback — the UA is shared and spoofable, and counting it would make the number meaningless. - A helpful vote is
E3— one person's opinion, recorded as a hint. Almost every retrieval is agent-initiated, and the person shown the "did this help?" button did not ask the question, so a vote surveys what the transport layer can observe instead (measured 2026-10-16: 3 of the 24 most-retrieved lessons carried any vote, 6 votes in total). A vote is a reuse hint; it is not CI verification and does not claim the lesson passed a sandbox run. - Regression-benchmark citations are
E3— a curated query references the lesson: sandbox-level evidence, not external reuse. - A declared
verified by:/contributors:line isE3— it is parsed out of the lesson's own body, so anyone who can edit the lesson can write it. It is reported as a hint and cannot conferE4. - This is a query over live signals. The authoritative
evidence_levelfor a lesson lives in its frontmatter and follows the one-step-at-a-time promotion rules above; me_events does not edit it.
How evidence affects scoring¶
scripts/score_lessons.py keeps the existing quality score unchanged — the CI gate (--threshold) still measures writing quality — and adds a trust score on top:
So an E0 lesson keeps 70% of its quality score and an E4 lesson keeps all of it. The scorer also prints the corpus distribution (E0=344 E1=0 …), which is the honest current picture: everything starts self-reported until maintainers begin promoting.
Where it shows up¶
- Search results — a purple
E0–E4badge on every card, with the meaning on hover (docs/search/index.html). - Lesson pages —
Evidence E2 — Local smoke reproducedin the page metadata (scripts/build_lesson_pages.py). - Index data —
evidence_levelis emitted per lesson byscripts/misakanet-index.pyintolessons.json. - Schema —
schemas/lesson.jsonconstrains the field to the E0–E4 enum.
The canonical implementation is misakanet/evidence.py; use normalize_evidence_level() rather than reading the raw field, so unknown values keep degrading to E0.