@fenglimg/fabric-cli 2.0.0 → 2.1.0-rc.2

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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -5
  3. package/dist/chunk-BATF4PEJ.js +361 -0
  4. package/dist/{chunk-OBQU6NHO.js → chunk-COI5VDFU.js} +0 -18
  5. package/dist/chunk-F46ORPOA.js +903 -0
  6. package/dist/chunk-HFQVXY6P.js +86 -0
  7. package/dist/chunk-L4Q55UC4.js +52 -0
  8. package/dist/chunk-LFIKMVY7.js +27 -0
  9. package/dist/chunk-MF3OTILQ.js +544 -0
  10. package/dist/chunk-PWLW3B57.js +18 -0
  11. package/dist/chunk-RYAFBNES.js +33 -0
  12. package/dist/chunk-T5RPGCCM.js +40 -0
  13. package/dist/chunk-WU6GAPKH.js +36 -0
  14. package/dist/config-XJIPZNUP.js +13 -0
  15. package/dist/doctor-QVNPHLJK.js +920 -0
  16. package/dist/index.js +23 -8
  17. package/dist/{init-BIRSIOXO.js → install-2HDO5FTQ.js} +807 -705
  18. package/dist/metrics-ACEQFPDU.js +122 -0
  19. package/dist/onboard-coverage-MFCAEBDO.js +220 -0
  20. package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-FC6P3WFE.js} +34 -28
  21. package/dist/scope-explain-2F2R5URO.js +33 -0
  22. package/dist/status-GLQWLWH6.js +23 -0
  23. package/dist/store-XTSE5TY6.js +105 -0
  24. package/dist/sync-BJCWDPNC.js +245 -0
  25. package/dist/uninstall-TAXSUSKH.js +1073 -0
  26. package/dist/whoami-B6AEMSEV.js +31 -0
  27. package/package.json +30 -5
  28. package/templates/hooks/cite-policy-evict.cjs +231 -0
  29. package/templates/hooks/configs/README.md +29 -6
  30. package/templates/hooks/configs/claude-code.json +14 -3
  31. package/templates/hooks/configs/codex-hooks.json +6 -3
  32. package/templates/hooks/configs/cursor-hooks.json +8 -10
  33. package/templates/hooks/fabric-hint.cjs +873 -105
  34. package/templates/hooks/knowledge-hint-broad.cjs +549 -135
  35. package/templates/hooks/knowledge-hint-narrow.cjs +830 -26
  36. package/templates/hooks/lib/banner-i18n.cjs +309 -0
  37. package/templates/hooks/lib/bindings-snapshot-reader.cjs +81 -0
  38. package/templates/hooks/lib/cite-contract-reminder.cjs +179 -0
  39. package/templates/hooks/lib/cite-line-parser.cjs +180 -0
  40. package/templates/hooks/lib/client-adapter.cjs +106 -0
  41. package/templates/hooks/lib/config-cache.cjs +107 -0
  42. package/templates/hooks/lib/state-store.cjs +84 -0
  43. package/templates/hooks/lib/summary-fallback.cjs +210 -0
  44. package/templates/skills/fabric-archive/SKILL.md +97 -419
  45. package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
  46. package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
  47. package/templates/skills/fabric-archive/ref/i18n-policy.md +86 -0
  48. package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
  49. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +218 -0
  50. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +62 -0
  51. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +68 -0
  52. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +108 -0
  53. package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
  54. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
  55. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
  56. package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
  57. package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
  58. package/templates/skills/fabric-import/SKILL.md +77 -514
  59. package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
  60. package/templates/skills/fabric-import/ref/i18n-policy.md +79 -0
  61. package/templates/skills/fabric-import/ref/output-contract.md +61 -0
  62. package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
  63. package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
  64. package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
  65. package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
  66. package/templates/skills/fabric-review/SKILL.md +90 -284
  67. package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
  68. package/templates/skills/fabric-review/ref/i18n-policy.md +111 -0
  69. package/templates/skills/fabric-review/ref/modify-flow.md +103 -0
  70. package/templates/skills/fabric-review/ref/output-contract.md +58 -0
  71. package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
  72. package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
  73. package/templates/skills/fabric-review/ref/worked-examples.md +95 -0
  74. package/templates/skills/fabric-sync/SKILL.md +46 -0
  75. package/templates/skills/lib/shared-policy.md +69 -0
  76. package/dist/chunk-6ICJICVU.js +0 -10
  77. package/dist/chunk-74SZWYPH.js +0 -658
  78. package/dist/chunk-EYIDD2YS.js +0 -1000
  79. package/dist/doctor-T7JWODKG.js +0 -282
  80. package/dist/hooks-Y74Y5LQS.js +0 -12
  81. package/dist/scan-LMK3UCWL.js +0 -22
  82. package/dist/serve-H554BHLG.js +0 -124
  83. package/templates/agents-md/AGENTS.md.template +0 -59
  84. package/templates/bootstrap/CLAUDE.md +0 -8
  85. package/templates/bootstrap/codex-AGENTS-header.md +0 -6
  86. package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
@@ -1,588 +1,151 @@
1
1
  ---
2
2
  name: fabric-import
3
- description: Use this skill for cold-start enrichment of `.fabric/knowledge/` from existing project artifacts — mines `git log` and `docs/*.md` for candidate observations, proposes pending entries via `fab_extract_knowledge`, then deduplicates against canonical entries via `fab_review action: search` (rejecting obvious duplicates, modifying-to-merge marginal duplicates). Triggered by user prompts like "import knowledge from git history" / "bootstrap fabric for this repo" or by an explicit fabric-import skill mention. Default layer: team (project artifacts are team-shared). The 3-phase pipeline is resumable via `.fabric/.import-state.json`.
3
+ description: 冷启动从 git log + docs/*.md 回灌 .fabric/knowledge/pending (NOT code/data import). Triggers 导入历史/bootstrap fabric/mine changelog/挖掘 commit.
4
4
  allowed-tools: Read, Glob, Grep, Bash, mcp__fabric__fab_extract_knowledge, mcp__fabric__fab_review
5
5
  ---
6
6
 
7
- > **Surface**: This is a Skill (AI-driven, LLM judgment over git log + docs for cold-start enrichment). See [`docs/surfaces.md`](https://github.com/fenglimg/fabric/blob/main/docs/surfaces.md) for the CLI / Skill / MCP boundary.
7
+ > **Surface**: Skill (LLM judgment over git + docs). See [`docs/surfaces.md`](https://github.com/fenglimg/fabric/blob/main/docs/surfaces.md).
8
8
 
9
9
  ## Purpose
10
10
 
11
- `fabric-import` is a one-time (per project) cold-start skill that lifts existing project artifacts — git commit history and Markdown documentation — into the knowledge layer as pending entries. It is the bridge between a brand-new Fabric installation (which only has the 4–7 baseline entries produced by `fabric init`'s deterministic scan) and a useful corpus that reflects accumulated team thinking. Run it once when adopting Fabric on an existing repo, or after a major refactor that invalidates large chunks of canonical knowledge. Default layer is `team`: project artifacts in git/docs are team-shared by definition; the user can later layer-flip individual entries to `personal` via `fabric-review` modify.
11
+ One-time per-project cold-start: lift git commits + `docs/*.md` into `.fabric/knowledge/pending/` as `team`-layer entries. Bridges `fabric install`'s 4-7 baseline accumulated corpus. Run once on adoption or after major refactor.
12
12
 
13
13
  ## Precondition
14
14
 
15
- This skill is invoked when one of the following holds:
15
+ Invoke only when ANY: user explicit ("import knowledge" / "bootstrap fabric" / "mine changelog"); user named skill; SessionStart hook fired `shouldRecommendImport()`.
16
16
 
17
- - The user typed an explicit import request (e.g. "import knowledge from git history", "bootstrap fabric for this repo", "mine the changelog into pending", "fabric import")
18
- - The user explicitly mentioned this skill by name (`fabric-import`)
19
- - A `fabric import` CLI command was run (rc.4 wires this if shipped; otherwise treat as user prompt)
17
+ Else stop: `没有触发 import 信号;如需手动 import 请显式调用 fabric-import` / `No import signal detected; to manually import, explicitly invoke fabric-import` (per `fabric_language`).
20
18
 
21
- If none of the above hold, stop the skill immediately and tell the user `没有触发 import 信号;如需手动 import 请显式调用 fabric-import`.
19
+ SKIP when: `.fabric/` missing (→ `fabric install`); canonical > `import_skip_canonical_threshold` (default 50); state file `phase=complete` + `last_checkpoint_at <24h`.
22
20
 
23
- ### Phase 0 Sentinel Contract (rc.7 T1)
21
+ Required: `.fabric/` exists, `agents.meta.json` present, MCP `fab_extract_knowledge` + `fab_review` registered, working tree reasonably clean.
24
22
 
25
- **Sentinel file**: `.fabric/.import-requested` (empty content; presence-as-data).
23
+ ## Phase 0 Init
26
24
 
27
- This file is the cross-surface signal between `fabric init` (run in the
28
- user's terminal) and the AI client session that picks up the import
29
- recommendation. When `fabric init` ends with the clack confirm prompt
30
- "下次开 AI 时让我从 git log 抽更多知识吗?" and the user answers Y, the
31
- CLI writes this empty sentinel file. Two hooks read it:
25
+ Read/init `.fabric/.import-state.json`. Scan stale `.tmp-import-*`. State-corruption recovery `Read .../ref/state-recovery.md`.
32
26
 
33
- - `templates/hooks/knowledge-hint-broad.cjs` (SessionStart) appends an
34
- import-recommendation banner to the broad-injection stderr regardless of
35
- the rc.7 T8 `revision_hash` gate.
36
- - `templates/hooks/fabric-hint.cjs` (Stop) — bypasses the Signal C cooldown
37
- and emits the `signal:'import'` recommendation even when the underseed
38
- threshold or 24h cooldown would otherwise silence it.
27
+ > 旧 `.fabric/.import-requested` sentinel 机制已下线 (rc.8+);推荐由 SessionStart hook 的 underseed 自检触发(`shouldRecommendImport()`)。本 skill 不再读写 sentinel。
39
28
 
40
- **Phase 0 action for this skill**: read the sentinel state at the start of
41
- this skill invocation (informational only — proceed regardless of presence).
42
- The sentinel is **cleared in Step 3.4** (Phase 3 Completion) so subsequent
43
- sessions stop receiving the unconditional recommendation. If the skill
44
- fails or the user aborts before Step 3.4, the sentinel remains and the next
45
- session will see the recommendation again — this is intentional, the
46
- import is incomplete.
29
+ ## Phase 0.5 Config Load
47
30
 
48
- This skill SHOULD be skipped (warn the user, do not proceed) when:
31
+ Read `.fabric/fabric-config.json` for tunables (defaults if absent):
49
32
 
50
- - `.fabric/` does not exist — direct the user to run `fabric init` first; `fabric-import` is NOT a substitute for the deterministic init-scan
51
- - `.fabric/knowledge/` already holds **>50 canonical entries** across all types — the project is mature; use `fabric-archive` (per-session capture) and `fabric-review` (lifecycle review) instead; bulk import would just create dup churn
52
- - `.fabric/.import-state.json` exists with `phase: "complete"` and `last_checkpoint_at` is **<24h ago** — the user just ran import; surface the prior result rather than re-running
33
+ | Field | Default |
34
+ |---|---|
35
+ | `import_window_first_run_months` | 60 |
36
+ | `import_window_rerun_months` | 2 |
37
+ | `import_max_pending_per_run` | 10 |
38
+ | `import_max_commits_scan` | 500 |
39
+ | `import_skip_canonical_threshold` | 50 |
53
40
 
54
- Required preconditions before any MCP call:
41
+ First-run vs re-run by state file (ENOENT or `phase != complete && proposed == 0` → first-run window).
55
42
 
56
- - `.fabric/` directory exists in the project root
57
- - `.fabric/agents.meta.json` is present (init produced it; the id allocator reads it on later approve)
58
- - `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger is normal first-run)
59
- - `mcp__fabric__fab_extract_knowledge` AND `mcp__fabric__fab_review` MCP tools are registered and reachable
60
- - Working tree is reasonably clean (large uncommitted churn pollutes git-log mining; warn but allow)
43
+ ### Store routing (v2.1 multi-store)
61
44
 
62
- ## 3-Phase Pipeline (P1 reference / P2 mine / P3 dedup)
45
+ Import requires an **explicit target store** (E7) — mined entries are NOT auto-routed. Resolve candidates via `fabric scope-explain team` (writable stores in the read-set); if more than one writable store exists, `AskUserQuestion` for the target store alias before persisting (header/question translate, the alias options stay English routing keys). Single writable store → use it. Persist through `fab_extract_knowledge` with the chosen store; echo the target alias. Never write to a store the project did not declare (read-set bound).
63
46
 
64
- The pipeline runs strictly in order. Each phase reads the prior phase's outputs and updates `.fabric/.import-state.json` after every successful sub-step (not just at phase end). The skill is `Infer-not-Ask` for which phase to run (always all three when starting fresh, or resumes from the checkpoint phase).
47
+ ## UX i18n Policy
65
48
 
66
- ### Phase 1 Init-Scan Reference (NO RE-IMPLEMENTATION)
49
+ Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`). Emit prose per variant. Protected tokens NEVER translate (`fab_extract_knowledge`, `fab_review`, `.fabric/.import-state.json`, all enum strings, `MUST`/`NEVER`). Full 5-class taxonomy → `Read .../ref/i18n-policy.md`.
67
50
 
68
- > Verbatim boundary: `fabric init` (rc.1, deterministic CLI) already produces the baseline scan. Phase 1 of this skill **REFERENCES** that output. It does NOT redo the scan.
51
+ ## 3-Phase Pipeline
69
52
 
70
- The deterministic init-scan has already populated `.fabric/knowledge/team/` with 4–7 baseline entries derived from:
53
+ Strict P1→P2→P3 order. State write after every sub-step. Infer-not-Ask.
71
54
 
72
- - `package.json` (tech stack, scripts, key dependencies)
73
- - `README.md` first paragraph (project elevator pitch)
74
- - Build configuration (`tsconfig.json`, `pyproject.toml`, `Cargo.toml`, etc.)
75
- - Code style (`.editorconfig`, lint config)
76
- - CI configuration (`.github/workflows/`, `.gitlab-ci.yml`, etc.) when present
77
- - The first sentence of any top-level `LICENSE` (rare baseline signal)
55
+ ### Phase 1 Init-Scan Reference (NO RE-IMPLEMENT)
78
56
 
79
- Phase 1 actions performed by THIS skill:
57
+ `fabric install` produced baseline. Phase 1 REFERENCES, does NOT redo.
80
58
 
81
- 1. Read `.fabric/agents.meta.json` to confirm baseline counters exist (each type's `next_id` should be `>1` if init-scan landed entries; `=1` means init produced zero entries of that type — informational, not an error).
82
- 2. Glob `.fabric/knowledge/team/**/*.md` to enumerate baseline entry titles. Capture the list — Phase 2 uses these titles as a **negative filter** (signals already covered by init-scan should be skipped, not re-proposed).
83
- 3. If `.fabric/agents.meta.json` is missing OR `.fabric/knowledge/team/` is empty: STOP. Tell the user `请先运行 fabric init 完成基线扫描,再调用 fabric-import` and exit.
84
- 4. Update `.fabric/.import-state.json`: `phase = "P1-done"`, `p1_baseline_titles = [<list>]`, `last_checkpoint_at = <ISO8601 now>`.
59
+ 1. Read `agents.meta.json` confirm baseline counters.
60
+ 2. Glob `.fabric/knowledge/team/**/*.md` titles for P2 negative filter.
61
+ 3. If meta missing OR team/ empty: STOP. Tell user `请先运行 fabric install 完成基线扫描` / `Please run fabric install first` and exit.
62
+ 4. State: `phase=P1-done`, `p1_baseline_titles=[...]`, `last_checkpoint_at=<ISO>`.
85
63
 
86
- **Phase 1 produces no MCP calls.** It only reads the on-disk init-scan output.
64
+ No MCP calls.
87
65
 
88
- ### Phase 2 — LLM-Driven Git + Doc Mining
66
+ ### Phase 2 — LLM-Driven Mining
89
67
 
90
- For each candidate signal mined from git or docs, the skill classifies into one of the 5 types (`decisions / pitfalls / guidelines / models / processes`), drafts a slug per the 5-rule naming guideline (see fabric-archive for the canonical rules), and proposes a pending entry via `fab_extract_knowledge`. Default layer for every Phase 2 proposal: `team`.
68
+ Classify each candidate into 5 types (decisions/pitfalls/guidelines/models/processes), draft slug, propose via `fab_extract_knowledge`. Layer: `team`.
91
69
 
92
- #### Mandatory Scope Rule — Always Broad + Empty Paths (Q-1 Resolution)
70
+ #### Mandatory Scope Rule — broad + empty paths (NON-NEGOTIABLE)
93
71
 
94
- **EVERY `fab_extract_knowledge` call issued from this skill MUST set:**
72
+ Every call MUST `relevance_scope="broad"` AND `relevance_paths=[]`. No exceptions. Why: import is LLM-driven (not session-driven); LLM-inferred narrow lies about applicability. Post-rc.37 A1 the server returns every selectable entry regardless of scope, so false-narrow no longer hides knowledge — but it still poisons doctor lint accounting + downstream consumers that read `relevance_paths` literally. Narrowing deferred to `fab_review.modify` post-import when the user has the real applicability surface. Full rationale + prohibitions + doctor lint #23 → `Read .../ref/phase-2-mining.md`.
95
73
 
96
- - `relevance_scope = "broad"`
97
- - `relevance_paths = []`
74
+ #### Step 2.1 — Git Mining
98
75
 
99
- 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.
76
+ `git log --since="<window> months ago" --pretty=format:"%H%n%s%n%b%n---ENDCOMMIT---" -n <cap>`. Conventional prefix type signal (feat→decision/model, fix→pitfall, refactor→decision, docs→guideline; chore/test/ci skip). Extract observation Skip Tree `fab_extract_knowledge` (broad+[]). Cap: `import_max_pending_per_run`.
100
77
 
101
- **Rationale why fabric-import cannot bind paths from git history:**
78
+ #### Step 2.1.5 Proposed Reason
102
79
 
103
- 1. `fabric-import` is LLM-driven (mines git log + docs), not session-driven (no live `edit_paths` signal).
104
- 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.
105
- 3. LLM-inferred `relevance_paths` from historical commit metadata produces false-narrow bindings — entries get filtered out for paths they actually govern. False-narrow is worse than broad because it silently hides knowledge during plan-context filtering.
106
- 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/`).
80
+ Infer one of: `decision-confirmation` | `new-dependency-or-pattern` | `wrong-turn-revert` | `diagnostic-then-fix` | `explicit-user-mark` | `dismissal-with-reason`. Fallback: `new-dependency-or-pattern`. 11-row table → ref.
107
81
 
108
- **Strict prohibitionsDO NOT attempt any of the following:**
109
-
110
- - DO NOT derive `relevance_paths` from `git log --name-only` / `git show --stat` / `git diff` file lists.
111
- - 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/**"]`).
112
- - DO NOT extract path-shaped tokens from commit subjects / bodies / doc text and lift them into `relevance_paths`.
113
- - DO NOT classify a candidate as `relevance_scope = "narrow"` under ANY heuristic.
114
- - DO NOT copy the public-prefix-generalization logic from fabric-archive Phase 1.5 — that logic is valid only when bound to a real-time `edit_paths` signal from an active session, which fabric-import lacks.
115
-
116
- **Cross-reference — fabric-import vs fabric-archive scope handling:**
117
-
118
- | Skill | Scope decision | Why |
119
- |------------------|--------------------|-----------------------------------------------------------------------|
120
- | `fabric-archive` | narrow OR broad, case-by-case per Phase 1.5 rules | Has live `edit_paths` from the active session — the actual applicability surface. |
121
- | `fabric-import` | ALWAYS broad + `[]` (this skill) | LLM-only, no live session signal; git-history paths are effect-surface, not applicability-surface. |
122
-
123
- `fabric-archive`'s Phase 1.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.
124
-
125
- **Post-import narrowing path — deferred to user, via `fab_review.modify`:**
126
-
127
- After import completes, the user reviews each kept pending entry via `fabric-review`. When the user judges that an imported entry is actually narrow-scoped, they (or the reviewing Agent on their explicit instruction) issue:
82
+ #### Step 2.2 Docs Mining
128
83
 
129
- ```ts
130
- mcp__fabric__fab_review({
131
- action: "modify",
132
- pending_path: "<the imported pending or its post-approval canonical path>",
133
- changes: {
134
- relevance_scope: "narrow",
135
- relevance_paths: ["packages/server/src/retry/**", "packages/server/src/lib/retry.ts"]
136
- }
137
- })
138
- ```
84
+ `find docs/ -maxdepth 3 -name '*.md'` + root `*.md`. Skip README / CHANGELOG / LICENSE / CODE_OF_CONDUCT / CONTRIBUTING / <300B files. Same call shape. Shared cap.
139
85
 
140
- This is the ONLY legal path for an imported entry to acquire `relevance_paths`. The narrowing decision is the user's, informed by the actual `relevance_paths` candidates they propose — not the skill's, inferred from git metadata.
86
+ #### Skip Decision Tree
141
87
 
142
- **Lint backstop:** doctor lint #23 (`narrow_no_paths`) warns on any `relevance_scope=narrow` entry with empty `relevance_paths`. If this skill ever deviates from the broad+[] rule and writes narrow without paths, lint #23 catches the mistake post-hoc.
88
+ Skip if: cosmetic-only / metadata-only / in baseline / not classifiable / slug not derivable to 2-5 kebab words.
143
89
 
144
- #### Step 2.1 — Git Log Mining
90
+ #### Dry-Run
145
91
 
146
- Bash command (executed via the `Bash` tool):
92
+ Explicit token `--dry-run` in invocation → skip MCP, render bilingual preview table (every Scope row `broad+[]`). State NOT written. P3 skipped. v2.0.0-rc.37 NEW-10 dropped legacy substring fallback on bare `dry-run` / `预览` (false-positive on incidental mentions).
147
93
 
148
- ```bash
149
- git log --since="2 months ago" --pretty=format:"%H%n%s%n%b%n---ENDCOMMIT---" -n 200
150
- ```
94
+ Full MCP call shape, Step 2.1.5 table, dry-run templates, T5 idempotency → `Read .../ref/phase-2-mining.md`.
151
95
 
152
- Tolerate empty output (shallow clone or new repo). Cap the working set at the **most recent 200 commits** regardless of date range to bound LLM context.
96
+ ### Phase 3 LLM-Driven Dedup
153
97
 
154
- For each commit:
98
+ For each P2 pending: check vs canonical. Semantic compare is LLM's job — `fab_review` does NOT compare meaning.
155
99
 
156
- 1. Inspect the conventional-commit prefix in the subject line. Strong signals:
157
- - `feat(...)` with a non-empty body likely **decision** or **model** (a new capability landed; the body usually explains why)
158
- - `fix(...)` with body length >100 chars → likely **pitfall** (a bug worth diagnosing was non-trivial)
159
- - `refactor(...)` with body likely **decision** (architectural choice was made)
160
- - `docs(...)` → usually a **guideline** if the body announces a convention; skip if it's just typo/reformat
161
- - `chore(...)`, `test(...)`, `ci(...)` → almost always skip (mechanical; no reusable insight)
162
- 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 knowledge_language; mirror fabric-archive M3 style).
163
- 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.
164
- 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):
100
+ 1. **3.1** `fab_review action="search"` filter by `type`, top 5.
101
+ 2. **3.2** — Classify each pair: `duplicate` (reject pending) | `subsumption` (reject pending) | `subsumption-with-novelty` (modify canonical + reject pending) | `contradiction` (leave + flag) | `genuinely-new` (keep).
102
+ 3. **3.3** Issue `fab_review` reject / modify.
103
+ 4. **3.4** — `phase=complete` + `final_summary` + roll-up.
165
104
 
166
- ```ts
167
- mcp__fabric__fab_extract_knowledge({
168
- source_sessions: ["fabric-import-<ISO8601-date>"], // T5: array form; stable per import run
169
- recent_paths: ["<files touched by this commit, capped at 20>"], // provenance only, NOT a path-binding signal
170
- user_messages_summary: "<zh-CN 1-2 sentence summary of the commit's core observation; cite the commit sha as 'src=<sha7>'>",
171
- type: "decisions" | "pitfalls" | "guidelines" | "models" | "processes",
172
- slug: "<kebab-case 2-5 words derived from commit subject + body>",
173
- relevance_scope: "broad", // MANDATORY — never "narrow" from fabric-import
174
- relevance_paths: [], // MANDATORY — never derived from git history
175
- // v2.0.0-rc.7 T6: fabric-import defaults to `new-dependency-or-pattern`
176
- // because git-log mining surfaces newly-introduced abstractions/conventions.
177
- // session_context cites the commit / doc origin so future-self reviewers
178
- // know this is an LLM-mined entry rather than a live-session capture.
179
- proposed_reason: "new-dependency-or-pattern",
180
- session_context: "Imported from git log analysis. Origin: commit <sha7> (<subject 30 chars>). No live session — see commit body for full context."
181
- })
182
- ```
105
+ Full call shapes + 5-way classification → `Read .../ref/phase-3-dedup.md`.
183
106
 
184
- Note: `recent_paths` continues to carry the touched-file list for **provenance display** (so the user can audit which commit produced which entry). It is NOT lifted into `relevance_paths` — those two fields serve different purposes and the prohibition on path inference from git history applies.
107
+ ## Checkpoint Logic
185
108
 
186
- 5. On success the server returns `{pending_path, idempotency_key}`. Append to `.fabric/.import-state.json`:
187
- - `p2_processed_commits[].push({sha: <full sha>, skipped: false, pending_path, type, slug})`
188
- - `last_checkpoint_at = <ISO8601 now>`
189
- Update is atomic (write to temp file then rename) so a crash between commits never corrupts the state file.
190
- 6. **Hard cap**: at most **10 new pending entries** per Phase 2 run. When the cap is reached, mark `p2_cap_reached = true` and stop git-log iteration (the user can re-invoke for more — idempotent resume picks up from the next unprocessed commit).
109
+ State file `.fabric/.import-state.json` is single resumability source. Atomic write: Step A `Write .tmp` Step B `Bash mv` (POSIX `rename(2)`). `Write` alone NOT atomic.
191
110
 
192
- #### Step 2.2 Docs Mining
111
+ Resume contract: re-invoke MUST NOT dup-propose / re-dedup. By `phase`: `P1-done`→2.1, `P2-done`→3.1, `complete <24h`→skip, `≥24h`→confirm.
193
112
 
194
- Bash command (executed via the `Bash` tool):
113
+ Full rationale + 4KB POSIX constraint + state schema + 6-step Resume → `Read .../ref/checkpoint-state.md`.
195
114
 
196
- ```bash
197
- find docs/ -maxdepth 3 -name '*.md' -type f 2>/dev/null
198
- ls -1 *.md 2>/dev/null # root-level architectural docs
199
- ```
115
+ ## Default Knobs
200
116
 
201
- For each Markdown file:
117
+ Layer `team` / scope `broad` / paths `[]` are contract-locked (no override). Max pending = config / dry-run via keyword / re-run <24h blocked. Full table → ref.
202
118
 
203
- 1. **Skip filter**:
204
- - `README.md` → skip (its first paragraph already lives in init-scan; its body is too generic for fine-grained classification)
205
- - `CHANGELOG.md` → skip (rendered from commit log; mining commits already covers it)
206
- - `LICENSE.md`, `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md` → skip (boilerplate)
207
- - Files <300 bytes → skip (too thin to extract meaningful observations)
208
- 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.
209
- 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. The mined doc's own path goes into `recent_paths` for provenance display ONLY — it is NOT lifted into `relevance_paths`.
210
- 4. Append to `.fabric/.import-state.json`:
211
- - `p2_processed_docs[].push({path: <doc path>, observations_proposed: <count>, pending_paths: [...]})`
212
- 5. **Hard cap shared with Step 2.1**: total new pending entries across git + docs is capped at 10 per Phase 2 run.
119
+ ## Hard Rules
213
120
 
214
- #### Skip Decision Tree (when to NOT propose)
121
+ ### DISPLAY (per entry)
215
122
 
216
- ```
217
- A candidate signal surfaces (commit body or doc section).
218
- ├─ Is it cosmetic only? ("fix typo", whitespace, formatting)
219
- │ └─ YES → skip
220
- ├─ Is the body just metadata? (Co-Authored-By, Signed-off-by, no prose)
221
- │ └─ YES → skip
222
- ├─ Is the same observation already covered by an init-scan baseline title (Phase 1 list)?
223
- │ └─ YES → skip (don't re-propose what init already captured)
224
- ├─ Does the observation fit one of {decisions, pitfalls, guidelines, models, processes}?
225
- │ └─ NO → skip (not classifiable = not yet ripe)
226
- ├─ Is the slug derivable as 2-5 kebab-case words?
227
- │ └─ NO → skip (signal too vague for stable identifier)
228
- └─ Else → propose via fab_extract_knowledge
229
- ```
123
+ `[type=...]` `[layer=team]` `[scope=broad]` `slug=...` `src=<sha7-or-path>` + `pending_path`. zh-CN body + EN headings. Roll-up: proposed / kept / rejected_dup / merged / contradictions_flagged. Final `phase` on exit. Never hide source / show `idempotency_key` / auto-classify `personal`.
230
124
 
231
- After Step 2.2 completes (or hits the cap), update `.fabric/.import-state.json`: `phase = "P2-done"`, `last_checkpoint_at = <ISO8601 now>`.
125
+ ### WRITE
232
126
 
233
- #### Dry-Run Mode
127
+ NEVER write entry via `Edit`/`Write`/`Bash` — only `fab_extract_knowledge` (P2) + `fab_review` (P3).
234
128
 
235
- When the user invocation includes `dry-run` / `预览` / `--dry-run` keywords, Phase 2 runs WITHOUT calling `fab_extract_knowledge`. Instead it prints a table:
129
+ NEVER batch P2 candidates / skip P1 ref / call `fab_review.approve` / `git mv` directly / infer layer-flip / non-atomic state / exceed cap / `relevance_scope="narrow"` / non-empty `relevance_paths` / copy fabric-archive Phase 1.5 logic.
236
130
 
237
- ```md
238
- # Import Dry Run — would propose N pending entries (all relevance_scope=broad, relevance_paths=[])
131
+ Narrowing post-import = `fab_review.modify` (out-of-band).
239
132
 
240
- | # | Source | Type | Slug | Scope | Summary (zh-CN) |
241
- |---|-----------------------|-----------|-------------------------------|-------|------------------------------------------------------------|
242
- | 1 | git c0a351d | decisions | layer-flip-id-mutation | broad+[] | layer 切换是唯一合法的 stable_id 变更途径,绑定原子事务。 |
243
- | 2 | docs/architecture.md | decisions | monolith-over-microservices | broad+[] | 决定保留单体架构,三人团队不值微服务运维成本。 |
244
- | 3 | git 50367b5 | pitfalls | thundering-herd-no-backoff | broad+[] | 重试无指数回退导致雪崩;必须 jittered exponential backoff。|
245
- ```
246
-
247
- Every dry-run row MUST show `broad+[]` in the Scope column (it is a 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.
248
-
249
- ### Phase 3 — LLM-Driven Dedup vs Canonical
250
-
251
- For each pending entry created in Phase 2 (read from `p2_processed_commits[].pending_path` and `p2_processed_docs[].pending_paths`), check if it duplicates / contradicts / is subsumed by an existing canonical entry. **Semantic comparison is the LLM's job — `fab_review` does not compare meaning.**
252
-
253
- #### Step 3.1 — Search Canonical of Same Type
254
-
255
- For each just-proposed pending entry (read its frontmatter via the `Read` tool to get type + slug + title):
256
-
257
- ```ts
258
- mcp__fabric__fab_review({
259
- action: "search",
260
- query: "<title or summary keywords from the pending entry>",
261
- filters: { type: "<same type as pending>" }
262
- })
263
- ```
264
-
265
- The server returns ranked `items[]` of CANONICAL entries (not pending) of the same type. Cap the comparison set at the top 5 results.
266
-
267
- #### Step 3.2 — Semantic Compare
268
-
269
- For each `(pending, canonical)` pair the LLM judges:
270
-
271
- - **Duplicate** — same essential claim. Heuristics: title keyword overlap >60%, summary asserts the same outcome with no novel evidence. Action: **reject** the new pending.
272
- - **Subsumption** (pending narrower) — canonical fully covers the pending plus more. Action: **reject** the new pending (canonical already serves).
273
- - **Subsumption-with-novelty** (pending adds evidence) — canonical covers the claim but the new pending brings new evidence (commit sha, file paths). Action: **modify** the canonical to merge in the new evidence; **reject** the new pending citing the modified canonical.
274
- - **Contradiction** — opposing claims about the same scope. Action: leave pending; flag for user via roll-up. The user must decide via `fabric-review` later — `fabric-import` does NOT auto-resolve contradictions.
275
- - **Genuinely new** — no canonical match. Action: leave pending in place (will surface in next `fabric-review` run for normal approval flow).
276
-
277
- #### Step 3.3 — Issue Dedup MCP Calls
278
-
279
- For each `reject`-classified pending:
280
-
281
- ```ts
282
- mcp__fabric__fab_review({
283
- action: "reject",
284
- pending_paths: ["<the new pending path>"],
285
- reason: "duplicate of <stable_id of canonical>" // OR "subsumed by <stable_id>"
286
- })
287
- ```
288
-
289
- For each `subsumption-with-novelty` case (modify canonical, then reject pending):
290
-
291
- ```ts
292
- // Step A: merge new evidence into canonical
293
- mcp__fabric__fab_review({
294
- action: "modify",
295
- pending_path: "<canonical's pending_path-style relative path>",
296
- changes: { summary: "<merged summary; original + new evidence cite>" }
297
- })
298
-
299
- // Step B: reject the now-superseded pending
300
- mcp__fabric__fab_review({
301
- action: "reject",
302
- pending_paths: ["<the new pending path>"],
303
- reason: "merged into <stable_id of modified canonical>"
304
- })
305
- ```
306
-
307
- Append to `.fabric/.import-state.json` after EACH successful MCP call:
308
-
309
- - `p3_dedup_completed[].push({pending_path: <new pending>, action: "reject" | "modify-then-reject" | "kept", canonical_ref: "<stable_id>" | null})`
310
- - `last_checkpoint_at = <ISO8601 now>`
311
-
312
- #### Step 3.4 — Phase 3 Completion
313
-
314
- After all Phase 2 outputs are dedup-reviewed:
315
-
316
- - Update `.fabric/.import-state.json`: `phase = "complete"`, `last_checkpoint_at = <ISO8601 now>`, `final_summary = {proposed: N, kept: K, rejected_dup: R, merged: M, contradictions_flagged: C}`.
317
- - Render the final roll-up to the user (see Output Contract below).
318
- - **rc.7 T1 sentinel clear**: if `.fabric/.import-requested` exists (the
319
- cross-surface signal from `fabric init`'s Y-confirm hand-off — see Phase 0
320
- contract below), delete it now via `Bash: rm -f .fabric/.import-requested`.
321
- Failure to remove is non-fatal: log a warning but do not error out — the
322
- user can manually delete the sentinel if needed. The sentinel's lifecycle
323
- ends here so the SessionStart and Stop hooks stop unconditionally
324
- recommending fabric-import.
325
-
326
- The user MAY manually delete `.fabric/.import-state.json` to reset, or the skill MAY offer a one-line "reset state and re-run from scratch?" prompt the next time it is invoked with `phase="complete"` already present.
327
-
328
- ## Checkpoint Logic — `.fabric/.import-state.json`
329
-
330
- The state file lives at `.fabric/.import-state.json` and is the single source of resumability for fabric-import. It is written via `atomicWriteJson` (write-temp-then-rename) so a crash between phases / between sub-steps never corrupts it.
331
-
332
- ### Schema (all fields)
333
-
334
- ```json
335
- {
336
- "phase": "P1-done | P2-done | complete",
337
- "started_at": "<ISO8601 first invocation>",
338
- "last_checkpoint_at": "<ISO8601 most recent successful sub-step>",
339
- "p1_baseline_titles": ["<title1>", "<title2>"],
340
- "p2_processed_commits": [
341
- { "sha": "<full sha>", "skipped": true,
342
- "skip_reason": "cosmetic | metadata-only | already-in-baseline | unclassifiable | overlong-slug" },
343
- { "sha": "<full sha>", "skipped": false,
344
- "pending_path": "knowledge/pending/<type>/<slug>.md",
345
- "type": "<one of 5>", "slug": "<kebab-case-slug>" }
346
- ],
347
- "p2_processed_docs": [
348
- { "path": "docs/<file>.md", "observations_proposed": 2,
349
- "pending_paths": ["<path1>", "<path2>"] }
350
- ],
351
- "p2_cap_reached": false,
352
- "p3_dedup_completed": [
353
- { "pending_path": "<new pending path>",
354
- "action": "reject | modify-then-reject | kept",
355
- "canonical_ref": "<stable_id or null>" }
356
- ],
357
- "errors": [
358
- { "step": "P2.git", "ref": "<commit sha or doc path>", "error": "<message>" }
359
- ],
360
- "final_summary": {
361
- "proposed": 0, "kept": 0, "rejected_dup": 0, "merged": 0, "contradictions_flagged": 0
362
- }
363
- }
364
- ```
365
-
366
- ### Resume Logic (Idempotent Re-Invocation)
367
-
368
- On every skill invocation, BEFORE Phase 1 starts:
369
-
370
- 1. Read `.fabric/.import-state.json`. ENOENT → fresh run, initialize state with `phase: "P1-done"` after Phase 1 completes (state file is created at end of Phase 1, not at start).
371
- 2. If `phase === "complete"` AND `last_checkpoint_at < 24h ago` → SKIP this invocation (precondition warning above) unless user explicitly typed `re-run import` or `reset import`.
372
- 3. If `phase === "complete"` AND `last_checkpoint_at ≥ 24h ago` → ask the user (free-text prompt, NOT AskUserQuestion since this is rare): "上次 import 已完成 (<N> 天前)。重新运行将基于当前 canonical 重做 P2/P3。继续?(y/n)"; if `n`, exit.
373
- 4. If `phase === "P1-done"` → skip Phase 1; resume from Phase 2 Step 2.1; iterate git log skipping any sha already in `p2_processed_commits[]`.
374
- 5. If `phase === "P2-done"` → skip Phase 1 + Phase 2; resume from Phase 3 Step 3.1; iterate Phase 2 outputs skipping any pending_path already in `p3_dedup_completed[]`.
375
- 6. After every successful sub-step (one commit processed, one doc processed, one dedup pair resolved), atomically write the updated state file. Failures append to `errors[]` and proceed (or halt with prompt if cumulative errors `>5`).
376
-
377
- The contract: re-invoking fabric-import after ANY interruption (Ctrl-C, crash, network blip on MCP) MUST NOT propose duplicates of already-proposed entries and MUST NOT redo already-completed dedup decisions.
378
-
379
- ## Default Behavior & Knobs
380
-
381
- | Knob | Default | Override |
382
- |-------------------------------------|-------------|----------------------------------------------------------------|
383
- | Layer for new entries | `team` | User explicit instruction ("import these as personal") |
384
- | `relevance_scope` for new entries | `broad` | NONE — contract-locked; narrowing deferred to `fab_review.modify` post-import |
385
- | `relevance_paths` for new entries | `[]` | NONE — contract-locked; populating deferred to `fab_review.modify` post-import |
386
- | Max new pending entries per P2 run | `10` | User explicit ("import up to 25"); skill caps at 50 hard |
387
- | Git log window | `2 months` | User explicit ("import the full year") |
388
- | Docs scan depth | `3` | User explicit ("scan docs/ recursively") |
389
- | Dry-run mode | OFF | User keyword `dry-run` / `预览` / `--dry-run` |
390
- | Re-run within 24h of complete | BLOCKED | User keyword `re-run import` / `reset import` |
391
-
392
- ## Hard Rules — DISPLAY / WRITE Split
393
-
394
- ### DISPLAY Rules
395
-
396
- - MUST present every proposed pending entry with explicit `[type=...]`, `[layer=team]`, `[scope=broad]`, `slug=...`, AND `src=<commit-sha7 or doc-path>` so the user can audit the provenance and the (constant) scope.
397
- - MUST display zh-CN body for proposed summaries (M3 style consistent with fabric-archive / fabric-review).
398
- - MUST display EN section headings.
399
- - MUST surface the resolved `pending_path` returned by `fab_extract_knowledge` in the per-entry display block.
400
- - MUST display the final roll-up with proposed / kept / rejected_dup / merged / contradictions_flagged counts.
401
- - MUST display the `.fabric/.import-state.json` `phase` value when the skill exits (so the user knows whether re-invocation is required).
402
- - NEVER hide the source signal; provenance is the only audit trail for bulk-imported entries.
403
- - NEVER classify a Phase 2 candidate as `personal` automatically — default `team` is contract-locked; only flip layer at the user's explicit instruction (and even then, do it post-import via fabric-review).
404
- - NEVER show raw `idempotency_key` to the user (internal server-side concern).
405
-
406
- ### WRITE Rules
407
-
408
- - NEVER write a knowledge entry directly via `Edit` / `Write` / `Bash`; the only legal write paths are `mcp__fabric__fab_extract_knowledge` (Phase 2) and `mcp__fabric__fab_review` (Phase 3).
409
- - NEVER batch multiple Phase 2 candidates into a single `fab_extract_knowledge` call; one call per candidate.
410
- - NEVER skip the Phase 1 reference step — even if init-scan landed zero entries, the skill MUST verify `.fabric/agents.meta.json` is present.
411
- - NEVER call `fab_review action="approve"` from this skill — promotion of pending → canonical is `fabric-review`'s concern, not import's. Imported entries land in `pending/` and wait for normal review flow.
412
- - NEVER call `git mv` directly — layer flips during Phase 3 dedup go through `fab_review action="modify"` with `changes.layer`, which is a server-side transaction.
413
- - NEVER infer a layer-flip target without explicit user instruction — fabric-import defaults `team`; if the user later wants `personal` for an entry, that's a `fabric-review` modify call, not an import-time decision.
414
- - NEVER overwrite `.fabric/.import-state.json` non-atomically — use `atomicWriteJson` (write-temp-then-rename).
415
- - NEVER exceed the 10-entry-per-run hard cap without explicit user override.
416
- - NEVER pass `relevance_scope = "narrow"` to `fab_extract_knowledge` — every call from this skill MUST use `relevance_scope: "broad"`. No heuristic, no Agent judgment, no per-candidate override (see "Mandatory Scope Rule" in Phase 2).
417
- - NEVER populate `relevance_paths` with a non-empty array on import — every call from this skill MUST pass `relevance_paths: []`. Do not derive paths from `git log --name-only`, `git show --stat`, commit subjects/bodies, or the path of a mined Markdown file.
418
- - NEVER copy fabric-archive's Phase 1.5 scope-decision logic (narrow-vs-broad rules, public-prefix generalization, glob blacklist) into this skill — that logic requires a live `edit_paths` signal from an active session, which fabric-import does not have.
419
- - Narrowing of imported entries happens out-of-band through `fab_review action="modify"` (issued by user via `fabric-review`), NOT inside this skill.
420
- - MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_proposed`, `fab_extract_knowledge`, `fab_review`, `MUST`, `NEVER`, `phase`, `.import-state.json`, `relevance_scope`, `relevance_paths`, `broad`, `narrow`.
133
+ Protected tokens (verbatim, no translate): `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_proposed`, `fab_extract_knowledge`, `fab_review`, `MUST`, `NEVER`, `phase`, `.import-state.json`, `relevance_scope`, `relevance_paths`, `broad`, `narrow`, `source_sessions`, `proposed_reason`, `session_context`, `intent_clues`, `tech_stack`, `impact`, `must_read_if`.
421
134
 
422
135
  ## Output Contract
423
136
 
424
- After Phase 3 completes (or on any phase exit due to cap / error / interrupt), the skill MUST produce a roll-up:
425
-
426
- ```md
427
- # Import Summary — phase=<P1-done | P2-done | complete>
428
-
429
- ## Phase 2 — Mining
430
- - Commits scanned: <N> (skipped: <S> — cosmetic/metadata/baseline-overlap)
431
- - Docs scanned: <D> (skipped: <DS> — README/CHANGELOG/boilerplate)
432
- - Pending proposed: <P> (cap_reached: <true|false>)
433
- - Scope: all <P> proposed entries use relevance_scope=broad, relevance_paths=[] (fabric-import contract).
434
-
435
- ## Phase 3 — Dedup
436
- - Kept (genuinely new): <K>
437
- - Rejected (duplicate): <RD>
438
- - Modified-then-rejected: <MR> (canonical entries enriched: <list of stable_ids>)
439
- - Contradictions flagged: <C> (require manual fabric-review)
440
-
441
- ## State
442
- - .fabric/.import-state.json phase: <phase>
443
- - last_checkpoint_at: <ISO8601>
444
- - Re-invoke to continue if phase != complete.
445
-
446
- ## Next Steps
447
- - Run `fabric-review` to approve the <K> kept pending entries.
448
- - Resolve <C> contradictions manually if any.
449
- - If any kept entry is actually narrow-scoped, narrow it via `fab_review action="modify"` with `changes.relevance_scope="narrow"` + `changes.relevance_paths=[...]` (this skill cannot narrow — see Mandatory Scope Rule in Phase 2).
450
- ```
451
-
452
- Also surface a one-line `git status` of `.fabric/knowledge/` so the user sees the new pending files appear (and any canonical files modified by dedup-merge).
137
+ Roll-up sections (per `fabric_language`): `Phase 2 — Mining` | `Phase 3 Dedup` | `State` | `Next Steps`. Plus one-line `git status .fabric/knowledge/`. Bilingual templates `Read .../ref/output-contract.md`.
453
138
 
454
139
  ## Worked Examples
455
140
 
456
- ### Example A Phase 2 git mining: feat commitpitfall entry
457
-
458
- Source signal: `git log` surfaces commit `50367b5` with subject `feat(server): add custom retry logic` and body explaining that initial implementation retried without exponential backoff, causing a thundering-herd outage during a brief upstream hiccup; the fix was jittered exponential backoff with a 30s ceiling.
459
-
460
- 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).
461
-
462
- Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for fabric-import):
463
-
464
- ```ts
465
- mcp__fabric__fab_extract_knowledge({
466
- source_sessions: ["fabric-import-2026-05-10"],
467
- recent_paths: ["packages/server/src/lib/retry.ts"], // provenance only
468
- user_messages_summary: "重试无指数退避会在短暂上游故障下放大成雪崩。修正:jittered exponential backoff,30 秒上限。src=50367b5",
469
- type: "pitfalls",
470
- slug: "retry-without-backoff-thundering-herd",
471
- relevance_scope: "broad", // MANDATORY
472
- relevance_paths: [], // MANDATORY — do NOT infer ["packages/server/src/lib/retry.ts"]
473
- proposed_reason: "new-dependency-or-pattern", // T6: import default
474
- session_context: "Imported from git log analysis. Origin: commit 50367b5 (feat(server): add custom retry logic). No live session — see commit body for full context."
475
- })
476
- ```
477
-
478
- Counter-example — DO NOT do this:
479
-
480
- ```ts
481
- // WRONG — this skill must never produce narrow + paths from git metadata.
482
- // The retry pitfall applies to every retry site, not just the file touched by 50367b5.
483
- mcp__fabric__fab_extract_knowledge({
484
- // ...
485
- relevance_scope: "narrow", // VIOLATION
486
- relevance_paths: ["packages/server/src/lib/retry.ts"] // VIOLATION
487
- })
488
- ```
489
-
490
- If the user later judges this pitfall to be narrow-scoped, they (via `fabric-review`) issue `fab_review action="modify"` with `changes.relevance_scope` + `changes.relevance_paths` — that is the legal narrowing path.
491
-
492
- State file delta:
493
- ```json
494
- { "p2_processed_commits": [
495
- { "sha": "50367b5...", "skipped": false,
496
- "pending_path": "knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md",
497
- "type": "pitfalls", "slug": "retry-without-backoff-thundering-herd" }
498
- ]
499
- }
500
- ```
501
-
502
- ### Example B — Phase 2 doc mining: architecture.md → decision entry
503
-
504
- Source signal: `docs/architecture.md` contains a section heading "## Why a monolith?" with body explaining the team chose monolith over microservices because the 3-engineer team couldn't justify the operational cost of multi-service deploys, and the dominant performance constraint (DB throughput) doesn't benefit from horizontal split.
505
-
506
- LLM analysis: this is a **decision** (≥2 alternatives weighed — monolith vs microservices — with explicit rationale). Slug candidates: `monolith-over-microservices-small-team` (5 words, 38 chars — passes 5 rules).
507
-
508
- Skill output (broad+[] mandatory; the doc's own path stays in `recent_paths` for provenance, NOT in `relevance_paths`):
509
-
510
- ```ts
511
- mcp__fabric__fab_extract_knowledge({
512
- source_session: "fabric-import-2026-05-10",
513
- recent_paths: ["docs/architecture.md"], // provenance only
514
- user_messages_summary: "选择单体架构而非微服务:3 人团队无法承担多服务运维成本,且主要性能瓶颈在 DB 吞吐而非应用层水平扩展。src=docs/architecture.md",
515
- type: "decisions",
516
- slug: "monolith-over-microservices-small-team",
517
- relevance_scope: "broad", // MANDATORY
518
- relevance_paths: [] // MANDATORY — a monolith-vs-microservices decision applies repo-wide, not only to docs/
519
- })
520
- ```
521
-
522
- ### Example C — Phase 3 dedup finds duplicate, rejects
523
-
524
- After Example A's pending entry (`retry-without-backoff-thundering-herd`) is proposed, Phase 3 runs:
525
-
526
- ```ts
527
- mcp__fabric__fab_review({
528
- action: "search",
529
- query: "retry backoff thundering herd",
530
- filters: { type: "pitfalls" }
531
- })
532
- ```
533
-
534
- Server returns 1 canonical match: `KT-P-0007--retry-no-jitter-amplification.md` with summary "重试缺少 jitter 在并发场景放大原始故障峰值". LLM judgment: the existing canonical asserts the same essential claim (retry without jitter amplifies failures) — this is a **duplicate**, not subsumption-with-novelty (the new pending offers no new evidence beyond restating the trap).
535
-
536
- Skill output:
537
-
538
- ```ts
539
- mcp__fabric__fab_review({
540
- action: "reject",
541
- pending_paths: ["knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md"],
542
- reason: "duplicate of KT-P-0007"
543
- })
544
- ```
545
-
546
- State file delta:
547
- ```json
548
- { "p3_dedup_completed": [
549
- { "pending_path": "knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md",
550
- "action": "reject", "canonical_ref": "KT-P-0007" }
551
- ]
552
- }
553
- ```
554
-
555
- Final roll-up to user reflects: 1 proposed, 0 kept, 1 rejected_dup, 0 merged, 0 contradictions.
556
-
557
- ### Example D — Post-import narrowing (out-of-band, NOT this skill)
558
-
559
- 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.
560
-
561
- The user issues (via `fabric-review`, NOT via this skill):
562
-
563
- ```ts
564
- mcp__fabric__fab_review({
565
- action: "modify",
566
- pending_path: "knowledge/team/decisions/monolith-over-microservices-small-team.md",
567
- changes: {
568
- relevance_scope: "narrow",
569
- relevance_paths: ["packages/server/**", "scripts/deploy/**"]
570
- }
571
- })
572
- ```
573
-
574
- Key invariants of this flow:
575
-
576
- - The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `fabric-import` inferring paths from git metadata.
577
- - The modify call goes through `fab_review`, not `fab_extract_knowledge`, because the entry already exists (post-import or post-approval).
578
- - 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.
141
+ 4 end-to-end (A feat→pitfall + WRONG counter-ex; B docs→decision; C P3 dupreject; D out-of-band narrow) → `Read .../ref/worked-examples.md`.
579
142
 
580
143
  ## Failure Recovery
581
144
 
582
- - **Phase 2 mid-run failure** (e.g. `fab_extract_knowledge` errors on commit 5 of 10): state already records commits 1–4; rerun resumes at commit 5 by skipping any sha in `p2_processed_commits[]`. Error appended to `errors[]`.
583
- - **Phase 3 mid-run failure** (e.g. `fab_review action="search"` MCP timeout on dedup pair 3 of 7): state records pairs 1–2 in `p3_dedup_completed[]`; rerun resumes at pair 3.
584
- - **Cumulative `errors[].length > 5`**: skill halts; asks free-text "继续 (y) / 中止并保留 state (n)".
585
- - **State file corruption**: skill renames it to `.fabric/.import-state.json.corrupt-<ISO8601>` and starts fresh from Phase 1.
586
- - **MCP tool unreachable**: skill halts before any work; surfaces "MCP 工具未注册;请检查 fabric server 是否运行" and exits without writing state.
145
+ - P2 mid-fail: state has `p2_processed_commits[]`; rerun skips them.
146
+ - P3 mid-fail: state has `p3_dedup_completed[]`; rerun resumes.
147
+ - `errors.length > 5`: halt + ask `继续 (y) / 中止并保留 state (n)` / `Continue (y) / Abort and keep state (n)`.
148
+ - State corruption: P0 detects rename `.json.corrupt-<ISO>` restart P1.
149
+ - MCP unreachable: halt + `MCP 工具未注册;请检查 fabric server 是否运行` / `MCP tool not registered; please check that the fabric server is running` exit without state write.
587
150
 
588
- The skill is `Check-not-Ask` for recovery: it inspects state and resumes deterministically; it does NOT ask the user where to resume from.
151
+ Resume policy: inspect existing state and continue from the last completed phase do not prompt the user mid-flow.