@contractspec/example.kb-update-pipeline 1.57.0 → 1.59.0
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/.turbo/turbo-build.log +58 -60
- package/.turbo/turbo-prebuild.log +1 -0
- package/CHANGELOG.md +25 -0
- package/dist/browser/docs/index.js +43 -0
- package/dist/browser/docs/kb-update-pipeline.docblock.js +43 -0
- package/dist/browser/entities/index.js +56 -0
- package/dist/browser/entities/models.js +56 -0
- package/dist/browser/events.js +132 -0
- package/dist/browser/example.js +35 -0
- package/dist/browser/handlers/index.js +109 -0
- package/dist/browser/handlers/memory.handlers.js +109 -0
- package/dist/browser/index.js +646 -0
- package/dist/browser/kb-update-pipeline.feature.js +61 -0
- package/dist/browser/operations/index.js +199 -0
- package/dist/browser/operations/pipeline.js +199 -0
- package/dist/browser/presentations.js +120 -0
- package/dist/browser/tests/operations.test-spec.js +85 -0
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +44 -1
- package/dist/docs/kb-update-pipeline.docblock.d.ts +2 -1
- package/dist/docs/kb-update-pipeline.docblock.d.ts.map +1 -0
- package/dist/docs/kb-update-pipeline.docblock.js +41 -28
- package/dist/entities/index.d.ts +2 -2
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +57 -3
- package/dist/entities/models.d.ts +53 -58
- package/dist/entities/models.d.ts.map +1 -1
- package/dist/entities/models.js +54 -71
- package/dist/events.d.ts +62 -68
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +122 -139
- package/dist/example.d.ts +2 -6
- package/dist/example.d.ts.map +1 -1
- package/dist/example.js +34 -47
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +110 -3
- package/dist/handlers/memory.handlers.d.ts +58 -60
- package/dist/handlers/memory.handlers.d.ts.map +1 -1
- package/dist/handlers/memory.handlers.js +104 -87
- package/dist/handlers/memory.handlers.test.d.ts +2 -0
- package/dist/handlers/memory.handlers.test.d.ts.map +1 -0
- package/dist/index.d.ts +14 -10
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +647 -12
- package/dist/kb-update-pipeline.feature.d.ts +1 -6
- package/dist/kb-update-pipeline.feature.d.ts.map +1 -1
- package/dist/kb-update-pipeline.feature.js +60 -140
- package/dist/node/docs/index.js +43 -0
- package/dist/node/docs/kb-update-pipeline.docblock.js +43 -0
- package/dist/node/entities/index.js +56 -0
- package/dist/node/entities/models.js +56 -0
- package/dist/node/events.js +132 -0
- package/dist/node/example.js +35 -0
- package/dist/node/handlers/index.js +109 -0
- package/dist/node/handlers/memory.handlers.js +109 -0
- package/dist/node/index.js +646 -0
- package/dist/node/kb-update-pipeline.feature.js +61 -0
- package/dist/node/operations/index.js +199 -0
- package/dist/node/operations/pipeline.js +199 -0
- package/dist/node/presentations.js +120 -0
- package/dist/node/tests/operations.test-spec.js +85 -0
- package/dist/operations/index.d.ts +2 -2
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +199 -2
- package/dist/operations/pipeline.d.ts +126 -132
- package/dist/operations/pipeline.d.ts.map +1 -1
- package/dist/operations/pipeline.js +189 -172
- package/dist/presentations.d.ts +3 -8
- package/dist/presentations.d.ts.map +1 -1
- package/dist/presentations.js +117 -67
- package/dist/tests/operations.test-spec.d.ts +3 -8
- package/dist/tests/operations.test-spec.d.ts.map +1 -1
- package/dist/tests/operations.test-spec.js +82 -90
- package/package.json +157 -41
- package/tsdown.config.js +1 -2
- package/.turbo/turbo-build$colon$bundle.log +0 -60
- package/dist/docs/kb-update-pipeline.docblock.js.map +0 -1
- package/dist/entities/models.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/example.js.map +0 -1
- package/dist/handlers/memory.handlers.js.map +0 -1
- package/dist/kb-update-pipeline.feature.js.map +0 -1
- package/dist/operations/pipeline.js.map +0 -1
- package/dist/presentations.js.map +0 -1
- package/dist/tests/operations.test-spec.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,647 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
// @bun
|
|
2
|
+
// src/docs/kb-update-pipeline.docblock.ts
|
|
3
|
+
import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
|
|
4
|
+
var docBlocks = [
|
|
5
|
+
{
|
|
6
|
+
id: "docs.examples.kb-update-pipeline.goal",
|
|
7
|
+
title: "KB Update Pipeline \u2014 Goal",
|
|
8
|
+
summary: "Automation proposes KB patches; humans verify; publishing is blocked until approvals are complete.",
|
|
9
|
+
kind: "goal",
|
|
10
|
+
visibility: "public",
|
|
11
|
+
route: "/docs/examples/kb-update-pipeline/goal",
|
|
12
|
+
tags: ["knowledge", "pipeline", "hitl", "audit"],
|
|
13
|
+
body: `## Why it matters
|
|
14
|
+
- Keeps humans as the verifiers (HITL) while automation does the busywork.
|
|
15
|
+
- Produces an auditable chain: source change -> diff -> proposal -> review -> publish.
|
|
16
|
+
|
|
17
|
+
## Guardrails
|
|
18
|
+
- High-risk changes require expert approval.
|
|
19
|
+
- Publishing fails if any included rule versions are not approved.
|
|
20
|
+
- Review requests emit notifications/events.`
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "docs.examples.kb-update-pipeline.reference",
|
|
24
|
+
title: "KB Update Pipeline \u2014 Reference",
|
|
25
|
+
summary: "Entities, contracts, and events for the KB update pipeline example.",
|
|
26
|
+
kind: "reference",
|
|
27
|
+
visibility: "public",
|
|
28
|
+
route: "/docs/examples/kb-update-pipeline",
|
|
29
|
+
tags: ["knowledge", "reference"],
|
|
30
|
+
body: `## Contracts
|
|
31
|
+
- kbPipeline.runWatch
|
|
32
|
+
- kbPipeline.createReviewTask
|
|
33
|
+
- kbPipeline.submitDecision
|
|
34
|
+
- kbPipeline.publishIfReady
|
|
35
|
+
|
|
36
|
+
## Events
|
|
37
|
+
- kb.change.detected
|
|
38
|
+
- kb.change.summarized
|
|
39
|
+
- kb.patch.proposed
|
|
40
|
+
- kb.review.requested
|
|
41
|
+
- kb.review.decided`
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
registerDocBlocks(docBlocks);
|
|
45
|
+
// src/entities/models.ts
|
|
46
|
+
import {
|
|
47
|
+
ScalarTypeEnum,
|
|
48
|
+
defineEnum,
|
|
49
|
+
defineSchemaModel
|
|
50
|
+
} from "@contractspec/lib.schema";
|
|
51
|
+
var ChangeRiskLevelEnum = defineEnum("ChangeRiskLevel", [
|
|
52
|
+
"low",
|
|
53
|
+
"medium",
|
|
54
|
+
"high"
|
|
55
|
+
]);
|
|
56
|
+
var ReviewAssignedRoleEnum = defineEnum("ReviewAssignedRole", [
|
|
57
|
+
"curator",
|
|
58
|
+
"expert"
|
|
59
|
+
]);
|
|
60
|
+
var ReviewDecisionEnum = defineEnum("ReviewDecision", [
|
|
61
|
+
"approve",
|
|
62
|
+
"reject"
|
|
63
|
+
]);
|
|
64
|
+
var ChangeCandidateModel = defineSchemaModel({
|
|
65
|
+
name: "ChangeCandidate",
|
|
66
|
+
description: "Candidate change detected in a source document.",
|
|
67
|
+
fields: {
|
|
68
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
69
|
+
sourceDocumentId: {
|
|
70
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
71
|
+
isOptional: false
|
|
72
|
+
},
|
|
73
|
+
detectedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
74
|
+
diffSummary: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
75
|
+
riskLevel: { type: ChangeRiskLevelEnum, isOptional: false }
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
var ReviewTaskModel = defineSchemaModel({
|
|
79
|
+
name: "ReviewTask",
|
|
80
|
+
description: "Human verification task for a change candidate.",
|
|
81
|
+
fields: {
|
|
82
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
83
|
+
changeCandidateId: {
|
|
84
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
85
|
+
isOptional: false
|
|
86
|
+
},
|
|
87
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
88
|
+
assignedRole: { type: ReviewAssignedRoleEnum, isOptional: false },
|
|
89
|
+
decision: { type: ReviewDecisionEnum, isOptional: true },
|
|
90
|
+
decidedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
91
|
+
decidedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// src/events.ts
|
|
95
|
+
import {
|
|
96
|
+
defineEvent,
|
|
97
|
+
defineSchemaModel as defineSchemaModel2,
|
|
98
|
+
StabilityEnum
|
|
99
|
+
} from "@contractspec/lib.contracts";
|
|
100
|
+
import { ScalarTypeEnum as ScalarTypeEnum2 } from "@contractspec/lib.schema";
|
|
101
|
+
var KbChangeDetectedPayload = defineSchemaModel2({
|
|
102
|
+
name: "KbChangeDetectedPayload",
|
|
103
|
+
description: "Emitted when a source change is detected.",
|
|
104
|
+
fields: {
|
|
105
|
+
changeCandidateId: {
|
|
106
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
107
|
+
isOptional: false
|
|
108
|
+
},
|
|
109
|
+
sourceDocumentId: {
|
|
110
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
111
|
+
isOptional: false
|
|
112
|
+
},
|
|
113
|
+
riskLevel: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
var KbChangeDetectedEvent = defineEvent({
|
|
117
|
+
meta: {
|
|
118
|
+
key: "kb.change.detected",
|
|
119
|
+
version: "1.0.0",
|
|
120
|
+
description: "KB source change detected.",
|
|
121
|
+
stability: StabilityEnum.Experimental,
|
|
122
|
+
owners: [],
|
|
123
|
+
tags: []
|
|
124
|
+
},
|
|
125
|
+
payload: KbChangeDetectedPayload
|
|
126
|
+
});
|
|
127
|
+
var KbChangeSummarizedPayload = defineSchemaModel2({
|
|
128
|
+
name: "KbChangeSummarizedPayload",
|
|
129
|
+
description: "Emitted when a change summary is produced.",
|
|
130
|
+
fields: {
|
|
131
|
+
changeCandidateId: {
|
|
132
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
133
|
+
isOptional: false
|
|
134
|
+
},
|
|
135
|
+
summary: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
136
|
+
riskLevel: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
var KbChangeSummarizedEvent = defineEvent({
|
|
140
|
+
meta: {
|
|
141
|
+
key: "kb.change.summarized",
|
|
142
|
+
version: "1.0.0",
|
|
143
|
+
description: "KB change summarized.",
|
|
144
|
+
stability: StabilityEnum.Experimental,
|
|
145
|
+
owners: [],
|
|
146
|
+
tags: []
|
|
147
|
+
},
|
|
148
|
+
payload: KbChangeSummarizedPayload
|
|
149
|
+
});
|
|
150
|
+
var KbPatchProposedPayload = defineSchemaModel2({
|
|
151
|
+
name: "KbPatchProposedPayload",
|
|
152
|
+
description: "Emitted when draft rule patches are proposed.",
|
|
153
|
+
fields: {
|
|
154
|
+
changeCandidateId: {
|
|
155
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
156
|
+
isOptional: false
|
|
157
|
+
},
|
|
158
|
+
proposedRuleVersionIds: {
|
|
159
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
160
|
+
isArray: true,
|
|
161
|
+
isOptional: false
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
var KbPatchProposedEvent = defineEvent({
|
|
166
|
+
meta: {
|
|
167
|
+
key: "kb.patch.proposed",
|
|
168
|
+
version: "1.0.0",
|
|
169
|
+
description: "KB rule patch proposed (draft versions created).",
|
|
170
|
+
stability: StabilityEnum.Experimental,
|
|
171
|
+
owners: [],
|
|
172
|
+
tags: []
|
|
173
|
+
},
|
|
174
|
+
payload: KbPatchProposedPayload
|
|
175
|
+
});
|
|
176
|
+
var KbReviewRequestedPayload = defineSchemaModel2({
|
|
177
|
+
name: "KbReviewRequestedPayload",
|
|
178
|
+
description: "Emitted when a review is requested.",
|
|
179
|
+
fields: {
|
|
180
|
+
reviewTaskId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
181
|
+
changeCandidateId: {
|
|
182
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
183
|
+
isOptional: false
|
|
184
|
+
},
|
|
185
|
+
assignedRole: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
var KbReviewRequestedEvent = defineEvent({
|
|
189
|
+
meta: {
|
|
190
|
+
key: "kb.review.requested",
|
|
191
|
+
version: "1.0.0",
|
|
192
|
+
description: "KB review requested.",
|
|
193
|
+
stability: StabilityEnum.Experimental,
|
|
194
|
+
owners: [],
|
|
195
|
+
tags: []
|
|
196
|
+
},
|
|
197
|
+
payload: KbReviewRequestedPayload
|
|
198
|
+
});
|
|
199
|
+
var KbReviewDecidedPayload = defineSchemaModel2({
|
|
200
|
+
name: "KbReviewDecidedPayload",
|
|
201
|
+
description: "Emitted when a review task is decided.",
|
|
202
|
+
fields: {
|
|
203
|
+
reviewTaskId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
204
|
+
decision: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
205
|
+
decidedBy: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
var KbReviewDecidedEvent = defineEvent({
|
|
209
|
+
meta: {
|
|
210
|
+
key: "kb.review.decided",
|
|
211
|
+
version: "1.0.0",
|
|
212
|
+
description: "KB review decided.",
|
|
213
|
+
stability: StabilityEnum.Experimental,
|
|
214
|
+
owners: [],
|
|
215
|
+
tags: []
|
|
216
|
+
},
|
|
217
|
+
payload: KbReviewDecidedPayload
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// src/example.ts
|
|
221
|
+
import { defineExample } from "@contractspec/lib.contracts";
|
|
222
|
+
var example = defineExample({
|
|
223
|
+
meta: {
|
|
224
|
+
key: "kb-update-pipeline",
|
|
225
|
+
version: "1.0.0",
|
|
226
|
+
title: "KB Update Pipeline",
|
|
227
|
+
description: "Automation proposes KB updates; humans verify; everything audited and notified.",
|
|
228
|
+
kind: "knowledge",
|
|
229
|
+
visibility: "public",
|
|
230
|
+
stability: "experimental",
|
|
231
|
+
owners: ["@platform.core"],
|
|
232
|
+
tags: ["knowledge", "pipeline", "hitl", "audit"]
|
|
233
|
+
},
|
|
234
|
+
docs: {
|
|
235
|
+
rootDocId: "docs.examples.kb-update-pipeline"
|
|
236
|
+
},
|
|
237
|
+
entrypoints: {
|
|
238
|
+
packageName: "@contractspec/example.kb-update-pipeline",
|
|
239
|
+
feature: "./feature",
|
|
240
|
+
contracts: "./contracts",
|
|
241
|
+
handlers: "./handlers",
|
|
242
|
+
docs: "./docs"
|
|
243
|
+
},
|
|
244
|
+
surfaces: {
|
|
245
|
+
templates: true,
|
|
246
|
+
sandbox: { enabled: true, modes: ["markdown", "specs", "builder"] },
|
|
247
|
+
studio: { enabled: true, installable: true },
|
|
248
|
+
mcp: { enabled: true }
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
var example_default = example;
|
|
252
|
+
|
|
253
|
+
// src/handlers/memory.handlers.ts
|
|
254
|
+
function createPipelineMemoryStore() {
|
|
255
|
+
return {
|
|
256
|
+
candidates: new Map,
|
|
257
|
+
reviewTasks: new Map,
|
|
258
|
+
proposedRuleVersionIdsByCandidate: new Map,
|
|
259
|
+
approvedRuleVersionIds: new Set,
|
|
260
|
+
notifications: []
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function stableId(prefix, value) {
|
|
264
|
+
return `${prefix}_${value.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
265
|
+
}
|
|
266
|
+
function createPipelineMemoryHandlers(store) {
|
|
267
|
+
async function runWatch(input) {
|
|
268
|
+
const candidates = [...store.candidates.values()].filter((c) => c.sourceDocumentId.startsWith(`${input.jurisdiction}_`) || true);
|
|
269
|
+
return { candidates };
|
|
270
|
+
}
|
|
271
|
+
async function createReviewTask(input) {
|
|
272
|
+
const candidate = store.candidates.get(input.changeCandidateId);
|
|
273
|
+
if (!candidate)
|
|
274
|
+
throw new Error("CHANGE_CANDIDATE_NOT_FOUND");
|
|
275
|
+
const assignedRole = candidate.riskLevel === "high" ? "expert" : "curator";
|
|
276
|
+
const id = stableId("review", input.changeCandidateId);
|
|
277
|
+
const task = {
|
|
278
|
+
id,
|
|
279
|
+
changeCandidateId: input.changeCandidateId,
|
|
280
|
+
status: "open",
|
|
281
|
+
assignedRole,
|
|
282
|
+
decision: undefined,
|
|
283
|
+
decidedAt: undefined,
|
|
284
|
+
decidedBy: undefined
|
|
285
|
+
};
|
|
286
|
+
store.reviewTasks.set(id, task);
|
|
287
|
+
store.notifications.push({
|
|
288
|
+
kind: "kb.review.requested",
|
|
289
|
+
reviewTaskId: id,
|
|
290
|
+
changeCandidateId: input.changeCandidateId,
|
|
291
|
+
assignedRole,
|
|
292
|
+
createdAt: new Date
|
|
293
|
+
});
|
|
294
|
+
return task;
|
|
295
|
+
}
|
|
296
|
+
async function proposeRulePatch(input) {
|
|
297
|
+
if (!store.candidates.has(input.changeCandidateId)) {
|
|
298
|
+
throw new Error("CHANGE_CANDIDATE_NOT_FOUND");
|
|
299
|
+
}
|
|
300
|
+
store.proposedRuleVersionIdsByCandidate.set(input.changeCandidateId, [
|
|
301
|
+
...input.proposedRuleVersionIds
|
|
302
|
+
]);
|
|
303
|
+
return { proposedRuleVersionIds: [...input.proposedRuleVersionIds] };
|
|
304
|
+
}
|
|
305
|
+
async function markRuleVersionApproved(input) {
|
|
306
|
+
store.approvedRuleVersionIds.add(input.ruleVersionId);
|
|
307
|
+
return { ruleVersionId: input.ruleVersionId };
|
|
308
|
+
}
|
|
309
|
+
async function submitDecision(input) {
|
|
310
|
+
const task = store.reviewTasks.get(input.reviewTaskId);
|
|
311
|
+
if (!task)
|
|
312
|
+
throw new Error("REVIEW_TASK_NOT_FOUND");
|
|
313
|
+
const candidate = store.candidates.get(task.changeCandidateId);
|
|
314
|
+
if (!candidate)
|
|
315
|
+
throw new Error("CHANGE_CANDIDATE_NOT_FOUND");
|
|
316
|
+
if (candidate.riskLevel === "high" && input.decision === "approve") {
|
|
317
|
+
if (input.decidedByRole !== "expert")
|
|
318
|
+
throw new Error("FORBIDDEN_ROLE");
|
|
319
|
+
}
|
|
320
|
+
const decided = {
|
|
321
|
+
...task,
|
|
322
|
+
status: "decided",
|
|
323
|
+
decision: input.decision,
|
|
324
|
+
decidedAt: new Date,
|
|
325
|
+
decidedBy: input.decidedBy
|
|
326
|
+
};
|
|
327
|
+
store.reviewTasks.set(decided.id, decided);
|
|
328
|
+
return decided;
|
|
329
|
+
}
|
|
330
|
+
async function publishIfReady(_input) {
|
|
331
|
+
const openTasks = [...store.reviewTasks.values()].filter((t) => t.status !== "decided");
|
|
332
|
+
if (openTasks.length) {
|
|
333
|
+
throw new Error("NOT_READY");
|
|
334
|
+
}
|
|
335
|
+
const rejected = [...store.reviewTasks.values()].some((t) => t.decision === "reject");
|
|
336
|
+
if (rejected)
|
|
337
|
+
return { published: false, reason: "REJECTED" };
|
|
338
|
+
for (const task of store.reviewTasks.values()) {
|
|
339
|
+
if (task.decision !== "approve")
|
|
340
|
+
continue;
|
|
341
|
+
const proposed = store.proposedRuleVersionIdsByCandidate.get(task.changeCandidateId) ?? [];
|
|
342
|
+
const unapproved = proposed.filter((id) => !store.approvedRuleVersionIds.has(id));
|
|
343
|
+
if (unapproved.length) {
|
|
344
|
+
throw new Error("NOT_READY");
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return { published: true };
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
runWatch,
|
|
351
|
+
createReviewTask,
|
|
352
|
+
proposeRulePatch,
|
|
353
|
+
markRuleVersionApproved,
|
|
354
|
+
submitDecision,
|
|
355
|
+
publishIfReady
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
// src/operations/pipeline.ts
|
|
359
|
+
import { defineCommand } from "@contractspec/lib.contracts";
|
|
360
|
+
import { ScalarTypeEnum as ScalarTypeEnum3, defineSchemaModel as defineSchemaModel3 } from "@contractspec/lib.schema";
|
|
361
|
+
var RunWatchInput = defineSchemaModel3({
|
|
362
|
+
name: "KbPipelineRunWatchInput",
|
|
363
|
+
description: "Trigger a watch cycle for KB sources (demo).",
|
|
364
|
+
fields: {
|
|
365
|
+
jurisdiction: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
var RunWatchOutput = defineSchemaModel3({
|
|
369
|
+
name: "KbPipelineRunWatchOutput",
|
|
370
|
+
description: "Output containing detected changes.",
|
|
371
|
+
fields: {
|
|
372
|
+
candidates: {
|
|
373
|
+
type: ChangeCandidateModel,
|
|
374
|
+
isArray: true,
|
|
375
|
+
isOptional: false
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
var CreateReviewTaskInput = defineSchemaModel3({
|
|
380
|
+
name: "KbPipelineCreateReviewTaskInput",
|
|
381
|
+
description: "Create a review task for a change candidate.",
|
|
382
|
+
fields: {
|
|
383
|
+
changeCandidateId: {
|
|
384
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
385
|
+
isOptional: false
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
var SubmitDecisionInput = defineSchemaModel3({
|
|
390
|
+
name: "KbPipelineSubmitDecisionInput",
|
|
391
|
+
description: "Submit a decision for a review task.",
|
|
392
|
+
fields: {
|
|
393
|
+
reviewTaskId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
394
|
+
decision: { type: ReviewDecisionEnum, isOptional: false },
|
|
395
|
+
decidedBy: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
396
|
+
decidedByRole: {
|
|
397
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
398
|
+
isOptional: false
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
var PublishIfReadyInput = defineSchemaModel3({
|
|
403
|
+
name: "KbPipelinePublishIfReadyInput",
|
|
404
|
+
description: "Publish snapshot if approvals are satisfied for a jurisdiction.",
|
|
405
|
+
fields: {
|
|
406
|
+
jurisdiction: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
var PublishIfReadyOutput = defineSchemaModel3({
|
|
410
|
+
name: "KbPipelinePublishIfReadyOutput",
|
|
411
|
+
description: "Output for publish-if-ready operation.",
|
|
412
|
+
fields: {
|
|
413
|
+
published: { type: ScalarTypeEnum3.Boolean(), isOptional: false },
|
|
414
|
+
reason: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true }
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
var KbPipelineRunWatchContract = defineCommand({
|
|
418
|
+
meta: {
|
|
419
|
+
key: "kbPipeline.runWatch",
|
|
420
|
+
version: "1.0.0",
|
|
421
|
+
stability: "experimental",
|
|
422
|
+
owners: ["@examples"],
|
|
423
|
+
tags: ["knowledge", "pipeline", "jobs"],
|
|
424
|
+
description: "Detect source changes and create change candidates.",
|
|
425
|
+
goal: "Automate discovery of updates needing review.",
|
|
426
|
+
context: "Scheduled job or manual trigger in demos."
|
|
427
|
+
},
|
|
428
|
+
io: { input: RunWatchInput, output: RunWatchOutput },
|
|
429
|
+
policy: { auth: "user" }
|
|
430
|
+
});
|
|
431
|
+
var KbPipelineCreateReviewTaskContract = defineCommand({
|
|
432
|
+
meta: {
|
|
433
|
+
key: "kbPipeline.createReviewTask",
|
|
434
|
+
version: "1.0.0",
|
|
435
|
+
stability: "experimental",
|
|
436
|
+
owners: ["@examples"],
|
|
437
|
+
tags: ["knowledge", "pipeline", "hitl"],
|
|
438
|
+
description: "Create a review task for a detected change.",
|
|
439
|
+
goal: "Route work to human verifiers.",
|
|
440
|
+
context: "Called after change detection or manual selection."
|
|
441
|
+
},
|
|
442
|
+
io: { input: CreateReviewTaskInput, output: ReviewTaskModel },
|
|
443
|
+
policy: { auth: "user" }
|
|
444
|
+
});
|
|
445
|
+
var KbPipelineSubmitDecisionContract = defineCommand({
|
|
446
|
+
meta: {
|
|
447
|
+
key: "kbPipeline.submitDecision",
|
|
448
|
+
version: "1.0.0",
|
|
449
|
+
stability: "experimental",
|
|
450
|
+
owners: ["@examples"],
|
|
451
|
+
tags: ["knowledge", "pipeline", "hitl", "rbac"],
|
|
452
|
+
description: "Submit approve/reject decision for a review task.",
|
|
453
|
+
goal: "Ensure humans verify before publishing.",
|
|
454
|
+
context: "Curator/expert reviews and decides."
|
|
455
|
+
},
|
|
456
|
+
io: {
|
|
457
|
+
input: SubmitDecisionInput,
|
|
458
|
+
output: ReviewTaskModel,
|
|
459
|
+
errors: {
|
|
460
|
+
FORBIDDEN_ROLE: {
|
|
461
|
+
description: "Role not allowed to approve the given risk level",
|
|
462
|
+
http: 403,
|
|
463
|
+
gqlCode: "FORBIDDEN_ROLE",
|
|
464
|
+
when: "curator attempts to approve a high-risk change"
|
|
465
|
+
},
|
|
466
|
+
REVIEW_TASK_NOT_FOUND: {
|
|
467
|
+
description: "Review task not found",
|
|
468
|
+
http: 404,
|
|
469
|
+
gqlCode: "REVIEW_TASK_NOT_FOUND",
|
|
470
|
+
when: "reviewTaskId is invalid"
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
policy: { auth: "user" }
|
|
475
|
+
});
|
|
476
|
+
var KbPipelinePublishIfReadyContract = defineCommand({
|
|
477
|
+
meta: {
|
|
478
|
+
key: "kbPipeline.publishIfReady",
|
|
479
|
+
version: "1.0.0",
|
|
480
|
+
stability: "experimental",
|
|
481
|
+
owners: ["@examples"],
|
|
482
|
+
tags: ["knowledge", "pipeline", "publishing"],
|
|
483
|
+
description: "Publish snapshot if ready (all approvals satisfied).",
|
|
484
|
+
goal: "Prevent publishing until all required approvals exist.",
|
|
485
|
+
context: "Called by job or UI to attempt publish."
|
|
486
|
+
},
|
|
487
|
+
io: {
|
|
488
|
+
input: PublishIfReadyInput,
|
|
489
|
+
output: PublishIfReadyOutput,
|
|
490
|
+
errors: {
|
|
491
|
+
NOT_READY: {
|
|
492
|
+
description: "Publishing is blocked because approvals are incomplete",
|
|
493
|
+
http: 409,
|
|
494
|
+
gqlCode: "NOT_READY",
|
|
495
|
+
when: "there are open review tasks or unapproved rule versions"
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
policy: { auth: "user" }
|
|
500
|
+
});
|
|
501
|
+
// src/kb-update-pipeline.feature.ts
|
|
502
|
+
import { defineFeature } from "@contractspec/lib.contracts";
|
|
503
|
+
var KbUpdatePipelineFeature = defineFeature({
|
|
504
|
+
meta: {
|
|
505
|
+
key: "kb-update-pipeline",
|
|
506
|
+
version: "1.0.0",
|
|
507
|
+
title: "KB Update Pipeline (HITL)",
|
|
508
|
+
description: "Automation proposes KB patches; humans verify; publishing is blocked until approvals are complete.",
|
|
509
|
+
domain: "knowledge",
|
|
510
|
+
owners: ["@examples"],
|
|
511
|
+
tags: ["knowledge", "pipeline", "hitl", "audit", "notifications"],
|
|
512
|
+
stability: "experimental"
|
|
513
|
+
},
|
|
514
|
+
operations: [
|
|
515
|
+
{ key: "kbPipeline.runWatch", version: "1.0.0" },
|
|
516
|
+
{ key: "kbPipeline.createReviewTask", version: "1.0.0" },
|
|
517
|
+
{ key: "kbPipeline.submitDecision", version: "1.0.0" },
|
|
518
|
+
{ key: "kbPipeline.publishIfReady", version: "1.0.0" }
|
|
519
|
+
],
|
|
520
|
+
events: [
|
|
521
|
+
{ key: "kb.change.detected", version: "1.0.0" },
|
|
522
|
+
{ key: "kb.change.summarized", version: "1.0.0" },
|
|
523
|
+
{ key: "kb.patch.proposed", version: "1.0.0" },
|
|
524
|
+
{ key: "kb.review.requested", version: "1.0.0" },
|
|
525
|
+
{ key: "kb.review.decided", version: "1.0.0" }
|
|
526
|
+
],
|
|
527
|
+
presentations: [
|
|
528
|
+
{ key: "kb.dashboard", version: "1.0.0" },
|
|
529
|
+
{ key: "kb.review.list", version: "1.0.0" },
|
|
530
|
+
{ key: "kb.review.form", version: "1.0.0" }
|
|
531
|
+
],
|
|
532
|
+
opToPresentation: [
|
|
533
|
+
{
|
|
534
|
+
op: { key: "kbPipeline.runWatch", version: "1.0.0" },
|
|
535
|
+
pres: { key: "kb.dashboard", version: "1.0.0" }
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
op: { key: "kbPipeline.createReviewTask", version: "1.0.0" },
|
|
539
|
+
pres: { key: "kb.review.list", version: "1.0.0" }
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
op: { key: "kbPipeline.submitDecision", version: "1.0.0" },
|
|
543
|
+
pres: { key: "kb.review.form", version: "1.0.0" }
|
|
544
|
+
}
|
|
545
|
+
],
|
|
546
|
+
presentationsTargets: [
|
|
547
|
+
{ key: "kb.dashboard", version: "1.0.0", targets: ["react", "markdown"] },
|
|
548
|
+
{ key: "kb.review.list", version: "1.0.0", targets: ["react", "markdown"] },
|
|
549
|
+
{ key: "kb.review.form", version: "1.0.0", targets: ["react"] }
|
|
550
|
+
],
|
|
551
|
+
capabilities: {
|
|
552
|
+
requires: [
|
|
553
|
+
{ key: "identity", version: "1.0.0" },
|
|
554
|
+
{ key: "notifications", version: "1.0.0" },
|
|
555
|
+
{ key: "audit-trail", version: "1.0.0" }
|
|
556
|
+
]
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// src/presentations.ts
|
|
561
|
+
import { definePresentation, StabilityEnum as StabilityEnum2 } from "@contractspec/lib.contracts";
|
|
562
|
+
var KbDashboardPresentation = definePresentation({
|
|
563
|
+
meta: {
|
|
564
|
+
key: "kb.dashboard",
|
|
565
|
+
version: "1.0.0",
|
|
566
|
+
title: "KB Update Dashboard",
|
|
567
|
+
description: "Overview of KB change candidates and review tasks.",
|
|
568
|
+
domain: "knowledge",
|
|
569
|
+
owners: ["@examples"],
|
|
570
|
+
tags: ["dashboard", "knowledge"],
|
|
571
|
+
stability: StabilityEnum2.Experimental,
|
|
572
|
+
goal: "Visualize status",
|
|
573
|
+
context: "Dashboard"
|
|
574
|
+
},
|
|
575
|
+
source: {
|
|
576
|
+
type: "component",
|
|
577
|
+
framework: "react",
|
|
578
|
+
componentKey: "KbDashboard",
|
|
579
|
+
props: ChangeCandidateModel
|
|
580
|
+
},
|
|
581
|
+
targets: ["react", "markdown"]
|
|
582
|
+
});
|
|
583
|
+
var KbReviewListPresentation = definePresentation({
|
|
584
|
+
meta: {
|
|
585
|
+
key: "kb.review.list",
|
|
586
|
+
version: "1.0.0",
|
|
587
|
+
title: "Review Tasks",
|
|
588
|
+
description: "List of pending review tasks for the current user.",
|
|
589
|
+
domain: "knowledge",
|
|
590
|
+
owners: ["@examples"],
|
|
591
|
+
tags: ["list", "review"],
|
|
592
|
+
stability: StabilityEnum2.Experimental,
|
|
593
|
+
goal: "List tasks",
|
|
594
|
+
context: "Inbox"
|
|
595
|
+
},
|
|
596
|
+
source: {
|
|
597
|
+
type: "component",
|
|
598
|
+
framework: "react",
|
|
599
|
+
componentKey: "ReviewTaskList",
|
|
600
|
+
props: ReviewTaskModel
|
|
601
|
+
},
|
|
602
|
+
targets: ["react", "markdown"]
|
|
603
|
+
});
|
|
604
|
+
var KbReviewFormPresentation = definePresentation({
|
|
605
|
+
meta: {
|
|
606
|
+
key: "kb.review.form",
|
|
607
|
+
version: "1.0.0",
|
|
608
|
+
title: "Review Change",
|
|
609
|
+
description: "Form to approve or reject a KB change candidate.",
|
|
610
|
+
domain: "knowledge",
|
|
611
|
+
owners: ["@examples"],
|
|
612
|
+
tags: ["form", "review"],
|
|
613
|
+
stability: StabilityEnum2.Experimental,
|
|
614
|
+
goal: "Review",
|
|
615
|
+
context: "Detail"
|
|
616
|
+
},
|
|
617
|
+
source: {
|
|
618
|
+
type: "component",
|
|
619
|
+
framework: "react",
|
|
620
|
+
componentKey: "ReviewDecisionForm",
|
|
621
|
+
props: ReviewTaskModel
|
|
622
|
+
},
|
|
623
|
+
targets: ["react"]
|
|
624
|
+
});
|
|
625
|
+
export {
|
|
626
|
+
example_default as example,
|
|
627
|
+
createPipelineMemoryStore,
|
|
628
|
+
createPipelineMemoryHandlers,
|
|
629
|
+
ReviewTaskModel,
|
|
630
|
+
ReviewDecisionEnum,
|
|
631
|
+
ReviewAssignedRoleEnum,
|
|
632
|
+
KbUpdatePipelineFeature,
|
|
633
|
+
KbReviewRequestedEvent,
|
|
634
|
+
KbReviewListPresentation,
|
|
635
|
+
KbReviewFormPresentation,
|
|
636
|
+
KbReviewDecidedEvent,
|
|
637
|
+
KbPipelineSubmitDecisionContract,
|
|
638
|
+
KbPipelineRunWatchContract,
|
|
639
|
+
KbPipelinePublishIfReadyContract,
|
|
640
|
+
KbPipelineCreateReviewTaskContract,
|
|
641
|
+
KbPatchProposedEvent,
|
|
642
|
+
KbDashboardPresentation,
|
|
643
|
+
KbChangeSummarizedEvent,
|
|
644
|
+
KbChangeDetectedEvent,
|
|
645
|
+
ChangeRiskLevelEnum,
|
|
646
|
+
ChangeCandidateModel
|
|
647
|
+
};
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//#region src/kb-update-pipeline.feature.d.ts
|
|
4
|
-
declare const KbUpdatePipelineFeature: _contractspec_lib_contracts0.FeatureModuleSpec;
|
|
5
|
-
//#endregion
|
|
6
|
-
export { KbUpdatePipelineFeature };
|
|
1
|
+
export declare const KbUpdatePipelineFeature: import("@contractspec/lib.contracts").FeatureModuleSpec;
|
|
7
2
|
//# sourceMappingURL=kb-update-pipeline.feature.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb-update-pipeline.feature.d.ts","
|
|
1
|
+
{"version":3,"file":"kb-update-pipeline.feature.d.ts","sourceRoot":"","sources":["../src/kb-update-pipeline.feature.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,uBAAuB,yDAwDlC,CAAC"}
|