@fenglimg/fabric-cli 2.2.0-rc.9 → 2.3.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/audit-PURSJJFH.js +734 -0
- package/dist/{chunk-YM4XATJF.js → chunk-722JU5BP.js} +2 -0
- package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
- package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
- package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
- package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
- package/dist/chunk-PP7QVRXH.js +565 -0
- package/dist/chunk-SL77FXX7.js +54 -0
- package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
- package/dist/doctor-S6KPGS35.js +27 -0
- package/dist/index.js +91 -81
- package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
- package/dist/{context-7NUKXDB6.js → inspect-5YZMJPFM.js} +11 -11
- package/dist/{install-v2-I6PJ6IFT.js → install-v2-KGIDII4H.js} +163 -364
- package/dist/{plan-context-hint-G75R4P4J.js → plan-context-hint-5TNGH3R4.js} +1 -1
- package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
- package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
- package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
- package/package.json +3 -7
- package/templates/hooks/cite-policy-evict.cjs +1 -1
- package/templates/hooks/configs/claude-code.json +1 -5
- package/templates/hooks/configs/codex-hooks.json +1 -5
- package/templates/hooks/fabric-hint.cjs +346 -138
- package/templates/hooks/knowledge-hint-broad.cjs +265 -75
- package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
- package/templates/hooks/knowledge-pretooluse.cjs +111 -0
- package/templates/hooks/lib/banner-i18n.cjs +31 -12
- package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
- package/templates/hooks/lib/event-writer.cjs +79 -0
- package/templates/hooks/lib/nudge-policy.cjs +11 -0
- package/templates/hooks/lib/theme.cjs +62 -0
- package/templates/hooks/post-tooluse-mutation.cjs +28 -39
- package/templates/skills/fabric-archive/SKILL.md +43 -12
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
- package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
- package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
- package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
- package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
- package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
- package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
- package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
- package/templates/skills/fabric-review/SKILL.md +28 -15
- package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
- package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
- package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
- package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
- package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
- package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
- package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
- package/templates/skills/fabric-store/SKILL.md +12 -27
- package/templates/skills/fabric-sync/SKILL.md +16 -35
- package/templates/skills/lib/shared-policy.md +6 -4
- package/dist/chunk-27HK6H5Y.js +0 -69
- package/dist/chunk-E7HJUU34.js +0 -1096
- package/dist/chunk-NLNH64A3.js +0 -43
- package/dist/chunk-QFIVFZRH.js +0 -13
- package/dist/doctor-MDTZWKBK.js +0 -24
- package/dist/metrics-HMFH4YHK.js +0 -135
- package/dist/scope-explain-HLJZ2M33.js +0 -48
- package/dist/status-4R3TM4FJ.js +0 -37
- package/dist/whoami-ITGEFWH4.js +0 -49
- package/templates/skills/fabric/SKILL.md +0 -100
- package/templates/skills/fabric-audit/SKILL.md +0 -63
- package/templates/skills/fabric-connect/SKILL.md +0 -48
- package/templates/skills/fabric-import/SKILL.md +0 -151
- package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
|
@@ -23,7 +23,7 @@ is the canonical taxonomy for this gate.
|
|
|
23
23
|
|-------|--------|-------------------------------------------------------|
|
|
24
24
|
| **E1** | `hook_passive` | stdout JSON `{decision:'block', ...}` from `fabric-hint.cjs` detected at skill entry (the Stop-hook reminder path). |
|
|
25
25
|
| **E2** | `explicit_user_invoke` | User prompt is a direct invocation: `fabric archive` / `/fabric-archive` / `archive what we just did` / `归档一下` / similar imperative. |
|
|
26
|
-
| **E3** | `ai_self_trigger` |
|
|
26
|
+
| **E3** | `ai_self_trigger` | DEFAULT else-branch: the AI invoked `fabric-archive` itself, following the AGENTS.md self-archive policy (a clear archival signal — `User-driven normative` or `Wrong-turn-and-revert` — surfaced this turn), AND none of the affirmative non-AI entry signals are present (no E1 hook `{decision:'block'}` block, no E2/E4 explicit user invocation, no E5 cron literal). v2.2 C1 W3b retired the AI-printed routing marker — E3 is now the deterministic else-branch, so routing no longer depends on the AI emitting an exact magic string (every other entry has its own non-AI affirmative detector; E3 is what remains). The signal category does not need to be conveyed to the skill — Phase 2.5's viability gate re-derives it independently. |
|
|
27
27
|
| **E4** | `user_range_rollback` | Prompt contains a **range hint** (parsed in Phase 0 — e.g. `今日` / `上周` / `rc.20`) AND the user is invoking. Sub-mode of E2. |
|
|
28
28
|
| **E5** | `cron` | Prompt contains literal `今日复盘` / `daily recap` / `daily-archive` AND no human is present (running under `/loop`, OS cron, or scheduled trigger). |
|
|
29
29
|
|
|
@@ -141,7 +141,7 @@ AskUserQuestion({
|
|
|
141
141
|
})
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
`
|
|
144
|
+
`fab_propose` is called with `onboard_slot: <slot>` set so each
|
|
145
145
|
proposed entry counts toward coverage once approved via fab_review.
|
|
146
146
|
|
|
147
147
|
| User choice | Action |
|
|
@@ -172,7 +172,7 @@ After Read-ing the slot-specific sources, classify the observation:
|
|
|
172
172
|
- `build-system-idiom` → type=`processes`, `proposed_reason=new-dependency-or-pattern`
|
|
173
173
|
- `domain-vocabulary` → type=`models`, `proposed_reason=new-dependency-or-pattern`
|
|
174
174
|
|
|
175
|
-
Call `
|
|
175
|
+
Call `fab_propose` with the inferred fields PLUS `onboard_slot:
|
|
176
176
|
<slot>`. The pending file's frontmatter will carry the slot label, and the
|
|
177
177
|
next `fabric onboard-coverage` run will see the slot as filled (once approved
|
|
178
178
|
via fab_review).
|
|
@@ -180,7 +180,7 @@ via fab_review).
|
|
|
180
180
|
Example:
|
|
181
181
|
|
|
182
182
|
```ts
|
|
183
|
-
|
|
183
|
+
mcp__fabric__fab_propose({
|
|
184
184
|
source_sessions: ["<current-session-id>"],
|
|
185
185
|
recent_paths: ["package.json", "tsconfig.json"],
|
|
186
186
|
user_messages_summary: "Project uses TypeScript + pnpm workspace + Vitest. Node 20 LTS target. ESM-only.",
|
|
@@ -214,4 +214,4 @@ mcp__fabric__fab_extract_knowledge({
|
|
|
214
214
|
- MUST emit `onboard_slot: <slot>` verbatim — the slot name is one of
|
|
215
215
|
the locked S5 strings (tech-stack-decision / architecture-pattern /
|
|
216
216
|
code-style-tone / build-system-idiom / domain-vocabulary). The
|
|
217
|
-
|
|
217
|
+
fab_propose schema enum will reject anything else.
|
|
@@ -35,7 +35,7 @@ Before Step 5 builds the cross-session context, drop sessions that the outcome l
|
|
|
35
35
|
- **(e) Never attempted (no `session_archive_attempted` event found for this `session_id`) → keep.** First-time scan; nothing to filter against.
|
|
36
36
|
- **(f) Cross-session pending dedupe** (operates on candidate observations, not on `session_id` filter): gather all `knowledge_proposed_ids` from `session_archive_attempted` events with `outcome === "proposed"` across ALL sessions in the recent window (NOT just the current candidate session). This builds a global set of idempotency keys already proposed by prior archive runs but not yet reviewed by the user (the active write store may still contain matching pending entries). When classifying new observations in Phase 3, drop any candidate whose computed `idempotency_key` matches an id already in this set — it was already proposed by an earlier archive run, the user just hasn't reviewed it yet, so re-proposing would duplicate pending entries and inflate `candidates_proposed` counts. Per Phase 4.5 dedupe consumer of `knowledge_proposed_ids`.
|
|
37
37
|
|
|
38
|
-
The resulting filtered `session_id[]` proceeds into Step 5's digest concatenation. Sessions filtered out in this step do NOT contribute to `### Cross-session digest`, are NOT included in `source_sessions` on any
|
|
38
|
+
The resulting filtered `session_id[]` proceeds into Step 5's digest concatenation. Sessions filtered out in this step do NOT contribute to `### Cross-session digest`, are NOT included in `source_sessions` on any fab_propose call, and are NOT referenced in `session_context` bodies.
|
|
39
39
|
|
|
40
40
|
### Constants (rc.25 — verbatim)
|
|
41
41
|
|
|
@@ -54,7 +54,7 @@ The resulting filtered `session_id[]` proceeds into Step 5's digest concatenatio
|
|
|
54
54
|
Concatenate the loaded digests into a single `### Cross-session digest` block to carry into Phase 2.5 + Phase 1. Use this block to:
|
|
55
55
|
|
|
56
56
|
- Detect session-spanning patterns (e.g. a discussion that started in session A and continued in session B).
|
|
57
|
-
- Populate the `source_sessions` array on every
|
|
57
|
+
- Populate the `source_sessions` array on every fab_propose call — the array form (T5) replaces the legacy `source_session` string.
|
|
58
58
|
- Inform the `session_context` blob written to each pending entry's body (3-5 lines summarizing goal + key turning point, per T6).
|
|
59
59
|
|
|
60
60
|
## Graceful degradation
|
|
@@ -36,7 +36,7 @@ These force the gate to FAIL **unless** an archive signal also fires (i.e. anti-
|
|
|
36
36
|
1. **Typo-only edits** — the entire session is whitespace / spelling / formatting changes. No semantic content to archive.
|
|
37
37
|
2. **Pure refactor** — rename / move / extract with no behavior change AND no naming convention being established.
|
|
38
38
|
3. **Narrow rename request** — user asked to rename one symbol / file with no rationale. Zero generalization potential.
|
|
39
|
-
4. **Duplicate of existing canonical** — v2.0.0-rc.37 NEW-4: this check is now **mandatory** (was "do a quick Glob before deciding"). Pre-PASS MUST step: for each candidate, call `
|
|
39
|
+
4. **Duplicate of existing canonical** — v2.0.0-rc.37 NEW-4: this check is now **mandatory** (was "do a quick Glob before deciding"). Pre-PASS MUST step: for each candidate, call `fab_pending action="search"` scoped by type/slug keywords so the MCP read path searches mounted stores. If duplicate found → drop candidate. Silently writing a near-duplicate is the highest-noise failure mode.
|
|
40
40
|
|
|
41
41
|
## Gate-FAIL user messages (E2 / E4 only)
|
|
42
42
|
|
|
@@ -62,7 +62,7 @@ Step 5: SCOPE GATE
|
|
|
62
62
|
|
|
63
63
|
Step 6: ATTACH evidence_paths to FRONTMATTER (rc.37 NEW-7 upgrade)
|
|
64
64
|
Pass evidence_candidate_paths (from Step 2, post-blacklist Step 3) to
|
|
65
|
-
|
|
65
|
+
fab_propose as the `evidence_paths` input field. Server writes
|
|
66
66
|
them to frontmatter `evidence_paths: [...]` (NOT to body `## Evidence`).
|
|
67
67
|
This makes evidence consumable by plan-context retrieval as structured
|
|
68
68
|
data instead of forcing markdown re-parsing every recall. The legacy
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
For each candidate, identify the **`related`** graph edges to other KB entries — the store-qualified `stable_id`s this entry semantically links to (the decision it supersedes, the pitfall it explains, the model it instantiates). You discovered these ids during the session via `fab_recall` / plan-context, so cite the ones you actually saw, NEVER invent stable_ids.
|
|
4
4
|
|
|
5
|
-
Because `
|
|
5
|
+
Because `fab_propose` has no dedicated `related` input, record the candidate edges as one line inside `session_context` (e.g. `related: team:KT-DEC-0007, team:KT-PIT-0011`) so they survive to approve-time frontmatter authoring (`fabric-review` writes the canonical `related: [...]` frontmatter).
|
|
6
6
|
|
|
7
7
|
## §4 privacy iron law — KT→KP is FORBIDDEN
|
|
8
8
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Five Knowledge Types (verbose)
|
|
6
6
|
|
|
7
7
|
- **model** — A reusable mental abstraction or domain object schema. Worth-archive signal: the user names something ("the X pattern", "the Y phase"). Skip-it signal: ad-hoc terminology used once. Positive: "Wave-1/Wave-2 task DAG decomposition for parallel-safe planning". Negative: "the thing we did just now" (too thin, no reusable abstraction).
|
|
8
|
-
- **decision** — A choice between alternatives with rationale. Worth-archive signal: ≥2 options were weighed AND a rationale was given. Skip-it signal: the choice was forced by external constraint with no real alternative. Positive: "Single .cjs hook script over three per-client scripts — rationale: identical stdout JSON shape across Claude/Codex". Negative: "Used the existing
|
|
8
|
+
- **decision** — A choice between alternatives with rationale. Worth-archive signal: ≥2 options were weighed AND a rationale was given. Skip-it signal: the choice was forced by external constraint with no real alternative. Positive: "Single .cjs hook script over three per-client scripts — rationale: identical stdout JSON shape across Claude/Codex". Negative: "Used the existing fab_propose schema" (no alternative was considered).
|
|
9
9
|
- **guideline** — A normative rule for future similar situations. Worth-archive signal: the user said "always" / "never" / "from now on". Skip-it signal: a one-off preference that won't generalize. Positive: "Slug naming: kebab-case, 2-5 words, 20-40 chars, semantic core only". Negative: "Use 4-space indent in this one file" (too narrow).
|
|
10
10
|
- **pitfall** — A trap that wasted time and is non-obvious. Worth-archive signal: a bug took >15 min to diagnose AND is repeatable. Skip-it signal: a typo or one-time API quirk. Positive: "deepMerge replaces arrays — hooks.Stop[] needs special-case append-with-dedupe". Negative: "Forgot a comma in JSON" (too obvious).
|
|
11
11
|
- **process** — A multi-step procedure with a stable shape. Worth-archive signal: the steps were executed in a specific order AND the order matters. Skip-it signal: a one-shot script with no reusable structure. Positive: "fab_review approve = counter++ → frontmatter inject → git mv → meta rebuild → event append (5 atomic steps)". Negative: "Ran the tests, then committed" (trivial, no reusable shape).
|
|
@@ -25,7 +25,7 @@ For EACH `session_id` in the run's scope (multi-session E4 runs emit MULTIPLE ev
|
|
|
25
25
|
|
|
26
26
|
| Skill terminal state | outcome | candidates_proposed | knowledge_proposed_ids |
|
|
27
27
|
|----------------------------------------------------------------------|----------------------|---------------------|-------------------------------------------------|
|
|
28
|
-
| Phase 4 wrote ≥ 1 pending entry | `proposed` | N (count written) | `[idempotency_key_1, idempotency_key_2, ...]` (from each
|
|
28
|
+
| Phase 4 wrote ≥ 1 pending entry | `proposed` | N (count written) | `[idempotency_key_1, idempotency_key_2, ...]` (from each fab_propose response) |
|
|
29
29
|
| Phase 2.5 viability_failed AND entry_point ∈ {E2_explicit, E4_user_range} AND user saw + accepted the gate-FAIL message | `viability_failed` | 0 | `[]` |
|
|
30
30
|
| Phase 3 batch review — user dismissed ALL presented candidates | `user_dismissed` | 0 | `[]` |
|
|
31
31
|
| Phase 1 filter dropped every session in scope OR Phase 2.5 silent-skip path (E1_hook / E3_ai_self_trigger / E5_cron) | `skipped_no_signal` | 0 | `[]` |
|
|
@@ -5,15 +5,16 @@
|
|
|
5
5
|
## Full MCP tool call shape
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
|
|
8
|
+
mcp__fabric__fab_propose({
|
|
9
9
|
source_sessions: ["<session id1>", "<session id2>", ...], // T5: array form (Phase 1)
|
|
10
10
|
recent_paths: ["<path1>", "<path2>", ...], // capped at archive_max_recent_paths (config-resolved, default 20)
|
|
11
11
|
user_messages_summary: "<compact prose ≤500 chars>",
|
|
12
12
|
type: "decisions" | "pitfalls" | "guidelines" | "models" | "processes",
|
|
13
13
|
slug: "<kebab-case-2-to-5-words>",
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
// v2.2 C1 (W1): author-facing scope is TWO fields only — `audience` + `paths`.
|
|
15
|
+
// The engine derives layer / visibility_store / store / relevance_scope.
|
|
16
|
+
audience: "team" | "personal" | "project:<id>" | "org:<...>", // WHO it's for (open coordinate); omit → engine default (project:<active> | team)
|
|
17
|
+
paths: ["<glob1>", "<literal2>", ...], // relevance anchors; non-empty ⇒ narrow, empty/omit ⇒ broad (relevance_scope is derived from this — no separate flag)
|
|
17
18
|
// v2.0.0-rc.7 T6: required fields for future-self reviewability.
|
|
18
19
|
proposed_reason:
|
|
19
20
|
"explicit-user-mark" // user said "always / never / 下次注意" etc.
|
|
@@ -78,7 +79,7 @@ The server returns `{ pending_path, idempotency_key }`. Display `pending_path` t
|
|
|
78
79
|
|
|
79
80
|
## Idempotency Notes (T5 array-form, rc.7+)
|
|
80
81
|
|
|
81
|
-
The MCP tool derives `idempotency_key = sha256({source_session, type, slug})`. Calling `
|
|
82
|
+
The MCP tool derives `idempotency_key = sha256({source_session, type, slug})`. Calling `fab_propose` twice with the same `(source_session, type, slug)` triple is SAFE: the server appends new evidence to the existing pending file rather than overwriting or producing duplicates. The skill MAY be re-invoked on the same session without producing junk.
|
|
82
83
|
|
|
83
84
|
If the skill needs to record a genuinely separate observation in the same session+type, the slug MUST differ.
|
|
84
85
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Loaded on demand.** SKILL.md hot path retains a 2-line mention of the 2-step atomic write pattern + a pointer to this file. This file holds the full Atomic State Write rationale, events.jsonl 4KB constraint, complete schema, and resume-logic state machine.
|
|
4
4
|
|
|
5
|
-
The state file lives at `.fabric/.import-state.json` and is the single source of resumability for
|
|
5
|
+
The state file lives at `.fabric/.import-state.json` and is the single source of resumability for archive source mode. It is written via the explicit 2-step atomic pattern documented below so a crash between phases / between sub-steps never corrupts it.
|
|
6
6
|
|
|
7
7
|
## Atomic State Write (2-step pattern)
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ This 2-step pattern is mandatory for every state file update. `mv` is atomic on
|
|
|
15
15
|
|
|
16
16
|
Crash safety expectations:
|
|
17
17
|
|
|
18
|
-
- Crash between Step A and Step B → leaves `.fabric/.import-state.json.tmp`. Phase 0 residue scan (see `ref/state-recovery.md`) triages it on next invocation.
|
|
18
|
+
- Crash between Step A and Step B → leaves `.fabric/.import-state.json.tmp`. Phase 0 residue scan (see `ref/source-state-recovery.md`) triages it on next invocation.
|
|
19
19
|
- Crash during Step B (between the `rename` syscall start and return) → POSIX `rename` is atomic; either the prior `.import-state.json` is intact, or the new one is in place. No torn state.
|
|
20
20
|
- Crash before Step A → no state mutation occurred; prior state file is unchanged.
|
|
21
21
|
|
|
@@ -82,4 +82,4 @@ On every skill invocation, BEFORE Phase 1 starts:
|
|
|
82
82
|
5. If `phase === "P2-done"` → skip Phase 1 + Phase 2; resume from Phase 3 Step 3.1; iterate Phase 2 outputs skipping any pending_path already in `p3_dedup_completed[]`.
|
|
83
83
|
6. After every successful sub-step (one commit processed, one doc processed, one dedup pair resolved), write the updated state file via the 2-step `.tmp` + `mv` pattern. Failures append to `errors[]` and proceed (or halt with prompt if cumulative errors `>5`).
|
|
84
84
|
|
|
85
|
-
The contract: re-invoking
|
|
85
|
+
The contract: re-invoking archive source mode after ANY interruption (Ctrl-C, crash, network blip on MCP) MUST NOT propose duplicates of already-proposed entries and MUST NOT redo already-completed dedup decisions.
|
package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md}
RENAMED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
> **Loaded on demand.** SKILL.md hot path retains the Phase 3 purpose statement + 4-step outline + completion sentinel. This file holds the full Step 3.1/3.2/3.3/3.4 MCP call shapes, semantic compare 5-way classification, and the underseed sentinel rationale.
|
|
4
4
|
|
|
5
|
-
For each pending entry created in Phase 2 (read from `p2_processed_commits[].pending_path` and `p2_processed_docs[].pending_paths`), check if it duplicates / contradicts / is subsumed by an existing canonical entry. **Semantic comparison is the LLM's job — `
|
|
5
|
+
For each pending entry created in Phase 2 (read from `p2_processed_commits[].pending_path` and `p2_processed_docs[].pending_paths`), check if it duplicates / contradicts / is subsumed by an existing canonical entry. **Semantic comparison is the LLM's job — `fab_pending` does not compare meaning.**
|
|
6
6
|
|
|
7
7
|
## Step 3.1 — Search Canonical of Same Type
|
|
8
8
|
|
|
9
9
|
For each just-proposed pending entry (read its frontmatter via the `Read` tool to get type + slug + title):
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
|
|
12
|
+
mcp__fabric__fab_pending({
|
|
13
13
|
action: "search",
|
|
14
14
|
query: "<title or summary keywords from the pending entry>",
|
|
15
15
|
filters: { type: "<same type as pending>" }
|
|
@@ -25,7 +25,7 @@ For each `(pending, canonical)` pair the LLM judges:
|
|
|
25
25
|
- **Duplicate** — same essential claim. LLM 主观判断:标题与摘要表达同一核心结论,新 pending 未提供新证据。具体阈值不可量化。Action: **reject** the new pending.
|
|
26
26
|
- **Subsumption** (pending narrower) — canonical fully covers the pending plus more. Action: **reject** the new pending (canonical already serves).
|
|
27
27
|
- **Subsumption-with-novelty** (pending adds evidence) — canonical covers the claim but the new pending brings new evidence (commit sha, file paths). Action: **modify** the canonical to merge in the new evidence; **reject** the new pending citing the modified canonical.
|
|
28
|
-
- **Contradiction** — opposing claims about the same scope. Action: leave pending; flag for user via roll-up. The user must decide via `fabric-review` later — `
|
|
28
|
+
- **Contradiction** — opposing claims about the same scope. Action: leave pending; flag for user via roll-up. The user must decide via `fabric-review` later — `archive source mode` does NOT auto-resolve contradictions.
|
|
29
29
|
- **Genuinely new** — no canonical match. Action: leave pending in place (will surface in next `fabric-review` run for normal approval flow).
|
|
30
30
|
|
|
31
31
|
## Step 3.3 — Issue Dedup MCP Calls
|
|
@@ -68,7 +68,7 @@ Append to `.fabric/.import-state.json` after EACH successful MCP call:
|
|
|
68
68
|
After all Phase 2 outputs are dedup-reviewed:
|
|
69
69
|
|
|
70
70
|
- Update `.fabric/.import-state.json`: `phase = "complete"`, `last_checkpoint_at = <ISO8601 now>`, `final_summary = {proposed: N, kept: K, rejected_dup: R, merged: M, contradictions_flagged: C}`.
|
|
71
|
-
- Render the final roll-up to the user (see Output Contract — see `ref/output-contract.md`).
|
|
71
|
+
- Render the final roll-up to the user (see Output Contract — see `ref/source-output-contract.md`).
|
|
72
72
|
|
|
73
73
|
> Setting `phase = "complete"` in `.fabric/.import-state.json` is enough to silence the SessionStart underseed self-check banner (`shouldRecommendImport()` returns false for any non-`absent` state). 无需额外清理 sentinel 文件 — 该机制已在 rc.8 下线。
|
|
74
74
|
|
package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md}
RENAMED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
## Mandatory Scope Rule — Always Broad + Empty Paths (Q-1 Resolution)
|
|
6
6
|
|
|
7
|
-
**EVERY `
|
|
7
|
+
**EVERY `fab_propose` call issued from this skill MUST set:**
|
|
8
8
|
|
|
9
9
|
- `relevance_scope = "broad"`
|
|
10
10
|
- `relevance_paths = []`
|
|
11
11
|
|
|
12
12
|
This is non-negotiable and applies to BOTH Step 2.1 (git mining) AND Step 2.2 (docs mining). No exceptions, no per-candidate override, no Agent judgment.
|
|
13
13
|
|
|
14
|
-
**Rationale — why
|
|
14
|
+
**Rationale — why archive source mode cannot bind paths from git history:**
|
|
15
15
|
|
|
16
|
-
1. `
|
|
16
|
+
1. `archive source mode` is LLM-driven (mines git log + docs), not session-driven (no live `edit_paths` signal).
|
|
17
17
|
2. `git diff --stat` lists files touched by a commit, but those files are the commit's **effect surface**, not the **applicability surface** of the underlying observation. A pitfall surfaced by a fix in `packages/server/src/retry.ts` may apply to every retry call-site in the repo, not just that one file.
|
|
18
18
|
3. LLM-inferred `relevance_paths` from historical commit metadata produces false-narrow bindings — `relevance_paths` becomes a lie about applicability. Post-rc.37 A1 the server no longer filters by `relevance_scope`, so false-narrow does NOT hide knowledge from AI recall (every selectable entry is surfaced regardless of scope). The damage is now downstream: doctor lint accounting, future-AI judgment, and any consumer that reads `relevance_paths` literally treats the wrong globs as ground truth. Broad+[] keeps the metadata honest until the user has the real applicability surface in hand to declare narrow.
|
|
19
19
|
4. Doc-mined observations are usually architectural / cross-cutting (a `docs/architecture.md` "Why a monolith?" decision applies to the whole codebase, not just to `docs/`).
|
|
@@ -24,16 +24,16 @@ This is non-negotiable and applies to BOTH Step 2.1 (git mining) AND Step 2.2 (d
|
|
|
24
24
|
- DO NOT derive `relevance_paths` from the path of a mined Markdown file (e.g. do NOT bind a `docs/architecture.md` observation to `["docs/**"]`).
|
|
25
25
|
- DO NOT extract path-shaped tokens from commit subjects / bodies / doc text and lift them into `relevance_paths`.
|
|
26
26
|
- DO NOT classify a candidate as `relevance_scope = "narrow"` under ANY heuristic.
|
|
27
|
-
- DO NOT copy the public-prefix-generalization logic from fabric-archive Phase 3.5 — that logic is valid only when bound to a real-time `edit_paths` signal from an active session, which
|
|
27
|
+
- DO NOT copy the public-prefix-generalization logic from fabric-archive Phase 3.5 — that logic is valid only when bound to a real-time `edit_paths` signal from an active session, which archive source mode lacks.
|
|
28
28
|
|
|
29
|
-
**Cross-reference —
|
|
29
|
+
**Cross-reference — archive source mode vs fabric-archive scope handling:**
|
|
30
30
|
|
|
31
31
|
| Skill | Scope decision | Why |
|
|
32
32
|
|------------------|--------------------|-----------------------------------------------------------------------|
|
|
33
33
|
| `fabric-archive` | narrow OR broad, case-by-case per Phase 3.5 rules | Has live `edit_paths` from the active session — the actual applicability surface. |
|
|
34
|
-
| `
|
|
34
|
+
| `archive source mode` | ALWAYS broad + `[]` (this skill) | LLM-only, no live session signal; git-history paths are effect-surface, not applicability-surface. |
|
|
35
35
|
|
|
36
|
-
`fabric-archive`'s Phase 3.5 scope decision (narrow-vs-broad rules + public-prefix generalization + glob blacklist) is INTENTIONALLY MORE PERMISSIVE than
|
|
36
|
+
`fabric-archive`'s Phase 3.5 scope decision (narrow-vs-broad rules + public-prefix generalization + glob blacklist) is INTENTIONALLY MORE PERMISSIVE than archive source mode because archive has the data to bind safely. archive source mode is the STRICTER case.
|
|
37
37
|
|
|
38
38
|
**Post-import narrowing path — deferred to user, via `fab_review.modify`:**
|
|
39
39
|
|
|
@@ -77,16 +77,16 @@ For each commit:
|
|
|
77
77
|
- `chore(...)`, `test(...)`, `ci(...)` → almost always skip (mechanical; no reusable insight)
|
|
78
78
|
2. Read the commit body. Extract the LLM-judged "core observation" — what would a future engineer want to know about this commit beyond the diff? Aim for 1–2 sentences in zh-CN (project fabric_language; mirror fabric-archive M3 style).
|
|
79
79
|
3. Apply the **Skip Decision Tree** below. If the commit is skip-worthy, record it in `p2_processed_commits[]` with `skipped: true` and move on.
|
|
80
|
-
4. For non-skipped commits, classify type / propose slug / draft summary. Then call `
|
|
80
|
+
4. For non-skipped commits, classify type / propose slug / draft summary. Then call `fab_propose` with the **mandatory broad + [] scope** (see "Mandatory Scope Rule" above):
|
|
81
81
|
|
|
82
82
|
```ts
|
|
83
|
-
|
|
84
|
-
source_sessions: ["fabric-
|
|
83
|
+
mcp__fabric__fab_propose({
|
|
84
|
+
source_sessions: ["fabric-archive-source-<ISO8601-date>"], // T5: array form; stable per import run
|
|
85
85
|
recent_paths: ["<files touched by this commit, capped at 20>"], // provenance only, NOT a path-binding signal
|
|
86
86
|
user_messages_summary: "<zh-CN 1-2 sentence summary of the commit's core observation; cite the commit sha as 'src=<sha7>'>",
|
|
87
87
|
type: "decisions" | "pitfalls" | "guidelines" | "models" | "processes",
|
|
88
88
|
slug: "<kebab-case 2-5 words derived from commit subject + body>",
|
|
89
|
-
relevance_scope: "broad", // MANDATORY — never "narrow" from
|
|
89
|
+
relevance_scope: "broad", // MANDATORY — never "narrow" from archive source mode
|
|
90
90
|
relevance_paths: [], // MANDATORY — never derived from git history
|
|
91
91
|
proposed_reason: "<inferred per Step 2.1.5 — varies>",
|
|
92
92
|
session_context: "Imported from git log analysis. Origin: commit <sha7> (<subject 30 chars>). No live session — see commit body for full context.",
|
|
@@ -108,7 +108,7 @@ Note: `recent_paths` carries the touched-file list for **provenance display** on
|
|
|
108
108
|
|
|
109
109
|
## Step 2.1.5 — Proposed Reason Inference (rc.7 T6)
|
|
110
110
|
|
|
111
|
-
For each non-skipped commit OR doc section, infer `proposed_reason` from prefix + body signal jointly. The 6 reasons below are the full enum accepted by `
|
|
111
|
+
For each non-skipped commit OR doc section, infer `proposed_reason` from prefix + body signal jointly. The 6 reasons below are the full enum accepted by `fab_propose` (schema-locked):
|
|
112
112
|
|
|
113
113
|
| Source signal | Body cue | Inferred reason |
|
|
114
114
|
|---|---|---|
|
|
@@ -148,7 +148,7 @@ For each Markdown file:
|
|
|
148
148
|
- `LICENSE.md`, `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md` → skip (boilerplate)
|
|
149
149
|
- Files <300 bytes → skip (too thin to extract meaningful observations)
|
|
150
150
|
2. Read the file. Identify candidate observations: section headings that read like decisions ("we chose X over Y"), guidelines ("always do X"), pitfalls ("don't do Y because..."), or process steps ("the deploy procedure is..."). Architecture diagrams in fenced code blocks are strong **model** signals.
|
|
151
|
-
3. For each observation, classify type / propose slug / draft summary. Call `
|
|
151
|
+
3. For each observation, classify type / propose slug / draft summary. Call `fab_propose` with the same shape as Step 2.1 (including the **mandatory `relevance_scope: "broad"` + `relevance_paths: []`**), replacing `recent_paths` with `[<this doc path>]` and citing `src=<doc-relative-path>` in the summary.
|
|
152
152
|
4. Append to `.fabric/.import-state.json`:
|
|
153
153
|
- `p2_processed_docs[].push({path: <doc path>, observations_proposed: <count>, pending_paths: [...]})`
|
|
154
154
|
5. **Hard cap shared with Step 2.1**: total new pending entries across git + docs is capped at `import_max_pending_per_run` (config-resolved, default 10) per Phase 2 run.
|
|
@@ -167,14 +167,14 @@ A candidate signal surfaces (commit body or doc section).
|
|
|
167
167
|
│ └─ NO → skip (not classifiable = not yet ripe)
|
|
168
168
|
├─ Is the slug derivable as 2-5 kebab-case words?
|
|
169
169
|
│ └─ NO → skip (signal too vague for stable identifier)
|
|
170
|
-
└─ Else → propose via
|
|
170
|
+
└─ Else → propose via fab_propose
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
After Step 2.2 completes (or hits the cap), update `.fabric/.import-state.json`: `phase = "P2-done"`, `last_checkpoint_at = <ISO8601 now>`.
|
|
174
174
|
|
|
175
175
|
## Dry-Run Mode
|
|
176
176
|
|
|
177
|
-
When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WITHOUT calling `
|
|
177
|
+
When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WITHOUT calling `fab_propose`. Instead it prints a table. v2.0.0-rc.37 NEW-10 dropped the legacy substring fallback on bare `dry-run` / `预览` because those caused false positives on incidental mentions ("preview the table" / "do a dry run later"). UX i18n Policy class 4 — header + column titles bilingualized; row content (slug / commit sha / doc path) NOT translated. Protected tokens `broad`, `relevance_scope`, `relevance_paths` appear verbatim:
|
|
178
178
|
|
|
179
179
|
### zh-CN variant (`fabric_language === "zh-CN"`)
|
|
180
180
|
|
|
@@ -200,14 +200,14 @@ When the user invocation carries the verbatim token `--dry-run`, Phase 2 runs WI
|
|
|
200
200
|
| 3 | git 50367b5 | pitfalls | thundering-herd-no-backoff | broad+[] | Retries without exponential backoff caused a thundering herd outage. |
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
Every dry-run row MUST show `broad+[]` in the Scope column (constant for
|
|
203
|
+
Every dry-run row MUST show `broad+[]` in the Scope column (constant for archive source mode). A row showing anything else is a skill bug — refuse to proceed and surface the violation. Dry-run output is informational only. The state file is NOT written to in dry-run mode (so a real run later starts clean). Phase 3 is also skipped in dry-run.
|
|
204
204
|
|
|
205
205
|
## Idempotency Note — T5 array form
|
|
206
206
|
|
|
207
|
-
The server derives `idempotency_key = sha256({source_session, type, slug})` for every `
|
|
207
|
+
The server derives `idempotency_key = sha256({source_session, type, slug})` for every `fab_propose` call. Re-invoking with the same `(source_session, type, slug)` triple is SAFE: the server appends new evidence to the existing pending file rather than overwriting or producing duplicates — this is why `archive source mode` resume after Ctrl-C / crash never produces duplicate pending entries for already-processed commits.
|
|
208
208
|
|
|
209
|
-
**T5 array-form note (rc.7+)**: when `source_sessions` is passed as an array (rc.7 T5 contract), only `source_sessions[0]` participates in the server-side idempotency hash. Server formula at `packages/server/src/services/extract-knowledge.ts:78` is `sha256(JSON.stringify({source_session: sourceSessions[0], type, slug}))`. Implications for
|
|
209
|
+
**T5 array-form note (rc.7+)**: when `source_sessions` is passed as an array (rc.7 T5 contract), only `source_sessions[0]` participates in the server-side idempotency hash. Server formula at `packages/server/src/services/extract-knowledge.ts:78` is `sha256(JSON.stringify({source_session: sourceSessions[0], type, slug}))`. Implications for archive source mode:
|
|
210
210
|
|
|
211
|
-
- Every Phase 2 call uses `source_sessions: ["fabric-
|
|
212
|
-
- If a future enhancement adds a trailing element (e.g. `["fabric-
|
|
211
|
+
- Every Phase 2 call uses `source_sessions: ["fabric-archive-source-<ISO8601-date>"]` (single-element array, stable per import run). First-element-only rule means re-runs on the same date produce the same idempotency key per `(type, slug)` → resume-safe by construction.
|
|
212
|
+
- If a future enhancement adds a trailing element (e.g. `["fabric-archive-source-<date>", "<commit-sha>"]`), only the first element participates in the hash — the commit-sha tail would NOT change the idempotency key for the same `(type, slug)`. Plan accordingly.
|
|
213
213
|
- The formula is intentionally stable across the rc.5 → rc.7 migration; adding or removing tail entries does NOT change the idempotency key, preserving rc.5 single-session compat.
|
|
@@ -13,7 +13,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
|
|
|
13
13
|
- Commits scanned: <N> (skipped: <S> — cosmetic/metadata/baseline-overlap)
|
|
14
14
|
- Docs scanned: <D> (skipped: <DS> — README/CHANGELOG/boilerplate)
|
|
15
15
|
- Pending proposed: <P> (cap_reached: <true|false>)
|
|
16
|
-
- Scope: all <P> proposed entries use relevance_scope=broad, relevance_paths=[] (
|
|
16
|
+
- Scope: all <P> proposed entries use relevance_scope=broad, relevance_paths=[] (archive source mode contract).
|
|
17
17
|
|
|
18
18
|
## Phase 3 — Dedup
|
|
19
19
|
- Kept (genuinely new): <K>
|
|
@@ -41,7 +41,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
|
|
|
41
41
|
- 扫描 commit 数: <N> (跳过: <S> — cosmetic/metadata/与 baseline 重叠)
|
|
42
42
|
- 扫描文档数: <D> (跳过: <DS> — README/CHANGELOG/样板文件)
|
|
43
43
|
- 提议 pending: <P> (cap_reached: <true|false>)
|
|
44
|
-
- 作用域: 全部 <P> 条提议使用 relevance_scope=broad, relevance_paths=[] (
|
|
44
|
+
- 作用域: 全部 <P> 条提议使用 relevance_scope=broad, relevance_paths=[] (archive source mode 契约)。
|
|
45
45
|
|
|
46
46
|
## Phase 3 — 去重
|
|
47
47
|
- 保留 (新知识): <K>
|
|
@@ -52,7 +52,7 @@ UX i18n Policy class 1 — render either the en variant or the zh-CN variant per
|
|
|
52
52
|
## 状态
|
|
53
53
|
- .fabric/.import-state.json phase: <phase>
|
|
54
54
|
- last_checkpoint_at: <ISO8601>
|
|
55
|
-
- 如 phase != complete, 请重新调用
|
|
55
|
+
- 如 phase != complete, 请重新调用 archive source mode 续作。
|
|
56
56
|
|
|
57
57
|
## 下一步
|
|
58
58
|
- 运行 `fabric-review` 审批 <K> 条新 pending。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Phase 0 + 0.1 — State Recovery (
|
|
1
|
+
# Phase 0 + 0.1 — State Recovery (archive source mode ref-only)
|
|
2
2
|
|
|
3
3
|
> **Loaded on demand.** Only relevant when a prior import crashed mid-phase, leaving `.tmp-*` residue or a torn `.fabric/.import-state.json`. SKILL.md's hot path inline says "scan for .tmp residue + load state" — this file is the full recovery procedure (atomic-write pattern, sweep rules, corruption detection, fallback to fresh import).
|
|
4
4
|
|
|
@@ -46,7 +46,7 @@ On corruption (any condition above):
|
|
|
46
46
|
1. `Bash: mv .fabric/.import-state.json .fabric/.import-state.json.corrupt-<ISO8601>`
|
|
47
47
|
(preserve the corrupt file for postmortem; do NOT silently overwrite).
|
|
48
48
|
2. Phase 1 restarts from scratch (Phase 1 produces no MCP calls, so re-run
|
|
49
|
-
is safe — re-querying mounted store canonical titles via `
|
|
49
|
+
is safe — re-querying mounted store canonical titles via `fab_pending search`
|
|
50
50
|
idempotent; the `p1_baseline_titles` array is regenerated).
|
|
51
51
|
3. DO NOT attempt automatic partial recovery; corrupt state is a signal
|
|
52
52
|
that something serious happened (disk-full, kill -9 mid-write, fs
|
|
@@ -8,11 +8,11 @@ Source signal: `git log` surfaces commit `50367b5` with subject `feat(server): a
|
|
|
8
8
|
|
|
9
9
|
LLM analysis: this is a **pitfall** (a non-obvious trap that wasted time and is repeatable across services). The body itself documents the trap. Slug candidates: `retry-without-backoff-thundering-herd` (5 words, 38 chars — passes 5 rules).
|
|
10
10
|
|
|
11
|
-
Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for
|
|
11
|
+
Skill output (note `relevance_scope: "broad"` + `relevance_paths: []` — mandatory for archive source mode):
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
|
|
15
|
-
source_sessions: ["fabric-
|
|
14
|
+
mcp__fabric__fab_propose({
|
|
15
|
+
source_sessions: ["fabric-archive-source-2026-05-10"],
|
|
16
16
|
recent_paths: ["packages/server/src/lib/retry.ts"], // provenance only
|
|
17
17
|
user_messages_summary: "重试无指数退避会在短暂上游故障下放大成雪崩。修正:jittered exponential backoff,30 秒上限。src=50367b5",
|
|
18
18
|
type: "pitfalls",
|
|
@@ -29,7 +29,7 @@ Counter-example — DO NOT do this:
|
|
|
29
29
|
```ts
|
|
30
30
|
// WRONG — this skill must never produce narrow + paths from git metadata.
|
|
31
31
|
// The retry pitfall applies to every retry site, not just the file touched by 50367b5.
|
|
32
|
-
|
|
32
|
+
mcp__fabric__fab_propose({
|
|
33
33
|
// ...
|
|
34
34
|
relevance_scope: "narrow", // VIOLATION
|
|
35
35
|
relevance_paths: ["packages/server/src/lib/retry.ts"] // VIOLATION
|
|
@@ -57,8 +57,8 @@ LLM analysis: this is a **decision** (≥2 alternatives weighed — monolith vs
|
|
|
57
57
|
Skill output (broad+[] mandatory; the doc's own path stays in `recent_paths` for provenance, NOT in `relevance_paths`):
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
|
-
|
|
61
|
-
source_sessions: ["fabric-
|
|
60
|
+
mcp__fabric__fab_propose({
|
|
61
|
+
source_sessions: ["fabric-archive-source-2026-05-10"],
|
|
62
62
|
recent_paths: ["docs/architecture.md"], // provenance only
|
|
63
63
|
user_messages_summary: "选择单体架构而非微服务:3 人团队无法承担多服务运维成本,且主要性能瓶颈在 DB 吞吐而非应用层水平扩展。src=docs/architecture.md",
|
|
64
64
|
type: "decisions",
|
|
@@ -73,7 +73,7 @@ mcp__fabric__fab_extract_knowledge({
|
|
|
73
73
|
After Example A's pending entry (`retry-without-backoff-thundering-herd`) is proposed, Phase 3 runs:
|
|
74
74
|
|
|
75
75
|
```ts
|
|
76
|
-
|
|
76
|
+
mcp__fabric__fab_pending({
|
|
77
77
|
action: "search",
|
|
78
78
|
query: "retry backoff thundering herd",
|
|
79
79
|
filters: { type: "pitfalls" }
|
|
@@ -105,7 +105,7 @@ Final roll-up to user reflects: 1 proposed, 0 kept, 1 rejected_dup, 0 merged, 0
|
|
|
105
105
|
|
|
106
106
|
## Example D — Post-import narrowing (out-of-band, NOT this skill)
|
|
107
107
|
|
|
108
|
-
This example documents the legal narrowing path; it is NOT performed by `
|
|
108
|
+
This example documents the legal narrowing path; it is NOT performed by `archive source mode` itself. After Example B's `monolith-over-microservices-small-team` decision is imported (with `relevance_scope=broad`, `relevance_paths=[]`) and later approved into canonical via `fabric-review`, the user decides the decision is actually narrow to the server package's deploy tooling.
|
|
109
109
|
|
|
110
110
|
The user issues (via `fabric-review`, NOT via this skill):
|
|
111
111
|
|
|
@@ -122,6 +122,6 @@ mcp__fabric__fab_review({
|
|
|
122
122
|
|
|
123
123
|
Key invariants of this flow:
|
|
124
124
|
|
|
125
|
-
- The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `
|
|
126
|
-
- The modify call goes through `fab_review`, not `
|
|
125
|
+
- The narrowing decision originates from the **user**, informed by the actual paths they propose — not from `archive source mode` inferring paths from git metadata.
|
|
126
|
+
- The modify call goes through `fab_review`, not `fab_propose`, because the entry already exists (post-import or post-approval).
|
|
127
127
|
- If the user later flips the entry's layer from `team` to `personal`, server-side auto-degrades scope back to `broad` and clears `relevance_paths` (see rc.5 C3 acceptance criterion; personal knowledge crosses projects so paths don't generalize). This is the only legal way for `relevance_paths` to be re-cleared.
|
|
@@ -11,7 +11,7 @@ Session: User and agent debated whether the Stop-hook should be one .cjs script
|
|
|
11
11
|
Skill output:
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
|
|
14
|
+
mcp__fabric__fab_propose({
|
|
15
15
|
source_sessions: ["WFS-2026-05-10-rc2"],
|
|
16
16
|
recent_paths: ["templates/claude-hooks/", "packages/cli/src/commands/hooks.ts"],
|
|
17
17
|
user_messages_summary: "User pushed back on three-script proposal; agreed single .cjs because stdout JSON shape is universal across Claude Code and Codex CLI.",
|
|
@@ -37,7 +37,7 @@ Session: deepMerge silently replaced the existing `hooks.Stop[]` array in `.clau
|
|
|
37
37
|
Skill output:
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
|
|
40
|
+
mcp__fabric__fab_propose({
|
|
41
41
|
source_sessions: ["WFS-2026-05-10-rc2"],
|
|
42
42
|
recent_paths: ["packages/cli/src/config/json.ts"],
|
|
43
43
|
user_messages_summary: "deepMerge default behavior REPLACES arrays. hooks.Stop[] needs an array-append-with-dedupe special case keyed on .command string match.",
|
|
@@ -60,7 +60,7 @@ Session: User mentioned across three projects that they prefer 2-space indent in
|
|
|
60
60
|
Skill output:
|
|
61
61
|
|
|
62
62
|
```ts
|
|
63
|
-
|
|
63
|
+
mcp__fabric__fab_propose({
|
|
64
64
|
source_sessions: ["WFS-2026-05-10-rc2"],
|
|
65
65
|
recent_paths: [".editorconfig"],
|
|
66
66
|
user_messages_summary: "Personal indent preference: 2-space TS / 4-space Py. Stable across multiple projects, not project-specific.",
|