@contractspec/example.versioned-knowledge-base 3.7.6 → 3.7.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/.turbo/turbo-build.log +45 -42
- package/AGENTS.md +50 -26
- package/CHANGELOG.md +21 -0
- package/README.md +80 -35
- package/dist/browser/entities/index.js +1 -1
- package/dist/browser/entities/models.js +1 -1
- package/dist/browser/events.js +1 -1
- package/dist/browser/index.js +52 -3
- package/dist/browser/knowledge-snapshot-publication.migration.js +50 -0
- package/dist/browser/operations/index.js +2 -2
- package/dist/browser/operations/kb.js +2 -2
- package/dist/contracts.test.d.ts +1 -0
- package/dist/entities/index.js +1 -1
- package/dist/entities/models.js +1 -1
- package/dist/events.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +52 -3
- package/dist/knowledge-snapshot-publication.migration.d.ts +2 -0
- package/dist/knowledge-snapshot-publication.migration.js +51 -0
- package/dist/node/entities/index.js +1 -1
- package/dist/node/entities/models.js +1 -1
- package/dist/node/events.js +1 -1
- package/dist/node/index.js +52 -3
- package/dist/node/knowledge-snapshot-publication.migration.js +50 -0
- package/dist/node/operations/index.js +2 -2
- package/dist/node/operations/kb.js +2 -2
- package/dist/operations/index.js +2 -2
- package/dist/operations/kb.js +2 -2
- package/package.json +21 -7
- package/src/contracts.test.ts +17 -0
- package/src/docs/versioned-knowledge-base.docblock.ts +21 -21
- package/src/entities/models.ts +60 -60
- package/src/events.ts +77 -77
- package/src/example.ts +28 -28
- package/src/handlers/memory.handlers.test.ts +65 -65
- package/src/handlers/memory.handlers.ts +185 -185
- package/src/index.ts +3 -2
- package/src/knowledge-snapshot-publication.migration.ts +51 -0
- package/src/operations/kb.ts +161 -161
- package/src/versioned-knowledge-base.feature.ts +35 -35
- package/tsconfig.json +7 -17
- package/tsdown.config.js +7 -13
package/src/events.ts
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
1
|
import { defineEvent } from '@contractspec/lib.contracts-spec';
|
|
2
|
-
import {
|
|
2
|
+
import { defineSchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';
|
|
3
3
|
|
|
4
4
|
const KbSourceIngestedPayload = defineSchemaModel({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
name: 'KbSourceIngestedPayload',
|
|
6
|
+
description: 'Emitted when a source document is ingested.',
|
|
7
|
+
fields: {
|
|
8
|
+
sourceDocumentId: {
|
|
9
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
10
|
+
isOptional: false,
|
|
11
|
+
},
|
|
12
|
+
jurisdiction: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
13
|
+
hash: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
14
|
+
},
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
export const KbSourceIngestedEvent = defineEvent({
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
meta: {
|
|
19
|
+
key: 'kb.source.ingested',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
description: 'Source document ingested (immutable).',
|
|
22
|
+
stability: 'experimental',
|
|
23
|
+
owners: ['@examples'],
|
|
24
|
+
tags: ['knowledge'],
|
|
25
|
+
},
|
|
26
|
+
payload: KbSourceIngestedPayload,
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
const KbRuleVersionCreatedPayload = defineSchemaModel({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
name: 'KbRuleVersionCreatedPayload',
|
|
31
|
+
description: 'Emitted when a rule version draft is created.',
|
|
32
|
+
fields: {
|
|
33
|
+
ruleVersionId: {
|
|
34
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
35
|
+
isOptional: false,
|
|
36
|
+
},
|
|
37
|
+
ruleId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
38
|
+
jurisdiction: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
39
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
40
|
+
},
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
export const KbRuleVersionCreatedEvent = defineEvent({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
meta: {
|
|
45
|
+
key: 'kb.ruleVersion.created',
|
|
46
|
+
version: '1.0.0',
|
|
47
|
+
description: 'Rule version created (draft).',
|
|
48
|
+
stability: 'experimental',
|
|
49
|
+
owners: ['@examples'],
|
|
50
|
+
tags: ['knowledge'],
|
|
51
|
+
},
|
|
52
|
+
payload: KbRuleVersionCreatedPayload,
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
const KbRuleVersionApprovedPayload = defineSchemaModel({
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
name: 'KbRuleVersionApprovedPayload',
|
|
57
|
+
description: 'Emitted when a rule version is approved.',
|
|
58
|
+
fields: {
|
|
59
|
+
ruleVersionId: {
|
|
60
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
61
|
+
isOptional: false,
|
|
62
|
+
},
|
|
63
|
+
approver: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
64
|
+
},
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
export const KbRuleVersionApprovedEvent = defineEvent({
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
meta: {
|
|
69
|
+
key: 'kb.ruleVersion.approved',
|
|
70
|
+
version: '1.0.0',
|
|
71
|
+
description: 'Rule version approved (human verified).',
|
|
72
|
+
stability: 'experimental',
|
|
73
|
+
owners: ['@examples'],
|
|
74
|
+
tags: ['knowledge'],
|
|
75
|
+
},
|
|
76
|
+
payload: KbRuleVersionApprovedPayload,
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
const KbSnapshotPublishedPayload = defineSchemaModel({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
80
|
+
name: 'KbSnapshotPublishedPayload',
|
|
81
|
+
description: 'Emitted when a KB snapshot is published.',
|
|
82
|
+
fields: {
|
|
83
|
+
snapshotId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
84
|
+
jurisdiction: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
85
|
+
includedRuleVersionsCount: {
|
|
86
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
87
|
+
isOptional: false,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
export const KbSnapshotPublishedEvent = defineEvent({
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
meta: {
|
|
94
|
+
key: 'kb.snapshot.published',
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
description: 'KB snapshot published.',
|
|
97
|
+
stability: 'experimental',
|
|
98
|
+
owners: ['@examples'],
|
|
99
|
+
tags: ['knowledge'],
|
|
100
|
+
},
|
|
101
|
+
payload: KbSnapshotPublishedPayload,
|
|
102
102
|
});
|
package/src/example.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import { defineExample } from '@contractspec/lib.contracts-spec';
|
|
2
2
|
|
|
3
3
|
const example = defineExample({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
4
|
+
meta: {
|
|
5
|
+
key: 'versioned-knowledge-base',
|
|
6
|
+
version: '1.0.0',
|
|
7
|
+
title: 'Versioned Knowledge Base',
|
|
8
|
+
description:
|
|
9
|
+
'Curated KB with immutable sources, reviewable rule versions, and published snapshots.',
|
|
10
|
+
kind: 'knowledge',
|
|
11
|
+
visibility: 'public',
|
|
12
|
+
stability: 'experimental',
|
|
13
|
+
owners: ['@platform.core'],
|
|
14
|
+
tags: ['knowledge', 'versioning', 'snapshots'],
|
|
15
|
+
},
|
|
16
|
+
docs: {
|
|
17
|
+
rootDocId: 'docs.examples.versioned-knowledge-base',
|
|
18
|
+
},
|
|
19
|
+
entrypoints: {
|
|
20
|
+
packageName: '@contractspec/example.versioned-knowledge-base',
|
|
21
|
+
feature: './feature',
|
|
22
|
+
contracts: './contracts',
|
|
23
|
+
handlers: './handlers',
|
|
24
|
+
docs: './docs',
|
|
25
|
+
},
|
|
26
|
+
surfaces: {
|
|
27
|
+
templates: true,
|
|
28
|
+
sandbox: { enabled: true, modes: ['markdown', 'specs', 'builder'] },
|
|
29
|
+
studio: { enabled: true, installable: true },
|
|
30
|
+
mcp: { enabled: true },
|
|
31
|
+
},
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
export default example;
|
|
@@ -3,79 +3,79 @@ import { describe, expect, it } from 'bun:test';
|
|
|
3
3
|
import { createMemoryKbHandlers, createMemoryKbStore } from './memory.handlers';
|
|
4
4
|
|
|
5
5
|
describe('@contractspec/example.versioned-knowledge-base memory handlers', () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
it('requires sourceRefs for rule versions (traceability)', async () => {
|
|
7
|
+
const store = createMemoryKbStore();
|
|
8
|
+
const kb = createMemoryKbHandlers(store);
|
|
9
|
+
await kb.createRule({ id: 'rule_1', jurisdiction: 'EU', topicKey: 't1' });
|
|
10
|
+
await expect(
|
|
11
|
+
kb.upsertRuleVersion({ ruleId: 'rule_1', content: 'x', sourceRefs: [] })
|
|
12
|
+
).rejects.toThrow('SOURCE_REFS_REQUIRED');
|
|
13
|
+
});
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
it('snapshot includes only approved rule versions for that jurisdiction', async () => {
|
|
16
|
+
const store = createMemoryKbStore();
|
|
17
|
+
const kb = createMemoryKbHandlers(store);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
await kb.createRule({ id: 'rule_eu', jurisdiction: 'EU', topicKey: 'tax' });
|
|
20
|
+
await kb.createRule({ id: 'rule_fr', jurisdiction: 'FR', topicKey: 'tax' });
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
const euDraft = await kb.upsertRuleVersion({
|
|
23
|
+
ruleId: 'rule_eu',
|
|
24
|
+
content: 'EU rule content',
|
|
25
|
+
sourceRefs: [{ sourceDocumentId: 'src1' }],
|
|
26
|
+
});
|
|
27
|
+
const frDraft = await kb.upsertRuleVersion({
|
|
28
|
+
ruleId: 'rule_fr',
|
|
29
|
+
content: 'FR rule content',
|
|
30
|
+
sourceRefs: [{ sourceDocumentId: 'src2' }],
|
|
31
|
+
});
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const euApproved = await kb.approveRuleVersion({
|
|
34
|
+
ruleVersionId: euDraft.id,
|
|
35
|
+
approver: 'expert_1',
|
|
36
|
+
});
|
|
37
|
+
await kb.approveRuleVersion({
|
|
38
|
+
ruleVersionId: frDraft.id,
|
|
39
|
+
approver: 'expert_1',
|
|
40
|
+
});
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const snapshot = await kb.publishSnapshot({
|
|
43
|
+
jurisdiction: 'EU',
|
|
44
|
+
asOfDate: new Date('2026-01-01T00:00:00.000Z'),
|
|
45
|
+
});
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
expect(snapshot.includedRuleVersionIds).toEqual([euApproved.id]);
|
|
48
|
+
});
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
it('search is scoped to snapshot + jurisdiction', async () => {
|
|
51
|
+
const store = createMemoryKbStore();
|
|
52
|
+
const kb = createMemoryKbHandlers(store);
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
await kb.createRule({
|
|
55
|
+
id: 'rule_eu',
|
|
56
|
+
jurisdiction: 'EU',
|
|
57
|
+
topicKey: 'topic',
|
|
58
|
+
});
|
|
59
|
+
const euDraft = await kb.upsertRuleVersion({
|
|
60
|
+
ruleId: 'rule_eu',
|
|
61
|
+
content: 'This is about reporting obligations',
|
|
62
|
+
sourceRefs: [{ sourceDocumentId: 'src1' }],
|
|
63
|
+
});
|
|
64
|
+
await kb.approveRuleVersion({ ruleVersionId: euDraft.id, approver: 'u1' });
|
|
65
|
+
const snap = await kb.publishSnapshot({
|
|
66
|
+
jurisdiction: 'EU',
|
|
67
|
+
asOfDate: new Date('2026-01-01T00:00:00.000Z'),
|
|
68
|
+
});
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
await expect(
|
|
71
|
+
kb.search({ snapshotId: snap.id, jurisdiction: 'FR', query: 'reporting' })
|
|
72
|
+
).rejects.toThrow('JURISDICTION_MISMATCH');
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
const ok = await kb.search({
|
|
75
|
+
snapshotId: snap.id,
|
|
76
|
+
jurisdiction: 'EU',
|
|
77
|
+
query: 'reporting',
|
|
78
|
+
});
|
|
79
|
+
expect(ok.items.map((i) => i.ruleVersionId)).toEqual([euDraft.id]);
|
|
80
|
+
});
|
|
81
81
|
});
|