@fenglimg/fabric-cli 2.0.0 → 2.0.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.
- package/LICENSE +21 -0
- package/README.md +6 -5
- package/dist/chunk-BATF4PEJ.js +361 -0
- package/dist/{chunk-OBQU6NHO.js → chunk-COI5VDFU.js} +0 -18
- package/dist/chunk-D25XJ4BC.js +880 -0
- package/dist/chunk-MF3OTILQ.js +544 -0
- package/dist/chunk-PWLW3B57.js +18 -0
- package/dist/config-XJIPZNUP.js +13 -0
- package/dist/doctor-EJDSEJSS.js +810 -0
- package/dist/index.js +15 -8
- package/dist/{init-BIRSIOXO.js → install-EKWMFLUU.js} +622 -711
- package/dist/metrics-ACEQFPDU.js +122 -0
- package/dist/onboard-coverage-MFCAEBDO.js +220 -0
- package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-FC6P3WFE.js} +34 -28
- package/dist/uninstall-MH7ZIB6M.js +1064 -0
- package/package.json +30 -5
- package/templates/hooks/cite-policy-evict.cjs +231 -0
- package/templates/hooks/configs/README.md +29 -6
- package/templates/hooks/configs/claude-code.json +14 -3
- package/templates/hooks/configs/codex-hooks.json +6 -3
- package/templates/hooks/configs/cursor-hooks.json +8 -10
- package/templates/hooks/fabric-hint.cjs +833 -105
- package/templates/hooks/knowledge-hint-broad.cjs +509 -135
- package/templates/hooks/knowledge-hint-narrow.cjs +791 -26
- package/templates/hooks/lib/banner-i18n.cjs +309 -0
- package/templates/hooks/lib/cite-contract-reminder.cjs +173 -0
- package/templates/hooks/lib/cite-line-parser.cjs +158 -0
- package/templates/hooks/lib/client-adapter.cjs +106 -0
- package/templates/hooks/lib/config-cache.cjs +107 -0
- package/templates/hooks/lib/state-store.cjs +84 -0
- package/templates/hooks/lib/summary-fallback.cjs +210 -0
- package/templates/skills/fabric-archive/SKILL.md +93 -419
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
- package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
- package/templates/skills/fabric-archive/ref/i18n-policy.md +86 -0
- package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +218 -0
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +62 -0
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +68 -0
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +108 -0
- package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
- package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
- package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
- package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
- package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
- package/templates/skills/fabric-import/SKILL.md +75 -516
- package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
- package/templates/skills/fabric-import/ref/i18n-policy.md +79 -0
- package/templates/skills/fabric-import/ref/output-contract.md +61 -0
- package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
- package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
- package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
- package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
- package/templates/skills/fabric-review/SKILL.md +86 -284
- package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
- package/templates/skills/fabric-review/ref/i18n-policy.md +111 -0
- package/templates/skills/fabric-review/ref/modify-flow.md +103 -0
- package/templates/skills/fabric-review/ref/output-contract.md +58 -0
- package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
- package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
- package/templates/skills/fabric-review/ref/worked-examples.md +95 -0
- package/templates/skills/lib/shared-policy.md +69 -0
- package/dist/chunk-6ICJICVU.js +0 -10
- package/dist/chunk-74SZWYPH.js +0 -658
- package/dist/chunk-EYIDD2YS.js +0 -1000
- package/dist/doctor-T7JWODKG.js +0 -282
- package/dist/hooks-Y74Y5LQS.js +0 -12
- package/dist/scan-LMK3UCWL.js +0 -22
- package/dist/serve-H554BHLG.js +0 -124
- package/templates/agents-md/AGENTS.md.template +0 -59
- package/templates/bootstrap/CLAUDE.md +0 -8
- package/templates/bootstrap/codex-AGENTS-header.md +0 -6
- package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
|
@@ -1,588 +1,147 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fabric-import
|
|
3
|
-
description:
|
|
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**:
|
|
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
|
-
|
|
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
|
-
|
|
15
|
+
Invoke only when ANY: user explicit ("import knowledge" / "bootstrap fabric" / "mine changelog"); user named skill; SessionStart hook fired `shouldRecommendImport()`.
|
|
16
16
|
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
21
|
+
Required: `.fabric/` exists, `agents.meta.json` present, MCP `fab_extract_knowledge` + `fab_review` registered, working tree reasonably clean.
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
## Phase 0 — Init
|
|
26
24
|
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
31
|
+
Read `.fabric/fabric-config.json` for tunables (defaults if absent):
|
|
49
32
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
41
|
+
First-run vs re-run by state file (ENOENT or `phase != complete && proposed == 0` → first-run window).
|
|
55
42
|
|
|
56
|
-
|
|
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
|
+
## UX i18n Policy
|
|
61
44
|
|
|
62
|
-
|
|
45
|
+
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`.
|
|
63
46
|
|
|
64
|
-
|
|
47
|
+
## 3-Phase Pipeline
|
|
65
48
|
|
|
66
|
-
|
|
49
|
+
Strict P1→P2→P3 order. State write after every sub-step. Infer-not-Ask.
|
|
67
50
|
|
|
68
|
-
|
|
51
|
+
### Phase 1 — Init-Scan Reference (NO RE-IMPLEMENT)
|
|
69
52
|
|
|
70
|
-
|
|
53
|
+
`fabric install` produced baseline. Phase 1 REFERENCES, does NOT redo.
|
|
71
54
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- CI configuration (`.github/workflows/`, `.gitlab-ci.yml`, etc.) when present
|
|
77
|
-
- The first sentence of any top-level `LICENSE` (rare baseline signal)
|
|
55
|
+
1. Read `agents.meta.json` → confirm baseline counters.
|
|
56
|
+
2. Glob `.fabric/knowledge/team/**/*.md` → titles for P2 negative filter.
|
|
57
|
+
3. If meta missing OR team/ empty: STOP. Tell user `请先运行 fabric install 完成基线扫描` / `Please run fabric install first` and exit.
|
|
58
|
+
4. State: `phase=P1-done`, `p1_baseline_titles=[...]`, `last_checkpoint_at=<ISO>`.
|
|
78
59
|
|
|
79
|
-
|
|
60
|
+
No MCP calls.
|
|
80
61
|
|
|
81
|
-
|
|
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>`.
|
|
62
|
+
### Phase 2 — LLM-Driven Mining
|
|
85
63
|
|
|
86
|
-
|
|
64
|
+
Classify each candidate into 5 types (decisions/pitfalls/guidelines/models/processes), draft slug, propose via `fab_extract_knowledge`. Layer: `team`.
|
|
87
65
|
|
|
88
|
-
|
|
66
|
+
#### Mandatory Scope Rule — broad + empty paths (NON-NEGOTIABLE)
|
|
89
67
|
|
|
90
|
-
|
|
68
|
+
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`.
|
|
91
69
|
|
|
92
|
-
####
|
|
70
|
+
#### Step 2.1 — Git Mining
|
|
93
71
|
|
|
94
|
-
|
|
72
|
+
`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`.
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
- `relevance_paths = []`
|
|
74
|
+
#### Step 2.1.5 — Proposed Reason
|
|
98
75
|
|
|
99
|
-
|
|
76
|
+
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.
|
|
100
77
|
|
|
101
|
-
|
|
102
|
-
|
|
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/`).
|
|
107
|
-
|
|
108
|
-
**Strict prohibitions — DO 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:
|
|
78
|
+
#### Step 2.2 — Docs Mining
|
|
128
79
|
|
|
129
|
-
|
|
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
|
-
```
|
|
80
|
+
`find docs/ -maxdepth 3 -name '*.md'` + root `*.md`. Skip README / CHANGELOG / LICENSE / CODE_OF_CONDUCT / CONTRIBUTING / <300B files. Same call shape. Shared cap.
|
|
139
81
|
|
|
140
|
-
|
|
82
|
+
#### Skip Decision Tree
|
|
141
83
|
|
|
142
|
-
|
|
84
|
+
Skip if: cosmetic-only / metadata-only / in baseline / not classifiable / slug not derivable to 2-5 kebab words.
|
|
143
85
|
|
|
144
|
-
####
|
|
86
|
+
#### Dry-Run
|
|
145
87
|
|
|
146
|
-
|
|
88
|
+
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
89
|
|
|
148
|
-
|
|
149
|
-
git log --since="2 months ago" --pretty=format:"%H%n%s%n%b%n---ENDCOMMIT---" -n 200
|
|
150
|
-
```
|
|
90
|
+
Full MCP call shape, Step 2.1.5 table, dry-run templates, T5 idempotency → `Read .../ref/phase-2-mining.md`.
|
|
151
91
|
|
|
152
|
-
|
|
92
|
+
### Phase 3 — LLM-Driven Dedup
|
|
153
93
|
|
|
154
|
-
For each
|
|
94
|
+
For each P2 pending: check vs canonical. Semantic compare is LLM's job — `fab_review` does NOT compare meaning.
|
|
155
95
|
|
|
156
|
-
1.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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):
|
|
96
|
+
1. **3.1** — `fab_review action="search"` filter by `type`, top 5.
|
|
97
|
+
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).
|
|
98
|
+
3. **3.3** — Issue `fab_review` reject / modify.
|
|
99
|
+
4. **3.4** — `phase=complete` + `final_summary` + roll-up.
|
|
165
100
|
|
|
166
|
-
|
|
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
|
-
```
|
|
101
|
+
Full call shapes + 5-way classification → `Read .../ref/phase-3-dedup.md`.
|
|
183
102
|
|
|
184
|
-
|
|
103
|
+
## Checkpoint Logic
|
|
185
104
|
|
|
186
|
-
|
|
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).
|
|
105
|
+
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
106
|
|
|
192
|
-
|
|
107
|
+
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
108
|
|
|
194
|
-
|
|
109
|
+
Full rationale + 4KB POSIX constraint + state schema + 6-step Resume → `Read .../ref/checkpoint-state.md`.
|
|
195
110
|
|
|
196
|
-
|
|
197
|
-
find docs/ -maxdepth 3 -name '*.md' -type f 2>/dev/null
|
|
198
|
-
ls -1 *.md 2>/dev/null # root-level architectural docs
|
|
199
|
-
```
|
|
111
|
+
## Default Knobs
|
|
200
112
|
|
|
201
|
-
|
|
113
|
+
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
114
|
|
|
203
|
-
|
|
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.
|
|
115
|
+
## Hard Rules
|
|
213
116
|
|
|
214
|
-
|
|
117
|
+
### DISPLAY (per entry)
|
|
215
118
|
|
|
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
|
-
```
|
|
119
|
+
`[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
120
|
|
|
231
|
-
|
|
121
|
+
### WRITE
|
|
232
122
|
|
|
233
|
-
|
|
123
|
+
NEVER write entry via `Edit`/`Write`/`Bash` — only `fab_extract_knowledge` (P2) + `fab_review` (P3).
|
|
234
124
|
|
|
235
|
-
|
|
125
|
+
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
126
|
|
|
237
|
-
|
|
238
|
-
# Import Dry Run — would propose N pending entries (all relevance_scope=broad, relevance_paths=[])
|
|
127
|
+
Narrowing post-import = `fab_review.modify` (out-of-band).
|
|
239
128
|
|
|
240
|
-
|
|
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`.
|
|
129
|
+
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
130
|
|
|
422
131
|
## Output Contract
|
|
423
132
|
|
|
424
|
-
|
|
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).
|
|
133
|
+
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
134
|
|
|
454
135
|
## Worked Examples
|
|
455
136
|
|
|
456
|
-
|
|
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.
|
|
137
|
+
4 end-to-end (A feat→pitfall + WRONG counter-ex; B docs→decision; C P3 dup→reject; D out-of-band narrow) → `Read .../ref/worked-examples.md`.
|
|
579
138
|
|
|
580
139
|
## Failure Recovery
|
|
581
140
|
|
|
582
|
-
-
|
|
583
|
-
-
|
|
584
|
-
-
|
|
585
|
-
-
|
|
586
|
-
-
|
|
141
|
+
- P2 mid-fail: state has `p2_processed_commits[]`; rerun skips them.
|
|
142
|
+
- P3 mid-fail: state has `p3_dedup_completed[]`; rerun resumes.
|
|
143
|
+
- `errors.length > 5`: halt + ask `继续 (y) / 中止并保留 state (n)` / `Continue (y) / Abort and keep state (n)`.
|
|
144
|
+
- State corruption: P0 detects → rename `.json.corrupt-<ISO>` → restart P1.
|
|
145
|
+
- MCP unreachable: halt + `MCP 工具未注册;请检查 fabric server 是否运行` / `MCP tool not registered; please check that the fabric server is running` → exit without state write.
|
|
587
146
|
|
|
588
|
-
|
|
147
|
+
Resume policy: inspect existing state and continue from the last completed phase — do not prompt the user mid-flow.
|