@fenglimg/fabric-cli 2.0.0-rc.35 → 2.0.0-rc.37

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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{chunk-XVS4F3P6.js → chunk-D25XJ4BC.js} +49 -5
  3. package/dist/{chunk-G2CIOLD4.js → chunk-WWNXR34K.js} +1 -16
  4. package/dist/{doctor-2FCRAWDZ.js → doctor-764NFF3X.js} +112 -16
  5. package/dist/index.js +7 -6
  6. package/dist/{install-HOTE5BPA.js → install-U7MGIJ2L.js} +50 -22
  7. package/dist/metrics-ACEQFPDU.js +122 -0
  8. package/dist/{uninstall-BIJ5GLEU.js → uninstall-MH7ZIB6M.js} +6 -18
  9. package/package.json +30 -4
  10. package/templates/hooks/cite-policy-evict.cjs +80 -91
  11. package/templates/hooks/configs/README.md +19 -0
  12. package/templates/hooks/configs/codex-hooks.json +3 -0
  13. package/templates/hooks/configs/cursor-hooks.json +2 -1
  14. package/templates/hooks/fabric-hint.cjs +146 -8
  15. package/templates/hooks/knowledge-hint-broad.cjs +65 -104
  16. package/templates/hooks/knowledge-hint-narrow.cjs +122 -5
  17. package/templates/hooks/lib/cite-line-parser.cjs +7 -1
  18. package/templates/hooks/lib/client-adapter.cjs +106 -0
  19. package/templates/hooks/lib/config-cache.cjs +107 -0
  20. package/templates/hooks/lib/state-store.cjs +84 -0
  21. package/templates/skills/fabric-archive/SKILL.md +29 -7
  22. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  23. package/templates/skills/fabric-archive/ref/i18n-policy.md +6 -0
  24. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +1 -1
  25. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -0
  26. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +25 -11
  27. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +43 -15
  28. package/templates/skills/fabric-import/SKILL.md +75 -163
  29. package/templates/skills/fabric-import/ref/i18n-policy.md +6 -0
  30. package/templates/skills/fabric-import/ref/phase-2-mining.md +2 -2
  31. package/templates/skills/fabric-review/SKILL.md +31 -25
  32. package/templates/skills/fabric-review/ref/i18n-policy.md +6 -0
  33. package/templates/skills/fabric-review/ref/modify-flow.md +9 -1
  34. package/templates/skills/fabric-review/ref/per-mode-flows.md +1 -1
  35. package/templates/skills/lib/shared-policy.md +69 -0
  36. package/dist/serve-43JTEM3U.js +0 -142
@@ -4,232 +4,144 @@ description: 冷启动从 git log + docs/*.md 回灌 .fabric/knowledge/pending (
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 install`'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:
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
- - zh-CN: `没有触发 import 信号;如需手动 import 请显式调用 fabric-import`
24
- - en: `No import signal detected; to manually import, explicitly invoke fabric-import`
21
+ Required: `.fabric/` exists, `agents.meta.json` present, MCP `fab_extract_knowledge` + `fab_review` registered, working tree reasonably clean.
25
22
 
26
- (Render per `fabric_language` resolved in Phase 0.5 Config Load below class 2 of the UX i18n Policy.)
23
+ ## Phase 0 — Init
27
24
 
28
- > **Recommendation source (rc.8+)**: 过去版本的 `.fabric/.import-requested` sentinel 机制已下线;推荐由 SessionStart hook 的 underseed 自检触发(`templates/hooks/knowledge-hint-broad.cjs` `shouldRecommendImport()`:`agents.meta.json` 存在 + canonical 节点数 < `underseed_node_threshold` + `.import-state.json` 缺失三条件齐备时一次性提示)。本 skill 不再读写 sentinel 文件,也不需要在 Phase 3 完成时手动清理它。
25
+ Read/init `.fabric/.import-state.json`. Scan stale `.tmp-import-*`. State-corruption recovery `Read .../ref/state-recovery.md`.
29
26
 
30
- This skill SHOULD be skipped (warn the user, do not proceed) when:
27
+ > `.fabric/.import-requested` sentinel 机制已下线 (rc.8+);推荐由 SessionStart hook underseed 自检触发(`shouldRecommendImport()`)。本 skill 不再读写 sentinel。
31
28
 
32
- - `.fabric/` does not exist direct the user to run `fabric install` first; `fabric-import` is NOT a substitute for the deterministic install-scan
33
- - `.fabric/knowledge/` already holds **>`import_skip_canonical_threshold` canonical entries (config-resolved, default 50)** 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
34
- - `.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
29
+ ## Phase 0.5Config Load
35
30
 
36
- Required preconditions before any MCP call:
31
+ Read `.fabric/fabric-config.json` for tunables (defaults if absent):
37
32
 
38
- - `.fabric/` directory exists in the project root
39
- - `.fabric/agents.meta.json` is present (init produced it; the id allocator reads it on later approve)
40
- - `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger is normal first-run)
41
- - `mcp__fabric__fab_extract_knowledge` AND `mcp__fabric__fab_review` MCP tools are registered and reachable
42
- - Working tree is reasonably clean (large uncommitted churn pollutes git-log mining; warn but allow)
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 |
43
40
 
44
- ### Phase 0 Init (state-recovery ref-only)
41
+ First-run vs re-run by state file (ENOENT or `phase != complete && proposed == 0` → first-run window).
45
42
 
46
- On invocation: read/initialize `.fabric/.import-state.json` (resumable phase tracker — see Checkpoint Logic section below for schema). Scan workspace for stale `.tmp-import-*` residues (`.fabric/.import-state.json.tmp-*`). For details on the .tmp scan + state corruption recovery (rare — only triggers when a prior import crashed mid-phase), `Read packages/cli/templates/skills/fabric-import/ref/state-recovery.md` (or `.claude/skills/fabric-import/ref/state-recovery.md` post-install).
43
+ ## UX i18n Policy
47
44
 
48
- ### Phase 0.5 Config Load
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`.
49
46
 
50
- Before any Phase 1 work, the skill MUST read `.fabric/fabric-config.json`
51
- to resolve the following tunables (with documented defaults if absent):
47
+ ## 3-Phase Pipeline
52
48
 
53
- | Config field | Default | Used by |
54
- |---|---|---|
55
- | `import_window_first_run_months` | 60 | Step 2.1 (--since arg construction, first-run window) |
56
- | `import_window_rerun_months` | 2 | Step 2.1 (--since arg construction, re-run window) |
57
- | `import_max_pending_per_run` | 10 | Step 2.1/2.2 hard cap on new pending entries per run |
58
- | `import_max_commits_scan` | 500 | Step 2.1 `-n` arg (commit-scan budget) |
59
- | `import_skip_canonical_threshold` | 50 | Precondition skip gate (canonical-entry maturity check) |
49
+ Strict P1→P2→P3 order. State write after every sub-step. Infer-not-Ask.
60
50
 
61
- If `.fabric/fabric-config.json` is missing or unreadable, use defaults silently.
62
- Whether the run is "first-run" vs "re-run" is decided by inspecting
63
- `.fabric/.import-state.json`: ENOENT (or any state with `phase != "complete"`
64
- and `final_summary.proposed == 0`) → first-run window; otherwise re-run window.
51
+ ### Phase 1 Init-Scan Reference (NO RE-IMPLEMENT)
65
52
 
66
- ### UX i18n Policy
53
+ `fabric install` produced baseline. Phase 1 REFERENCES, does NOT redo.
67
54
 
68
- Read `.fabric/fabric-config.json` `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`). Emit user-facing prose in the resolved variant. Protected tokens (`fab_extract_knowledge`, `fab_review`, `.fabric/.import-state.json`, schema/scope/layer enum values) are NEVER translated.
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>`.
69
59
 
70
- `AskUserQuestion` policy: `header` + `question` translate; `options[]` are routing keys — stay English regardless of locale.
60
+ No MCP calls.
71
61
 
72
- **For the full 5-class taxonomy + edge cases:** `Read packages/cli/templates/skills/fabric-import/ref/i18n-policy.md` (or `.claude/skills/fabric-import/ref/i18n-policy.md` post-install).
62
+ ### Phase 2 LLM-Driven Mining
73
63
 
74
- ## 3-Phase Pipeline (P1 reference / P2 mine / P3 dedup)
64
+ Classify each candidate into 5 types (decisions/pitfalls/guidelines/models/processes), draft slug, propose via `fab_extract_knowledge`. Layer: `team`.
75
65
 
76
- 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).
66
+ #### Mandatory Scope Rule broad + empty paths (NON-NEGOTIABLE)
77
67
 
78
- ### Phase 1Init-Scan Reference (NO RE-IMPLEMENTATION)
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`.
79
69
 
80
- > Verbatim boundary: `fabric install` (v2.0+, deterministic CLI) already produces the baseline scan. Phase 1 of this skill **REFERENCES** that output. It does NOT redo the scan.
70
+ #### Step 2.1 Git Mining
81
71
 
82
- The deterministic init-scan has already populated `.fabric/knowledge/team/` with 4–7 baseline entries derived from:
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`.
83
73
 
84
- - `package.json` (tech stack, scripts, key dependencies)
85
- - `README.md` first paragraph (project elevator pitch)
86
- - Build configuration (`tsconfig.json`, `pyproject.toml`, `Cargo.toml`, etc.)
87
- - Code style (`.editorconfig`, lint config)
88
- - CI configuration (`.github/workflows/`, `.gitlab-ci.yml`, etc.) when present
89
- - The first sentence of any top-level `LICENSE` (rare baseline signal)
74
+ #### Step 2.1.5 Proposed Reason
90
75
 
91
- Phase 1 actions performed by THIS skill:
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.
92
77
 
93
- 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).
94
- 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).
95
- 3. If `.fabric/agents.meta.json` is missing OR `.fabric/knowledge/team/` is empty: STOP. Tell the user (UX i18n Policy class 2 — errors/preconditions):
78
+ #### Step 2.2Docs Mining
96
79
 
97
- - zh-CN: `请先运行 fabric install 完成基线扫描,再调用 fabric-import`
98
- - en: `Please run fabric install first to complete the baseline scan, then invoke fabric-import`
99
-
100
- …and exit.
101
- 4. Update `.fabric/.import-state.json`: `phase = "P1-done"`, `p1_baseline_titles = [<list>]`, `last_checkpoint_at = <ISO8601 now>`.
102
-
103
- **Phase 1 produces no MCP calls.** It only reads the on-disk init-scan output.
104
-
105
- ### Phase 2 — LLM-Driven Git + Doc Mining
106
-
107
- 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`.
108
-
109
- #### Mandatory Scope Rule — Always Broad + Empty Paths (Q-1 Resolution)
110
-
111
- **EVERY `fab_extract_knowledge` call issued from this skill MUST set:**
112
-
113
- - `relevance_scope = "broad"`
114
- - `relevance_paths = []`
115
-
116
- This is non-negotiable. Applies to BOTH Step 2.1 (git mining) AND Step 2.2 (docs mining). No exceptions, no per-candidate override, no Agent judgment.
117
-
118
- **Why broad-only:** fabric-import is LLM-driven (mines git/docs), not session-driven. Git's touched-files list is the commit's effect-surface, not the observation's applicability-surface; LLM-inferred narrow bindings produce false-narrow that silently hides knowledge. Doc observations are usually cross-cutting. Narrowing of imported entries is deferred to `fab_review.modify` (user decision, post-import).
119
-
120
- For the full rationale + strict prohibitions list + fabric-archive cross-reference + post-import narrowing path + doctor lint #23 backstop, `Read packages/cli/templates/skills/fabric-import/ref/phase-2-mining.md` (or `.claude/skills/fabric-import/ref/phase-2-mining.md` post-install) §"Mandatory Scope Rule".
121
-
122
- #### Step 2.1 — Git Log Mining (summary)
123
-
124
- Run `git log --since="<window> months ago" --pretty=format:"%H%n%s%n%b%n---ENDCOMMIT---" -n <commits-cap>` (window/cap from Phase 0.5 config). For each commit: inspect conventional-commit prefix → infer type signal (feat→decision/model, fix→pitfall, refactor→decision, docs→guideline; chore/test/ci usually skip) → read body → extract core observation → apply Skip Decision Tree → classify type/slug/summary → call `fab_extract_knowledge` with broad+[] scope. Hard cap: `import_max_pending_per_run` (default 10) per run.
125
-
126
- #### Step 2.1.5 — Proposed Reason Inference
127
-
128
- Infer one of 6 enum values: `decision-confirmation` | `new-dependency-or-pattern` | `wrong-turn-revert` | `diagnostic-then-fix` | `explicit-user-mark` | `dismissal-with-reason`. Fallback: `new-dependency-or-pattern`. Full source-signal × body-cue mapping table in ref.
129
-
130
- #### Step 2.2 — Docs Mining (summary)
131
-
132
- `find docs/ -maxdepth 3 -name '*.md'` + root `*.md`. Skip README.md / CHANGELOG.md / LICENSE.md / CODE_OF_CONDUCT.md / CONTRIBUTING.md / files <300 bytes. Identify decision/guideline/pitfall/process/model heading patterns. Same `fab_extract_knowledge` call shape as Step 2.1. Cap shared with Step 2.1.
80
+ `find docs/ -maxdepth 3 -name '*.md'` + root `*.md`. Skip README / CHANGELOG / LICENSE / CODE_OF_CONDUCT / CONTRIBUTING / <300B files. Same call shape. Shared cap.
133
81
 
134
82
  #### Skip Decision Tree
135
83
 
136
- Skip if: cosmetic-only, metadata-only body, already in init-scan baseline, not classifiable to 5 types, or slug not derivable to 2-5 kebab words. Otherwise propose.
84
+ Skip if: cosmetic-only / metadata-only / in baseline / not classifiable / slug not derivable to 2-5 kebab words.
137
85
 
138
- #### Dry-Run Mode
86
+ #### Dry-Run
139
87
 
140
- `dry-run` / `预览` / `--dry-run` keyword → skip MCP calls, render bilingual preview table instead. Every row Scope column shows `broad+[]` (constant for fabric-import). State file NOT written. Phase 3 also skipped.
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).
141
89
 
142
- For full Step 2.1 MCP call shape (all rc.7/rc.23 fields), the Step 2.1.5 inference table (11 rows), bilingual dry-run templates (zh-CN + en), and T5 array-form idempotency notes, `Read packages/cli/templates/skills/fabric-import/ref/phase-2-mining.md` (or `.claude/skills/fabric-import/ref/phase-2-mining.md` post-install).
90
+ Full MCP call shape, Step 2.1.5 table, dry-run templates, T5 idempotency `Read .../ref/phase-2-mining.md`.
143
91
 
144
- ### Phase 3 — LLM-Driven Dedup vs Canonical
92
+ ### Phase 3 — LLM-Driven Dedup
145
93
 
146
- For each pending entry created in Phase 2, 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.**
94
+ For each P2 pending: check vs canonical. Semantic compare is LLM's job — `fab_review` does NOT compare meaning.
147
95
 
148
- **4-step summary:**
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.
149
100
 
150
- 1. **Step 3.1** `fab_review action="search"` filtered by `type`, cap top 5 canonical results.
151
- 2. **Step 3.2** — LLM classifies each (pending, canonical) pair: `duplicate` (reject pending) | `subsumption` (reject pending) | `subsumption-with-novelty` (modify canonical + reject pending) | `contradiction` (leave + flag) | `genuinely-new` (keep).
152
- 3. **Step 3.3** — Issue `fab_review` reject / modify MCP calls per classification.
153
- 4. **Step 3.4** — Update state to `phase="complete"` + write `final_summary`. Render roll-up.
101
+ Full call shapes + 5-way classification `Read .../ref/phase-3-dedup.md`.
154
102
 
155
- For full Step 3.1/3.3 MCP call shapes, the 5-way semantic compare classification with action-per-case, and the rc.8 sentinel-removal note, `Read packages/cli/templates/skills/fabric-import/ref/phase-3-dedup.md` (or `.claude/skills/fabric-import/ref/phase-3-dedup.md` post-install).
103
+ ## Checkpoint Logic
156
104
 
157
- ## Checkpoint Logic — `.fabric/.import-state.json`
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.
158
106
 
159
- State file `.fabric/.import-state.json` is the single source of resumability. Every write uses the 2-step atomic pattern: **Step A** `Write` to `.fabric/.import-state.json.tmp` **Step B** `Bash: mv .tmp` to commit. POSIX `rename(2)` guarantees atomicity. `Write` alone is NOT atomic.
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.
160
108
 
161
- Resume contract: re-invoking fabric-import after ANY interruption (Ctrl-C, crash, MCP network blip) MUST NOT propose duplicates and MUST NOT redo completed dedup. Resume per `phase` field: `P1-done` → resume Phase 2.1; `P2-done` → resume Phase 3.1; `complete` AND <24h → skip; ≥24h → confirm with user.
109
+ Full rationale + 4KB POSIX constraint + state schema + 6-step Resume `Read .../ref/checkpoint-state.md`.
162
110
 
163
- For the full Atomic State Write rationale + crash-safety reasoning, the events.jsonl 4KB POSIX atomicity constraint (single-line + self-truncate rules), the complete `.import-state.json` JSON schema, and the 6-step Resume Logic state machine, `Read packages/cli/templates/skills/fabric-import/ref/checkpoint-state.md` (or `.claude/skills/fabric-import/ref/checkpoint-state.md` post-install).
111
+ ## Default Knobs
164
112
 
165
- ## Default Behavior & Knobs
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.
166
114
 
167
- | Knob | Default | Override |
168
- |-------------------------------------|-------------|----------------------------------------------------------------|
169
- | Layer for new entries | `team` | User explicit instruction ("import these as personal") |
170
- | `relevance_scope` for new entries | `broad` | NONE — contract-locked; narrowing deferred to `fab_review.modify` post-import |
171
- | `relevance_paths` for new entries | `[]` | NONE — contract-locked; populating deferred to `fab_review.modify` post-import |
172
- | Max new pending entries per P2 run | config-resolved (default 10, max 50) | `import_max_pending_per_run` in `.fabric/fabric-config.json`; user explicit ("import up to 25") |
173
- | Git log window | config-resolved (default 60 first-run / 2 re-run, months) | `import_window_first_run_months` / `import_window_rerun_months`; user explicit ("import the full year") |
174
- | Git log commit-scan cap | config-resolved (default 500) | `import_max_commits_scan` in `.fabric/fabric-config.json` |
175
- | Skip-import canonical threshold | config-resolved (default 50) | `import_skip_canonical_threshold` in `.fabric/fabric-config.json` |
176
- | Docs scan depth | `3` | User explicit ("scan docs/ recursively") |
177
- | Dry-run mode | OFF | User keyword `dry-run` / `预览` / `--dry-run` |
178
- | Re-run within 24h of complete | BLOCKED | User keyword `re-run import` / `reset import` |
115
+ ## Hard Rules
179
116
 
180
- ## Hard Rules — DISPLAY / WRITE Split
117
+ ### DISPLAY (per entry)
181
118
 
182
- ### DISPLAY Rules
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`.
183
120
 
184
- - 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.
185
- - MUST display zh-CN body for proposed summaries (M3 style consistent with fabric-archive / fabric-review).
186
- - MUST display EN section headings.
187
- - MUST surface the resolved `pending_path` returned by `fab_extract_knowledge` in the per-entry display block.
188
- - MUST display the final roll-up with proposed / kept / rejected_dup / merged / contradictions_flagged counts.
189
- - MUST display the `.fabric/.import-state.json` `phase` value when the skill exits (so the user knows whether re-invocation is required).
190
- - NEVER hide the source signal; provenance is the only audit trail for bulk-imported entries.
191
- - 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).
192
- - NEVER show raw `idempotency_key` to the user (internal server-side concern).
121
+ ### WRITE
193
122
 
194
- ### WRITE Rules
123
+ NEVER write entry via `Edit`/`Write`/`Bash` — only `fab_extract_knowledge` (P2) + `fab_review` (P3).
195
124
 
196
- - 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).
197
- - NEVER batch multiple Phase 2 candidates into a single `fab_extract_knowledge` call; one call per candidate.
198
- - NEVER skip the Phase 1 reference step — even if init-scan landed zero entries, the skill MUST verify `.fabric/agents.meta.json` is present.
199
- - 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.
200
- - 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.
201
- - 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.
202
- - NEVER overwrite `.fabric/.import-state.json` non-atomically — use the 2-step `.tmp` + `mv` pattern documented in "Atomic State Write" under Checkpoint Logic (Step A: `Write` to `.fabric/.import-state.json.tmp`; Step B: `Bash: mv` to commit).
203
- - NEVER exceed the 10-entry-per-run hard cap without explicit user override.
204
- - 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).
205
- - 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.
206
- - 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.
207
- - Narrowing of imported entries happens out-of-band through `fab_review action="modify"` (issued by user via `fabric-review`), NOT inside this skill.
208
- - 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`, `source_sessions`, `proposed_reason`, `session_context`, `intent_clues`, `tech_stack`, `impact`, `must_read_if`.
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.
209
126
 
210
- ## Output Contract
127
+ Narrowing post-import = `fab_review.modify` (out-of-band).
211
128
 
212
- After Phase 3 completes (or on any phase exit due to cap / error / interrupt), the skill MUST produce a roll-up. UX i18n Policy class 1 — render either en or zh-CN variant per `fabric_language`. Section names: `Phase 2 — Mining` (commits scanned / docs scanned / pending proposed / scope confirmation), `Phase 3 — Dedup` (kept / rejected_dup / modified-then-rejected / contradictions_flagged), `State` (phase + last_checkpoint_at), `Next Steps` (fabric-review for kept entries; manual resolve for contradictions; narrowing via `fab_review action="modify"`).
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`.
213
130
 
214
- For the full bilingual roll-up templates (zh-CN + en) with all section/field placeholders, `Read packages/cli/templates/skills/fabric-import/ref/output-contract.md` (or `.claude/skills/fabric-import/ref/output-contract.md` post-install).
131
+ ## Output Contract
215
132
 
216
- 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`.
217
134
 
218
135
  ## Worked Examples
219
136
 
220
- Four end-to-end examples — (A) feat commit pitfall entry showing broad+[] discipline and the "WRONG" counter-example; (B) docs/architecture.md decision entry; (C) Phase 3 dedup finds duplicate reject MCP call; (D) post-import narrowing via `fab_review.modify` (out-of-band, NOT this skill) live in `packages/cli/templates/skills/fabric-import/ref/worked-examples.md` (or `.claude/skills/fabric-import/ref/worked-examples.md` post-install). Load when you want to see complete MCP call shapes + state file deltas in realistic scenarios.
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`.
221
138
 
222
139
  ## Failure Recovery
223
140
 
224
- - **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[]`.
225
- - **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.
226
- - **Cumulative `errors[].length > 5`**: skill halts; asks free-text confirmation (UX i18n Policy class 3 confirmation prompts):
227
- - zh-CN: `继续 (y) / 中止并保留 state (n)`
228
- - en: `Continue (y) / Abort and keep state (n)`
229
- - **State file corruption**: handled by Phase 0.1 — Phase 0.1 detects corruption (JSON parse error / missing required fields / phase enum violation), renames the file to `.fabric/.import-state.json.corrupt-<ISO8601>`, and restarts from Phase 1. See "Phase 0.1 — State Corruption Recovery" above.
230
- - **MCP tool unreachable**: skill halts before any work; surfaces (UX i18n Policy class 2 errors/preconditions):
231
- - zh-CN: `MCP 工具未注册;请检查 fabric server 是否运行`
232
- - en: `MCP tool not registered; please check that the fabric server is running`
233
- …and exits without writing state.
234
-
235
- The skill is `Check-not-Ask` for recovery: it inspects state and resumes deterministically; it does NOT ask the user where to resume from.
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.
146
+
147
+ Resume policy: inspect existing state and continue from the last completed phase do not prompt the user mid-flow.
@@ -1,5 +1,11 @@
1
1
  # UX i18n Policy — fabric-import full reference
2
2
 
3
+ > **Shared core (rc.37 NEW-13):** the cross-skill invariants — protected-token
4
+ > NEVER-translate list, AskUserQuestion routing-key rule, layer heuristic, and
5
+ > events-emit convention — live once in `../../lib/shared-policy.md`. This file
6
+ > keeps only the fabric-import-specific 5-class examples. Read the shared lib
7
+ > for the common rules; do not fork them here.
8
+
3
9
  > **Loaded on demand.** Only consult when you need to disambiguate which of the 5 classes a given string belongs to. SKILL.md gives the operative rule.
4
10
 
5
11
  ## UX i18n Policy (5-class bilingualization)
@@ -15,7 +15,7 @@ This is non-negotiable and applies to BOTH Step 2.1 (git mining) AND Step 2.2 (d
15
15
 
16
16
  1. `fabric-import` is LLM-driven (mines git log + docs), not session-driven (no live `edit_paths` signal).
17
17
  2. `git diff --stat` lists files touched by a commit, but those files are the commit's **effect surface**, not the **applicability surface** of the underlying observation. A pitfall surfaced by a fix in `packages/server/src/retry.ts` may apply to every retry call-site in the repo, not just that one file.
18
- 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.
18
+ 3. LLM-inferred `relevance_paths` from historical commit metadata produces false-narrow bindings — `relevance_paths` becomes a lie about applicability. Post-rc.37 A1 the server no longer filters by `relevance_scope`, so false-narrow does NOT hide knowledge from AI recall (every selectable entry is surfaced regardless of scope). The damage is now downstream: doctor lint accounting, future-AI judgment, and any consumer that reads `relevance_paths` literally treats the wrong globs as ground truth. Broad+[] keeps the metadata honest until the user has the real applicability surface in hand to declare narrow.
19
19
  4. Doc-mined observations are usually architectural / cross-cutting (a `docs/architecture.md` "Why a monolith?" decision applies to the whole codebase, not just to `docs/`).
20
20
 
21
21
  **Strict prohibitions — DO NOT attempt any of the following:**
@@ -174,7 +174,7 @@ After Step 2.2 completes (or hits the cap), update `.fabric/.import-state.json`:
174
174
 
175
175
  ## Dry-Run Mode
176
176
 
177
- When the user invocation includes `dry-run` / `预览` / `--dry-run` keywords, Phase 2 runs WITHOUT calling `fab_extract_knowledge`. Instead it prints a table. UX i18n Policy class 4 — header + column titles bilingualized; row content (slug / commit sha / doc path) NOT translated. Protected tokens `broad`, `relevance_scope`, `relevance_paths` appear verbatim:
177
+ When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WITHOUT calling `fab_extract_knowledge`. Instead it prints a table. v2.0.0-rc.37 NEW-10 dropped the legacy substring fallback on bare `dry-run` / `预览` because those caused false positives on incidental mentions ("preview the table" / "do a dry run later"). UX i18n Policy class 4 — header + column titles bilingualized; row content (slug / commit sha / doc path) NOT translated. Protected tokens `broad`, `relevance_scope`, `relevance_paths` appear verbatim:
178
178
 
179
179
  ### zh-CN variant (`fabric_language === "zh-CN"`)
180
180
 
@@ -48,46 +48,46 @@ Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`); emi
48
48
 
49
49
  ## Mode Inference (System Infers — NEVER Ask)
50
50
 
51
- > Verbatim from rc.3 locked decisions:
52
- > "review 永远走 fabric-review skill,**模式从上下文推断**(4 种 mode:pending queue / by topic / health overview / revisit existing)"
51
+ > Locked decision (KT-DEC-0006): "Review mode inferred from context, not solicited via AskUserQuestion."
53
52
  > "**AskUserQuestion 仅在真有选择时用**——'何种 mode' 不是真选择(系统能推断),'approve/reject/modify 单条' 是真选择"
54
53
 
55
- The skill MUST infer one of {`pending`, `topic`, `health`, `revisit`} BEFORE any user-facing output.
54
+ The skill MUST infer one of **2 modes** BEFORE any user-facing output (v2.0.0-rc.37 NEW-12 simplified 4 → 2):
56
55
 
57
- ### 3-Step Inference Algorithm
56
+ - **`pending`** — triage the write-side backlog (`.fabric/knowledge/pending/`): approve / reject / modify / defer per item. The dominant entry point.
57
+ - **`maintain`** — sustain the EXISTING canonical KB: browse by topic (search), survey staleness/health, or revisit a specific entry. Merges the legacy `topic` + `health` + `revisit` modes — they are all "operate on already-canonical knowledge", distinct from triaging new drafts.
58
58
 
59
- **Step 1 — Recent user message keyword scan.** Match against priority order:
59
+ ### 2-Step Inference Algorithm
60
+
61
+ **Step 1 — Recent user message keyword scan:**
60
62
 
61
63
  | Keywords (zh-CN + en) | Inferred mode |
62
64
  |---|---|
63
65
  | "approve", "review pending", "promote", "what's queued", "审核 pending", "通过" | `pending` |
64
- | "search for X about Y", "find entries about <topic>", "关于…的知识", "找一下 <topic>" | `topic` |
65
- | "what's stale", "demote old", "health check", "过期的", "陈旧的", "整理一下" | `health` |
66
- | "look at <id>", "revisit KT-…", "show <slug>", "再看下 <id>", "回顾" | `revisit` |
67
-
68
- Exactly one row matches → lock mode, skip to Step 3.
69
-
70
- **Step 2 — events.jsonl tail scan.** If Step 1 yielded 0 or >1 matches, tail (last 200 lines) `.fabric/events.jsonl`:
66
+ | "search/find about <topic>", "what's stale", "demote old", "health check", "look at <id>", "revisit KT-…", "关于…的知识", "过期的", "陈旧的", "整理一下", "再看下 <id>", "回顾" | `maintain` |
71
67
 
72
- - `>5` recent `knowledge_proposed` since last `knowledge_promoted` `pending` (write side piled up).
73
- - `≥1` `knowledge_demoted` or `lint` events in 24h → `health` (corpus quality signal).
74
- - Recent `knowledge_layer_changed` for the entry user referenced → `revisit`.
68
+ A `maintain`-row match lock `maintain`. A `pending`-row match (or 0/ambiguous) fall to Step 2.
75
69
 
76
- **Step 3Pending count default.** Still ambiguous → glob `.fabric/knowledge/pending/**/*.md`:
70
+ **Step 2Backlog default.** Glob `.fabric/knowledge/pending/**/*.md`:
77
71
 
78
72
  - Count ≥ `review_hint_pending_count` (default 10) OR oldest mtime > `review_hint_pending_age_days` (default 7) → `pending` (overflow, same threshold as Stop-hook).
79
73
  - Otherwise → default `pending` (most common review entry point).
80
74
 
81
- `Read ref/per-mode-flows.md` for 5 inference examples and anti-pattern restatement.
75
+ > Back-compat: the legacy 4-mode names (`topic` / `health` / `revisit`) still resolve — they all map to `maintain`. Old session traces / muscle memory keep working.
76
+
77
+ `Read ref/per-mode-flows.md` for inference examples and anti-pattern restatement.
82
78
 
83
79
  ## Per-Mode Flow
84
80
 
85
81
  Each mode produces user-facing output, then routes per-item or per-batch decisions through `fab_review` actions. Display body = zh-CN summaries (M3 style); section headings = EN.
86
82
 
87
- - **`pending`** — list pending entries → run Semantic Check (see `ref/semantic-check.md`) → per-item AskUserQuestion `{approve, reject, modify, defer, skip}` → route per choice (modify path = `ref/modify-flow.md`).
88
- - **`topic`** — extract keywords → `fab_review action="search"` render top-N (cap `review_topic_result_cap`) only AskUserQuestion when user signals action verb.
89
- - **`health`** — `fab_review action="list"` + tail events compute stale render dashboard per-stale AskUserQuestion `{defer, demote, skip}`.
90
- - **`revisit`** — user referenced specific id/slug → `Read` canonical file directly OR `fab_review action="list"` with narrow filters display body + history AskUserQuestion only if pending.
83
+ - **`pending`** — list pending entries → run Semantic Check (see `ref/semantic-check.md`) → per-item AskUserQuestion `{approve, reject, modify, defer, skip}` → route per choice. The modify branch chooses between two explicit actions (rc.37 NEW-12):
84
+ - `fab_review action="modify-content"` edit scalars (title/summary/maturity/tags/relevance_*); NEVER flips layer.
85
+ - `fab_review action="modify-layer"` the dedicated layer-flip path (`changes.layer` required); may reallocate the stable_id + emit an id-redirect.
86
+ - (Legacy `action="modify"` still works it routes by whether `changes.layer` is present.) See `ref/modify-flow.md`.
87
+ - **`maintain`** — sub-flow inferred from the same keywords:
88
+ - *browse-by-topic*: extract keywords → `fab_review action="search"` → render top-N (cap `review_topic_result_cap`) → AskUserQuestion only on an action verb.
89
+ - *health/staleness*: `fab_review action="list"` + tail events → compute stale → render dashboard → per-stale AskUserQuestion `{defer, demote, skip}`.
90
+ - *revisit*: user referenced a specific id/slug → `Read` canonical file directly OR `fab_review action="list"` with narrow filters → display body + history → AskUserQuestion only if actionable.
91
91
 
92
92
  `Read ref/per-mode-flows.md` for full step-by-step procedures, bilingual rendering blocks (en + zh-CN per-item display, AskUserQuestion templates, health dashboard format), and the rc.7 T6 `proposed_reason` + `## Why proposed` + `## Session context` rendering contract.
93
93
 
@@ -97,11 +97,17 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
97
97
 
98
98
  Semantic check is the LLM's job — the MCP tool does NOT compare meaning. Run during `pending` mode (and on demand during `topic`): for each pending entry, `fab_review action="search"` scoped by `filters.type` → LLM judges semantically against returned canonical entries → surface one of three flags as informational:
99
99
 
100
- - `⚠ Possible duplicate of <stable_id>` — same essential claim
101
- - `⚠ Contradicts <stable_id>` — opposing claims, same scope
102
- - `⚠ Subsumed by <stable_id>; consider modify-to-merge` — fully covered
100
+ - `⚠ Possible duplicate of <stable_id> (overlap: high)` — same essential claim
101
+ - `⚠ Contradicts <stable_id> (overlap: high)` — opposing claims, same scope
102
+ - `⚠ Subsumed by <stable_id> (overlap: medium+); consider modify-to-merge` — fully covered
103
+
104
+ **Quantified overlap band (rc.37 NEW-12).** The LLM still judges meaning (no embedding %), but MUST tag each flag with a 3-level band so the signal is comparable across entries and the user can triage at a glance:
105
+
106
+ - `high` — ≥ ~80% of the candidate's essential claim is restated; near-certain dup/contradiction. Recommend reject-as-duplicate or modify-to-merge.
107
+ - `medium` — substantial conceptual overlap but the new entry adds a distinct facet (different path scope, added caveat). Recommend modify-to-harmonize.
108
+ - `low` — adjacent topic, not a real overlap. Do NOT raise a flag at `low` — it is below the surfacing threshold (suppresses noise).
103
109
 
104
- Thresholds intentionally NOT quantified (no similarity %). User decides: still-approve (flag informational), modify-to-harmonize, or reject-as-duplicate (reason MUST cite existing stable_id).
110
+ Only `medium`+ flags are surfaced. User decides: still-approve (flag informational), modify-to-harmonize, or reject-as-duplicate (reason MUST cite existing stable_id).
105
111
 
106
112
  DO NOT AskUserQuestion "is this a duplicate?" — LLM already judged. User only chooses approve/reject/modify.
107
113
 
@@ -1,5 +1,11 @@
1
1
  # UX i18n Policy — fabric-review full reference
2
2
 
3
+ > **Shared core (rc.37 NEW-13):** the cross-skill invariants — protected-token
4
+ > NEVER-translate list, AskUserQuestion routing-key rule, layer heuristic, and
5
+ > events-emit convention — live once in `../../lib/shared-policy.md`. This file
6
+ > keeps only the fabric-review-specific 5-class examples. Read the shared lib
7
+ > for the common rules; do not fork them here.
8
+
3
9
  > **Loaded on demand.** Only consult when you need to disambiguate which of the 5 classes a given string belongs to. SKILL.md gives the operative rule.
4
10
 
5
11
  ## UX i18n Policy (5-class bilingualization)
@@ -2,7 +2,15 @@
2
2
 
3
3
  ## Modify Sub-Flow
4
4
 
5
- `modify` is the only action that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?}`. Server semantics:
5
+ The modify family is the only action group that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?, relevance_scope?, relevance_paths?}`.
6
+
7
+ **v2.0.0-rc.37 NEW-12 — explicit split.** Prefer the dedicated action over the legacy combined `modify`:
8
+
9
+ - `action="modify-content"` — scalar edits (title/summary/tags/maturity/relevance_*); stable_id PRESERVED; the server STRIPS any `changes.layer` so this path can never flip layer. Emits `knowledge_slug_renamed` only when slug derives from title.
10
+ - `action="modify-layer"` — the dedicated layer-flip path; `changes.layer` is REQUIRED. The ONLY legal stable_id mutation in the system (see Layer-Flip Rules below).
11
+ - `action="modify"` (legacy alias) — still accepted; routes to content-edit OR layer-flip by whether `changes.layer` is present. New call sites should use the explicit pair.
12
+
13
+ Server semantics (identical regardless of which action selected the path):
6
14
 
7
15
  - **title / summary / tags / maturity changes** → in-place rewrite; stable_id PRESERVED; emits `knowledge_slug_renamed` only when slug derives from title.
8
16
  - **layer change** → the ONLY legal stable_id mutation in the system.
@@ -152,4 +152,4 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
152
152
 
153
153
  ### Anti-Pattern (Hard Rule restatement)
154
154
 
155
- NEVER emit an `AskUserQuestion` whose options include {pending, topic, health, revisit}. The user does not pick the mode. If inference is genuinely ambiguous after all 3 steps, default to `pending` and proceed; the user can always cancel and redirect.
155
+ NEVER emit an `AskUserQuestion` whose options include {pending, maintain} (or the legacy {topic, health, revisit} aliases). The user does not pick the mode. If inference is genuinely ambiguous after both steps, default to `pending` and proceed; the user can always cancel and redirect. (rc.37 NEW-12 collapsed the 4 legacy modes to 2: `pending` + `maintain`.)
@@ -0,0 +1,69 @@
1
+ # Shared skill policy — cross-skill canonical core (rc.37 NEW-13)
2
+
3
+ > **Single source of truth** for the policy invariants that fabric-archive,
4
+ > fabric-review, and fabric-import all depend on. Each skill's `ref/` keeps
5
+ > only its skill-specific examples and points here (`../../lib/shared-policy.md`)
6
+ > for the common rules. Edit invariants HERE — never fork them per skill.
7
+
8
+ ## 1. Protected tokens — NEVER translated
9
+
10
+ When rendering bilingual (zh-CN ↔ en) output, prose is translated but the
11
+ following classes of token appear **verbatim in both variants**:
12
+
13
+ - **MCP tool + field names**: `fab_extract_knowledge`, `fab_review`,
14
+ `fab_recall`, `fab_plan_context`, `fab_get_knowledge_sections`,
15
+ `relevance_scope`, `relevance_paths`, `source_sessions`, `proposed_reason`,
16
+ `session_context`, `intent_clues`, `tech_stack`, `impact`, `must_read_if`,
17
+ `evidence_paths`, `tags`, `pending_path`, `layer`.
18
+ - **Enum / routing values**: `narrow`, `broad`, `team`, `personal`, `draft`,
19
+ `verified`, `proven`, `knowledge_scope_degraded`.
20
+ - **Imperatives + paths**: `MUST`, `NEVER`, `.fabric/knowledge/`, file paths.
21
+
22
+ The authoritative machine-checked list is `PROTECTED_TOKENS` in
23
+ `@fenglimg/fabric-shared` (enforced by `scripts/lint-protected-tokens.ts`).
24
+ Bilingualization scope is **prose ONLY**.
25
+
26
+ ## 2. AskUserQuestion routing-key invariant
27
+
28
+ When any skill issues an `AskUserQuestion`:
29
+
30
+ - `header` + `question` → user-facing prose → **translated** per
31
+ `.fabric/fabric-config.json` → `fabric_language`.
32
+ - `options[]` entries → **routing keys** consumed by the skill's `switch`
33
+ over the returned choice → stay **English** in BOTH variants.
34
+
35
+ Canonical option arrays (English in every locale):
36
+
37
+ - Per-item review action: `["approve", "reject", "modify", "defer", "skip"]`
38
+ - Stale-item action (review health mode): `["defer", "demote", "skip"]`
39
+ - Layer-flip target: `["team", "personal"]`
40
+
41
+ A skill that translates `options[]` MUST then dual-string-match
42
+ (`choice === "approve" || choice === "通过"`); avoid this — keep options
43
+ English so the state machine stays single-string.
44
+
45
+ ## 3. Layer heuristic (team vs personal)
46
+
47
+ Default classification when archiving / proposing knowledge:
48
+
49
+ - **强 team** — cross-cutting decisions, architecture, shared pitfalls,
50
+ conventions the whole repo depends on.
51
+ - **强 personal** — individual workflow preferences, local environment quirks,
52
+ notes scoped to one contributor (`KP-*` ids, in-repo `~/.fabric` root).
53
+ - **默认 team** — when ambiguous, default to `team` (shared visibility is the
54
+ safer default; a mis-scoped personal entry hides knowledge from the team).
55
+
56
+ This block is itself a protected token sequence — render `强 team` /
57
+ `强 personal` / `默认 team` verbatim.
58
+
59
+ ## 4. Events emit convention
60
+
61
+ Skills persist lifecycle via MCP tools (which emit the canonical events) —
62
+ they do NOT hand-write `.fabric/events.jsonl`:
63
+
64
+ - `fab_extract_knowledge` → `knowledge_proposed` (+ archive-attempt events).
65
+ - `fab_review` approve → `knowledge_promote_started` → `knowledge_promoted`.
66
+ - `fab_review` modify-layer → `knowledge_layer_changed` (+ id-redirect).
67
+
68
+ Never instruct the user to delete or hand-edit the event ledger; it is the
69
+ append-only audit trail. Counter rollups live in `.fabric/metrics.jsonl`.