@fenglimg/fabric-shared 2.1.0-rc.2 → 2.2.0-rc.10
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/dist/chunk-2GLIAZ5M.js +251 -0
- package/dist/{chunk-WVPDH4BF.js → chunk-5AKCRBKJ.js} +551 -382
- package/dist/{chunk-R2J7DAED.js → chunk-AQMDXC6J.js} +545 -517
- package/dist/chunk-BDJQIOQO.js +206 -0
- package/dist/chunk-C7WZPYZE.js +129 -0
- package/dist/{chunk-3SZRB42B.js → chunk-O6GIHZF3.js} +14 -0
- package/dist/errors/index.d.ts +12 -1
- package/dist/errors/index.js +9 -3
- package/dist/i18n/index.d.ts +29 -23
- package/dist/i18n/index.js +7 -3
- package/dist/{index-GQpaWTm-.d.ts → index-D_gT1CEA.d.ts} +125 -28
- package/dist/index.d.ts +2348 -1187
- package/dist/index.js +1675 -835
- package/dist/node/atomic-write.d.ts +26 -1
- package/dist/node/atomic-write.js +8 -65
- package/dist/node/mcp-payload-guard.d.ts +32 -1
- package/dist/node/mcp-payload-guard.js +16 -2
- package/dist/node.d.ts +10 -1
- package/dist/node.js +32 -1
- package/dist/schemas/api-contracts.d.ts +319 -100
- package/dist/schemas/api-contracts.js +3 -3
- package/dist/templates/bootstrap-canonical.d.ts +50 -23
- package/dist/templates/bootstrap-canonical.js +12 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/types-qg4xXVuT.d.ts +8 -0
- package/package.json +3 -2
- package/dist/chunk-MDWTGOAY.js +0 -101
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/schemas/api-contracts.ts
|
|
2
|
-
import { z as
|
|
2
|
+
import { z as z3 } from "zod";
|
|
3
3
|
|
|
4
4
|
// src/onboard-slots.ts
|
|
5
5
|
import { z } from "zod";
|
|
@@ -13,58 +13,91 @@ var ONBOARD_SLOT_NAMES = [
|
|
|
13
13
|
var onboardSlotSchema = z.enum(ONBOARD_SLOT_NAMES);
|
|
14
14
|
var ONBOARD_SLOT_TOTAL = ONBOARD_SLOT_NAMES.length;
|
|
15
15
|
|
|
16
|
+
// src/schemas/scope.ts
|
|
17
|
+
import { z as z2 } from "zod";
|
|
18
|
+
var PERSONAL_SCOPE = "personal";
|
|
19
|
+
var KNOWN_SCOPE_PREFIXES = ["personal", "team", "project", "org"];
|
|
20
|
+
var SCOPE_COORDINATE_PATTERN = /^[a-z0-9_-]+(:[a-z0-9_-]+)*$/u;
|
|
21
|
+
var scopeCoordinateSchema = z2.string().min(1).regex(
|
|
22
|
+
SCOPE_COORDINATE_PATTERN,
|
|
23
|
+
"scope coordinate must be ':'-joined lowercase [a-z0-9_-] segments"
|
|
24
|
+
);
|
|
25
|
+
function scopeRoot(coordinate) {
|
|
26
|
+
const colon = coordinate.indexOf(":");
|
|
27
|
+
return colon === -1 ? coordinate : coordinate.slice(0, colon);
|
|
28
|
+
}
|
|
29
|
+
function isPersonalScope(coordinate) {
|
|
30
|
+
return scopeRoot(coordinate) === PERSONAL_SCOPE;
|
|
31
|
+
}
|
|
32
|
+
var entryScopeMetadataSchema = z2.object({
|
|
33
|
+
semantic_scope: scopeCoordinateSchema,
|
|
34
|
+
// Store alias or UUID. Validated as a non-empty string here; the resolver
|
|
35
|
+
// (P0.6) maps alias→UUID and verifies the store is in the read-set.
|
|
36
|
+
visibility_store: z2.string().min(1)
|
|
37
|
+
}).strict();
|
|
38
|
+
|
|
16
39
|
// src/schemas/api-contracts.ts
|
|
17
|
-
var structuredWarningSchema =
|
|
18
|
-
code:
|
|
19
|
-
file:
|
|
20
|
-
line:
|
|
21
|
-
|
|
40
|
+
var structuredWarningSchema = z3.object({
|
|
41
|
+
code: z3.string(),
|
|
42
|
+
file: z3.string(),
|
|
43
|
+
line: z3.number().optional(),
|
|
44
|
+
message: z3.string().optional(),
|
|
45
|
+
action_hint: z3.string()
|
|
22
46
|
});
|
|
23
|
-
var _knowledgeTypeEnum =
|
|
24
|
-
var _maturityEnum =
|
|
25
|
-
var _layerEnum =
|
|
26
|
-
var _ruleDescriptionSchema =
|
|
27
|
-
summary:
|
|
28
|
-
intent_clues:
|
|
29
|
-
tech_stack:
|
|
30
|
-
impact:
|
|
31
|
-
must_read_if:
|
|
32
|
-
entities:
|
|
47
|
+
var _knowledgeTypeEnum = z3.enum(["models", "decisions", "guidelines", "pitfalls", "processes"]);
|
|
48
|
+
var _maturityEnum = z3.enum(["draft", "verified", "proven"]);
|
|
49
|
+
var _layerEnum = z3.enum(["personal", "team"]);
|
|
50
|
+
var _ruleDescriptionSchema = z3.object({
|
|
51
|
+
summary: z3.string(),
|
|
52
|
+
intent_clues: z3.array(z3.string()),
|
|
53
|
+
tech_stack: z3.array(z3.string()),
|
|
54
|
+
impact: z3.array(z3.string()),
|
|
55
|
+
must_read_if: z3.string(),
|
|
56
|
+
entities: z3.array(z3.string()).optional(),
|
|
33
57
|
// v2.0: optional knowledge-entry fields. Absent for v1.x rules; present for
|
|
34
58
|
// entries that declare frontmatter `id/type/maturity/layer`.
|
|
35
|
-
id:
|
|
59
|
+
id: z3.string().optional(),
|
|
36
60
|
knowledge_type: _knowledgeTypeEnum.optional(),
|
|
37
61
|
maturity: _maturityEnum.optional(),
|
|
38
62
|
knowledge_layer: _layerEnum.optional(),
|
|
39
|
-
layer_reason:
|
|
40
|
-
created_at:
|
|
63
|
+
layer_reason: z3.string().optional(),
|
|
64
|
+
created_at: z3.string().optional(),
|
|
41
65
|
// v2.0.0-rc.38 UX-3 (D-MCP fold ③): these three were previously carried ONLY
|
|
42
66
|
// as top-level mirrors on the index item. With the mirrors removed,
|
|
43
67
|
// `description` becomes their canonical (and only) home, so the schema must
|
|
44
68
|
// validate them here. Optional + default-safe (tags/[]/broad) so legacy
|
|
45
69
|
// entries without frontmatter still parse.
|
|
46
|
-
tags:
|
|
47
|
-
relevance_scope:
|
|
48
|
-
relevance_paths:
|
|
70
|
+
tags: z3.array(z3.string()).optional(),
|
|
71
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional(),
|
|
72
|
+
relevance_paths: z3.array(z3.string()).optional(),
|
|
73
|
+
// v2.2 H2-related (W1-T7) — W1-REVIEW codex HIGH-2: the MCP-facing description
|
|
74
|
+
// schema must also carry `related`, else zod strips the graph edges on output
|
|
75
|
+
// validation and they never reach the client (MC1 include_related / fabric-
|
|
76
|
+
// connect would see nothing). Mirrors the agents-meta ruleDescriptionSchema.
|
|
77
|
+
related: z3.array(z3.string()).optional()
|
|
49
78
|
});
|
|
50
|
-
var _descriptionIndexItemSchema =
|
|
51
|
-
stable_id:
|
|
52
|
-
description: _ruleDescriptionSchema
|
|
79
|
+
var _descriptionIndexItemSchema = z3.object({
|
|
80
|
+
stable_id: z3.string(),
|
|
81
|
+
description: _ruleDescriptionSchema,
|
|
82
|
+
// recall dedupe marker: true when this candidate is ALSO injected in full at
|
|
83
|
+
// SessionStart ("ALWAYS-ACTIVE RULES" = broad model/guideline). MUST be
|
|
84
|
+
// declared here or zod .strip() drops it at the MCP boundary (KT-PIT-0005),
|
|
85
|
+
// silently breaking the marker even though recall() sets it. Only ever true.
|
|
86
|
+
always_active: z3.boolean().optional()
|
|
53
87
|
});
|
|
54
|
-
var _requirementProfileSchema =
|
|
55
|
-
target_path:
|
|
56
|
-
known_tech:
|
|
57
|
-
|
|
58
|
-
detected_entities: z2.array(z2.string())
|
|
88
|
+
var _requirementProfileSchema = z3.object({
|
|
89
|
+
target_path: z3.string(),
|
|
90
|
+
known_tech: z3.array(z3.string()),
|
|
91
|
+
detected_entities: z3.array(z3.string())
|
|
59
92
|
});
|
|
60
|
-
var planContextInputSchema =
|
|
61
|
-
paths:
|
|
62
|
-
intent:
|
|
63
|
-
known_tech:
|
|
64
|
-
detected_entities:
|
|
65
|
-
client_hash:
|
|
66
|
-
correlation_id:
|
|
67
|
-
session_id:
|
|
93
|
+
var planContextInputSchema = z3.object({
|
|
94
|
+
paths: z3.array(z3.string()).min(1).describe("Candidate file paths to build neutral rule selection context for"),
|
|
95
|
+
intent: z3.string().optional().describe("User-stated requirement or implementation intent; used only to build a neutral requirement profile"),
|
|
96
|
+
known_tech: z3.array(z3.string()).optional().describe("Known technologies involved in the requirement profile"),
|
|
97
|
+
detected_entities: z3.record(z3.array(z3.string())).optional().describe("Optional path-keyed detected entities for the requirement profile"),
|
|
98
|
+
client_hash: z3.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection"),
|
|
99
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
|
|
100
|
+
session_id: z3.string().optional().describe(
|
|
68
101
|
"Recommended: pass the current client session id (Claude Code: $session_id; Codex: corresponding identifier) \u2014 enables cross-session debt tracking in fabric doctor and accurate archive-hint cross-session count. Falls back gracefully if omitted."
|
|
69
102
|
),
|
|
70
103
|
// v2.0-rc.5 A3 (TASK-007): `include_deprecated` removed — it was a no-op
|
|
@@ -73,49 +106,58 @@ var planContextInputSchema = z2.object({
|
|
|
73
106
|
// v2/rc.2 (Q6): client-supplied layer scope. When omitted, the server
|
|
74
107
|
// falls back to fabric-config.default_layer_filter (TASK-002) so a single
|
|
75
108
|
// workspace policy controls the default. Explicit values override.
|
|
76
|
-
layer_filter:
|
|
109
|
+
layer_filter: z3.enum(["team", "personal", "both"]).optional().describe(
|
|
77
110
|
"Restrict description_index to the named layer. Default: fabric-config.default_layer_filter (TASK-002)."
|
|
78
111
|
),
|
|
79
112
|
// v2.0-rc.5 C3 (TASK-012): explicit path context for `narrow` relevance
|
|
80
113
|
// filtering. When omitted, the server falls back to `paths` so existing
|
|
81
114
|
// callers see narrowing against the requested paths. When the resolved
|
|
82
115
|
// list is empty, the narrow filter fails open (every narrow entry passes).
|
|
83
|
-
target_paths:
|
|
116
|
+
target_paths: z3.array(z3.string()).optional().describe(
|
|
84
117
|
"Path context for narrow-scope relevance filtering. Defaults to `paths`; empty = no filter."
|
|
85
118
|
)
|
|
86
119
|
});
|
|
87
|
-
var _preflightDiagnosticSchema =
|
|
120
|
+
var _preflightDiagnosticSchema = z3.object({
|
|
88
121
|
// v2.0.0-rc.38 UX-2: `empty_shell_suppressed` surfaces draft entries whose
|
|
89
122
|
// description carries no selection signal (summary === stable_id + empty
|
|
90
123
|
// intent_clues/tech_stack/impact). They are filtered out of `candidates` to
|
|
91
124
|
// cut noise; this diagnostic names them so `fabric doctor` /
|
|
92
125
|
// --enrich-descriptions can prompt enrichment.
|
|
93
|
-
code:
|
|
94
|
-
severity:
|
|
95
|
-
message:
|
|
96
|
-
stable_ids:
|
|
97
|
-
path:
|
|
126
|
+
code: z3.enum(["missing_description", "empty_shell_suppressed"]),
|
|
127
|
+
severity: z3.literal("warn"),
|
|
128
|
+
message: z3.string(),
|
|
129
|
+
stable_ids: z3.array(z3.string()).optional(),
|
|
130
|
+
path: z3.string().optional()
|
|
98
131
|
});
|
|
99
|
-
var planContextOutputSchema =
|
|
100
|
-
revision_hash:
|
|
101
|
-
stale:
|
|
102
|
-
selection_token:
|
|
103
|
-
entries:
|
|
104
|
-
|
|
105
|
-
path:
|
|
132
|
+
var planContextOutputSchema = z3.object({
|
|
133
|
+
revision_hash: z3.string(),
|
|
134
|
+
stale: z3.boolean(),
|
|
135
|
+
selection_token: z3.string(),
|
|
136
|
+
entries: z3.array(
|
|
137
|
+
z3.object({
|
|
138
|
+
path: z3.string(),
|
|
106
139
|
requirement_profile: _requirementProfileSchema
|
|
107
140
|
})
|
|
108
141
|
),
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
// v2.2 payload de-dup: single top-level echo of the caller's `intent` (was
|
|
143
|
+
// duplicated into every entry's requirement_profile). Omitted when no intent.
|
|
144
|
+
intent: z3.string().optional(),
|
|
145
|
+
candidates: z3.array(_descriptionIndexItemSchema),
|
|
146
|
+
// v2.2 A-INFRA-3 (W1-T3-TOPK) / MC4-payload-budget (W1-T4): number of
|
|
147
|
+
// lower-ranked candidates dropped by the unified truncation chain (top_k cap
|
|
148
|
+
// + payload-budget trim). Present and > 0 ONLY when truncation fired, so the
|
|
149
|
+
// steady-state wire shape is unchanged. Lets the LLM know the returned set is
|
|
150
|
+
// not exhaustive ("N more exist; narrow your intent").
|
|
151
|
+
omitted_candidate_count: z3.number().int().nonnegative().optional(),
|
|
152
|
+
preflight_diagnostics: z3.array(_preflightDiagnosticSchema),
|
|
153
|
+
warnings: z3.array(structuredWarningSchema).optional(),
|
|
112
154
|
// v2.0.0-rc.22 Scope D T-D2: optional auto-heal banner fields. Surfaced
|
|
113
155
|
// ONLY when the loadActiveMetaOrStale call detected drift and rebuilt the
|
|
114
156
|
// meta in-place. Downstream CLI / hint renderers use this pair to render a
|
|
115
157
|
// "knowledge meta auto-healed (was <prev>, now <curr>)" notice without
|
|
116
158
|
// having to query the event ledger.
|
|
117
|
-
auto_healed:
|
|
118
|
-
previous_revision_hash:
|
|
159
|
+
auto_healed: z3.boolean().optional(),
|
|
160
|
+
previous_revision_hash: z3.string().optional(),
|
|
119
161
|
// v2.0.0-rc.37 NEW-24: stale-id redirect map. Populated when one or more
|
|
120
162
|
// recent fab_review modify-layer flips reassigned a canonical stable_id
|
|
121
163
|
// and the NEW id is in this response's description_index. Callers that
|
|
@@ -123,7 +165,13 @@ var planContextOutputSchema = z2.object({
|
|
|
123
165
|
// the new id before issuing fab_get_knowledge_sections / fab_recall. Empty
|
|
124
166
|
// (field omitted) when no actionable redirects exist for the surfaced
|
|
125
167
|
// candidate set. See packages/server/src/services/id-redirect.ts.
|
|
126
|
-
redirects:
|
|
168
|
+
redirects: z3.record(z3.string()).optional(),
|
|
169
|
+
// lifecycle-refactor W3-T2 (§7 图谱消费): related-expansion provenance map
|
|
170
|
+
// (appended id → surfaced source id). Present only when `include_related` was
|
|
171
|
+
// requested AND at least one in-corpus one-hop neighbour was appended. Omitted
|
|
172
|
+
// on the graph-empty / steady-state path. Additive — declare it here or zod
|
|
173
|
+
// strips it on output validation.
|
|
174
|
+
related_appended: z3.record(z3.string()).optional()
|
|
127
175
|
});
|
|
128
176
|
var planContextAnnotations = {
|
|
129
177
|
readOnlyHint: true,
|
|
@@ -132,63 +180,69 @@ var planContextAnnotations = {
|
|
|
132
180
|
openWorldHint: false,
|
|
133
181
|
title: "Plan rule context"
|
|
134
182
|
};
|
|
135
|
-
var planContextHintNarrowEntrySchema =
|
|
136
|
-
id:
|
|
137
|
-
type:
|
|
138
|
-
maturity:
|
|
139
|
-
summary:
|
|
183
|
+
var planContextHintNarrowEntrySchema = z3.object({
|
|
184
|
+
id: z3.string(),
|
|
185
|
+
type: z3.string(),
|
|
186
|
+
maturity: z3.string(),
|
|
187
|
+
summary: z3.string(),
|
|
188
|
+
// W2-2 (KT-DEC-0027): the entry's must_read_if trigger hook, forwarded for the
|
|
189
|
+
// SessionStart REFERENCE rendering (decision/pitfall/process → title + hook).
|
|
190
|
+
// Optional — omitted when the frontmatter declares none.
|
|
191
|
+
must_read_if: z3.string().optional()
|
|
140
192
|
});
|
|
141
|
-
var planContextHintOutputSchema =
|
|
142
|
-
version:
|
|
143
|
-
revision_hash:
|
|
144
|
-
target_paths:
|
|
145
|
-
narrow:
|
|
146
|
-
broad_count:
|
|
193
|
+
var planContextHintOutputSchema = z3.object({
|
|
194
|
+
version: z3.literal(1),
|
|
195
|
+
revision_hash: z3.string(),
|
|
196
|
+
target_paths: z3.array(z3.string()),
|
|
197
|
+
narrow: z3.array(planContextHintNarrowEntrySchema),
|
|
198
|
+
broad_count: z3.number().int().nonnegative()
|
|
147
199
|
});
|
|
148
|
-
var knowledgeSectionsInputSchema =
|
|
149
|
-
selection_token:
|
|
150
|
-
ai_selected_stable_ids:
|
|
200
|
+
var knowledgeSectionsInputSchema = z3.object({
|
|
201
|
+
selection_token: z3.string().min(1).describe("Selection token returned by fab_plan_context"),
|
|
202
|
+
ai_selected_stable_ids: z3.array(z3.string()).describe(
|
|
151
203
|
"Stable ids picked from fab_plan_context candidates[].stable_id; choose 1..N to fetch bodies for"
|
|
152
204
|
),
|
|
153
|
-
ai_selection_reasons:
|
|
154
|
-
|
|
155
|
-
|
|
205
|
+
ai_selection_reasons: z3.record(z3.string().min(1)).optional().default({}).describe(
|
|
206
|
+
"Optional reason for each AI-selected L1 stable_id (audit telemetry). Omit to fetch bodies without annotating \u2014 server defaults to {} rather than rejecting the documented two-step call."
|
|
207
|
+
),
|
|
208
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
|
|
209
|
+
session_id: z3.string().optional().describe("Optional caller-provided session id for Event Ledger records"),
|
|
156
210
|
// v2.0 rc.5 TASK-014 (C5): optional client identity hash propagated into
|
|
157
211
|
// knowledge_consumed events. Falls back to empty string when unset — full
|
|
158
212
|
// client-identity propagation deferred to rc.6.
|
|
159
|
-
client_hash:
|
|
213
|
+
client_hash: z3.string().optional().describe("Optional caller-provided client hash propagated into knowledge_consumed events")
|
|
160
214
|
});
|
|
161
|
-
var knowledgeSectionsOutputSchema =
|
|
162
|
-
revision_hash:
|
|
215
|
+
var knowledgeSectionsOutputSchema = z3.object({
|
|
216
|
+
revision_hash: z3.string(),
|
|
163
217
|
// v2.0.0-rc.38 UX-13 (D-MCP step-2 audit): the deprecated `precedence`
|
|
164
218
|
// L2/L1/L0 tuple (flagged "removed in rc.24" but still emitted) is gone — it
|
|
165
219
|
// was a constant 3-string field on every response read by no production
|
|
166
|
-
// consumer.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
path:
|
|
220
|
+
// consumer. v2.0.0-rc.38 Goal B: the dead L0/L1/L2 `level` axis was retired
|
|
221
|
+
// too (dead-write — no consumer ordered by it).
|
|
222
|
+
selected_stable_ids: z3.array(z3.string()),
|
|
223
|
+
rules: z3.array(
|
|
224
|
+
z3.object({
|
|
225
|
+
stable_id: z3.string(),
|
|
226
|
+
path: z3.string(),
|
|
173
227
|
// v2.0.0-rc.23 TASK-013 (F8b): replaced the legacy
|
|
174
228
|
// `sections: Record<string,string>` (keyed by the 4-element A-set enum)
|
|
175
229
|
// with the full markdown body (frontmatter stripped). Callers scan the
|
|
176
230
|
// body for whichever B-set heading they need (Summary / Why proposed /
|
|
177
231
|
// Session context / Evidence) — section-name discipline is now a writer
|
|
178
232
|
// convention, not an API contract.
|
|
179
|
-
body:
|
|
233
|
+
body: z3.string()
|
|
180
234
|
})
|
|
181
235
|
),
|
|
182
|
-
diagnostics:
|
|
236
|
+
diagnostics: z3.array(
|
|
183
237
|
// v2.0.0-rc.23 TASK-013 (F8b): `missing_section` was removed alongside the
|
|
184
238
|
// A-set enum. `missing_knowledge_metadata` stays as the warn-level signal
|
|
185
239
|
// for un-migrated v1.x entries (no knowledge_type AND no knowledge_layer
|
|
186
240
|
// in frontmatter). Does NOT block selection.
|
|
187
|
-
|
|
188
|
-
code:
|
|
189
|
-
severity:
|
|
190
|
-
stable_id:
|
|
191
|
-
message:
|
|
241
|
+
z3.object({
|
|
242
|
+
code: z3.enum(["missing_knowledge_metadata", "unresolved_selected_id"]),
|
|
243
|
+
severity: z3.literal("warn"),
|
|
244
|
+
stable_id: z3.string(),
|
|
245
|
+
message: z3.string()
|
|
192
246
|
})
|
|
193
247
|
),
|
|
194
248
|
// v2/rc.3 (Q6) + v2.0.0-rc.37 NEW-24: present iff at least one stable_id in
|
|
@@ -198,87 +252,96 @@ var knowledgeSectionsOutputSchema = z2.object({
|
|
|
198
252
|
// (old_id → new_id) when multiple rewrites fire in one fetch. Both shapes
|
|
199
253
|
// are accepted for forward-compat; readers should branch on shape and
|
|
200
254
|
// refresh their cached ids accordingly.
|
|
201
|
-
redirect_to:
|
|
202
|
-
|
|
203
|
-
|
|
255
|
+
redirect_to: z3.union([
|
|
256
|
+
z3.object({ stable_id: z3.string() }),
|
|
257
|
+
z3.record(z3.string())
|
|
204
258
|
]).optional().describe(
|
|
205
259
|
"Post-layer-flip redirect. Pre-rc.37: { stable_id } shape from rc.3 fab_review/modify. rc.37+: also accepts a (old_id \u2192 new_id) map for fab_get_knowledge_sections / fab_recall transparent rewrite."
|
|
206
260
|
),
|
|
207
|
-
warnings:
|
|
261
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
208
262
|
});
|
|
209
263
|
var knowledgeSectionsAnnotations = {
|
|
210
264
|
readOnlyHint: true,
|
|
211
265
|
idempotentHint: true,
|
|
212
266
|
destructiveHint: false,
|
|
213
267
|
openWorldHint: false,
|
|
214
|
-
title: "
|
|
268
|
+
title: "Fetch knowledge entry bodies"
|
|
215
269
|
};
|
|
216
|
-
var recallInputSchema =
|
|
217
|
-
paths:
|
|
218
|
-
"Candidate file paths to recall Fabric
|
|
219
|
-
),
|
|
220
|
-
intent:
|
|
221
|
-
known_tech:
|
|
222
|
-
detected_entities:
|
|
223
|
-
client_hash:
|
|
224
|
-
correlation_id:
|
|
225
|
-
session_id:
|
|
270
|
+
var recallInputSchema = z3.object({
|
|
271
|
+
paths: z3.array(z3.string()).min(1).describe(
|
|
272
|
+
"Candidate file paths to recall Fabric knowledge entries for. Same semantics as fab_plan_context.paths."
|
|
273
|
+
),
|
|
274
|
+
intent: z3.string().optional().describe("User-stated requirement or implementation intent; used to build a neutral requirement profile."),
|
|
275
|
+
known_tech: z3.array(z3.string()).optional().describe("Known technologies involved."),
|
|
276
|
+
detected_entities: z3.record(z3.array(z3.string())).optional().describe("Optional path-keyed detected entities."),
|
|
277
|
+
client_hash: z3.string().optional().describe("Revision hash from a prior call; enables stale detection."),
|
|
278
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records."),
|
|
279
|
+
session_id: z3.string().optional().describe(
|
|
226
280
|
"Current client session id (Claude Code: $session_id; Codex: corresponding identifier). Enables cross-session debt tracking. Falls back gracefully if omitted."
|
|
227
281
|
),
|
|
228
|
-
layer_filter:
|
|
282
|
+
layer_filter: z3.enum(["team", "personal", "both"]).optional().describe(
|
|
229
283
|
"Restrict recall to the named layer. Default: fabric-config.default_layer_filter."
|
|
230
284
|
),
|
|
231
|
-
target_paths:
|
|
285
|
+
target_paths: z3.array(z3.string()).optional().describe(
|
|
232
286
|
"Path context for narrow-scope relevance filtering. Defaults to `paths`; empty = no filter."
|
|
233
287
|
),
|
|
234
|
-
ids:
|
|
235
|
-
"Optional explicit stable_ids to
|
|
288
|
+
ids: z3.array(z3.string()).optional().describe(
|
|
289
|
+
"Optional explicit stable_ids to SCOPE the returned read paths. When omitted, `paths` carries one read path per surfaced candidate. The candidate DESCRIPTION index is always returned in full for discovery \u2014 `ids` only narrows which read paths are surfaced (e.g. when you already know which entries to Read). Stale ids are redirect-rewritten before matching."
|
|
290
|
+
),
|
|
291
|
+
// W1-3 / KT-DEC-0031: graph expansion (surface related read paths, no body).
|
|
292
|
+
include_related: z3.boolean().optional().describe(
|
|
293
|
+
"When true, also surface the one-hop `related` graph neighbours (of the surfaced entries) that are present in the candidate set \u2014 their descriptions and read paths, NOT their bodies."
|
|
236
294
|
)
|
|
237
295
|
});
|
|
238
|
-
var recallOutputSchema =
|
|
239
|
-
revision_hash:
|
|
240
|
-
stale:
|
|
241
|
-
// Selection token surfaced for callers who want to continue the conversation
|
|
242
|
-
// with fab_get_knowledge_sections (e.g. fetch additional ids later) — every
|
|
243
|
-
// recall response is still token-backed internally.
|
|
244
|
-
selection_token: z2.string(),
|
|
296
|
+
var recallOutputSchema = z3.object({
|
|
297
|
+
revision_hash: z3.string(),
|
|
298
|
+
stale: z3.boolean(),
|
|
245
299
|
// v2.0.0-rc.38 UX-1/UX-4: mirrors planContextOutputSchema fold ① — per-path
|
|
246
300
|
// description_index collapsed into a single top-level `candidates`, and
|
|
247
301
|
// `preflight_diagnostics` lifted out of the removed `shared` wrapper.
|
|
248
|
-
entries:
|
|
249
|
-
|
|
250
|
-
path:
|
|
302
|
+
entries: z3.array(
|
|
303
|
+
z3.object({
|
|
304
|
+
path: z3.string(),
|
|
251
305
|
requirement_profile: _requirementProfileSchema
|
|
252
306
|
})
|
|
253
307
|
),
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
severity: z2.literal("warn"),
|
|
270
|
-
stable_id: z2.string(),
|
|
271
|
-
message: z2.string()
|
|
308
|
+
// v2.2 payload de-dup: single top-level echo of the caller's `intent` (was
|
|
309
|
+
// duplicated into every entry's requirement_profile). Omitted when no intent.
|
|
310
|
+
intent: z3.string().optional(),
|
|
311
|
+
// W1 (KT-DEC-0026): the discovery index — every surfaced candidate's
|
|
312
|
+
// DESCRIPTION (summary / intent_clues / must_read_if / related ...). No body.
|
|
313
|
+
candidates: z3.array(_descriptionIndexItemSchema),
|
|
314
|
+
// W1 (KT-DEC-0026): the read-path index — one entry per surfaced candidate
|
|
315
|
+
// (scoped by `ids` when provided), in ranked order. `path` is the on-disk
|
|
316
|
+
// knowledge file the agent Reads to load the body on demand; `store` is the
|
|
317
|
+
// originating store alias (omitted for unqualified entries).
|
|
318
|
+
paths: z3.array(
|
|
319
|
+
z3.object({
|
|
320
|
+
stable_id: z3.string(),
|
|
321
|
+
path: z3.string(),
|
|
322
|
+
store: z3.object({ alias: z3.string() }).optional()
|
|
272
323
|
})
|
|
273
324
|
),
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
325
|
+
// Number of lower-ranked candidates dropped by the retrieval budget. Present
|
|
326
|
+
// (and > 0) ONLY when truncation fired — keeps the steady-state wire shape
|
|
327
|
+
// unchanged while signalling "more exist; narrow your intent".
|
|
328
|
+
omitted_candidate_count: z3.number().int().nonnegative().optional(),
|
|
329
|
+
preflight_diagnostics: z3.array(_preflightDiagnosticSchema),
|
|
330
|
+
warnings: z3.array(structuredWarningSchema).optional(),
|
|
331
|
+
auto_healed: z3.boolean().optional(),
|
|
332
|
+
previous_revision_hash: z3.string().optional(),
|
|
333
|
+
// v2.0.0-rc.37 NEW-24: parallel to planContextOutputSchema.redirects — stale
|
|
334
|
+
// (pre layer-flip) ids in `ids` are redirect-rewritten before matching; the
|
|
335
|
+
// surfaced map exposes the substitution so callers refresh cached state.
|
|
336
|
+
redirects: z3.record(z3.string()).optional(),
|
|
337
|
+
// lifecycle-refactor W3-T2 (§7 图谱消费): related-expansion provenance map
|
|
338
|
+
// (appended id → surfaced source id). Present only when include_related
|
|
339
|
+
// appended an in-corpus neighbour. Omitted on the steady-state path.
|
|
340
|
+
related_appended: z3.record(z3.string()).optional(),
|
|
341
|
+
// v2.2 MC1-recall-pack: standing behavioral directive (cite-before-edit) +
|
|
342
|
+
// dynamic discovery hints, so the one-call recall is self-describing.
|
|
343
|
+
directive: z3.string(),
|
|
344
|
+
next_steps: z3.array(z3.string()).optional()
|
|
282
345
|
});
|
|
283
346
|
var recallAnnotations = {
|
|
284
347
|
readOnlyHint: true,
|
|
@@ -287,34 +350,34 @@ var recallAnnotations = {
|
|
|
287
350
|
openWorldHint: false,
|
|
288
351
|
title: "Recall Fabric knowledge (one-call)"
|
|
289
352
|
};
|
|
290
|
-
var archiveScanInputSchema =
|
|
291
|
-
range:
|
|
353
|
+
var archiveScanInputSchema = z3.object({
|
|
354
|
+
range: z3.union([z3.array(z3.string()).min(1), z3.literal("all")]).optional().describe(
|
|
292
355
|
"Phase 0 scope: explicit session_id[] to constrain the scan, or the 'all' sentinel. Omitted = scan everything since the last knowledge_proposed anchor."
|
|
293
356
|
),
|
|
294
|
-
now_ms:
|
|
295
|
-
correlation_id:
|
|
296
|
-
session_id:
|
|
357
|
+
now_ms: z3.number().int().nonnegative().optional().describe("Override for the anti-loop cooldown clock (testing). Defaults to Date.now()."),
|
|
358
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records."),
|
|
359
|
+
session_id: z3.string().optional().describe("Current client session id; recorded for cross-session debt tracking.")
|
|
297
360
|
});
|
|
298
|
-
var archiveScanOutputSchema =
|
|
361
|
+
var archiveScanOutputSchema = z3.object({
|
|
299
362
|
// ts of the most recent knowledge_proposed event (the lower bound), or null
|
|
300
363
|
// when the workspace has never archived (scan everything).
|
|
301
|
-
anchor_ts:
|
|
364
|
+
anchor_ts: z3.number().nullable(),
|
|
302
365
|
// Distinct session_ids since the anchor that survived the outcome filter,
|
|
303
366
|
// in first-seen order — ready for the Skill to load digests + stitch.
|
|
304
|
-
session_ids:
|
|
367
|
+
session_ids: z3.array(z3.string()),
|
|
305
368
|
// Sessions dropped by the filter, with the rule that fired (audit/debug).
|
|
306
|
-
dropped:
|
|
307
|
-
|
|
308
|
-
session_id:
|
|
309
|
-
reason:
|
|
369
|
+
dropped: z3.array(
|
|
370
|
+
z3.object({
|
|
371
|
+
session_id: z3.string(),
|
|
372
|
+
reason: z3.enum(["user_dismissed", "cooldown", "no_new_signal"])
|
|
310
373
|
})
|
|
311
374
|
),
|
|
312
375
|
// max ts examined across the scan — becomes the next covered_through_ts.
|
|
313
|
-
covered_through_ts:
|
|
376
|
+
covered_through_ts: z3.number().nullable(),
|
|
314
377
|
// Idempotency keys already proposed by prior archive runs but not yet
|
|
315
378
|
// reviewed (Phase 4.5 cross-session pending dedupe). Drop matching candidates.
|
|
316
|
-
already_proposed_keys:
|
|
317
|
-
warnings:
|
|
379
|
+
already_proposed_keys: z3.array(z3.string()),
|
|
380
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
318
381
|
});
|
|
319
382
|
var archiveScanAnnotations = {
|
|
320
383
|
readOnlyHint: true,
|
|
@@ -323,7 +386,7 @@ var archiveScanAnnotations = {
|
|
|
323
386
|
openWorldHint: false,
|
|
324
387
|
title: "Scan event ledger for archive candidates (deterministic)"
|
|
325
388
|
};
|
|
326
|
-
var ProposedReasonSchema =
|
|
389
|
+
var ProposedReasonSchema = z3.enum([
|
|
327
390
|
"explicit-user-mark",
|
|
328
391
|
"diagnostic-then-fix",
|
|
329
392
|
"decision-confirmation",
|
|
@@ -331,7 +394,7 @@ var ProposedReasonSchema = z2.enum([
|
|
|
331
394
|
"new-dependency-or-pattern",
|
|
332
395
|
"dismissal-with-reason"
|
|
333
396
|
]);
|
|
334
|
-
var
|
|
397
|
+
var PROPOSED_REASON_DESCRIPTIONS_ZH = {
|
|
335
398
|
"explicit-user-mark": "\u7528\u6237\u663E\u5F0F\u6807\u8BB0\u9700\u5F52\u6863\uFF08always / never / \u4E0B\u6B21\u6CE8\u610F \u7B49\u89C4\u8303\u6027\u8BED\u8A00\uFF09\u3002",
|
|
336
399
|
"diagnostic-then-fix": "\u8BCA\u65AD\u8FC7\u7A0B\u53D1\u73B0\u65B0\u6A21\u5F0F\u6216\u8E29\u5751\uFF0C\u4FEE\u590D\u540E\u503C\u5F97\u6C89\u6DC0\u3002",
|
|
337
400
|
"decision-confirmation": "\u22652 \u5019\u9009\u65B9\u6848\u7ECF\u6743\u8861\u540E\u786E\u8BA4\u9009\u578B\uFF0C\u9700\u4FDD\u7559 rationale\u3002",
|
|
@@ -339,21 +402,41 @@ var PROPOSED_REASON_DESCRIPTIONS = {
|
|
|
339
402
|
"new-dependency-or-pattern": "\u5F15\u5165\u65B0\u4F9D\u8D56 / \u65B0\u6A21\u5F0F / \u65B0\u547D\u540D\u7EA6\u5B9A\u3002",
|
|
340
403
|
"dismissal-with-reason": "\u7528\u6237\u660E\u786E\u62D2\u7EDD\u67D0\u65B9\u6848\u5E76\u7ED9\u51FA\u539F\u56E0\uFF0C\u539F\u56E0\u5373\u53EF\u5F52\u6863\u77E5\u8BC6\u3002"
|
|
341
404
|
};
|
|
342
|
-
var
|
|
343
|
-
|
|
405
|
+
var PROPOSED_REASON_DESCRIPTIONS_EN = {
|
|
406
|
+
"explicit-user-mark": "User explicitly marked this for archival (normative language: always / never / next time, etc.).",
|
|
407
|
+
"diagnostic-then-fix": "A new pattern or pitfall surfaced during diagnosis and is worth retaining after the fix.",
|
|
408
|
+
"decision-confirmation": "A choice was confirmed after weighing \u22652 candidate approaches; the rationale must be preserved.",
|
|
409
|
+
"wrong-turn-revert": "A path was tried then reverted; the wrong turn itself is a pitfall worth recording.",
|
|
410
|
+
"new-dependency-or-pattern": "Introduces a new dependency / pattern / naming convention.",
|
|
411
|
+
"dismissal-with-reason": "The user explicitly rejected an approach and gave a reason; the reason is archivable knowledge."
|
|
412
|
+
};
|
|
413
|
+
var PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE = {
|
|
414
|
+
"zh-CN": PROPOSED_REASON_DESCRIPTIONS_ZH,
|
|
415
|
+
en: PROPOSED_REASON_DESCRIPTIONS_EN
|
|
416
|
+
};
|
|
417
|
+
var _sourceSessionsField = z3.array(z3.string().min(1)).min(1);
|
|
418
|
+
var _FabExtractKnowledgeInputBaseSchema = z3.object({
|
|
344
419
|
// v2.0.0-rc.7 T5: array form. rc.23 dropped the legacy single-string alias.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
420
|
+
// v2.2 全砍 F13: REQUIRED in the base schema (was `.optional()`) so the MCP
|
|
421
|
+
// tool's advertised inputSchema (registerTool reads `.shape`) matches the
|
|
422
|
+
// requirement the superRefine enforces. Previously a caller reading the schema
|
|
423
|
+
// saw it optional, omitted it, and got rejected at parse — a contract lie.
|
|
424
|
+
source_sessions: _sourceSessionsField.describe(
|
|
425
|
+
"Originating session ids (REQUIRED, non-empty array); correlates with Event Ledger records. Array form (T5+, rc.23 made it the sole accepted shape)."
|
|
426
|
+
),
|
|
427
|
+
recent_paths: z3.array(z3.string()).describe("Workspace paths recently touched in the source session \u2014 used as scope hints"),
|
|
428
|
+
user_messages_summary: z3.string().describe("Skill-side summary of the user's intent/messages, kept compact"),
|
|
429
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).describe("Knowledge type bucket (plural form, mirrors directory layout)"),
|
|
430
|
+
slug: z3.string().describe("URL-safe short identifier proposed by the Skill; server may sanitize"),
|
|
431
|
+
// Store-only cutover: layer is a compatibility audience hint. The server
|
|
432
|
+
// resolves the actual write target through semantic_scope/write_routes and
|
|
433
|
+
// writes to the selected mounted store's knowledge/pending/<type>/ tree.
|
|
354
434
|
// Defaults to 'team' to preserve existing call sites (Skill bumps as needed).
|
|
355
|
-
layer:
|
|
356
|
-
"
|
|
435
|
+
layer: z3.enum(["team", "personal"]).optional().describe(
|
|
436
|
+
"Compatibility storage audience. 'personal' writes to the personal store; non-personal writes resolve by semantic_scope/write_routes. Defaults to 'team'."
|
|
437
|
+
),
|
|
438
|
+
semantic_scope: z3.string().regex(SCOPE_COORDINATE_PATTERN).optional().describe(
|
|
439
|
+
"Logical audience/write route coordinate for this pending entry, e.g. personal, team, project:fabric-v2, org:acme:team:platform. Server validates and resolves it through write_routes."
|
|
357
440
|
),
|
|
358
441
|
// v2.0.0-rc.7 T6: proposed_reason — required enum that drives `## Why
|
|
359
442
|
// proposed` rendering. Skills (archive / import / review) infer the
|
|
@@ -365,7 +448,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
365
448
|
// captures the session goal + key turning point. Future-self review reads
|
|
366
449
|
// this without conversation transcript access. Min length guards against
|
|
367
450
|
// empty placeholders; cap is soft (no max), Skill caps at ~600 chars.
|
|
368
|
-
session_context:
|
|
451
|
+
session_context: z3.string().min(20, { message: "session_context must be \u226520 chars (3-5 lines describing goal + turning point)" }).describe(
|
|
369
452
|
"3-5 line markdown blob \u2014 session goal + key turning point. Reviewed by future-self without transcript access."
|
|
370
453
|
),
|
|
371
454
|
// v2.0.0-rc.8 A1 (skill-contract-fix): relevance scope/paths on the
|
|
@@ -379,10 +462,10 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
379
462
|
// a `knowledge_scope_degraded` event keyed by `pending:<idempotency_key>`.
|
|
380
463
|
// NOTE: these fields MUST NOT be part of the idempotency hash inputs at
|
|
381
464
|
// extract-knowledge.ts:78 — preserves rc.5→rc.7 collision detection.
|
|
382
|
-
relevance_scope:
|
|
465
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional().describe(
|
|
383
466
|
"Optional relevance scope. 'narrow' restricts plan-context-hint surfacing to relevance_paths; 'broad' always surfaces. Omit to let the meta-builder default to 'broad'. Personal + narrow is silently degraded to broad + []."
|
|
384
467
|
),
|
|
385
|
-
relevance_paths:
|
|
468
|
+
relevance_paths: z3.array(z3.string()).optional().describe(
|
|
386
469
|
"Optional path anchors for narrow scope. Workspace-relative globs or paths. Omit to let the meta-builder default to []. Ignored when scope is broad (server preserves the array for audit)."
|
|
387
470
|
),
|
|
388
471
|
// v2.0.0-rc.23 TASK-006 (a-C1): four optional structured fields that the
|
|
@@ -399,16 +482,16 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
399
482
|
// relevance_paths follow the same rule). Including them would let an LLM
|
|
400
483
|
// re-roll of the same observation create a second pending file just because
|
|
401
484
|
// its inferred metadata wording drifted.
|
|
402
|
-
intent_clues:
|
|
485
|
+
intent_clues: z3.array(z3.string()).optional().describe(
|
|
403
486
|
"Short LLM-readable triggers describing when this rule should fire and when it should not. Each item \u226480 chars, imperative phrasing (e.g. 'when editing Cocos UI batch code', 'NOT for non-batch contexts'). Optional \u2014 omit when the skill cannot infer cleanly."
|
|
404
487
|
),
|
|
405
|
-
tech_stack:
|
|
488
|
+
tech_stack: z3.array(z3.string()).optional().describe(
|
|
406
489
|
"Tech stack / languages / frameworks the rule applies to (e.g. ['typescript', 'cocos-creator', 'nodejs']). Inferred from recent_paths file extensions and manifest files. Optional \u2014 omit when the rule is stack-agnostic."
|
|
407
490
|
),
|
|
408
|
-
impact:
|
|
491
|
+
impact: z3.array(z3.string()).optional().describe(
|
|
409
492
|
"Consequences of ignoring this rule, used by the LLM to weight relevance vs cost. Each item \u2264120 chars (e.g. 'O(n\xB2) re-render on every frame', 'silent data loss on collision'). Optional \u2014 omit when impact is not observable."
|
|
410
493
|
),
|
|
411
|
-
must_read_if:
|
|
494
|
+
must_read_if: z3.string().optional().describe(
|
|
412
495
|
"One-line strong trigger; when this condition holds the entry is considered required reading. Single line \u2264160 chars (e.g. 'touching anything under packages/cli/src/commands/hooks.ts'). Optional \u2014 omit when no single strong trigger fits."
|
|
413
496
|
),
|
|
414
497
|
// v2.0.0-rc.37 NEW-37 (werewolf dogfood remediation): optional tags array.
|
|
@@ -419,7 +502,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
419
502
|
// IDEMPOTENCY: tags MUST NOT 参与 idempotency_key hash(同 relevance_*
|
|
420
503
|
// / intent_clues 等可变字段一致),re-extract 时 tags 调整不应产生重复
|
|
421
504
|
// pending file。
|
|
422
|
-
tags:
|
|
505
|
+
tags: z3.array(z3.string()).optional().describe(
|
|
423
506
|
"Optional topic tags (2-4 kebab-case strings recommended). Drives cross-entry retrieval + topic clustering. Skill-inferred from session content; omit when not confidently inferable. Empty array allowed but discouraged (degrades narrow hint topic signal)."
|
|
424
507
|
),
|
|
425
508
|
// v2.0.0-rc.23 TASK-014 (F8c): optional onboard-slot tag. The S5 slot
|
|
@@ -454,7 +537,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
454
537
|
// signal was captured. Like relevance_paths it MUST NOT participate in
|
|
455
538
|
// the idempotency_key hash (an idempotent re-extract may surface a
|
|
456
539
|
// slightly different read set without spawning a duplicate pending).
|
|
457
|
-
evidence_paths:
|
|
540
|
+
evidence_paths: z3.array(z3.string()).optional().describe(
|
|
458
541
|
"Workspace-relative paths the agent CONSULTED (read but never modified) while building this knowledge. Documents context without affecting activation. Lifted from the legacy body ## Evidence markdown block into structured frontmatter so plan-context retrieval can read it as data."
|
|
459
542
|
)
|
|
460
543
|
});
|
|
@@ -463,7 +546,7 @@ var FabExtractKnowledgeInputSchema = _FabExtractKnowledgeInputBaseSchema.superRe
|
|
|
463
546
|
const hasArray = Array.isArray(value.source_sessions) && value.source_sessions.length > 0;
|
|
464
547
|
if (!hasArray) {
|
|
465
548
|
ctx.addIssue({
|
|
466
|
-
code:
|
|
549
|
+
code: z3.ZodIssueCode.custom,
|
|
467
550
|
message: "source_sessions (non-empty string array) is required",
|
|
468
551
|
path: ["source_sessions"]
|
|
469
552
|
});
|
|
@@ -471,12 +554,12 @@ var FabExtractKnowledgeInputSchema = _FabExtractKnowledgeInputBaseSchema.superRe
|
|
|
471
554
|
}
|
|
472
555
|
);
|
|
473
556
|
var FabExtractKnowledgeInputShape = _FabExtractKnowledgeInputBaseSchema.shape;
|
|
474
|
-
var FabExtractKnowledgeOutputSchema =
|
|
475
|
-
pending_path:
|
|
476
|
-
idempotency_key:
|
|
557
|
+
var FabExtractKnowledgeOutputSchema = z3.object({
|
|
558
|
+
pending_path: z3.string().describe("Workspace-relative path to the persisted pending entry"),
|
|
559
|
+
idempotency_key: z3.string().describe("Stable key derived from inputs; identical inputs yield identical key"),
|
|
477
560
|
// v2.0.0-rc.23 TASK-009 (d): optional warnings surface for the first-reconcile
|
|
478
561
|
// gate (`meta_stale` / `reconcile_failed`). Absent on the steady-state path.
|
|
479
|
-
warnings:
|
|
562
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
480
563
|
});
|
|
481
564
|
var fabExtractKnowledgeAnnotations = {
|
|
482
565
|
readOnlyHint: false,
|
|
@@ -485,21 +568,21 @@ var fabExtractKnowledgeAnnotations = {
|
|
|
485
568
|
openWorldHint: false,
|
|
486
569
|
title: "Extract pending knowledge entry"
|
|
487
570
|
};
|
|
488
|
-
var _fabReviewFiltersSchema =
|
|
489
|
-
type:
|
|
490
|
-
layer:
|
|
491
|
-
maturity:
|
|
492
|
-
tags:
|
|
571
|
+
var _fabReviewFiltersSchema = z3.object({
|
|
572
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).optional(),
|
|
573
|
+
layer: z3.enum(["team", "personal", "both"]).optional(),
|
|
574
|
+
maturity: z3.enum(["draft", "verified", "proven"]).optional(),
|
|
575
|
+
tags: z3.array(z3.string()).optional(),
|
|
493
576
|
// rc.4 TASK-006 fix (c): ISO-8601 lower bound on entry created_at; entries
|
|
494
577
|
// strictly older than this threshold are excluded from list / search
|
|
495
578
|
// results. Additive optional field — existing callers unaffected.
|
|
496
|
-
created_after:
|
|
579
|
+
created_after: z3.string().datetime().optional(),
|
|
497
580
|
// v2.0.0-rc.27 TASK-001 (§2.2/§2.3): opt-in surfacing of lifecycle-filtered
|
|
498
581
|
// entries. Default (omit both) hides rejected entries and deferred entries
|
|
499
582
|
// whose deferred_until is in the future. Pass true to include them — e.g.
|
|
500
583
|
// for vacuum tooling, audit dashboards, or "show me what I parked" UX.
|
|
501
|
-
include_rejected:
|
|
502
|
-
include_deferred:
|
|
584
|
+
include_rejected: z3.boolean().optional(),
|
|
585
|
+
include_deferred: z3.boolean().optional(),
|
|
503
586
|
// v2.0.0-rc.27 TASK-006 (audit §2.23): opt-in body inspection. Default
|
|
504
587
|
// list/search return only frontmatter-derived fields — a malicious
|
|
505
588
|
// pending entry could hide a prompt-injection payload under `## Evidence`
|
|
@@ -509,41 +592,57 @@ var _fabReviewFiltersSchema = z2.object({
|
|
|
509
592
|
// default-off design keeps the wire payload small for routine list
|
|
510
593
|
// calls; reviewer workflows pass `true` before approving so the body
|
|
511
594
|
// is rendered into the reviewer's UI for visual scan.
|
|
512
|
-
include_body:
|
|
595
|
+
include_body: z3.boolean().optional()
|
|
513
596
|
}).optional();
|
|
514
|
-
var _fabReviewModifyChangesSchema =
|
|
515
|
-
title:
|
|
516
|
-
summary:
|
|
597
|
+
var _fabReviewModifyChangesSchema = z3.object({
|
|
598
|
+
title: z3.string().optional(),
|
|
599
|
+
summary: z3.string().optional(),
|
|
517
600
|
// Q7: writing `layer` here triggers a layer-flip; downstream callers may
|
|
518
601
|
// observe a redirect_to in fab_get_knowledge_sections if stable_id changes.
|
|
519
|
-
layer:
|
|
520
|
-
maturity:
|
|
521
|
-
tags:
|
|
602
|
+
layer: z3.enum(["team", "personal"]).optional(),
|
|
603
|
+
maturity: z3.enum(["draft", "verified", "proven"]).optional(),
|
|
604
|
+
tags: z3.array(z3.string()).optional(),
|
|
522
605
|
// v2.0-rc.5 C3 (TASK-012): relevance scope/paths patches. Applied to
|
|
523
606
|
// pending AND canonical entries. When an explicit team→personal layer flip
|
|
524
607
|
// arrives on a narrow entry, the server auto-degrades to broad + [] and
|
|
525
608
|
// emits a `knowledge_scope_degraded` event regardless of what the caller
|
|
526
609
|
// sent in these fields (personal-implies-broad).
|
|
527
|
-
relevance_scope:
|
|
528
|
-
relevance_paths:
|
|
610
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional(),
|
|
611
|
+
relevance_paths: z3.array(z3.string()).optional(),
|
|
612
|
+
// v2.2 project-scope migration: re-scope an existing entry's resolution
|
|
613
|
+
// coordinate (e.g. team → project:fabric-v2) WITHOUT moving stores
|
|
614
|
+
// (scope ⊥ store, S42/A2). The in-place modify path keeps visibility_store
|
|
615
|
+
// intact, so a team→project flip just relabels who recall surfaces it to
|
|
616
|
+
// (G-FILTER, cross-store-recall.ts) — the entry stays physically in the
|
|
617
|
+
// same shared store. A personal-root coordinate is rejected here: landing
|
|
618
|
+
// an entry in the personal store is a store move, which is the dedicated
|
|
619
|
+
// modify-layer path (R5#3 privacy boundary), never an in-place scalar edit.
|
|
620
|
+
semantic_scope: z3.string().regex(SCOPE_COORDINATE_PATTERN).optional(),
|
|
621
|
+
// v2.2 graph edges (KT-DEC-0031 wiki seam): write the `related` H2 adjacency
|
|
622
|
+
// (bare or store-qualified stable_ids this entry points at). REPLACE semantics
|
|
623
|
+
// mirror tags/relevance_paths — the caller (fabric-connect) reads existing
|
|
624
|
+
// edges via fab_recall and sends the merged set. Absent this field the modify
|
|
625
|
+
// path silently dropped `related` via zod .strip() (KT-PIT-0005 recurrence),
|
|
626
|
+
// leaving the only programmatic related-write path non-functional.
|
|
627
|
+
related: z3.array(z3.string()).optional()
|
|
529
628
|
});
|
|
530
|
-
var FabReviewInputSchema =
|
|
531
|
-
|
|
532
|
-
action:
|
|
629
|
+
var FabReviewInputSchema = z3.discriminatedUnion("action", [
|
|
630
|
+
z3.object({
|
|
631
|
+
action: z3.literal("list"),
|
|
533
632
|
filters: _fabReviewFiltersSchema
|
|
534
633
|
}),
|
|
535
|
-
|
|
536
|
-
action:
|
|
537
|
-
pending_paths:
|
|
634
|
+
z3.object({
|
|
635
|
+
action: z3.literal("approve"),
|
|
636
|
+
pending_paths: z3.array(z3.string()).min(1)
|
|
538
637
|
}),
|
|
539
|
-
|
|
540
|
-
action:
|
|
541
|
-
pending_paths:
|
|
542
|
-
reason:
|
|
638
|
+
z3.object({
|
|
639
|
+
action: z3.literal("reject"),
|
|
640
|
+
pending_paths: z3.array(z3.string()).min(1),
|
|
641
|
+
reason: z3.string().min(1)
|
|
543
642
|
}),
|
|
544
|
-
|
|
545
|
-
action:
|
|
546
|
-
pending_path:
|
|
643
|
+
z3.object({
|
|
644
|
+
action: z3.literal("modify"),
|
|
645
|
+
pending_path: z3.string().min(1),
|
|
547
646
|
changes: _fabReviewModifyChangesSchema
|
|
548
647
|
}),
|
|
549
648
|
// v2.0.0-rc.37 NEW-12: explicit modify split. `modify-content` edits scalar
|
|
@@ -552,177 +651,176 @@ var FabReviewInputSchema = z2.discriminatedUnion("action", [
|
|
|
552
651
|
// (changes.layer REQUIRED) which may reallocate the stable_id + emit an
|
|
553
652
|
// id-redirect (rc.37 NEW-24). Legacy `modify` stays for back-compat and
|
|
554
653
|
// routes by whether changes.layer is present.
|
|
555
|
-
|
|
556
|
-
action:
|
|
557
|
-
pending_path:
|
|
654
|
+
z3.object({
|
|
655
|
+
action: z3.literal("modify-content"),
|
|
656
|
+
pending_path: z3.string().min(1),
|
|
558
657
|
changes: _fabReviewModifyChangesSchema
|
|
559
658
|
}),
|
|
560
|
-
|
|
561
|
-
action:
|
|
562
|
-
pending_path:
|
|
659
|
+
z3.object({
|
|
660
|
+
action: z3.literal("modify-layer"),
|
|
661
|
+
pending_path: z3.string().min(1),
|
|
563
662
|
changes: _fabReviewModifyChangesSchema.extend({
|
|
564
|
-
layer:
|
|
663
|
+
layer: z3.enum(["team", "personal"])
|
|
565
664
|
})
|
|
566
665
|
}),
|
|
567
|
-
|
|
568
|
-
action:
|
|
569
|
-
query:
|
|
666
|
+
z3.object({
|
|
667
|
+
action: z3.literal("search"),
|
|
668
|
+
query: z3.string().min(1),
|
|
570
669
|
filters: _fabReviewFiltersSchema
|
|
571
670
|
}),
|
|
572
|
-
|
|
573
|
-
action:
|
|
574
|
-
pending_paths:
|
|
575
|
-
until:
|
|
576
|
-
reason:
|
|
671
|
+
z3.object({
|
|
672
|
+
action: z3.literal("defer"),
|
|
673
|
+
pending_paths: z3.array(z3.string()).min(1),
|
|
674
|
+
until: z3.string().datetime().optional(),
|
|
675
|
+
reason: z3.string().optional()
|
|
577
676
|
})
|
|
578
677
|
]);
|
|
579
678
|
var FabReviewInputShape = {
|
|
580
|
-
action:
|
|
679
|
+
action: z3.enum(["list", "approve", "reject", "modify", "modify-content", "modify-layer", "search", "defer"]).describe(
|
|
581
680
|
"Action selector. Discriminates the per-action fields below; required. modify-content edits scalars (no layer); modify-layer is the layer-flip path (changes.layer required); modify is the legacy combined alias."
|
|
582
681
|
),
|
|
583
682
|
filters: _fabReviewFiltersSchema.describe(
|
|
584
683
|
"Optional filters (type/layer/maturity/tags/created_after). Used by action=list and action=search."
|
|
585
684
|
),
|
|
586
|
-
pending_paths:
|
|
685
|
+
pending_paths: z3.array(z3.string()).min(1).optional().describe(
|
|
587
686
|
"Workspace-relative pending entry paths. Required when action=approve|reject|defer (non-empty array)."
|
|
588
687
|
),
|
|
589
|
-
pending_path:
|
|
688
|
+
pending_path: z3.string().min(1).optional().describe(
|
|
590
689
|
"Workspace-relative pending OR canonical entry path. Required when action=modify."
|
|
591
690
|
),
|
|
592
|
-
reason:
|
|
691
|
+
reason: z3.string().optional().describe(
|
|
593
692
|
"Reason string. Required (non-empty) when action=reject; optional when action=defer."
|
|
594
693
|
),
|
|
595
694
|
changes: _fabReviewModifyChangesSchema.optional().describe(
|
|
596
|
-
"Frontmatter scalar patches (title/summary/layer/maturity/tags/relevance_
|
|
695
|
+
"Frontmatter scalar patches (title/summary/layer/maturity/tags/relevance_*/semantic_scope/related). Required when action=modify. semantic_scope re-scopes the entry's resolution coordinate in place (e.g. team \u2192 project:<id>) without moving stores; personal-root coordinates are rejected (use modify-layer)."
|
|
597
696
|
),
|
|
598
|
-
query:
|
|
697
|
+
query: z3.string().min(1).optional().describe(
|
|
599
698
|
"Substring query against title/summary/tags/path. Required (non-empty) when action=search."
|
|
600
699
|
),
|
|
601
|
-
until:
|
|
700
|
+
until: z3.string().datetime().optional().describe(
|
|
602
701
|
"ISO-8601 datetime upper bound for the deferral. Optional; used only when action=defer."
|
|
603
702
|
)
|
|
604
703
|
};
|
|
605
|
-
var _fabReviewListItemSchema =
|
|
606
|
-
pending_path:
|
|
704
|
+
var _fabReviewListItemSchema = z3.object({
|
|
705
|
+
pending_path: z3.string(),
|
|
607
706
|
// v2.0.0-rc.27 TASK-001 (§2.12): for personal-layer entries `pending_path`
|
|
608
707
|
// carries the human-friendly `~/...` form (legacy contract) while
|
|
609
708
|
// `pending_path_absolute` carries the os-expanded absolute path. Programmatic
|
|
610
709
|
// consumers (Read tool, fs.readFile, downstream MCP servers) should prefer
|
|
611
710
|
// the absolute variant — the `~` is a shell-only sigil that breaks every
|
|
612
711
|
// non-shell consumer. Team entries omit this field because their
|
|
613
|
-
// `pending_path` is already
|
|
614
|
-
pending_path_absolute:
|
|
615
|
-
type:
|
|
616
|
-
layer:
|
|
617
|
-
maturity:
|
|
618
|
-
tags:
|
|
619
|
-
title:
|
|
620
|
-
summary:
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
|
|
625
|
-
origin: z2.enum(["team", "personal"]).optional(),
|
|
712
|
+
// `pending_path` is already store-resolved and unambiguous.
|
|
713
|
+
pending_path_absolute: z3.string().optional(),
|
|
714
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]),
|
|
715
|
+
layer: z3.enum(["team", "personal"]),
|
|
716
|
+
maturity: z3.enum(["draft", "verified", "proven"]),
|
|
717
|
+
tags: z3.array(z3.string()).optional(),
|
|
718
|
+
title: z3.string().optional(),
|
|
719
|
+
summary: z3.string().optional(),
|
|
720
|
+
// Store-only cutover: origin reflects the resolved store audience where the
|
|
721
|
+
// pending file lives; layer reflects the declared classification that will
|
|
722
|
+
// drive approval semantics.
|
|
723
|
+
origin: z3.enum(["team", "personal"]).optional(),
|
|
626
724
|
// v2.0.0-rc.27 TASK-001 (§2.2/§2.3): frontmatter status markers. Default
|
|
627
725
|
// "active" (or absent). `rejected` entries are excluded from list/search
|
|
628
726
|
// unless filters.include_rejected=true; `deferred` entries are excluded
|
|
629
727
|
// when deferred_until is in the future. Authored by reject/defer write
|
|
630
728
|
// paths — never by extract or approve.
|
|
631
|
-
status:
|
|
632
|
-
deferred_until:
|
|
729
|
+
status: z3.enum(["active", "rejected", "deferred"]).optional(),
|
|
730
|
+
deferred_until: z3.string().datetime().optional(),
|
|
633
731
|
// v2.0.0-rc.27 TASK-006 (audit §2.23): full body content (everything
|
|
634
732
|
// after the closing `---` of frontmatter). Surfaced only when caller
|
|
635
733
|
// passes `filters.include_body: true`. Default-omitted to keep payload
|
|
636
734
|
// small for routine list calls.
|
|
637
|
-
body:
|
|
735
|
+
body: z3.string().optional()
|
|
638
736
|
});
|
|
639
|
-
var _fabReviewSearchItemSchema =
|
|
640
|
-
// Search hits live in one of two trees:
|
|
641
|
-
// - "pending" →
|
|
642
|
-
// - "canonical" →
|
|
643
|
-
area:
|
|
644
|
-
path:
|
|
645
|
-
path_absolute:
|
|
646
|
-
type:
|
|
647
|
-
layer:
|
|
648
|
-
maturity:
|
|
649
|
-
tags:
|
|
650
|
-
title:
|
|
651
|
-
summary:
|
|
652
|
-
origin:
|
|
653
|
-
status:
|
|
654
|
-
deferred_until:
|
|
655
|
-
body:
|
|
737
|
+
var _fabReviewSearchItemSchema = z3.object({
|
|
738
|
+
// Search hits live in one of two store trees:
|
|
739
|
+
// - "pending" → mounted store `knowledge/pending/`
|
|
740
|
+
// - "canonical" → mounted store `knowledge/{decisions,pitfalls,...}`
|
|
741
|
+
area: z3.enum(["pending", "canonical"]),
|
|
742
|
+
path: z3.string(),
|
|
743
|
+
path_absolute: z3.string().optional(),
|
|
744
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]),
|
|
745
|
+
layer: z3.enum(["team", "personal"]),
|
|
746
|
+
maturity: z3.enum(["draft", "verified", "proven"]),
|
|
747
|
+
tags: z3.array(z3.string()).optional(),
|
|
748
|
+
title: z3.string().optional(),
|
|
749
|
+
summary: z3.string().optional(),
|
|
750
|
+
origin: z3.enum(["team", "personal"]).optional(),
|
|
751
|
+
status: z3.enum(["active", "rejected", "deferred"]).optional(),
|
|
752
|
+
deferred_until: z3.string().datetime().optional(),
|
|
753
|
+
body: z3.string().optional(),
|
|
656
754
|
// For pending hits the upstream stable_id may still be unassigned — keep it
|
|
657
755
|
// optional so canonical hits (which always have one) parse alongside pending
|
|
658
756
|
// hits in the same array.
|
|
659
|
-
stable_id:
|
|
757
|
+
stable_id: z3.string().optional()
|
|
660
758
|
});
|
|
661
|
-
var FabReviewOutputSchema =
|
|
662
|
-
|
|
663
|
-
action:
|
|
664
|
-
items:
|
|
665
|
-
warnings:
|
|
759
|
+
var FabReviewOutputSchema = z3.discriminatedUnion("action", [
|
|
760
|
+
z3.object({
|
|
761
|
+
action: z3.literal("list"),
|
|
762
|
+
items: z3.array(_fabReviewListItemSchema),
|
|
763
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
666
764
|
}),
|
|
667
|
-
|
|
668
|
-
action:
|
|
669
|
-
approved:
|
|
670
|
-
warnings:
|
|
765
|
+
z3.object({
|
|
766
|
+
action: z3.literal("approve"),
|
|
767
|
+
approved: z3.array(z3.object({ pending_path: z3.string(), stable_id: z3.string() })),
|
|
768
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
671
769
|
}),
|
|
672
|
-
|
|
673
|
-
action:
|
|
674
|
-
rejected:
|
|
675
|
-
warnings:
|
|
770
|
+
z3.object({
|
|
771
|
+
action: z3.literal("reject"),
|
|
772
|
+
rejected: z3.array(z3.string()),
|
|
773
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
676
774
|
}),
|
|
677
|
-
|
|
678
|
-
action:
|
|
679
|
-
pending_path:
|
|
775
|
+
z3.object({
|
|
776
|
+
action: z3.literal("modify"),
|
|
777
|
+
pending_path: z3.string(),
|
|
680
778
|
// When a layer-flip occurred, prior_stable_id and new_stable_id differ.
|
|
681
|
-
prior_stable_id:
|
|
682
|
-
new_stable_id:
|
|
683
|
-
warnings:
|
|
779
|
+
prior_stable_id: z3.string().optional(),
|
|
780
|
+
new_stable_id: z3.string().optional(),
|
|
781
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
684
782
|
}),
|
|
685
|
-
|
|
686
|
-
action:
|
|
783
|
+
z3.object({
|
|
784
|
+
action: z3.literal("search"),
|
|
687
785
|
// v2.0.0-rc.29 TASK-007 (BUG-M4): search returns the new search-item
|
|
688
786
|
// shape with `area` discriminator + neutrally-named `path` field.
|
|
689
|
-
items:
|
|
690
|
-
warnings:
|
|
787
|
+
items: z3.array(_fabReviewSearchItemSchema),
|
|
788
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
691
789
|
}),
|
|
692
|
-
|
|
693
|
-
action:
|
|
694
|
-
deferred:
|
|
695
|
-
warnings:
|
|
790
|
+
z3.object({
|
|
791
|
+
action: z3.literal("defer"),
|
|
792
|
+
deferred: z3.array(z3.string()),
|
|
793
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
696
794
|
})
|
|
697
795
|
]);
|
|
698
796
|
var FabReviewOutputShape = {
|
|
699
|
-
action:
|
|
797
|
+
action: z3.enum(["list", "approve", "reject", "modify", "search", "defer"]).describe(
|
|
700
798
|
"Echoes the input action; clients can switch on it for per-variant fields below."
|
|
701
799
|
),
|
|
702
|
-
items:
|
|
800
|
+
items: z3.array(z3.union([_fabReviewListItemSchema, _fabReviewSearchItemSchema])).optional().describe(
|
|
703
801
|
"Pending entries (action=list, `pending_path` shape) or pending+canonical entries (action=search, `area`+`path` shape)."
|
|
704
802
|
),
|
|
705
|
-
approved:
|
|
803
|
+
approved: z3.array(z3.object({ pending_path: z3.string(), stable_id: z3.string() })).optional().describe(
|
|
706
804
|
"Allocated stable ids paired with their original pending paths. Present when action=approve."
|
|
707
805
|
),
|
|
708
|
-
rejected:
|
|
806
|
+
rejected: z3.array(z3.string()).optional().describe(
|
|
709
807
|
"Pending paths that were rejected (files retained on disk; doctor owns vacuum). Present when action=reject."
|
|
710
808
|
),
|
|
711
|
-
pending_path:
|
|
809
|
+
pending_path: z3.string().optional().describe(
|
|
712
810
|
"Echoed target path for the modification. Present when action=modify."
|
|
713
811
|
),
|
|
714
|
-
prior_stable_id:
|
|
812
|
+
prior_stable_id: z3.string().optional().describe(
|
|
715
813
|
"Prior stable id. Present when action=modify AND a layer-flip reallocated the id."
|
|
716
814
|
),
|
|
717
|
-
new_stable_id:
|
|
815
|
+
new_stable_id: z3.string().optional().describe(
|
|
718
816
|
"New stable id after reallocation. Present when action=modify AND a layer-flip reallocated the id."
|
|
719
817
|
),
|
|
720
|
-
deferred:
|
|
818
|
+
deferred: z3.array(z3.string()).optional().describe(
|
|
721
819
|
"Pending paths that were deferred (files retained on disk). Present when action=defer."
|
|
722
820
|
),
|
|
723
821
|
// v2.0.0-rc.23 TASK-009 (d): optional warnings surface for the first-reconcile
|
|
724
822
|
// gate (`meta_stale` / `reconcile_failed`). Absent on the steady-state path.
|
|
725
|
-
warnings:
|
|
823
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
726
824
|
};
|
|
727
825
|
var fabReviewAnnotations = {
|
|
728
826
|
readOnlyHint: false,
|
|
@@ -731,35 +829,35 @@ var fabReviewAnnotations = {
|
|
|
731
829
|
openWorldHint: false,
|
|
732
830
|
title: "Review pending knowledge entries"
|
|
733
831
|
};
|
|
734
|
-
var citeContractMetricsSchema =
|
|
735
|
-
decisions_cited:
|
|
736
|
-
pitfalls_cited:
|
|
737
|
-
contract_with:
|
|
738
|
-
contract_missing:
|
|
739
|
-
hard_violated:
|
|
740
|
-
cite_id_unresolved:
|
|
741
|
-
skip_count:
|
|
832
|
+
var citeContractMetricsSchema = z3.object({
|
|
833
|
+
decisions_cited: z3.number().int().nonnegative(),
|
|
834
|
+
pitfalls_cited: z3.number().int().nonnegative(),
|
|
835
|
+
contract_with: z3.number().int().nonnegative(),
|
|
836
|
+
contract_missing: z3.number().int().nonnegative(),
|
|
837
|
+
hard_violated: z3.number().int().nonnegative(),
|
|
838
|
+
cite_id_unresolved: z3.number().int().nonnegative(),
|
|
839
|
+
skip_count: z3.record(z3.string(), z3.number().int().nonnegative())
|
|
742
840
|
});
|
|
743
|
-
var citeLayerTypeBreakdownSchema =
|
|
744
|
-
team:
|
|
745
|
-
personal:
|
|
841
|
+
var citeLayerTypeBreakdownSchema = z3.object({
|
|
842
|
+
team: z3.record(z3.string(), z3.number().int().nonnegative()),
|
|
843
|
+
personal: z3.record(z3.string(), z3.number().int().nonnegative())
|
|
746
844
|
});
|
|
747
|
-
var citeCoverageReportSchema =
|
|
748
|
-
status:
|
|
749
|
-
marker_ts:
|
|
750
|
-
marker_emitted_now:
|
|
751
|
-
since_ts:
|
|
752
|
-
client_filter:
|
|
845
|
+
var citeCoverageReportSchema = z3.object({
|
|
846
|
+
status: z3.enum(["ok", "skipped"]),
|
|
847
|
+
marker_ts: z3.number().int().nonnegative(),
|
|
848
|
+
marker_emitted_now: z3.boolean(),
|
|
849
|
+
since_ts: z3.number().int().nonnegative(),
|
|
850
|
+
client_filter: z3.enum(["cc", "codex", "all"]),
|
|
753
851
|
// v2.0.0-rc.24 TASK-08: layer filter discriminator. Optional so pre-TASK-10
|
|
754
852
|
// CLI callers (which never set the flag) still parse. Defaults to "all" at
|
|
755
853
|
// the service layer.
|
|
756
|
-
layer_filter:
|
|
757
|
-
metrics:
|
|
758
|
-
edits_touched:
|
|
759
|
-
qualifying_cites:
|
|
760
|
-
recalled_unverified:
|
|
761
|
-
expected_but_missed:
|
|
762
|
-
total_turns:
|
|
854
|
+
layer_filter: z3.enum(["team", "personal", "all"]).optional(),
|
|
855
|
+
metrics: z3.object({
|
|
856
|
+
edits_touched: z3.number().int().nonnegative(),
|
|
857
|
+
qualifying_cites: z3.number().int().nonnegative(),
|
|
858
|
+
recalled_unverified: z3.number().int().nonnegative(),
|
|
859
|
+
expected_but_missed: z3.number().int().nonnegative(),
|
|
860
|
+
total_turns: z3.number().int().nonnegative(),
|
|
763
861
|
// v2.0.0-rc.38 UX-8 (C, user-authorized): cite-policy COMPLIANCE rate —
|
|
764
862
|
// the corrected G-CITE semantic. The legacy qualifying_cites/edits ratio
|
|
765
863
|
// measured "how often an applicable KB id existed" (a function of corpus
|
|
@@ -768,38 +866,102 @@ var citeCoverageReportSchema = z2.object({
|
|
|
768
866
|
// `KB: none [reason]` (the policy explicitly allows the none sentinel) —
|
|
769
867
|
// over the turns where a cite was expected. null when no cite-expected
|
|
770
868
|
// turns observed (avoids a misleading 0/0 → 0). Range [0,1].
|
|
771
|
-
cite_compliance_rate:
|
|
772
|
-
compliant_cites:
|
|
773
|
-
noncompliant_cites:
|
|
869
|
+
cite_compliance_rate: z3.number().min(0).max(1).nullable().optional(),
|
|
870
|
+
compliant_cites: z3.number().int().nonnegative().optional(),
|
|
871
|
+
noncompliant_cites: z3.number().int().nonnegative().optional(),
|
|
774
872
|
// Edit signals lacking session_id → uncorrelatable, silently excluded from
|
|
775
873
|
// expected_but_missed. >0 typically means a stale pre-session_id hook is
|
|
776
874
|
// installed (run `fabric install`). Surfaced so the denominator gap is
|
|
777
875
|
// visible rather than a silent 100% confound.
|
|
778
|
-
uncorrelatable_edits:
|
|
876
|
+
uncorrelatable_edits: z3.number().int().nonnegative().optional(),
|
|
877
|
+
// v2.1 ⑤ cite-redesign (P5): recall-based coverage口径. The redesign infers
|
|
878
|
+
// a citation from real behavior — an in-session fab_recall
|
|
879
|
+
// (knowledge_context_planned) whose target_paths overlap a subsequently
|
|
880
|
+
// edited file IS the citation, no hand-written `KB:` line required.
|
|
881
|
+
// recall_backed_edits = correlatable edits preceded (within the recall
|
|
882
|
+
// window) by such an overlapping recall. recall_coverage_rate =
|
|
883
|
+
// recall_backed_edits / edits_touched (null when no edits). Additive — the
|
|
884
|
+
// legacy first-line-`KB:` metrics above are unchanged (back-compat).
|
|
885
|
+
recall_backed_edits: z3.number().int().nonnegative().optional(),
|
|
886
|
+
recall_coverage_rate: z3.number().min(0).max(1).nullable().optional(),
|
|
887
|
+
// v2.2.0-rc.1 W1-T3 (cite 诚实拆分 / lifecycle §3): exposed_and_mutated is a
|
|
888
|
+
// WEAK auxiliary signal — strictly SEPARATE from cite_compliance_rate (which
|
|
889
|
+
// is the true explicit-adherence rate, currently ~2.5%). It MUST NOT be
|
|
890
|
+
// merged into compliance: it estimates "a narrow PreToolUse-surfaced KB id
|
|
891
|
+
// whose contract-specific glob was subsequently edited (mutated) in the same
|
|
892
|
+
// session, and was not [dismissed] that round". It credits NOTHING toward the
|
|
893
|
+
// real `KB:`-line compliance — it is an observational hint that surfaced
|
|
894
|
+
// knowledge influenced an edit, surfaced ONLY as its own field so the renderer
|
|
895
|
+
// can label it "weak signal, NOT counted toward true adherence". Three
|
|
896
|
+
// conditions (all required): (1) id came from a `hook_surface_emitted` with
|
|
897
|
+
// hook_name === "knowledge-hint-narrow"; (2) the id's contract glob is
|
|
898
|
+
// SPECIFIC (excludes `**/*` wildcards and generic guideline-type entries);
|
|
899
|
+
// (3) the id was not [dismissed] in the same session. `count` = number of
|
|
900
|
+
// distinct (session_id, stable_id) pairs satisfying all three; `ids` =
|
|
901
|
+
// sorted distinct stable_ids (capped, diagnostics only). Always >= 0; null/
|
|
902
|
+
// absent on degraded/skipped reports.
|
|
903
|
+
exposed_and_mutated: z3.object({
|
|
904
|
+
count: z3.number().int().nonnegative(),
|
|
905
|
+
ids: z3.array(z3.string()).optional()
|
|
906
|
+
}).optional(),
|
|
907
|
+
// lifecycle-refactor W2-T4 (§5 row7 PostToolUse / §0 下沉 doctor): mutation
|
|
908
|
+
// funnel rebuilt offline from the new `file_mutated` PostToolUse marker —
|
|
909
|
+
// the权威 signal that a mutation actually completed (path + tool_call_id),
|
|
910
|
+
// distinct from the PreToolUse `edit_intent_checked` EDIT-INTENT signal that
|
|
911
|
+
// feeds `edits_touched`. mutations_observed.count = number of distinct
|
|
912
|
+
// `file_mutated` events in window (per-call tool_call_id dedup guards the
|
|
913
|
+
// PostToolUse parallel-fire race). Strictly ADDITIVE — never folded into
|
|
914
|
+
// cite_compliance_rate (honesty 铁律, mirrors exposed_and_mutated). Absent on
|
|
915
|
+
// degraded/skipped reports.
|
|
916
|
+
mutations_observed: z3.object({
|
|
917
|
+
count: z3.number().int().nonnegative()
|
|
918
|
+
}).optional(),
|
|
919
|
+
// lifecycle-refactor W2-T4 (§5 row7 mutation_pool + downgrade): low-confidence
|
|
920
|
+
// mutation attribution pool. A `file_mutated` event is `attributed` ONLY when
|
|
921
|
+
// its `source_event_id` links back to a `hook_surface_emitted` (surfaced/cited
|
|
922
|
+
// knowledge) in window — attribution key = store_id + stable_id +
|
|
923
|
+
// source_event_id (distinct dedup so multi-store never double-counts). Every
|
|
924
|
+
// other mutation (no source_event_id, or a source_event_id that does not
|
|
925
|
+
// resolve to a surfaced event) downgrades to `unattributed_workspace_dirty`.
|
|
926
|
+
// NOTE: this is the events.jsonl-only attribution. The §9 git-diff fallback
|
|
927
|
+
// (升 fallback via session shell event + baseline) is a SPECULATIVE
|
|
928
|
+
// implementation note — deliberately NOT run here (doctor stays read-only,
|
|
929
|
+
// no git diff / no disk write). Additive; absent on degraded/skipped reports.
|
|
930
|
+
mutation_pool: z3.object({
|
|
931
|
+
attributed: z3.number().int().nonnegative(),
|
|
932
|
+
unattributed_workspace_dirty: z3.number().int().nonnegative()
|
|
933
|
+
}).optional(),
|
|
934
|
+
// lifecycle-refactor W2-T4 (§5 row2 SessionEnd funnel 对账下沉 doctor): the
|
|
935
|
+
// SessionEnd hook only O(1)-appends a `session_ended` marker; this counts the
|
|
936
|
+
// distinct sessions that emitted one (funnel "closed" boundary). Purely an
|
|
937
|
+
// observability marker — not joined into any rate. Additive.
|
|
938
|
+
sessions_closed: z3.object({
|
|
939
|
+
count: z3.number().int().nonnegative()
|
|
940
|
+
}).optional()
|
|
779
941
|
}),
|
|
780
|
-
per_client:
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
edits_touched:
|
|
784
|
-
qualifying_cites:
|
|
785
|
-
recalled_unverified:
|
|
786
|
-
expected_but_missed:
|
|
787
|
-
total_turns:
|
|
942
|
+
per_client: z3.record(
|
|
943
|
+
z3.string(),
|
|
944
|
+
z3.object({
|
|
945
|
+
edits_touched: z3.number().int().nonnegative().optional(),
|
|
946
|
+
qualifying_cites: z3.number().int().nonnegative().optional(),
|
|
947
|
+
recalled_unverified: z3.number().int().nonnegative().optional(),
|
|
948
|
+
expected_but_missed: z3.number().int().nonnegative().optional(),
|
|
949
|
+
total_turns: z3.number().int().nonnegative().optional()
|
|
788
950
|
})
|
|
789
951
|
).optional(),
|
|
790
|
-
dismissed_reason_histogram:
|
|
791
|
-
none_reason_histogram:
|
|
952
|
+
dismissed_reason_histogram: z3.record(z3.string(), z3.number().int().nonnegative()).optional(),
|
|
953
|
+
none_reason_histogram: z3.record(z3.string(), z3.number().int().nonnegative()).optional(),
|
|
792
954
|
// v2.0.0-rc.24 TASK-08: contract-policy audit metrics. Status discriminates
|
|
793
955
|
// populated vs degraded modes. contract_metrics + per_layer_type are emitted
|
|
794
956
|
// (zeroed) in degraded modes so the renderer iterates one stable shape.
|
|
795
|
-
contract_metrics_status:
|
|
957
|
+
contract_metrics_status: z3.enum(["ok", "skipped:bootstrap_drift", "awaiting_marker"]).optional(),
|
|
796
958
|
contract_metrics: citeContractMetricsSchema.optional(),
|
|
797
959
|
per_layer_type: citeLayerTypeBreakdownSchema.optional(),
|
|
798
|
-
contract_marker_ts:
|
|
799
|
-
generated_at:
|
|
960
|
+
contract_marker_ts: z3.number().int().nonnegative().optional(),
|
|
961
|
+
generated_at: z3.string()
|
|
800
962
|
});
|
|
801
|
-
var ledgerSourceSchema =
|
|
802
|
-
var timestampFilterSchema =
|
|
963
|
+
var ledgerSourceSchema = z3.enum(["ai", "human"]);
|
|
964
|
+
var timestampFilterSchema = z3.preprocess((value) => {
|
|
803
965
|
if (value === void 0 || value === null || value === "") {
|
|
804
966
|
return void 0;
|
|
805
967
|
}
|
|
@@ -818,38 +980,38 @@ var timestampFilterSchema = z2.preprocess((value) => {
|
|
|
818
980
|
return Number.isNaN(parsed) ? value : parsed;
|
|
819
981
|
}
|
|
820
982
|
return value;
|
|
821
|
-
},
|
|
822
|
-
var ledgerQuerySchema =
|
|
983
|
+
}, z3.number().int().nonnegative());
|
|
984
|
+
var ledgerQuerySchema = z3.object({
|
|
823
985
|
source: ledgerSourceSchema.optional(),
|
|
824
986
|
since: timestampFilterSchema.optional()
|
|
825
987
|
});
|
|
826
|
-
var historyStateQuerySchema =
|
|
827
|
-
ledger_id:
|
|
988
|
+
var historyStateQuerySchema = z3.object({
|
|
989
|
+
ledger_id: z3.string().trim().min(1).optional(),
|
|
828
990
|
ts: timestampFilterSchema.optional()
|
|
829
991
|
}).superRefine((value, ctx) => {
|
|
830
992
|
const provided = [value.ledger_id, value.ts].filter((entry) => entry !== void 0);
|
|
831
993
|
if (provided.length !== 1) {
|
|
832
994
|
ctx.addIssue({
|
|
833
|
-
code:
|
|
995
|
+
code: z3.ZodIssueCode.custom,
|
|
834
996
|
message: "Provide exactly one of ledger_id or ts.",
|
|
835
997
|
path: ["ledger_id"]
|
|
836
998
|
});
|
|
837
999
|
}
|
|
838
1000
|
});
|
|
839
|
-
var humanLockApproveRequestSchema =
|
|
840
|
-
file:
|
|
841
|
-
start_line:
|
|
842
|
-
end_line:
|
|
843
|
-
new_hash:
|
|
1001
|
+
var humanLockApproveRequestSchema = z3.object({
|
|
1002
|
+
file: z3.string().min(1),
|
|
1003
|
+
start_line: z3.number().int().positive(),
|
|
1004
|
+
end_line: z3.number().int().positive(),
|
|
1005
|
+
new_hash: z3.string().min(1)
|
|
844
1006
|
});
|
|
845
|
-
var humanLockFileParamsSchema =
|
|
846
|
-
file:
|
|
1007
|
+
var humanLockFileParamsSchema = z3.object({
|
|
1008
|
+
file: z3.string().min(1)
|
|
847
1009
|
});
|
|
848
|
-
var annotateIntentRequestSchema =
|
|
849
|
-
ledger_entry_id:
|
|
850
|
-
annotation:
|
|
1010
|
+
var annotateIntentRequestSchema = z3.object({
|
|
1011
|
+
ledger_entry_id: z3.string().min(1),
|
|
1012
|
+
annotation: z3.string().trim().min(1)
|
|
851
1013
|
});
|
|
852
|
-
var KnowledgeTypeSchema =
|
|
1014
|
+
var KnowledgeTypeSchema = z3.enum([
|
|
853
1015
|
"models",
|
|
854
1016
|
// entities, data structures, relationships
|
|
855
1017
|
"decisions",
|
|
@@ -861,10 +1023,10 @@ var KnowledgeTypeSchema = z2.enum([
|
|
|
861
1023
|
"processes"
|
|
862
1024
|
// workflows, state machines, operational steps
|
|
863
1025
|
]);
|
|
864
|
-
var MaturitySchema =
|
|
865
|
-
var LayerSchema =
|
|
866
|
-
var StableIdSchema =
|
|
867
|
-
var KnowledgeEntryFrontmatterSchema =
|
|
1026
|
+
var MaturitySchema = z3.enum(["draft", "verified", "proven"]);
|
|
1027
|
+
var LayerSchema = z3.enum(["personal", "team"]);
|
|
1028
|
+
var StableIdSchema = z3.string().regex(/^K[PT]-(MOD|DEC|GLD|PIT|PRO)-\d{4,}$/);
|
|
1029
|
+
var KnowledgeEntryFrontmatterSchema = z3.object({
|
|
868
1030
|
id: StableIdSchema,
|
|
869
1031
|
// e.g., "KT-DEC-0042"
|
|
870
1032
|
type: KnowledgeTypeSchema,
|
|
@@ -873,9 +1035,9 @@ var KnowledgeEntryFrontmatterSchema = z2.object({
|
|
|
873
1035
|
// draft | verified | proven
|
|
874
1036
|
layer: LayerSchema,
|
|
875
1037
|
// personal | team
|
|
876
|
-
layer_reason:
|
|
1038
|
+
layer_reason: z3.string().optional(),
|
|
877
1039
|
// why this layer (for ambiguous cases)
|
|
878
|
-
created_at:
|
|
1040
|
+
created_at: z3.string()
|
|
879
1041
|
// ISO 8601 timestamp
|
|
880
1042
|
// Note: 'tags' and other fields can be added later but core schema is these 6
|
|
881
1043
|
});
|
|
@@ -906,6 +1068,13 @@ export {
|
|
|
906
1068
|
ONBOARD_SLOT_NAMES,
|
|
907
1069
|
onboardSlotSchema,
|
|
908
1070
|
ONBOARD_SLOT_TOTAL,
|
|
1071
|
+
PERSONAL_SCOPE,
|
|
1072
|
+
KNOWN_SCOPE_PREFIXES,
|
|
1073
|
+
SCOPE_COORDINATE_PATTERN,
|
|
1074
|
+
scopeCoordinateSchema,
|
|
1075
|
+
scopeRoot,
|
|
1076
|
+
isPersonalScope,
|
|
1077
|
+
entryScopeMetadataSchema,
|
|
909
1078
|
structuredWarningSchema,
|
|
910
1079
|
planContextInputSchema,
|
|
911
1080
|
planContextOutputSchema,
|
|
@@ -922,7 +1091,7 @@ export {
|
|
|
922
1091
|
archiveScanOutputSchema,
|
|
923
1092
|
archiveScanAnnotations,
|
|
924
1093
|
ProposedReasonSchema,
|
|
925
|
-
|
|
1094
|
+
PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE,
|
|
926
1095
|
FabExtractKnowledgeInputSchema,
|
|
927
1096
|
FabExtractKnowledgeInputShape,
|
|
928
1097
|
FabExtractKnowledgeOutputSchema,
|