@fenglimg/fabric-cli 2.2.0 → 2.3.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +2 -2
  2. package/dist/audit-PURSJJFH.js +734 -0
  3. package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
  4. package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
  5. package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
  6. package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
  7. package/dist/chunk-PP7QVRXH.js +565 -0
  8. package/dist/chunk-SL77FXX7.js +54 -0
  9. package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
  10. package/dist/doctor-S6KPGS35.js +27 -0
  11. package/dist/index.js +90 -80
  12. package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
  13. package/dist/{context-UJCGYOT6.js → inspect-5YZMJPFM.js} +10 -10
  14. package/dist/{install-v2-3KJX3YRO.js → install-v2-KGIDII4H.js} +163 -364
  15. package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
  16. package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
  17. package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
  18. package/package.json +3 -7
  19. package/templates/hooks/cite-policy-evict.cjs +1 -1
  20. package/templates/hooks/configs/claude-code.json +1 -5
  21. package/templates/hooks/configs/codex-hooks.json +1 -5
  22. package/templates/hooks/fabric-hint.cjs +67 -41
  23. package/templates/hooks/knowledge-hint-broad.cjs +82 -24
  24. package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
  25. package/templates/hooks/knowledge-pretooluse.cjs +111 -0
  26. package/templates/hooks/lib/banner-i18n.cjs +12 -11
  27. package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
  28. package/templates/hooks/lib/event-writer.cjs +79 -0
  29. package/templates/hooks/lib/nudge-policy.cjs +11 -0
  30. package/templates/hooks/lib/theme.cjs +62 -0
  31. package/templates/hooks/post-tooluse-mutation.cjs +28 -39
  32. package/templates/skills/fabric-archive/SKILL.md +29 -12
  33. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  34. package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
  35. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
  36. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
  37. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
  38. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
  39. package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
  40. package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
  41. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
  42. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
  43. package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
  44. package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
  45. package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
  46. package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
  47. package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
  48. package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
  49. package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
  50. package/templates/skills/fabric-review/SKILL.md +19 -15
  51. package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
  52. package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
  53. package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
  54. package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
  55. package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
  56. package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
  57. package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
  58. package/templates/skills/fabric-store/SKILL.md +12 -27
  59. package/templates/skills/fabric-sync/SKILL.md +16 -35
  60. package/templates/skills/lib/shared-policy.md +6 -4
  61. package/dist/chunk-27HK6H5Y.js +0 -69
  62. package/dist/chunk-E7HJUU34.js +0 -1096
  63. package/dist/chunk-NLNH64A3.js +0 -43
  64. package/dist/chunk-QFIVFZRH.js +0 -13
  65. package/dist/doctor-MDTZWKBK.js +0 -24
  66. package/dist/metrics-HMFH4YHK.js +0 -135
  67. package/dist/scope-explain-HLJZ2M33.js +0 -48
  68. package/dist/status-4R3TM4FJ.js +0 -37
  69. package/dist/whoami-ITGEFWH4.js +0 -49
  70. package/templates/skills/fabric/SKILL.md +0 -100
  71. package/templates/skills/fabric-audit/SKILL.md +0 -63
  72. package/templates/skills/fabric-connect/SKILL.md +0 -48
  73. package/templates/skills/fabric-import/SKILL.md +0 -151
  74. package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
@@ -4,16 +4,16 @@
4
4
 
5
5
  ## Mandatory Scope Rule — Always Broad + Empty Paths (Q-1 Resolution)
6
6
 
7
- **EVERY `fab_extract_knowledge` call issued from this skill MUST set:**
7
+ **EVERY `fab_propose` call issued from this skill MUST set:**
8
8
 
9
9
  - `relevance_scope = "broad"`
10
10
  - `relevance_paths = []`
11
11
 
12
12
  This is non-negotiable and applies to BOTH Step 2.1 (git mining) AND Step 2.2 (docs mining). No exceptions, no per-candidate override, no Agent judgment.
13
13
 
14
- **Rationale — why fabric-import cannot bind paths from git history:**
14
+ **Rationale — why archive source mode cannot bind paths from git history:**
15
15
 
16
- 1. `fabric-import` is LLM-driven (mines git log + docs), not session-driven (no live `edit_paths` signal).
16
+ 1. `archive source mode` is LLM-driven (mines git log + docs), not session-driven (no live `edit_paths` signal).
17
17
  2. `git diff --stat` lists files touched by a commit, but those files are the commit's **effect surface**, not the **applicability surface** of the underlying observation. A pitfall surfaced by a fix in `packages/server/src/retry.ts` may apply to every retry call-site in the repo, not just that one file.
18
18
  3. LLM-inferred `relevance_paths` from historical commit metadata produces false-narrow bindings — `relevance_paths` becomes a lie about applicability. Post-rc.37 A1 the server no longer filters by `relevance_scope`, so false-narrow does NOT hide knowledge from AI recall (every selectable entry is surfaced regardless of scope). The damage is now downstream: doctor lint accounting, future-AI judgment, and any consumer that reads `relevance_paths` literally treats the wrong globs as ground truth. Broad+[] keeps the metadata honest until the user has the real applicability surface in hand to declare narrow.
19
19
  4. Doc-mined observations are usually architectural / cross-cutting (a `docs/architecture.md` "Why a monolith?" decision applies to the whole codebase, not just to `docs/`).
@@ -24,16 +24,16 @@ This is non-negotiable and applies to BOTH Step 2.1 (git mining) AND Step 2.2 (d
24
24
  - DO NOT derive `relevance_paths` from the path of a mined Markdown file (e.g. do NOT bind a `docs/architecture.md` observation to `["docs/**"]`).
25
25
  - DO NOT extract path-shaped tokens from commit subjects / bodies / doc text and lift them into `relevance_paths`.
26
26
  - DO NOT classify a candidate as `relevance_scope = "narrow"` under ANY heuristic.
27
- - DO NOT copy the public-prefix-generalization logic from fabric-archive Phase 3.5 — that logic is valid only when bound to a real-time `edit_paths` signal from an active session, which fabric-import lacks.
27
+ - DO NOT copy the public-prefix-generalization logic from fabric-archive Phase 3.5 — that logic is valid only when bound to a real-time `edit_paths` signal from an active session, which archive source mode lacks.
28
28
 
29
- **Cross-reference — fabric-import vs fabric-archive scope handling:**
29
+ **Cross-reference — archive source mode vs fabric-archive scope handling:**
30
30
 
31
31
  | Skill | Scope decision | Why |
32
32
  |------------------|--------------------|-----------------------------------------------------------------------|
33
33
  | `fabric-archive` | narrow OR broad, case-by-case per Phase 3.5 rules | Has live `edit_paths` from the active session — the actual applicability surface. |
34
- | `fabric-import` | ALWAYS broad + `[]` (this skill) | LLM-only, no live session signal; git-history paths are effect-surface, not applicability-surface. |
34
+ | `archive source mode` | ALWAYS broad + `[]` (this skill) | LLM-only, no live session signal; git-history paths are effect-surface, not applicability-surface. |
35
35
 
36
- `fabric-archive`'s Phase 3.5 scope decision (narrow-vs-broad rules + public-prefix generalization + glob blacklist) is INTENTIONALLY MORE PERMISSIVE than fabric-import because archive has the data to bind safely. fabric-import is the STRICTER case.
36
+ `fabric-archive`'s Phase 3.5 scope decision (narrow-vs-broad rules + public-prefix generalization + glob blacklist) is INTENTIONALLY MORE PERMISSIVE than archive source mode because archive has the data to bind safely. archive source mode is the STRICTER case.
37
37
 
38
38
  **Post-import narrowing path — deferred to user, via `fab_review.modify`:**
39
39
 
@@ -77,16 +77,16 @@ For each commit:
77
77
  - `chore(...)`, `test(...)`, `ci(...)` → almost always skip (mechanical; no reusable insight)
78
78
  2. Read the commit body. Extract the LLM-judged "core observation" — what would a future engineer want to know about this commit beyond the diff? Aim for 1–2 sentences in zh-CN (project fabric_language; mirror fabric-archive M3 style).
79
79
  3. Apply the **Skip Decision Tree** below. If the commit is skip-worthy, record it in `p2_processed_commits[]` with `skipped: true` and move on.
80
- 4. For non-skipped commits, classify type / propose slug / draft summary. Then call `fab_extract_knowledge` with the **mandatory broad + [] scope** (see "Mandatory Scope Rule" above):
80
+ 4. For non-skipped commits, classify type / propose slug / draft summary. Then call `fab_propose` with the **mandatory broad + [] scope** (see "Mandatory Scope Rule" above):
81
81
 
82
82
  ```ts
83
- mcp__fabric__fab_extract_knowledge({
84
- source_sessions: ["fabric-import-<ISO8601-date>"], // T5: array form; stable per import run
83
+ mcp__fabric__fab_propose({
84
+ source_sessions: ["fabric-archive-source-<ISO8601-date>"], // T5: array form; stable per import run
85
85
  recent_paths: ["<files touched by this commit, capped at 20>"], // provenance only, NOT a path-binding signal
86
86
  user_messages_summary: "<zh-CN 1-2 sentence summary of the commit's core observation; cite the commit sha as 'src=<sha7>'>",
87
87
  type: "decisions" | "pitfalls" | "guidelines" | "models" | "processes",
88
88
  slug: "<kebab-case 2-5 words derived from commit subject + body>",
89
- relevance_scope: "broad", // MANDATORY — never "narrow" from fabric-import
89
+ relevance_scope: "broad", // MANDATORY — never "narrow" from archive source mode
90
90
  relevance_paths: [], // MANDATORY — never derived from git history
91
91
  proposed_reason: "<inferred per Step 2.1.5 — varies>",
92
92
  session_context: "Imported from git log analysis. Origin: commit <sha7> (<subject 30 chars>). No live session — see commit body for full context.",
@@ -108,7 +108,7 @@ Note: `recent_paths` carries the touched-file list for **provenance display** on
108
108
 
109
109
  ## Step 2.1.5 — Proposed Reason Inference (rc.7 T6)
110
110
 
111
- For each non-skipped commit OR doc section, infer `proposed_reason` from prefix + body signal jointly. The 6 reasons below are the full enum accepted by `fab_extract_knowledge` (schema-locked):
111
+ For each non-skipped commit OR doc section, infer `proposed_reason` from prefix + body signal jointly. The 6 reasons below are the full enum accepted by `fab_propose` (schema-locked):
112
112
 
113
113
  | Source signal | Body cue | Inferred reason |
114
114
  |---|---|---|
@@ -148,7 +148,7 @@ For each Markdown file:
148
148
  - `LICENSE.md`, `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md` → skip (boilerplate)
149
149
  - Files <300 bytes → skip (too thin to extract meaningful observations)
150
150
  2. Read the file. Identify candidate observations: section headings that read like decisions ("we chose X over Y"), guidelines ("always do X"), pitfalls ("don't do Y because..."), or process steps ("the deploy procedure is..."). Architecture diagrams in fenced code blocks are strong **model** signals.
151
- 3. For each observation, classify type / propose slug / draft summary. Call `fab_extract_knowledge` with the same shape as Step 2.1 (including the **mandatory `relevance_scope: "broad"` + `relevance_paths: []`**), replacing `recent_paths` with `[<this doc path>]` and citing `src=<doc-relative-path>` in the summary.
151
+ 3. For each observation, classify type / propose slug / draft summary. Call `fab_propose` with the same shape as Step 2.1 (including the **mandatory `relevance_scope: "broad"` + `relevance_paths: []`**), replacing `recent_paths` with `[<this doc path>]` and citing `src=<doc-relative-path>` in the summary.
152
152
  4. Append to `.fabric/.import-state.json`:
153
153
  - `p2_processed_docs[].push({path: <doc path>, observations_proposed: <count>, pending_paths: [...]})`
154
154
  5. **Hard cap shared with Step 2.1**: total new pending entries across git + docs is capped at `import_max_pending_per_run` (config-resolved, default 10) per Phase 2 run.
@@ -167,14 +167,14 @@ A candidate signal surfaces (commit body or doc section).
167
167
  │ └─ NO → skip (not classifiable = not yet ripe)
168
168
  ├─ Is the slug derivable as 2-5 kebab-case words?
169
169
  │ └─ NO → skip (signal too vague for stable identifier)
170
- └─ Else → propose via fab_extract_knowledge
170
+ └─ Else → propose via fab_propose
171
171
  ```
172
172
 
173
173
  After Step 2.2 completes (or hits the cap), update `.fabric/.import-state.json`: `phase = "P2-done"`, `last_checkpoint_at = <ISO8601 now>`.
174
174
 
175
175
  ## Dry-Run Mode
176
176
 
177
- When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WITHOUT calling `fab_extract_knowledge`. Instead it prints a table. v2.0.0-rc.37 NEW-10 dropped the legacy substring fallback on bare `dry-run` / `预览` because those caused false positives on incidental mentions ("preview the table" / "do a dry run later"). UX i18n Policy class 4 — header + column titles bilingualized; row content (slug / commit sha / doc path) NOT translated. Protected tokens `broad`, `relevance_scope`, `relevance_paths` appear verbatim:
177
+ When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WITHOUT calling `fab_propose`. Instead it prints a table. v2.0.0-rc.37 NEW-10 dropped the legacy substring fallback on bare `dry-run` / `预览` because those caused false positives on incidental mentions ("preview the table" / "do a dry run later"). UX i18n Policy class 4 — header + column titles bilingualized; row content (slug / commit sha / doc path) NOT translated. Protected tokens `broad`, `relevance_scope`, `relevance_paths` appear verbatim:
178
178
 
179
179
  ### zh-CN variant (`fabric_language === "zh-CN"`)
180
180
 
@@ -200,14 +200,14 @@ When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WI
200
200
  | 3 | git 50367b5 | pitfalls | thundering-herd-no-backoff | broad+[] | Retries without exponential backoff caused a thundering herd outage. |
201
201
  ```
202
202
 
203
- Every dry-run row MUST show `broad+[]` in the Scope column (constant for fabric-import). A row showing anything else is a skill bug — refuse to proceed and surface the violation. Dry-run output is informational only. The state file is NOT written to in dry-run mode (so a real run later starts clean). Phase 3 is also skipped in dry-run.
203
+ Every dry-run row MUST show `broad+[]` in the Scope column (constant for archive source mode). A row showing anything else is a skill bug — refuse to proceed and surface the violation. Dry-run output is informational only. The state file is NOT written to in dry-run mode (so a real run later starts clean). Phase 3 is also skipped in dry-run.
204
204
 
205
205
  ## Idempotency Note — T5 array form
206
206
 
207
- The server derives `idempotency_key = sha256({source_session, type, slug})` for every `fab_extract_knowledge` call. Re-invoking with the same `(source_session, type, slug)` triple is SAFE: the server appends new evidence to the existing pending file rather than overwriting or producing duplicates — this is why `fabric-import` resume after Ctrl-C / crash never produces duplicate pending entries for already-processed commits.
207
+ The server derives `idempotency_key = sha256({source_session, type, slug})` for every `fab_propose` call. Re-invoking with the same `(source_session, type, slug)` triple is SAFE: the server appends new evidence to the existing pending file rather than overwriting or producing duplicates — this is why `archive source mode` resume after Ctrl-C / crash never produces duplicate pending entries for already-processed commits.
208
208
 
209
- **T5 array-form note (rc.7+)**: when `source_sessions` is passed as an array (rc.7 T5 contract), only `source_sessions[0]` participates in the server-side idempotency hash. Server formula at `packages/server/src/services/extract-knowledge.ts:78` is `sha256(JSON.stringify({source_session: sourceSessions[0], type, slug}))`. Implications for fabric-import:
209
+ **T5 array-form note (rc.7+)**: when `source_sessions` is passed as an array (rc.7 T5 contract), only `source_sessions[0]` participates in the server-side idempotency hash. Server formula at `packages/server/src/services/extract-knowledge.ts:78` is `sha256(JSON.stringify({source_session: sourceSessions[0], type, slug}))`. Implications for archive source mode:
210
210
 
211
- - Every Phase 2 call uses `source_sessions: ["fabric-import-<ISO8601-date>"]` (single-element array, stable per import run). First-element-only rule means re-runs on the same date produce the same idempotency key per `(type, slug)` → resume-safe by construction.
212
- - If a future enhancement adds a trailing element (e.g. `["fabric-import-<date>", "<commit-sha>"]`), only the first element participates in the hash — the commit-sha tail would NOT change the idempotency key for the same `(type, slug)`. Plan accordingly.
211
+ - Every Phase 2 call uses `source_sessions: ["fabric-archive-source-<ISO8601-date>"]` (single-element array, stable per import run). First-element-only rule means re-runs on the same date produce the same idempotency key per `(type, slug)` → resume-safe by construction.
212
+ - If a future enhancement adds a trailing element (e.g. `["fabric-archive-source-<date>", "<commit-sha>"]`), only the first element participates in the hash — the commit-sha tail would NOT change the idempotency key for the same `(type, slug)`. Plan accordingly.
213
213
  - The formula is intentionally stable across the rc.5 → rc.7 migration; adding or removing tail entries does NOT change the idempotency key, preserving rc.5 single-session compat.
@@ -13,7 +13,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
13
13
  - Commits scanned: <N> (skipped: <S> — cosmetic/metadata/baseline-overlap)
14
14
  - Docs scanned: <D> (skipped: <DS> — README/CHANGELOG/boilerplate)
15
15
  - Pending proposed: <P> (cap_reached: <true|false>)
16
- - Scope: all <P> proposed entries use relevance_scope=broad, relevance_paths=[] (fabric-import contract).
16
+ - Scope: all <P> proposed entries use relevance_scope=broad, relevance_paths=[] (archive source mode contract).
17
17
 
18
18
  ## Phase 3 — Dedup
19
19
  - Kept (genuinely new): <K>
@@ -41,7 +41,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
41
41
  - 扫描 commit 数: <N> (跳过: <S> — cosmetic/metadata/与 baseline 重叠)
42
42
  - 扫描文档数: <D> (跳过: <DS> — README/CHANGELOG/样板文件)
43
43
  - 提议 pending: <P> (cap_reached: <true|false>)
44
- - 作用域: 全部 <P> 条提议使用 relevance_scope=broad, relevance_paths=[] (fabric-import 契约)。
44
+ - 作用域: 全部 <P> 条提议使用 relevance_scope=broad, relevance_paths=[] (archive source mode 契约)。
45
45
 
46
46
  ## Phase 3 — 去重
47
47
  - 保留 (新知识): <K>
@@ -52,7 +52,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
52
52
  ## 状态
53
53
  - .fabric/.import-state.json phase: <phase>
54
54
  - last_checkpoint_at: <ISO8601>
55
- - 如 phase != complete, 请重新调用 fabric-import 续作。
55
+ - 如 phase != complete, 请重新调用 archive source mode 续作。
56
56
 
57
57
  ## 下一步
58
58
  - 运行 `fabric-review` 审批 <K> 条新 pending。
@@ -1,4 +1,4 @@
1
- # Phase 0 + 0.1 — State Recovery (fabric-import ref-only)
1
+ # Phase 0 + 0.1 — State Recovery (archive source mode ref-only)
2
2
 
3
3
  > **Loaded on demand.** Only relevant when a prior import crashed mid-phase, leaving `.tmp-*` residue or a torn `.fabric/.import-state.json`. SKILL.md's hot path inline says "scan for .tmp residue + load state" — this file is the full recovery procedure (atomic-write pattern, sweep rules, corruption detection, fallback to fresh import).
4
4
 
@@ -46,7 +46,7 @@ On corruption (any condition above):
46
46
  1. `Bash: mv .fabric/.import-state.json .fabric/.import-state.json.corrupt-<ISO8601>`
47
47
  (preserve the corrupt file for postmortem; do NOT silently overwrite).
48
48
  2. Phase 1 restarts from scratch (Phase 1 produces no MCP calls, so re-run
49
- is safe — re-querying mounted store canonical titles via `fab_review search`
49
+ is safe — re-querying mounted store canonical titles via `fab_pending search`
50
50
  idempotent; the `p1_baseline_titles` array is regenerated).
51
51
  3. DO NOT attempt automatic partial recovery; corrupt state is a signal
52
52
  that something serious happened (disk-full, kill -9 mid-write, fs
@@ -8,11 +8,11 @@ Source signal: `git log` surfaces commit `50367b5` with subject `feat(server): a
8
8
 
9
9
  LLM analysis: this is a **pitfall** (a non-obvious trap that wasted time and is repeatable across services). The body itself documents the trap. Slug candidates: `retry-without-backoff-thundering-herd` (5 words, 38 chars — passes 5 rules).
10
10
 
11
- Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for fabric-import):
11
+ Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for archive source mode):
12
12
 
13
13
  ```ts
14
- mcp__fabric__fab_extract_knowledge({
15
- source_sessions: ["fabric-import-2026-05-10"],
14
+ mcp__fabric__fab_propose({
15
+ source_sessions: ["fabric-archive-source-2026-05-10"],
16
16
  recent_paths: ["packages/server/src/lib/retry.ts"], // provenance only
17
17
  user_messages_summary: "重试无指数退避会在短暂上游故障下放大成雪崩。修正:jittered exponential backoff,30 秒上限。src=50367b5",
18
18
  type: "pitfalls",
@@ -29,7 +29,7 @@ Counter-example — DO NOT do this:
29
29
  ```ts
30
30
  // WRONG — this skill must never produce narrow + paths from git metadata.
31
31
  // The retry pitfall applies to every retry site, not just the file touched by 50367b5.
32
- mcp__fabric__fab_extract_knowledge({
32
+ mcp__fabric__fab_propose({
33
33
  // ...
34
34
  relevance_scope: "narrow", // VIOLATION
35
35
  relevance_paths: ["packages/server/src/lib/retry.ts"] // VIOLATION
@@ -57,8 +57,8 @@ LLM analysis: this is a **decision** (≥2 alternatives weighed — monolith vs
57
57
  Skill output (broad+[] mandatory; the doc's own path stays in `recent_paths` for provenance, NOT in `relevance_paths`):
58
58
 
59
59
  ```ts
60
- mcp__fabric__fab_extract_knowledge({
61
- source_sessions: ["fabric-import-2026-05-10"],
60
+ mcp__fabric__fab_propose({
61
+ source_sessions: ["fabric-archive-source-2026-05-10"],
62
62
  recent_paths: ["docs/architecture.md"], // provenance only
63
63
  user_messages_summary: "选择单体架构而非微服务:3 人团队无法承担多服务运维成本,且主要性能瓶颈在 DB 吞吐而非应用层水平扩展。src=docs/architecture.md",
64
64
  type: "decisions",
@@ -73,7 +73,7 @@ mcp__fabric__fab_extract_knowledge({
73
73
  After Example A's pending entry (`retry-without-backoff-thundering-herd`) is proposed, Phase 3 runs:
74
74
 
75
75
  ```ts
76
- mcp__fabric__fab_review({
76
+ mcp__fabric__fab_pending({
77
77
  action: "search",
78
78
  query: "retry backoff thundering herd",
79
79
  filters: { type: "pitfalls" }
@@ -105,7 +105,7 @@ Final roll-up to user reflects: 1 proposed, 0 kept, 1 rejected_dup, 0 merged, 0
105
105
 
106
106
  ## Example D — Post-import narrowing (out-of-band, NOT this skill)
107
107
 
108
- This example documents the legal narrowing path; it is NOT performed by `fabric-import` itself. After Example B's `monolith-over-microservices-small-team` decision is imported (with `relevance_scope=broad`, `relevance_paths=[]`) and later approved into canonical via `fabric-review`, the user decides the decision is actually narrow to the server package's deploy tooling.
108
+ This example documents the legal narrowing path; it is NOT performed by `archive source mode` itself. After Example B's `monolith-over-microservices-small-team` decision is imported (with `relevance_scope=broad`, `relevance_paths=[]`) and later approved into canonical via `fabric-review`, the user decides the decision is actually narrow to the server package's deploy tooling.
109
109
 
110
110
  The user issues (via `fabric-review`, NOT via this skill):
111
111
 
@@ -122,6 +122,6 @@ mcp__fabric__fab_review({
122
122
 
123
123
  Key invariants of this flow:
124
124
 
125
- - The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `fabric-import` inferring paths from git metadata.
126
- - The modify call goes through `fab_review`, not `fab_extract_knowledge`, because the entry already exists (post-import or post-approval).
125
+ - The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `archive source mode` inferring paths from git metadata.
126
+ - The modify call goes through `fab_review`, not `fab_propose`, because the entry already exists (post-import or post-approval).
127
127
  - If the user later flips the entry's layer from `team` to `personal`, server-side auto-degrades scope back to `broad` and clears `relevance_paths` (see rc.5 C3 acceptance criterion; personal knowledge crosses projects so paths don't generalize). This is the only legal way for `relevance_paths` to be re-cleared.
@@ -11,7 +11,7 @@ Session: User and agent debated whether the Stop-hook should be one .cjs script
11
11
  Skill output:
12
12
 
13
13
  ```ts
14
- mcp__fabric__fab_extract_knowledge({
14
+ mcp__fabric__fab_propose({
15
15
  source_sessions: ["WFS-2026-05-10-rc2"],
16
16
  recent_paths: ["templates/claude-hooks/", "packages/cli/src/commands/hooks.ts"],
17
17
  user_messages_summary: "User pushed back on three-script proposal; agreed single .cjs because stdout JSON shape is universal across Claude Code and Codex CLI.",
@@ -37,7 +37,7 @@ Session: deepMerge silently replaced the existing `hooks.Stop[]` array in `.clau
37
37
  Skill output:
38
38
 
39
39
  ```ts
40
- mcp__fabric__fab_extract_knowledge({
40
+ mcp__fabric__fab_propose({
41
41
  source_sessions: ["WFS-2026-05-10-rc2"],
42
42
  recent_paths: ["packages/cli/src/config/json.ts"],
43
43
  user_messages_summary: "deepMerge default behavior REPLACES arrays. hooks.Stop[] needs an array-append-with-dedupe special case keyed on .command string match.",
@@ -60,7 +60,7 @@ Session: User mentioned across three projects that they prefer 2-space indent in
60
60
  Skill output:
61
61
 
62
62
  ```ts
63
- mcp__fabric__fab_extract_knowledge({
63
+ mcp__fabric__fab_propose({
64
64
  source_sessions: ["WFS-2026-05-10-rc2"],
65
65
  recent_paths: [".editorconfig"],
66
66
  user_messages_summary: "Personal indent preference: 2-space TS / 4-space Py. Stable across multiple projects, not project-specific.",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: fabric-review
3
- description: 审 store-backed pending+canonical knowledge (NOT PR review):approve/reject/modify/revisit/defer。Triggers 审批/驳回/复审/重审/approve/reject/review pending.
4
- allowed-tools: Read, Glob, Grep, Bash, Edit, mcp__fabric__fab_review
3
+ description: 审 store-backed pending+canonical knowledge (NOT PR review):pending triage + maintain(含 retire 语义淘汰 + relate 关联建边)。Triggers 审批/review pending;淘汰陈旧/deprecate;连接知识/补 related 边.
4
+ allowed-tools: Read, Glob, Grep, Bash, Edit, mcp__fabric__fab_recall, mcp__fabric__fab_pending, mcp__fabric__fab_review
5
5
  ---
6
6
 
7
7
  > **Surface**: Skill (AI-driven, per-entry human-judgment routing). See [`docs/surfaces.md`](https://github.com/fenglimg/fabric/blob/main/docs/surfaces.md).
@@ -25,7 +25,7 @@ This skill is `Infer-not-Ask` for mode and `Ask-when-genuine` for per-item actio
25
25
  - Per-item action (approve / reject / modify / defer) IS surfaced via AskUserQuestion — the user must judge
26
26
  - Layer-flip target (team vs personal) IS surfaced via AskUserQuestion when modify includes layer change
27
27
 
28
- Required preconditions before any `fab_review` call: `.fabric/` exists; `mcp__fabric__fab_review` MCP tool registered; a write store is resolved for mutations; `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger normal first-run).
28
+ Required preconditions before any `fab_review` / `fab_pending` call: `.fabric/` exists; `mcp__fabric__fab_review` (write) + `mcp__fabric__fab_pending` (read) MCP tools registered; a write store is resolved for mutations; `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger normal first-run).
29
29
 
30
30
  ### Config Load
31
31
 
@@ -42,13 +42,13 @@ Missing or unreadable → defaults silently.
42
42
 
43
43
  ### Store routing (v2.1 multi-store)
44
44
 
45
- Review iterates **per-store** — the read-set may span multiple stores (`fabric scope-explain team` → resolved `readSet.stores`). Pending/backlog is reported per-store (NOT aggregated into one undifferentiated pile); each candidate's provenance store is surfaced in cites as `KB: <store-alias>:<id>`. Promotion (draft → verified/proven) is a normal edit + git commit **inside that store's own repo** — no cross-store move. A `dismissed`/`modify` that flips layer between team and personal still goes through `AskUserQuestion`. Never read `~/.fabric` store trees directly; go through the MCP recall path / `scope-explain`.
45
+ Review iterates **per-store** — the read-set may span multiple stores (`fabric info scope team` → resolved `readSet.stores`). Pending/backlog is reported per-store (NOT aggregated into one undifferentiated pile); each candidate's provenance store is surfaced in cites as `KB: <store-alias>:<id>`. Promotion (draft → verified/proven) is a normal edit + git commit **inside that store's own repo** — no cross-store move. A `dismissed`/`modify` that flips layer between team and personal still goes through `AskUserQuestion`. Never read `~/.fabric` store trees directly; go through the MCP recall path / `fabric info scope`.
46
46
 
47
47
  `Read ref/cite-contract.md` (v2.2 SK5) for the authoritative cite-contract reference — operator syntax, skip/dismissed reason dictionaries, type routing, audit semantics, backward-compat, and the adjudication ladder (AI-self → multi-LLM cold-eval → non-blocking queue) — sunk out of the bootstrap so cite/governance depth lives here, not in `.fabric/AGENTS.md`.
48
48
 
49
49
  ### UX i18n Policy
50
50
 
51
- Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`); emit user-facing prose in resolved variant. Protected tokens (`fab_review`, `fab_extract_knowledge`, `relevance_scope`, layer/scope enums, `stable_id`, the verbatim `强 team` / `强 personal` / `默认 team` block) NEVER translated. `AskUserQuestion` policy: `header` + `question` translate; `options[]` stay English (routing keys).
51
+ Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`); emit user-facing prose in resolved variant. Protected tokens (`fab_review`, `fab_pending`, `fab_propose`, `relevance_scope`, layer/scope enums, `stable_id`, the verbatim `强 team` / `强 personal` / `默认 team` block) NEVER translated. `AskUserQuestion` policy: `header` + `question` translate; `options[]` stay English (routing keys).
52
52
 
53
53
  `Read ref/i18n-policy.md` for the full 5-class taxonomy + edge cases.
54
54
 
@@ -59,7 +59,7 @@ Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`); emi
59
59
 
60
60
  The skill MUST infer one of **2 modes** BEFORE any user-facing output (v2.0.0-rc.37 NEW-12 simplified 4 → 2):
61
61
 
62
- - **`pending`** — triage the write-side backlog returned by `fab_review action="list"` (`pending_path` identifies each store-backed entry): approve / reject / modify / defer per item. The dominant entry point.
62
+ - **`pending`** — triage the write-side backlog returned by `fab_pending action="list"` (`pending_path` identifies each store-backed entry): approve / reject / modify / defer per item via `fab_review`. The dominant entry point.
63
63
  - **`maintain`** — sustain the EXISTING canonical KB: browse by topic (search), survey staleness/health, or revisit a specific entry. Merges the legacy `topic` + `health` + `revisit` modes — they are all "operate on already-canonical knowledge", distinct from triaging new drafts.
64
64
 
65
65
  ### 2-Step Inference Algorithm
@@ -69,11 +69,13 @@ The skill MUST infer one of **2 modes** BEFORE any user-facing output (v2.0.0-rc
69
69
  | Keywords (zh-CN + en) | Inferred mode |
70
70
  |---|---|
71
71
  | "approve", "review pending", "promote", "what's queued", "审核 pending", "通过" | `pending` |
72
- | "search/find about <topic>", "what's stale", "demote old", "health check", "look at <id>", "revisit KT-…", "关于…的知识", "过期的", "陈旧的", "整理一下", "再看下 <id>", "回顾" | `maintain` |
72
+ | "search/find about <topic>", "what's stale", "demote old", "health check", "look at <id>", "revisit KT-…", "关于…的知识", "过期的", "陈旧的", "整理一下", "再看下 <id>", "回顾" | `maintain` (browse/health/revisit) |
73
+ | "审计知识库", "清理陈旧知识", "知识库瘦身", "淘汰旧决策", "deprecate", "prune stale", "这些旧决策还要吗" | `maintain` → **retire** sub-flow |
74
+ | "连接知识", "找相关条目", "补 related 边", "知识库连通性", "link related", "建知识图谱" | `maintain` → **relate** sub-flow |
73
75
 
74
76
  A `maintain`-row match → lock `maintain`. A `pending`-row match (or 0/ambiguous) → fall to Step 2.
75
77
 
76
- **Step 2 — Backlog default.** Call `fab_review action="list"` and inspect returned `items[].pending_path`:
78
+ **Step 2 — Backlog default.** Call `fab_pending action="list"` and inspect returned `items[].pending_path`:
77
79
 
78
80
  - Count ≥ `review_hint_pending_count` (default 10) OR oldest mtime > `review_hint_pending_age_days` (default 7) → `pending` (overflow, same threshold as Stop-hook).
79
81
  - Otherwise → default `pending` (most common review entry point).
@@ -91,9 +93,11 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
91
93
  - `fab_review action="modify-layer"` — the dedicated layer-flip path (`changes.layer` required); may reallocate the stable_id + emit an id-redirect.
92
94
  - (Legacy `action="modify"` still works — it routes by whether `changes.layer` is present.) See `ref/modify-flow.md`.
93
95
  - **`maintain`** — sub-flow inferred from the same keywords:
94
- - *browse-by-topic*: extract keywords → `fab_review action="search"` → render top-N (cap `review_topic_result_cap`) → AskUserQuestion only on an action verb.
95
- - *health/staleness*: `fab_review action="list"` + tail events → compute stale → render dashboard → per-stale AskUserQuestion `{defer, demote, skip}`.
96
- - *revisit*: user referenced a specific id/slug → `Read` canonical file directly OR `fab_review action="list"` with narrow filters → display body + history → AskUserQuestion only if actionable.
96
+ - *browse-by-topic*: extract keywords → `fab_pending action="search"` → render top-N (cap `review_topic_result_cap`) → AskUserQuestion only on an action verb.
97
+ - *health/staleness*: `fab_pending action="list"` + tail events → compute stale → render dashboard → per-stale AskUserQuestion `{defer, demote, skip}`.
98
+ - *revisit*: user referenced a specific id/slug → `Read` canonical file directly OR `fab_pending action="list"` with narrow filters → display body + history → AskUserQuestion only if actionable.
99
+ - *retire* (W3-C, 吸收原 fabric-audit): 语义淘汰陈旧/孤儿/被取代的 **canonical** 条目。引擎 `fabric doctor`(给 orphan/stale/health 信号);守两条红线 **deprecate-over-delete**(陈旧≠该删,降 maturity / 标 `superseded-by` 保留 rationale)+ **rescue-before-delete**(删前必做独特-rationale 抢救检查)。逐条判三态 still-valid / superseded(deprecate)/ never-valid(rescue 后删空壳),处置经 `fab_review` 写路径落盘。**完整两条红线定义 / 意图→动作映射 / 三态流程 / scope 纠偏 → `Read ref/retire-mode.md`。**
100
+ - *relate* (W3-C, 吸收原 fabric-connect): **默认不主动建边**,仅用户显式「连一下 / 补 related」时进入。`fab_recall` 拿候选 + 现有 `related` → 按互补/规避/取代/同域/引用链判**高置信**隐藏关联(稀疏优于稠密)→ 落盘**复用 `fab_review` modify 写路径**(零新写面,追加源条目 `related` 数组)。§4 隐私铁律 `KT→KP` FORBIDDEN。**关联类型判据表 / 流程 / 约束 → `Read ref/relate-mode.md`。**
97
101
 
98
102
  `Read ref/per-mode-flows.md` for full step-by-step procedures, bilingual rendering blocks (en + zh-CN per-item display, AskUserQuestion templates, health dashboard format), and the rc.7 T6 `proposed_reason` + `## Why proposed` + `## Session context` rendering contract.
99
103
 
@@ -101,7 +105,7 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
101
105
 
102
106
  > Boundary B (locked): "extraction / classification / layer / slug / mode / **semantic dedup** → Skill (LLM); file write / frontmatter / idempotency / counter / layer-flip / atomic promote → MCP (deterministic)"
103
107
 
104
- Semantic check is the LLM's job — the MCP tool does NOT compare meaning. Run during `pending` mode (and on demand during `topic`): for each pending entry, `fab_review action="search"` scoped by `filters.type` → LLM judges semantically against returned canonical entries → surface one of three flags as informational:
108
+ Semantic check is the LLM's job — the MCP tool does NOT compare meaning. Run during `pending` mode (and on demand during `topic`): for each pending entry, `fab_pending action="search"` scoped by `filters.type` → LLM judges semantically against returned canonical entries → surface one of three flags as informational:
105
109
 
106
110
  - `⚠ Possible duplicate of <stable_id> (overlap: high)` — same essential claim
107
111
  - `⚠ Contradicts <stable_id> (overlap: high)` — opposing claims, same scope
@@ -135,7 +139,7 @@ Guideline/model entries surface in the SessionStart **ALWAYS-ACTIVE** sink as a
135
139
  - **Title/summary/tags/maturity** → in-place rewrite; stable_id PRESERVED.
136
140
  - **Layer change** → ONLY legal stable_id mutation. BEFORE call, AskUserQuestion `{team, personal}` to confirm target (this IS genuine choice). AFTER server returns, surface BOTH `prior_stable_id` and `new_stable_id` in roll-up — downstream agents may cache the prior id.
137
141
 
138
- **Import-origin entries** (`source_sessions[0]` starts with `fabric-import-`) ship with `relevance_scope=broad + relevance_paths=[]` by design; narrowing is fabric-review's responsibility. Render `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — pick 'modify' + say 'narrow to <paths>'` as informational hint. On `modify` of import-origin: extended option list `{narrow scope, edit summary, change layer, change maturity, skip}`; "narrow scope" → free-text follow-up → `changes: { relevance_scope: "narrow", relevance_paths: [<parsed>] }`. Personal layer auto-degrades narrow → broad+[] (server-side), emitting `knowledge_scope_degraded`.
142
+ **Source-mode entries** (`source_sessions[0]` starts with `fabric-archive-source-`) ship with `relevance_scope=broad + relevance_paths=[]` by design; narrowing is fabric-review's responsibility. Render `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — pick 'modify' + say 'narrow to <paths>'` as informational hint. On `modify` of import-origin: extended option list `{narrow scope, edit summary, change layer, change maturity, skip}`; "narrow scope" → free-text follow-up → `changes: { relevance_scope: "narrow", relevance_paths: [<parsed>] }`. Personal layer auto-degrades narrow → broad+[] (server-side), emitting `knowledge_scope_degraded`.
139
143
 
140
144
  `Read ref/modify-flow.md` for layer-flip server transaction (4-step), modify call shape examples (maturity bump / layer flip), and full narrowing flow with bilingual AskUserQuestion templates.
141
145
 
@@ -180,11 +184,11 @@ Pending entry presented for review
180
184
 
181
185
  - NEVER write a knowledge file directly via Edit/Write/Bash; the only legal mutation path is `mcp__fabric__fab_review`.
182
186
  - NEVER call `git mv` from this skill — layer flip and slug rename are server-side transactions.
183
- - NEVER invent an `action` value — `action` MUST be one of {`list`, `approve`, `reject`, `modify`, `search`, `defer`}.
187
+ - NEVER invent an `action` value — `fab_review action` MUST be one of {`approve`, `reject`, `modify`, `modify-content`, `modify-layer`, `defer`} (write-only); read actions {`list`, `search`} go through the read-only `fab_pending` tool.
184
188
  - NEVER batch heterogeneous decisions into a single MCP call. Approve and reject MAY be batched within their own action; modify MUST be one call per entry.
185
189
  - NEVER invoke `fab_review action="approve"` without at least one `pending_paths` entry.
186
190
  - NEVER infer a layer-flip target — the user MUST choose via AskUserQuestion.
187
- - MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `knowledge_scope_degraded`, `fab_review`, `MUST`, `NEVER`, `relevance_scope`, `relevance_paths`, `narrow`, `broad`, `proposed_reason`, `session_context`.
191
+ - MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `knowledge_scope_degraded`, `fab_review`, `fab_pending`, `MUST`, `NEVER`, `relevance_scope`, `relevance_paths`, `narrow`, `broad`, `proposed_reason`, `session_context`.
188
192
 
189
193
  ## Output Contract & events.jsonl Constraint (ref-only)
190
194
 
@@ -1,6 +1,6 @@
1
1
  # Cite-contract + 裁决阶梯参考 (v2.2 SK5)
2
2
 
3
- > 本文是 cite policy 与裁决(adjudication)的**权威详参**,从 bootstrap (`.fabric/AGENTS.md`) 下沉至此,避免 bootstrap 随治理细节膨胀。bootstrap 只留**可执行 core**(cite 行格式 + 验证义务 + operator 例),完整 enum 词典 / 类型路由 / 稽核 / backward-compat / 裁决阶梯看这里。`fabric doctor --cite-coverage` 的稽核口径以本文为准。
3
+ > 本文是 cite policy 与裁决(adjudication)的**权威详参**,从 bootstrap (`.fabric/AGENTS.md`) 下沉至此,避免 bootstrap 随治理细节膨胀。bootstrap 只留**可执行 core**(cite 行格式 + 验证义务 + operator 例),完整 enum 词典 / 类型路由 / 稽核 / backward-compat / 裁决阶梯看这里。`fabric audit cite` 的稽核口径以本文为准。
4
4
 
5
5
  ## 1. Cite 行格式 (回顾)
6
6
 
@@ -42,7 +42,7 @@ cite 尾段加 contract:`→ <operator> [<operator> ...]`
42
42
 
43
43
  ## 5. 稽核 + Backward compat
44
44
 
45
- - 稽核:`fabric doctor --cite-coverage [--since=7d] [--client=cc|codex|all]` 输出覆盖率,含 `KB: none` sentinel 拆分。不阻断工作,只记录。
45
+ - 稽核:`fabric audit cite [--since=7d] [--client=cc|codex|all]` 输出覆盖率,含 `KB: none` sentinel 拆分。不阻断工作,只记录。
46
46
  - Backward compat:解析器同时接受老 4-state tags(`planned` / `recalled` / `chained-from <id>`),都映射到 `[applied]` 语义;旧 session cite 仍计入 cite-coverage。
47
47
 
48
48
  ## 6. 裁决阶梯 (adjudication ladder)
@@ -49,13 +49,25 @@ mcp__fabric__fab_review({
49
49
 
50
50
  ---
51
51
 
52
+ ## Promotion Gate — verified → proven (v2.2 C1)
53
+
54
+ `maturity` promotion to `proven` is the foundational tier and runs a 3-part gate from `processes/maturity-promotion-rubric-v1`. The doctor `knowledge_broad_review_recheck`-adjacent `promotion_candidate` lint only SURFACES candidates (verified entries with `related` in-degree ≥3); the SUFFICIENT judgment lives here in review.
55
+
56
+ Before issuing `fab_review modify ... { maturity: "proven" }`, satisfy all three:
57
+
58
+ 1. **0 dismiss (NECESSARY — server-enforced).** The server REFUSES the verified→proven modify when the entry carries an unresolved dismissed cite (latest `assistant_turn_observed` verdict for its id is `dismissed`, last-write-wins). You do NOT need to pre-check this — the modify throws with an actionable message. To clear it, the entry must be re-affirmed (a later `applied` cite) or the objection addressed. Do not work around the block; resolving it IS the gate.
59
+ 2. **guideline/model summary cold-eval (NECESSARY for those two types).** For `guidelines`/`models`, run the zero-context self-sufficiency judge before promoting: build the batch with `summary-cold-eval.buildColdEvalBatch([{stable_id, summary}])` + `COLD_EVAL_RUBRIC`, hand it to a `maestro delegate` cold judge (body WITHHELD), and only proceed if `self_sufficient=true`. A FAIL means the summary only points at the body — fix the summary (modify) first, then re-judge. (decisions/pitfalls/processes skip this — they are reference, not always-active rules.)
60
+ 3. **Foundational affirmation (SUFFICIENT — human).** Surface AskUserQuestion confirming the reviewer judges the entry "foundational / load-bearing", not merely correct. Promotion to proven is a standing-rule claim; the human makes it.
61
+
62
+ Only after 1–3 hold, call `fab_review action="modify-content" changes={ maturity: "proven" }`. The modify itself stamps `last_review_confirmed_at` (every approve/modify is a review re-confirmation — this also resets the broad review-recheck clock).
63
+
52
64
  ## Narrowing Imported Entries
53
65
 
54
66
  The fabric-import skill creates pending entries with `relevance_scope=broad` + `relevance_paths=[]` as a deliberate contract — it cannot derive paths from git history. **Narrowing imported entries is fabric-review's responsibility.**
55
67
 
56
68
  ### Detection
57
69
 
58
- An entry is "import-origin" when `source_sessions[0]` starts with `fabric-import-` (e.g. `fabric-import-2026-05-10`).
70
+ An entry is "import-origin" when `source_sessions[0]` starts with `fabric-archive-source-` (e.g. `fabric-archive-source-2026-05-10`).
59
71
 
60
72
  ### Pending mode rendering
61
73
 
@@ -6,9 +6,9 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
6
6
 
7
7
  ## Mode: pending — Approve / Reject / Modify Backlog
8
8
 
9
- 1. Call `fab_review` with `action: "list"`, no filters (or `filters.layer="both"` if user explicitly mentioned both layers).
9
+ 1. Call `fab_pending` with `action: "list"`, no filters (or `filters.layer="both"` if user explicitly mentioned both layers).
10
10
  2. Server returns `items[]` (each = `{pending_path, type, layer, maturity, tags?, title?, summary?}`).
11
- 3. Before presenting, perform **Semantic Check** (see `ref/semantic-check.md`) by issuing one or more `action: "search"` calls scoped by `filters.type` to surface possible duplicates / contradictions among already-canonical entries.
11
+ 3. Before presenting, perform **Semantic Check** (see `ref/semantic-check.md`) by issuing one or more `fab_pending action="search"` calls scoped by `filters.type` to surface possible duplicates / contradictions among already-canonical entries.
12
12
  4. For each pending item, render a per-item block. v2.0.0-rc.7 T6: render `proposed_reason` (frontmatter) + `## Why proposed` line (body, 1-line enum explanation) + first line of `## Session context` so future-self has full context without re-reading the transcript. UX i18n Policy class 1 — roll-up templates; protected tokens (`pending_path`, `layer`, `team`, `decisions`, `proposed_reason`, `Tags`, etc.) appear verbatim in BOTH variants:
13
13
 
14
14
  **en variant** (`fabric_language === "en"`):
@@ -74,7 +74,7 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
74
74
  ## Mode: topic — Search & Surface Findings
75
75
 
76
76
  1. Extract the topic keyword(s) from the user's message (e.g. "find about deepMerge" → query="deepMerge").
77
- 2. Call `fab_review action="search"` with `query` and any obvious filters (if user said "team-only" → `filters.layer="team"`).
77
+ 2. Call `fab_pending action="search"` with `query` and any obvious filters (if user said "team-only" → `filters.layer="team"`).
78
78
  3. Server returns `items[]` ranked by relevance — these are entries already in mounted store `knowledge/<type>/` (NOT pending), unless `filters` says otherwise.
79
79
  4. Render top-N (cap at `review_topic_result_cap`, config-resolved, default 8) results with title / summary / pending_path.
80
80
  5. If the user follow-up indicates intent to act ("approve all", "modify the second one"), pivot into the corresponding pending mode action — the search result already gives the `pending_path` needed for the action.
@@ -84,7 +84,7 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
84
84
 
85
85
  ## Mode: health — Corpus Health & Stale Detection
86
86
 
87
- 1. Call `fab_review action="list"` with `filters.maturity="draft"` (or no filter for full corpus inspection).
87
+ 1. Call `fab_pending action="list"` with `filters.maturity="draft"` (or no filter for full corpus inspection).
88
88
  2. Tail `.fabric/events.jsonl` for layer_changed / demoted / rejected counts in the trailing 30 days.
89
89
  3. Compute stale candidates: pending entries with mtime older than `review_stale_pending_days` (config-resolved, default 14) OR maturity=draft entries with no recent evidence-append events.
90
90
  4. Render a corpus dashboard. UX i18n Policy class 1 — roll-up templates; render per `fabric_language`:
@@ -134,7 +134,7 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
134
134
  ## Mode: revisit — Specific Entry Deep Dive
135
135
 
136
136
  1. The user referenced a specific entry (by id `KT-D-7` or by slug `single-cjs-hook`).
137
- 2. Call `fab_review action="list"` with `filters` narrowed by best-guess fields; if the entry is canonical (has stable_id), use the path returned by `fab_review` instead of inventing a store path.
137
+ 2. Call `fab_pending action="list"` with `filters` narrowed by best-guess fields; if the entry is canonical (has stable_id), use the path returned by `fab_pending` instead of inventing a store path.
138
138
  3. Display the full body (frontmatter + content). Tail the events.jsonl for any history events tagged with this stable_id.
139
139
  4. Surface AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` only if the entry is still pending; for canonical entries the only mutation path is `modify` (incl. layer flip).
140
140
 
@@ -0,0 +1,33 @@
1
+ # Relate sub-flow — 知识图谱关联 (W3-C: 吸收原 fabric-connect)
2
+
3
+ `maintain` 模式的 **relate** 子流程:把孤立的 canonical 条目连成图,发现彼此**隐藏关联**(同一决策的正反面、pitfall↔规避它的 guideline、被取代↔取代),回写 frontmatter 的 `related: [<stable_id>...]` 图边(v2.2 H2)。下游 `fab_recall include_related:true` 据此一跳拉回连通知识。
4
+
5
+ `related` 是**有向引用**(A.related=[B] 表示「读 A 时也该看 B」),按需补反向边。
6
+
7
+ **默认不主动建边**:仅用户显式说「连一下 / 找相关条目 / 补 related 边 / 知识库连通性」时进入;不在任何 nudge 里主动提议(避免噪声边稀释图价值)。检索时临时拉关联直接 `fab_recall include_related:true`,无需建边。
8
+
9
+ ## 关联类型(提议 related 边的判据)
10
+
11
+ | 类型 | 例 |
12
+ |---|---|
13
+ | 互补 | decision「用 JWT」 ↔ pitfall「JWT 过期未刷新踩坑」 |
14
+ | 规避 | pitfall「sprite 黑边」 ↔ guideline「premultiplyAlpha 正确设置」 |
15
+ | 取代 | 旧 decision ↔ 取代它的新 decision(配合 deprecated/superseded-by) |
16
+ | 同域 | 同一子系统 / 共 relevance_paths 的条目 |
17
+ | 引用链 | A 的 rationale 依赖 B 的结论 |
18
+
19
+ ## 流程
20
+
21
+ 1. `fab_recall(paths=[...])` 拿候选 + 现有 `related`(读 description.related 看已连状态)。
22
+ 2. 对候选两两/成簇判隐藏关联(用上表判据);只提议**高置信**边,不为「话题相邻」乱连。
23
+ 3. 每条提议 = `(源 id, 目标 id, 类型, 一句理由)`;按需提议反向边。
24
+ 4. 落盘**复用既有 `fab_review` modify 写路径**(零新写面):在源条目 frontmatter 的 `related` inline 数组追加目标 stable_id;`fabric doctor --fix` reconcile 进 agents.meta。
25
+ 5. 回报新增/反向边数 + 连通性变化(孤岛减少)。
26
+
27
+ ## Constraints
28
+
29
+ - 本子流程**只提议 + 经 `fab_review` modify 写路径落盘**;不自行改 store `knowledge/`,不手改 store counters(派生态)。
30
+ - `related` MUST 只填**真实存在的 stable_id**(先 `fab_recall` 验证目标在库);NEVER 编造 / 指向 pending。
31
+ - **稀疏优于稠密**:宁缺毋滥。只连高置信关联;低置信「相邻」不连(信噪比 > 覆盖率)。
32
+ - 反向边按需补,不强制双向(有向语义:A 该带出 B ≠ B 该带出 A)。
33
+ - **§4 隐私铁律**:`KT→KP` FORBIDDEN(team 条目 MUST NOT 指向 personal id);不确定目标是否 personal 时 OMIT 该边。
@@ -0,0 +1,47 @@
1
+ # Retire sub-flow — 语义淘汰 canonical 条目 (W3-C: 吸收原 fabric-audit)
2
+
3
+ `maintain` 模式的 **retire** 子流程:把陈旧 / 孤儿 / 被取代的 **已 canonical** 条目按语义淘汰收口 —— 而不是一删了之。引擎是 `fabric doctor`(跑 lint、算 health、给 orphan/stale 信号);本子流程按用户意图挑动作,守两条红线,落盘仍走 `fab_review` 写路径(单一写路径,不自改 store `knowledge/`)。
4
+
5
+ 写新条目用 default archive;批量审 pending 用 `pending` 模式;retire 专管 **已归档条目的退役**。
6
+
7
+ ## 进入 retire 子流程
8
+
9
+ `maintain` 关键词命中「审计 / 体检知识库」「清理陈旧知识」「这些旧决策还要吗」「知识库瘦身」「淘汰旧决策」「deprecate 条目」,或 doctor 报了 orphan/stale/低 health 想逐条处置时。
10
+
11
+ ## 两条红线(NON-NEGOTIABLE)
12
+
13
+ 1. **deprecate-over-delete**:陈旧 ≠ 该删。一条「当时为什么这么决策」的 decision/pitfall 即使方案已换,其 rationale 仍是知识。退役 = 降 maturity(proven→verified→draft)/ 标 `deprecated` + 记 `superseded-by`(保留正文),而非 `rm`。删除只用于「从未成立 / 纯噪声 / 重复」的条目。
14
+ 2. **rescue-before-delete**:任何 *打算删* 的条目,删前必做抢救检查 —— 它是否携带别处没有的独特 rationale / 反例 / 边界?有则先 merge 进取代它的条目(或在新条目加 `related` 边指回),再删空壳。抢救检查没做过,不许删。
15
+
16
+ ## 意图 → 动作映射
17
+
18
+ | 意图 | 动作 |
19
+ |---|---|
20
+ | 体检 / 健康度 | `fabric doctor`(读 lint + health rollup);零阻断,只报告 |
21
+ | 找孤儿 / 陈旧条目 | `fabric doctor`(消费 orphan / stale / orphan-demote 信号) |
22
+ | 退役一条陈旧条目 | **不删** → 降 maturity 或标 deprecated + `superseded-by`;经 `fab_review` 落盘 |
23
+ | 删一条「从未成立 / 重复」条目 | 先跑 rescue 检查(独特 rationale?有则 merge/加 related);确认空壳后才删 |
24
+ | 被取代但有价值 | rescue:把独特 rationale merge 进取代条目,新条目加 `related` 边指回,再退役旧条目 |
25
+
26
+ ## 流程(逐条处置)
27
+
28
+ 1. `fabric doctor` 取 KB health + orphan/stale 候选清单(引擎给信号,不自算)。
29
+ 2. 对每个候选判 **三态**:still-valid(留) / superseded(退役,走 deprecate) / never-valid(删,走 rescue 检查)。
30
+ 3. superseded → deprecate:降 maturity 或标 deprecated + `superseded-by`,保留正文 rationale。
31
+ 4. never-valid → rescue-before-delete:独特知识?有则 merge + `related`,无则删空壳。
32
+ 5. 处置经 `fab_review` 写路径落盘(本子流程给决策,fab_review 做写入),保持单一写路径。
33
+
34
+ ## Scope re-assignment(迁移 / backfill 后纠偏)
35
+
36
+ `fabric store migrate backfill` 给老条目补 `semantic_scope`,**默认把所有 team-layer 条目标成 `semantic_scope: team`** —— over-broad 的保守默认,会让项目专属知识错误暴露给所有项目。纠偏:
37
+
38
+ - **team-scope 判定测试**:「换一个**没有本 app 代码**的不同 repo,这条知识还成立吗?」—— 成立才是 `team`。app **内部**跨功能 / 跨玩法复用的共享组件(同一 app 多处用)**≠ team**,仍是 `project:<id>`(跨玩法复用 ≠ 跨项目复用,如 VoiceRoom)。
39
+ - **纠偏动作**:`fabric store migrate scope <store> --to project:<id> --id <id>`。
40
+ - 完整判定树 / worked examples 见单一真源:`fabric-archive/ref/phase-3-7-semantic-scope.md`。
41
+
42
+ ## Constraints
43
+
44
+ - 本子流程**只读 + 给处置建议**;实际写入(降级 / 标记 / 删)经 `fab_review` 写路径,不自行改 store `knowledge/`。
45
+ - NEVER 绕过 rescue 检查直接删;删前 MUST 先跑抢救。删是最后手段,默认 deprecate。
46
+ - store counters 派生态严禁手改;退役改的是 markdown frontmatter(maturity / deprecated / superseded-by),再 `fabric doctor --fix` reconcile。
47
+ - health / orphan / stale 一律取自 `fabric doctor` JSON 输出,不在 skill 内重算(单一真源)。
@@ -10,7 +10,7 @@ Semantic check is the LLM's job — the MCP tool does NOT compare meaning.
10
10
 
11
11
  For each pending entry to be presented:
12
12
 
13
- 1. Call `fab_review action="search"` with `query=<title or summary keywords>` and `filters.type=<same type>` to fetch already-canonical entries of the same type.
13
+ 1. Call `fab_pending action="search"` with `query=<title or summary keywords>` and `filters.type=<same type>` to fetch already-canonical entries of the same type.
14
14
  2. Compare semantically (LLM judgment, not string match). 三类判断均为 LLM 主观判断 dup/subsumption;具体阈值不可量化(不使用百分比 / 相似度数值伪精度):
15
15
  - **Duplicate** — same essential claim. 标题与摘要表达同一核心结论,pending 未提供新证据或新上下文。Flag: `⚠ Possible duplicate of <stable_id>`.
16
16
  - **Contradiction** — opposing claims about the same subject. 例:一个 entry 说 "use X",pending 说 "avoid X",且作用域一致。Flag: `⚠ Contradicts <stable_id>`.
@@ -12,8 +12,8 @@ Inferred mode: `pending` (Step 1 keyword "review … pending").
12
12
 
13
13
  Skill flow:
14
14
 
15
- 1. `fab_review action="list"` → returns 3 pending items.
16
- 2. Semantic check on item 2 (`pending/decisions/single-cjs-hook.md`) — `fab_review action="search"` with `query="single cjs hook"` filter `type=decisions` returns canonical `KT-D-0007--single-cjs-hook-across-clients.md` (similarity high).
15
+ 1. `fab_pending action="list"` → returns 3 pending items.
16
+ 2. Semantic check on item 2 (`pending/decisions/single-cjs-hook.md`) — `fab_pending action="search"` with `query="single cjs hook"` filter `type=decisions` returns canonical `KT-D-0007--single-cjs-hook-across-clients.md` (similarity high).
17
17
  3. Display block:
18
18
 
19
19
  ```md
@@ -36,7 +36,7 @@ Inferred mode: `revisit` (Step 1 keyword "look at <id>").
36
36
 
37
37
  Skill flow:
38
38
 
39
- 1. Read the canonical path returned by `fab_review search` for `KT-G-0003`. Display body to user.
39
+ 1. Read the canonical path returned by `fab_pending search` for `KT-G-0003`. Display body to user.
40
40
  2. AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` — user picks `modify`.
41
41
  3. Skill detects user-stated intent "actually personal not team" — surface AskUserQuestion `{options: ["team", "personal"]}` with current layer=team noted; user confirms `personal`.
42
42
  4. Call:
@@ -60,7 +60,7 @@ Inferred mode: `health` (Step 1 keyword "stale").
60
60
 
61
61
  Skill flow:
62
62
 
63
- 1. `fab_review action="list"` (no filter) + tail events.jsonl for trailing-30d demoted/layer_changed counts.
63
+ 1. `fab_pending action="list"` (no filter) + tail events.jsonl for trailing-30d demoted/layer_changed counts.
64
64
  2. Compute stale candidates: 3 pending entries with mtime >14d (KP-G-5 candidate-pending, KT-P-9 candidate-pending, KP-G-3 canonical draft with no evidence-append in 21d).
65
65
  3. Render dashboard then loop per stale item.
66
66
  4. Per-item AskUserQuestion fires:
@@ -74,7 +74,7 @@ Skill flow:
74
74
  User: "review the pending knowledge".
75
75
 
76
76
  Inferred mode: `pending`. Skill lists 5 pending entries; entry 3's frontmatter
77
- shows `source_sessions[0] = "fabric-import-2026-05-10"` → import-origin.
77
+ shows `source_sessions[0] = "fabric-archive-source-2026-05-10"` → import-origin.
78
78
 
79
79
  Display block prepends warning line. User picks `modify` on entry 3.
80
80
  AskUserQuestion fires with extended options including `narrow scope`.