@fenglimg/fabric-cli 2.0.0 → 2.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-F46ORPOA.js +903 -0
- package/dist/chunk-HFQVXY6P.js +86 -0
- package/dist/chunk-L4Q55UC4.js +52 -0
- package/dist/chunk-LFIKMVY7.js +27 -0
- package/dist/chunk-MF3OTILQ.js +544 -0
- package/dist/chunk-PWLW3B57.js +18 -0
- package/dist/chunk-RYAFBNES.js +33 -0
- package/dist/chunk-T5RPGCCM.js +40 -0
- package/dist/chunk-WU6GAPKH.js +36 -0
- package/dist/config-XJIPZNUP.js +13 -0
- package/dist/doctor-QVNPHLJK.js +920 -0
- package/dist/index.js +23 -8
- package/dist/{init-BIRSIOXO.js → install-2HDO5FTQ.js} +807 -705
- 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/scope-explain-2F2R5URO.js +33 -0
- package/dist/status-GLQWLWH6.js +23 -0
- package/dist/store-XTSE5TY6.js +105 -0
- package/dist/sync-BJCWDPNC.js +245 -0
- package/dist/uninstall-TAXSUSKH.js +1073 -0
- package/dist/whoami-B6AEMSEV.js +31 -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 +873 -105
- package/templates/hooks/knowledge-hint-broad.cjs +549 -135
- package/templates/hooks/knowledge-hint-narrow.cjs +830 -26
- package/templates/hooks/lib/banner-i18n.cjs +309 -0
- package/templates/hooks/lib/bindings-snapshot-reader.cjs +81 -0
- package/templates/hooks/lib/cite-contract-reminder.cjs +179 -0
- package/templates/hooks/lib/cite-line-parser.cjs +180 -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 +97 -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 +77 -514
- 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 +90 -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/fabric-sync/SKILL.md +46 -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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Worked Examples (ref)
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** SKILL.md hot path points here for concrete end-to-end traces. These 4 examples illustrate Phase 2 mining (git + docs), Phase 3 dedup classification, and the out-of-band narrowing path that is NOT performed by this skill.
|
|
4
|
+
|
|
5
|
+
## Example A — Phase 2 git mining: feat commit → pitfall entry
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
LLM analysis: this is a **pitfall** (a non-obvious trap that wasted time and is repeatable across services). The body itself documents the trap. Slug candidates: `retry-without-backoff-thundering-herd` (5 words, 38 chars — passes 5 rules).
|
|
10
|
+
|
|
11
|
+
Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for fabric-import):
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
mcp__fabric__fab_extract_knowledge({
|
|
15
|
+
source_sessions: ["fabric-import-2026-05-10"],
|
|
16
|
+
recent_paths: ["packages/server/src/lib/retry.ts"], // provenance only
|
|
17
|
+
user_messages_summary: "重试无指数退避会在短暂上游故障下放大成雪崩。修正:jittered exponential backoff,30 秒上限。src=50367b5",
|
|
18
|
+
type: "pitfalls",
|
|
19
|
+
slug: "retry-without-backoff-thundering-herd",
|
|
20
|
+
relevance_scope: "broad", // MANDATORY
|
|
21
|
+
relevance_paths: [], // MANDATORY — do NOT infer ["packages/server/src/lib/retry.ts"]
|
|
22
|
+
proposed_reason: "diagnostic-then-fix", // Step 2.1.5: body describes long diagnostic chain (no-backoff → thundering-herd outage → root cause) → root-cause fix; this overrides the `feat(` prefix per the "body content wins over prefix" ambiguity rule.
|
|
23
|
+
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."
|
|
24
|
+
})
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Counter-example — DO NOT do this:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// WRONG — this skill must never produce narrow + paths from git metadata.
|
|
31
|
+
// The retry pitfall applies to every retry site, not just the file touched by 50367b5.
|
|
32
|
+
mcp__fabric__fab_extract_knowledge({
|
|
33
|
+
// ...
|
|
34
|
+
relevance_scope: "narrow", // VIOLATION
|
|
35
|
+
relevance_paths: ["packages/server/src/lib/retry.ts"] // VIOLATION
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
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.
|
|
40
|
+
|
|
41
|
+
State file delta:
|
|
42
|
+
```json
|
|
43
|
+
{ "p2_processed_commits": [
|
|
44
|
+
{ "sha": "50367b5...", "skipped": false,
|
|
45
|
+
"pending_path": "knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md",
|
|
46
|
+
"type": "pitfalls", "slug": "retry-without-backoff-thundering-herd" }
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Example B — Phase 2 doc mining: architecture.md → decision entry
|
|
52
|
+
|
|
53
|
+
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.
|
|
54
|
+
|
|
55
|
+
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).
|
|
56
|
+
|
|
57
|
+
Skill output (broad+[] mandatory; the doc's own path stays in `recent_paths` for provenance, NOT in `relevance_paths`):
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
mcp__fabric__fab_extract_knowledge({
|
|
61
|
+
source_sessions: ["fabric-import-2026-05-10"],
|
|
62
|
+
recent_paths: ["docs/architecture.md"], // provenance only
|
|
63
|
+
user_messages_summary: "选择单体架构而非微服务:3 人团队无法承担多服务运维成本,且主要性能瓶颈在 DB 吞吐而非应用层水平扩展。src=docs/architecture.md",
|
|
64
|
+
type: "decisions",
|
|
65
|
+
slug: "monolith-over-microservices-small-team",
|
|
66
|
+
relevance_scope: "broad", // MANDATORY
|
|
67
|
+
relevance_paths: [] // MANDATORY — a monolith-vs-microservices decision applies repo-wide, not only to docs/
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Example C — Phase 3 dedup finds duplicate, rejects
|
|
72
|
+
|
|
73
|
+
After Example A's pending entry (`retry-without-backoff-thundering-herd`) is proposed, Phase 3 runs:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
mcp__fabric__fab_review({
|
|
77
|
+
action: "search",
|
|
78
|
+
query: "retry backoff thundering herd",
|
|
79
|
+
filters: { type: "pitfalls" }
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
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).
|
|
84
|
+
|
|
85
|
+
Skill output:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
mcp__fabric__fab_review({
|
|
89
|
+
action: "reject",
|
|
90
|
+
pending_paths: ["knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md"],
|
|
91
|
+
reason: "duplicate of KT-P-0007"
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
State file delta:
|
|
96
|
+
```json
|
|
97
|
+
{ "p3_dedup_completed": [
|
|
98
|
+
{ "pending_path": "knowledge/pending/pitfalls/retry-without-backoff-thundering-herd.md",
|
|
99
|
+
"action": "reject", "canonical_ref": "KT-P-0007" }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Final roll-up to user reflects: 1 proposed, 0 kept, 1 rejected_dup, 0 merged, 0 contradictions.
|
|
105
|
+
|
|
106
|
+
## Example D — Post-import narrowing (out-of-band, NOT this skill)
|
|
107
|
+
|
|
108
|
+
This example documents the legal narrowing path; it is NOT performed by `fabric-import` itself. After Example B's `monolith-over-microservices-small-team` decision is imported (with `relevance_scope=broad`, `relevance_paths=[]`) and later approved into canonical via `fabric-review`, the user decides the decision is actually narrow to the server package's deploy tooling.
|
|
109
|
+
|
|
110
|
+
The user issues (via `fabric-review`, NOT via this skill):
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
mcp__fabric__fab_review({
|
|
114
|
+
action: "modify",
|
|
115
|
+
pending_path: "knowledge/team/decisions/monolith-over-microservices-small-team.md",
|
|
116
|
+
changes: {
|
|
117
|
+
relevance_scope: "narrow",
|
|
118
|
+
relevance_paths: ["packages/server/**", "scripts/deploy/**"]
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Key invariants of this flow:
|
|
124
|
+
|
|
125
|
+
- The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `fabric-import` inferring paths from git metadata.
|
|
126
|
+
- The modify call goes through `fab_review`, not `fab_extract_knowledge`, because the entry already exists (post-import or post-approval).
|
|
127
|
+
- If the user later flips the entry's layer from `team` to `personal`, server-side auto-degrades scope back to `broad` and clears `relevance_paths` (see rc.5 C3 acceptance criterion; personal knowledge crosses projects so paths don't generalize). This is the only legal way for `relevance_paths` to be re-cleared.
|
|
@@ -1,256 +1,140 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fabric-review
|
|
3
|
-
description:
|
|
3
|
+
description: 审 .fabric/knowledge pending+canonical (NOT PR review):approve/reject/modify/revisit/defer。Triggers 审批/驳回/复审/重审/approve/reject/review pending.
|
|
4
4
|
allowed-tools: Read, Glob, Grep, Bash, Edit, mcp__fabric__fab_review
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
> **Surface**:
|
|
7
|
+
> **Surface**: Skill (AI-driven, per-entry human-judgment routing). See [`docs/surfaces.md`](https://github.com/fenglimg/fabric/blob/main/docs/surfaces.md).
|
|
8
8
|
|
|
9
9
|
## Precondition
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Invoke this skill ONLY when ONE of the following holds:
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
13
|
+
- Stop-hook printed stdout JSON `{"decision":"block","reason":"..."}` carrying `signal=review` (pending overflow: count ≥ `review_hint_pending_count` (default 10) OR oldest age ≥ `review_hint_pending_age_days` (default 7) days)
|
|
14
|
+
- User typed an explicit review request (e.g. "review knowledge", "show pending", "approve what's queued", "what's stale", "look at KT-D-7")
|
|
15
|
+
- Agent判定 review backlog crossed the overflow threshold
|
|
16
16
|
|
|
17
|
-
If none
|
|
17
|
+
If none hold, stop the skill and tell the user:
|
|
18
|
+
|
|
19
|
+
- zh-CN: `没有触发 review 信号;如需手动 review 请显式调用 fabric-review`
|
|
20
|
+
- en: `No review signal detected; to manually review, explicitly invoke fabric-review`
|
|
18
21
|
|
|
19
22
|
This skill is `Infer-not-Ask` for mode and `Ask-when-genuine` for per-item actions:
|
|
20
23
|
|
|
21
24
|
- Mode (pending / topic / health / revisit) is INFERRED from context — NEVER surfaced via AskUserQuestion
|
|
22
25
|
- Per-item action (approve / reject / modify / defer) IS surfaced via AskUserQuestion — the user must judge
|
|
23
|
-
- Layer-flip target (team vs personal) IS surfaced via AskUserQuestion when modify
|
|
26
|
+
- Layer-flip target (team vs personal) IS surfaced via AskUserQuestion when modify includes layer change
|
|
27
|
+
|
|
28
|
+
Required preconditions before any `fab_review` call: `.fabric/` exists (or `~/.fabric/` for personal layer); `mcp__fabric__fab_review` MCP tool registered; `.fabric/agents.meta.json` present (id allocator reads it on approve); `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger normal first-run).
|
|
29
|
+
|
|
30
|
+
### Config Load
|
|
31
|
+
|
|
32
|
+
Read `.fabric/fabric-config.json`; resolve:
|
|
33
|
+
|
|
34
|
+
| Config field | Default | Used by |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `review_topic_result_cap` | 8 | topic mode top-N cap |
|
|
37
|
+
| `review_stale_pending_days` | 14 | health mode stale threshold (days) |
|
|
38
|
+
| `review_hint_pending_count` | 10 | precondition overflow signal (count) |
|
|
39
|
+
| `review_hint_pending_age_days` | 7 | precondition overflow signal (age) |
|
|
40
|
+
|
|
41
|
+
Missing or unreadable → defaults silently.
|
|
42
|
+
|
|
43
|
+
### Store routing (v2.1 multi-store)
|
|
44
|
+
|
|
45
|
+
Review iterates **per-store** — the read-set may span multiple stores (`fabric scope-explain team` → resolved `readSet.stores`). Pending/backlog is reported per-store (NOT aggregated into one undifferentiated pile); each candidate's provenance store is surfaced in cites as `KB: <store-alias>:<id>`. Promotion (draft → verified/proven) is a normal edit + git commit **inside that store's own repo** — no cross-store move. A `dismissed`/`modify` that flips layer between team and personal still goes through `AskUserQuestion`. Never read `~/.fabric` store trees directly; go through the MCP recall path / `scope-explain`.
|
|
46
|
+
|
|
47
|
+
### UX i18n Policy
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
Read `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`); emit user-facing prose in resolved variant. Protected tokens (`fab_review`, `fab_extract_knowledge`, `relevance_scope`, layer/scope enums, `stable_id`, the verbatim `强 team` / `强 personal` / `默认 team` block) NEVER translated. `AskUserQuestion` policy: `header` + `question` translate; `options[]` stay English (routing keys).
|
|
26
50
|
|
|
27
|
-
-
|
|
28
|
-
- `mcp__fabric__fab_review` MCP tool is registered and reachable
|
|
29
|
-
- `.fabric/agents.meta.json` is present (the id allocator reads it on approve)
|
|
30
|
-
- `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger is normal first-run)
|
|
51
|
+
`Read ref/i18n-policy.md` for the full 5-class taxonomy + edge cases.
|
|
31
52
|
|
|
32
53
|
## Mode Inference (System Infers — NEVER Ask)
|
|
33
54
|
|
|
34
|
-
>
|
|
35
|
-
> "review 永远走 fabric-review skill,**模式从上下文推断**(4 种 mode:pending queue / by topic / health overview / revisit existing)"
|
|
55
|
+
> Locked decision (KT-DEC-0006): "Review mode inferred from context, not solicited via AskUserQuestion."
|
|
36
56
|
> "**AskUserQuestion 仅在真有选择时用**——'何种 mode' 不是真选择(系统能推断),'approve/reject/modify 单条' 是真选择"
|
|
37
57
|
|
|
38
|
-
The skill MUST infer one of
|
|
58
|
+
The skill MUST infer one of **2 modes** BEFORE any user-facing output (v2.0.0-rc.37 NEW-12 simplified 4 → 2):
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
- **`pending`** — triage the write-side backlog (`.fabric/knowledge/pending/`): approve / reject / modify / defer per item. The dominant entry point.
|
|
61
|
+
- **`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.
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
### 2-Step Inference Algorithm
|
|
64
|
+
|
|
65
|
+
**Step 1 — Recent user message keyword scan:**
|
|
43
66
|
|
|
44
67
|
| Keywords (zh-CN + en) | Inferred mode |
|
|
45
68
|
|---|---|
|
|
46
69
|
| "approve", "review pending", "promote", "what's queued", "审核 pending", "通过" | `pending` |
|
|
47
|
-
| "search
|
|
48
|
-
| "what's stale", "demote old", "health check", "过期的", "陈旧的", "整理一下" | `health` |
|
|
49
|
-
| "look at <id>", "revisit KT-…", "show <slug>", "再看下 <id>", "回顾" | `revisit` |
|
|
70
|
+
| "search/find about <topic>", "what's stale", "demote old", "health check", "look at <id>", "revisit KT-…", "关于…的知识", "过期的", "陈旧的", "整理一下", "再看下 <id>", "回顾" | `maintain` |
|
|
50
71
|
|
|
51
|
-
|
|
72
|
+
A `maintain`-row match → lock `maintain`. A `pending`-row match (or 0/ambiguous) → fall to Step 2.
|
|
52
73
|
|
|
53
|
-
**Step 2 —
|
|
74
|
+
**Step 2 — Backlog default.** Glob `.fabric/knowledge/pending/**/*.md`:
|
|
54
75
|
|
|
55
|
-
- Count `
|
|
56
|
-
-
|
|
57
|
-
- If a recent `knowledge_layer_changed` event exists for the entry the user just referenced → infer `revisit`.
|
|
76
|
+
- Count ≥ `review_hint_pending_count` (default 10) OR oldest mtime > `review_hint_pending_age_days` (default 7) → `pending` (overflow, same threshold as Stop-hook).
|
|
77
|
+
- Otherwise → default `pending` (most common review entry point).
|
|
58
78
|
|
|
59
|
-
|
|
79
|
+
> Back-compat: the legacy 4-mode names (`topic` / `health` / `revisit`) still resolve — they all map to `maintain`. Old session traces / muscle memory keep working.
|
|
60
80
|
|
|
61
|
-
|
|
62
|
-
- Otherwise → default to `pending` (most common review entry point).
|
|
81
|
+
`Read ref/per-mode-flows.md` for inference examples and anti-pattern restatement.
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
## Per-Mode Flow
|
|
65
84
|
|
|
66
|
-
-
|
|
67
|
-
- "find anything about deepMerge" → `topic` (Step 1 keyword "find … about")
|
|
68
|
-
- "anything stale in our knowledge base?" → `health` (Step 1 keyword "stale")
|
|
69
|
-
- "look at KT-D-7" → `revisit` (Step 1 keyword "look at <id>")
|
|
70
|
-
- (Stop-hook fired with signal=review, no user typing) → `pending` (Step 3 default, overflow threshold tripped)
|
|
85
|
+
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.
|
|
71
86
|
|
|
72
|
-
|
|
87
|
+
- **`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):
|
|
88
|
+
- `fab_review action="modify-content"` — edit scalars (title/summary/maturity/tags/relevance_*); NEVER flips layer.
|
|
89
|
+
- `fab_review action="modify-layer"` — the dedicated layer-flip path (`changes.layer` required); may reallocate the stable_id + emit an id-redirect.
|
|
90
|
+
- (Legacy `action="modify"` still works — it routes by whether `changes.layer` is present.) See `ref/modify-flow.md`.
|
|
91
|
+
- **`maintain`** — sub-flow inferred from the same keywords:
|
|
92
|
+
- *browse-by-topic*: extract keywords → `fab_review action="search"` → render top-N (cap `review_topic_result_cap`) → AskUserQuestion only on an action verb.
|
|
93
|
+
- *health/staleness*: `fab_review action="list"` + tail events → compute stale → render dashboard → per-stale AskUserQuestion `{defer, demote, skip}`.
|
|
94
|
+
- *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.
|
|
73
95
|
|
|
74
|
-
|
|
96
|
+
`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.
|
|
75
97
|
|
|
76
|
-
##
|
|
98
|
+
## Semantic Check (LLM-Assisted Duplicate / Contradiction Detection)
|
|
77
99
|
|
|
78
|
-
|
|
100
|
+
> Boundary B (locked): "extraction / classification / layer / slug / mode / **semantic dedup** → Skill (LLM); file write / frontmatter / idempotency / counter / layer-flip / atomic promote → MCP (deterministic)"
|
|
79
101
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
1. Call `fab_review` with `action: "list"`, no filters (or `filters.layer="both"` if user explicitly mentioned both layers).
|
|
83
|
-
2. Server returns `items[]` (each = `{pending_path, type, layer, maturity, tags?, title?, summary?}`).
|
|
84
|
-
3. Before presenting, perform **Semantic Check** (see below) by issuing one or more `action: "search"` calls scoped by `filters.type` to surface possible duplicates / contradictions among already-canonical entries.
|
|
85
|
-
4. For each pending item, render a per-item block. v2.0.0-rc.7 T6: render
|
|
86
|
-
`proposed_reason` (frontmatter) + `## Why proposed` line (body, 1-line enum
|
|
87
|
-
explanation) + first line of `## Session context` so future-self has full
|
|
88
|
-
context without re-reading the transcript:
|
|
102
|
+
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:
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Summary: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
94
|
-
Maturity: draft Tags: [hook, cli]
|
|
95
|
-
Proposed reason: decision-confirmation — ≥2 候选方案经权衡后确认选型。
|
|
96
|
-
Session context: Session goal: ship Stop-hook for v2 release.
|
|
97
|
-
⚠ Possible duplicate of KT-D-0007 (similarity 0.78 on title + summary)
|
|
98
|
-
```
|
|
104
|
+
- `⚠ Possible duplicate of <stable_id> (overlap: high)` — same essential claim
|
|
105
|
+
- `⚠ Contradicts <stable_id> (overlap: high)` — opposing claims, same scope
|
|
106
|
+
- `⚠ Subsumed by <stable_id> (overlap: medium+); consider modify-to-merge` — fully covered
|
|
99
107
|
|
|
100
|
-
|
|
101
|
-
(parse the YAML block, key `proposed_reason`) and the `## Why proposed`
|
|
102
|
-
line / first non-blank line of `## Session context` from the body. If
|
|
103
|
-
either is missing on a pre-rc.7 pending entry, render `Proposed reason:
|
|
104
|
-
<legacy entry, no reason recorded>` and `Session context: <not recorded>`
|
|
105
|
-
so the reviewer can still proceed.
|
|
106
|
-
|
|
107
|
-
5. Surface a per-item AskUserQuestion:
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
AskUserQuestion({
|
|
111
|
-
header: "Review pending entry",
|
|
112
|
-
question: "What action for '单 .cjs hook 跨客户端'?",
|
|
113
|
-
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
114
|
-
})
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
6. Route the user's choice:
|
|
118
|
-
- `approve` → accumulate pending_path into a batch; flush via single `fab_review action="approve"` with `pending_paths=[…]` after the loop ends.
|
|
119
|
-
- `reject` → ask the user for a one-line reason via free-text follow-up; call `fab_review action="reject"` with `pending_paths=[path]` and `reason`.
|
|
120
|
-
- `modify` → see Modify Sub-Flow below.
|
|
121
|
-
- `defer` → call `fab_review action="defer"` with `pending_paths=[path]`; optional `until` ISO datetime if the user supplies one ("defer 2 weeks" → compute and set).
|
|
122
|
-
- `skip` → no MCP call; move to next item.
|
|
123
|
-
7. After the loop, display a roll-up: counts by action, list of newly-allocated `stable_id`s (from approve output), and tail of `.fabric/events.jsonl` showing the appended events.
|
|
124
|
-
|
|
125
|
-
### Mode: topic — Search & Surface Findings
|
|
126
|
-
|
|
127
|
-
1. Extract the topic keyword(s) from the user's message (e.g. "find about deepMerge" → query="deepMerge").
|
|
128
|
-
2. Call `fab_review action="search"` with `query` and any obvious filters (if user said "team-only" → `filters.layer="team"`).
|
|
129
|
-
3. Server returns `items[]` ranked by relevance — these are entries already in `.fabric/knowledge/{layer}/{type}/` (NOT pending), unless `filters` says otherwise.
|
|
130
|
-
4. Render top-N (cap at 8) results with title / summary / pending_path.
|
|
131
|
-
5. If the user follow-up indicates intent to act ("approve all", "modify the second one"), pivot into the corresponding pending mode action — the search result already gives the `pending_path` needed for the action.
|
|
132
|
-
6. NEVER surface a per-item AskUserQuestion just for browsing — only when the user signals an action verb.
|
|
133
|
-
|
|
134
|
-
### Mode: health — Corpus Health & Stale Detection
|
|
135
|
-
|
|
136
|
-
1. Call `fab_review action="list"` with `filters.maturity="draft"` (or no filter for full corpus inspection).
|
|
137
|
-
2. Tail `.fabric/events.jsonl` for layer_changed / demoted / rejected counts in the trailing 30 days.
|
|
138
|
-
3. Compute stale candidates: pending entries with mtime `>14 days` OR maturity=draft entries with no recent evidence-append events.
|
|
139
|
-
4. Render a corpus dashboard:
|
|
140
|
-
|
|
141
|
-
```md
|
|
142
|
-
## Health Overview
|
|
143
|
-
- Pending: 12 entries (oldest 18d) — recommend `defer` or `reject`
|
|
144
|
-
- Drafts: 8 (3 are stale candidates: KP-G-3, KP-G-5, KT-P-9)
|
|
145
|
-
- Layer flips (30d): 2
|
|
146
|
-
- Rejections (30d): 1
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
5. For each stale candidate, surface AskUserQuestion `{options: ["defer", "demote", "skip"]}`; route `defer` → `fab_review action="defer"`, `demote` → `fab_review action="modify"` with `changes.maturity` lowered (or `reject` if the user wants outright removal of a pending entry).
|
|
150
|
-
|
|
151
|
-
### Mode: revisit — Specific Entry Deep Dive
|
|
152
|
-
|
|
153
|
-
1. The user referenced a specific entry (by id `KT-D-7` or by slug `single-cjs-hook`).
|
|
154
|
-
2. Call `fab_review action="list"` with `filters` narrowed by best-guess fields; if the entry is canonical (has stable_id), `Read` the file directly at `.fabric/knowledge/{layer}/{type}/<id>--<slug>.md`.
|
|
155
|
-
3. Display the full body (frontmatter + content). Tail the events.jsonl for any history events tagged with this stable_id.
|
|
156
|
-
4. Surface AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` only if the entry is still pending; for canonical entries the only mutation path is `modify` (incl. layer flip).
|
|
157
|
-
|
|
158
|
-
## Semantic Check Guidance (LLM-Assisted Duplicate / Contradiction Detection)
|
|
159
|
-
|
|
160
|
-
> Boundary B (locked): "extraction classification / layer inference / slug naming / mode inference / **semantic dedup** → Skill (LLM); pending file write / frontmatter assembly / idempotency check / counter mgmt / layer-flip transaction / atomic promote → MCP (deterministic)"
|
|
161
|
-
|
|
162
|
-
Semantic check is the LLM's job — the MCP tool does NOT compare meaning. Run this check during `pending` mode (and on demand during `topic` mode):
|
|
163
|
-
|
|
164
|
-
For each pending entry to be presented:
|
|
165
|
-
|
|
166
|
-
1. Call `fab_review action="search"` with `query=<title or summary keywords>` and `filters.type=<same type>` to fetch already-canonical entries of the same type.
|
|
167
|
-
2. Compare semantically (LLM judgment, not string match):
|
|
168
|
-
- **Duplicate** — same essential claim. Heuristics: title keyword overlap >60%, summary asserts the same outcome with no novel context. Flag: `⚠ Possible duplicate of <stable_id>`.
|
|
169
|
-
- **Contradiction** — opposing claims about the same subject. Heuristics: one entry says "use X" while pending says "avoid X" on identical scope. Flag: `⚠ Contradicts <stable_id>`.
|
|
170
|
-
- **Subsumption** — pending fully covered by an existing entry plus extras. Flag: `⚠ Subsumed by <stable_id>; consider modify-to-merge`.
|
|
171
|
-
3. Surface the flag in the per-item display block (see pending mode step 4).
|
|
172
|
-
4. The user decides:
|
|
173
|
-
- Still approve → flag is informational; pending becomes canonical alongside the existing entry.
|
|
174
|
-
- Modify-to-harmonize → user supplies edits via `modify` action; consider merging language with the existing entry.
|
|
175
|
-
- Reject as duplicate → reason field MUST cite the existing stable_id (e.g. `reason="duplicate of KT-D-7"`).
|
|
176
|
-
|
|
177
|
-
DO NOT call `AskUserQuestion` to ask "is this a duplicate?" — the LLM has already judged. The user only chooses among approve / reject / modify, which is a genuine choice.
|
|
178
|
-
|
|
179
|
-
## Modify Sub-Flow & Layer-Flip Rules
|
|
180
|
-
|
|
181
|
-
`modify` is the only action that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?}`. Server semantics:
|
|
182
|
-
|
|
183
|
-
- **title / summary / tags / maturity changes** → in-place rewrite; stable_id PRESERVED; emits `knowledge_slug_renamed` only when slug derives from title.
|
|
184
|
-
- **layer change** → the ONLY legal stable_id mutation in the system.
|
|
185
|
-
|
|
186
|
-
### Layer-Flip Rules (the only legal stable_id mutation)
|
|
187
|
-
|
|
188
|
-
Triggered when `changes.layer` differs from current entry layer. Server-side transaction:
|
|
189
|
-
|
|
190
|
-
1. Allocate new id under target layer via `KnowledgeIdAllocator.allocate(new_layer, type)` (e.g. KT-D-7 in `team/decisions/` flips to KP-D-3 in `personal/decisions/`).
|
|
191
|
-
2. `git mv <old-layer>/<type>/<old-id>--<slug>.md <new-layer>/<type>/<new-id>--<slug>.md`.
|
|
192
|
-
3. Append `knowledge_layer_changed` event with `{from_layer, to_layer, prior_stable_id, new_stable_id}`.
|
|
193
|
-
4. Server response includes `prior_stable_id` and `new_stable_id` — surface BOTH to the user in the roll-up.
|
|
194
|
-
|
|
195
|
-
Skill responsibilities for layer flip:
|
|
196
|
-
|
|
197
|
-
- BEFORE calling fab_review, surface `AskUserQuestion {options: ["team", "personal"]}` to confirm target layer. The default in the question header should reflect the verbatim layer heuristic (default team unless 强 personal signals dominate). This IS a genuine choice — the user must pick.
|
|
198
|
-
- AFTER server returns, render: `Layer flipped: <prior_stable_id> → <new_stable_id>`. Do NOT silently swallow the id change — downstream agents may have cached the prior id.
|
|
108
|
+
**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:
|
|
199
109
|
|
|
200
|
-
|
|
110
|
+
- `high` — ≥ ~80% of the candidate's essential claim is restated; near-certain dup/contradiction. Recommend reject-as-duplicate or modify-to-merge.
|
|
111
|
+
- `medium` — substantial conceptual overlap but the new entry adds a distinct facet (different path scope, added caveat). Recommend modify-to-harmonize.
|
|
112
|
+
- `low` — adjacent topic, not a real overlap. Do NOT raise a flag at `low` — it is below the surfacing threshold (suppresses noise).
|
|
201
113
|
|
|
202
|
-
|
|
203
|
-
// Maturity bump only (no id change)
|
|
204
|
-
mcp__fabric__fab_review({
|
|
205
|
-
action: "modify",
|
|
206
|
-
pending_path: "knowledge/team/decisions/KT-D-0007--single-cjs-hook.md",
|
|
207
|
-
changes: { maturity: "verified" }
|
|
208
|
-
})
|
|
114
|
+
Only `medium`+ flags are surfaced. User decides: still-approve (flag informational), modify-to-harmonize, or reject-as-duplicate (reason MUST cite existing stable_id).
|
|
209
115
|
|
|
210
|
-
|
|
211
|
-
mcp__fabric__fab_review({
|
|
212
|
-
action: "modify",
|
|
213
|
-
pending_path: "knowledge/team/guidelines/KT-G-0003--indent-style.md",
|
|
214
|
-
changes: { layer: "personal" }
|
|
215
|
-
})
|
|
216
|
-
```
|
|
116
|
+
DO NOT AskUserQuestion "is this a duplicate?" — LLM already judged. User only chooses approve/reject/modify.
|
|
217
117
|
|
|
218
|
-
|
|
118
|
+
`Read ref/semantic-check.md` for full procedure + 三类判断的细化定义.
|
|
219
119
|
|
|
220
|
-
|
|
120
|
+
## Narrowing Imported Entries & Modify Sub-Flow
|
|
221
121
|
|
|
222
|
-
|
|
223
|
-
- Per-stale-item action (health mode): `["defer", "demote", "skip"]`
|
|
224
|
-
- Layer-flip target when modify path includes layer change: `["team", "personal"]`
|
|
225
|
-
- Reject reason follow-up (free-text, may use AskUserQuestion's free-form variant if available, otherwise plain prompt)
|
|
122
|
+
`modify` is the only action that mutates frontmatter or stable_id. Two paths:
|
|
226
123
|
|
|
227
|
-
|
|
124
|
+
- **Title/summary/tags/maturity** → in-place rewrite; stable_id PRESERVED.
|
|
125
|
+
- **Layer change** → ONLY legal stable_id mutation. BEFORE call, AskUserQuestion `{team, personal}` to confirm target (this IS genuine choice). AFTER server returns, surface BOTH `prior_stable_id` and `new_stable_id` in roll-up — downstream agents may cache the prior id.
|
|
228
126
|
|
|
229
|
-
-
|
|
230
|
-
- Whether to invoke this skill at all — Stop-hook signal or explicit user request decides
|
|
231
|
-
- Whether an entry is a duplicate — LLM semantic check answers
|
|
232
|
-
- Frontmatter parsing — deterministic, never asked
|
|
233
|
-
- Allocate next id — deterministic via KnowledgeIdAllocator, never asked
|
|
127
|
+
**Import-origin entries** (`source_sessions[0]` starts with `fabric-import-`) ship with `relevance_scope=broad + relevance_paths=[]` by design; narrowing is fabric-review's responsibility. Render `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — pick 'modify' + say 'narrow to <paths>'` as informational hint. On `modify` of import-origin: extended option list `{narrow scope, edit summary, change layer, change maturity, skip}`; "narrow scope" → free-text follow-up → `changes: { relevance_scope: "narrow", relevance_paths: [<parsed>] }`. Personal layer auto-degrades narrow → broad+[] (server-side), emitting `knowledge_scope_degraded`.
|
|
234
128
|
|
|
235
|
-
|
|
129
|
+
`Read ref/modify-flow.md` for layer-flip server transaction (4-step), modify call shape examples (maturity bump / layer flip), and full narrowing flow with bilingual AskUserQuestion templates.
|
|
236
130
|
|
|
237
|
-
|
|
238
|
-
AskUserQuestion({
|
|
239
|
-
header: "Review pending entry",
|
|
240
|
-
question: "What action for '{title}'? ({pending_path})",
|
|
241
|
-
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
242
|
-
})
|
|
243
|
-
```
|
|
131
|
+
## AskUserQuestion Policy
|
|
244
132
|
|
|
245
|
-
|
|
133
|
+
**DO ask** (genuine choices): per-pending action `{approve, reject, modify, defer, skip}` · per-stale action `{defer, demote, skip}` · layer-flip target `{team, personal}` · reject reason follow-up (free-text).
|
|
246
134
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
question: "Move '{title}' to which layer? (current: {current_layer})",
|
|
251
|
-
options: ["team", "personal"]
|
|
252
|
-
})
|
|
253
|
-
```
|
|
135
|
+
**DO NOT ask**: mode picking (inferred) · whether to invoke skill (Stop-hook/explicit decides) · whether duplicate (LLM judges) · frontmatter parsing (deterministic) · next id allocation (deterministic via KnowledgeIdAllocator).
|
|
136
|
+
|
|
137
|
+
`Read ref/askuserquestion-policy.md` for full DO/DO NOT lists + bilingual per-item question phrasing templates (pending action / layer-flip target).
|
|
254
138
|
|
|
255
139
|
## Decision Tree — Is This Entry Approvable?
|
|
256
140
|
|
|
@@ -289,94 +173,16 @@ Pending entry presented for review
|
|
|
289
173
|
- NEVER batch heterogeneous decisions into a single MCP call. Approve and reject MAY be batched within their own action; modify MUST be one call per entry.
|
|
290
174
|
- NEVER invoke `fab_review action="approve"` without at least one `pending_paths` entry.
|
|
291
175
|
- NEVER infer a layer-flip target — the user MUST choose via AskUserQuestion.
|
|
292
|
-
- MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `fab_review`, `MUST`, `NEVER`.
|
|
293
|
-
|
|
294
|
-
## Output Contract
|
|
295
|
-
|
|
296
|
-
After each invocation, the skill MUST produce a brief roll-up to the user:
|
|
297
|
-
|
|
298
|
-
```md
|
|
299
|
-
# Review Summary — mode={pending|topic|health|revisit}
|
|
300
|
-
- Listed: N entries
|
|
301
|
-
- Approved: M (new stable_ids: KT-D-12, KT-G-4, KP-P-2)
|
|
302
|
-
- Rejected: R
|
|
303
|
-
- Modified: U (incl. K layer flips)
|
|
304
|
-
- Deferred: D
|
|
305
|
-
- Skipped: S
|
|
306
|
-
|
|
307
|
-
## Events appended (.fabric/events.jsonl tail)
|
|
308
|
-
- knowledge_promote_started ×M
|
|
309
|
-
- knowledge_promoted ×M
|
|
310
|
-
- knowledge_layer_changed ×K
|
|
311
|
-
- knowledge_rejected ×R
|
|
312
|
-
- knowledge_deferred ×D
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
Also surface a one-line `git status` of `.fabric/knowledge/` so the user sees the file moves caused by approve / layer-flip.
|
|
316
|
-
|
|
317
|
-
## Worked Examples
|
|
318
|
-
|
|
319
|
-
### Example A — pending mode with semantic check flagging a duplicate (user chooses reject)
|
|
320
|
-
|
|
321
|
-
User: "review the pending knowledge".
|
|
322
|
-
|
|
323
|
-
Inferred mode: `pending` (Step 1 keyword "review … pending").
|
|
324
|
-
|
|
325
|
-
Skill flow:
|
|
326
|
-
|
|
327
|
-
1. `fab_review action="list"` → returns 3 pending items.
|
|
328
|
-
2. Semantic check on item 2 (`pending/decisions/single-cjs-hook.md`) — `fab_review action="search"` with `query="single cjs hook"` filter `type=decisions` returns canonical `KT-D-0007--single-cjs-hook-across-clients.md` (similarity high).
|
|
329
|
-
3. Display block:
|
|
330
|
-
|
|
331
|
-
```md
|
|
332
|
-
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
333
|
-
Title: 单 .cjs hook 跨客户端
|
|
334
|
-
Summary: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
335
|
-
⚠ Possible duplicate of KT-D-0007 (similarity 0.84 on title + summary)
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
4. AskUserQuestion fires; user picks `reject`.
|
|
339
|
-
5. Free-text follow-up: user types `duplicate of KT-D-7`.
|
|
340
|
-
6. `fab_review action="reject"` with `pending_paths=["knowledge/pending/decisions/single-cjs-hook.md"]` and `reason="duplicate of KT-D-7"`.
|
|
341
|
-
7. Roll-up reports: 1 rejected, 0 approved, events appended.
|
|
342
|
-
|
|
343
|
-
### Example B — revisit mode with layer flip (KT → KP)
|
|
344
|
-
|
|
345
|
-
User: "look at KT-G-3, that's actually personal not team".
|
|
346
|
-
|
|
347
|
-
Inferred mode: `revisit` (Step 1 keyword "look at <id>").
|
|
348
|
-
|
|
349
|
-
Skill flow:
|
|
350
|
-
|
|
351
|
-
1. Read `.fabric/knowledge/team/guidelines/KT-G-0003--indent-style.md`. Display body to user.
|
|
352
|
-
2. AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` — user picks `modify`.
|
|
353
|
-
3. Skill detects user-stated intent "actually personal not team" — surface AskUserQuestion `{options: ["team", "personal"]}` with current layer=team noted; user confirms `personal`.
|
|
354
|
-
4. Call:
|
|
355
|
-
|
|
356
|
-
```ts
|
|
357
|
-
mcp__fabric__fab_review({
|
|
358
|
-
action: "modify",
|
|
359
|
-
pending_path: "knowledge/team/guidelines/KT-G-0003--indent-style.md",
|
|
360
|
-
changes: { layer: "personal" }
|
|
361
|
-
})
|
|
362
|
-
```
|
|
176
|
+
- MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `knowledge_scope_degraded`, `fab_review`, `MUST`, `NEVER`, `relevance_scope`, `relevance_paths`, `narrow`, `broad`, `proposed_reason`, `session_context`.
|
|
363
177
|
|
|
364
|
-
|
|
365
|
-
6. Roll-up: `Layer flipped: KT-G-0003 → KP-G-0001`. `git status` shows the rename across layer roots.
|
|
178
|
+
## Output Contract & events.jsonl Constraint (ref-only)
|
|
366
179
|
|
|
367
|
-
|
|
180
|
+
After each invocation, produce a bilingual `# Review Summary` (en) / `# Review 汇总` (zh-CN) roll-up: listed/approved/rejected/modified/deferred/skipped counts + new stable_ids + tail of `.fabric/events.jsonl` events (`knowledge_promote_started`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_rejected`, `knowledge_deferred`). Also surface `git status` of `.fabric/knowledge/` so file moves are visible.
|
|
368
181
|
|
|
369
|
-
|
|
182
|
+
events.jsonl appends MUST stay single-line + ≤4KB (POSIX `PIPE_BUF` atomicity).
|
|
370
183
|
|
|
371
|
-
|
|
184
|
+
`Read ref/output-contract.md` for full bilingual rollup templates + per-field self-truncate caps (`session_context` 500 chars; `source_sessions` 5 entries; `recent_paths` 20 entries; `user_messages_summary` 500 chars).
|
|
372
185
|
|
|
373
|
-
|
|
186
|
+
## Worked Examples (ref-only)
|
|
374
187
|
|
|
375
|
-
|
|
376
|
-
2. Compute stale candidates: 3 pending entries with mtime >14d (KP-G-5 candidate-pending, KT-P-9 candidate-pending, KP-G-3 canonical draft with no evidence-append in 21d).
|
|
377
|
-
3. Render dashboard then loop per stale item.
|
|
378
|
-
4. Per-item AskUserQuestion fires:
|
|
379
|
-
- KP-G-5 → user picks `defer` (until="2026-06-01") → `fab_review action="defer"` with `until` set.
|
|
380
|
-
- KT-P-9 → user picks `defer` (no until) → `fab_review action="defer"` with no `until`.
|
|
381
|
-
- KP-G-3 → user picks `demote` → `fab_review action="modify"` with `changes.maturity="draft"` (already draft; equivalently demote means reject if pending — skill chooses correct action by inspecting current state).
|
|
382
|
-
5. Roll-up: 2 deferred, 1 modified, events appended (`knowledge_deferred ×2`, `knowledge_promote_started/promoted` not relevant; `knowledge_layer_changed` not relevant).
|
|
188
|
+
Four worked examples (pending-mode dedupe / revisit layer-flip / health mode / narrowing imported entries) live in `ref/worked-examples.md`. Load when you want to see how Mode + AskUserQuestion + MCP-call shape composes on real candidate sets.
|