Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions packages/kb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ A record's family is the stored `recordType` discriminant, valued against the sc
{
recordTypes: {
assertion: {
required: ['title', 'created', 'updated', 'tags'],
optional: ['last-verified', 'applies-to', 'sources', 'supersedes', 'superseded-by'],
required: ['created', 'tags', 'title', 'updated'],
optional: ['applies-to', 'diataxis', 'last-verified', 'sources', 'superseded-by', 'supersedes'],
recall: 'freshness',
immutable: false,
},
event: {
required: ['id', 'captured-at', 'session', 'cwd', 'summary'],
optional: ['repo', 'skill', 'model', 'tags', 'correction'],
required: ['captured-at', 'cwd', 'id', 'session', 'summary'],
optional: ['correction', 'model', 'repo', 'skill', 'tags'],
recall: 'recurrence-recency',
immutable: true,
},
Expand All @@ -108,15 +108,16 @@ A record's family is the stored `recordType` discriminant, valued against the sc
```yaml
# .kb/schema.yaml
recordTypes:
event:
immutable: true
recall: recurrence-recency
required: [id, captured-at, session, cwd, summary]
optional: [repo, skill, model, tags, correction]
assertion:
required: [created, tags, title, updated]
optional: [applies-to, diataxis, last-verified, sources, superseded-by, supersedes]
recall: freshness
required: [title, created, updated, tags]
optional: [last-verified, applies-to, sources, supersedes, superseded-by]
immutable: false
event:
required: [captured-at, cwd, id, session, summary]
optional: [correction, model, repo, skill, tags]
recall: recurrence-recency
immutable: true
```

Validation reads a record type's required set directly via `resolveRequiredForRecordType(schema, recordType)`. A malformed or structurally invalid `.kb/schema.yaml` throws at load time, naming the offending file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
"line": 4,
"rule": "frontmatter.required",
"severity": "error",
"message": "missing required field: updated"
"message": "missing required field: tags"
},
{
"path": "08-missing-required.md",
"line": 4,
"rule": "frontmatter.required",
"severity": "error",
"message": "missing required field: tags"
"message": "missing required field: updated"
},
{
"path": "09-unknown-type.md",
Expand Down
13 changes: 7 additions & 6 deletions packages/kb/src/schema/__tests__/default-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@ describe('defaultSchema', () => {
});

it('declares the canonical assertion required and optional field sets', () => {
expect(defaultSchema.recordTypes.assertion?.required).toEqual(['title', 'created', 'updated', 'tags']);
expect(defaultSchema.recordTypes.assertion?.required).toEqual(['created', 'tags', 'title', 'updated']);
expect(defaultSchema.recordTypes.assertion?.optional).toEqual([
'last-verified',
'applies-to',
'diataxis',
'last-verified',
'sources',
'supersedes',
'superseded-by',
'supersedes',
]);
expect(defaultSchema.recordTypes.assertion?.recall).toBe('freshness');
expect(defaultSchema.recordTypes.assertion?.immutable).toBe(false);
});

it('declares the immutable event record type with its spine', () => {
expect(defaultSchema.recordTypes.event?.required).toEqual(['id', 'captured-at', 'session', 'cwd', 'summary']);
expect(defaultSchema.recordTypes.event?.optional).toEqual(['repo', 'skill', 'model', 'tags', 'correction']);
expect(defaultSchema.recordTypes.event?.required).toEqual(['captured-at', 'cwd', 'id', 'session', 'summary']);
expect(defaultSchema.recordTypes.event?.optional).toEqual(['correction', 'model', 'repo', 'skill', 'tags']);
expect(defaultSchema.recordTypes.event?.recall).toBe('recurrence-recency');
expect(defaultSchema.recordTypes.event?.immutable).toBe(true);
});
Expand Down Expand Up @@ -55,6 +56,6 @@ describe('defaultSchema', () => {
};

expect(mutate).toThrow();
expect(required[0]).toBe('title');
expect(required[0]).toBe('created');
});
});
8 changes: 4 additions & 4 deletions packages/kb/src/schema/default-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import type { RecordTypeSchema, Schema } from '../types.ts';
// `Object.freeze` a downstream consumer could mutate the shared arrays and corrupt every later reader.

const assertion: RecordTypeSchema = {
required: Object.freeze(['title', 'created', 'updated', 'tags']),
optional: Object.freeze(['last-verified', 'applies-to', 'sources', 'supersedes', 'superseded-by']),
required: Object.freeze(['created', 'tags', 'title', 'updated']),
optional: Object.freeze(['applies-to', 'diataxis', 'last-verified', 'sources', 'superseded-by', 'supersedes']),
recall: 'freshness',
immutable: false,
};

const event: RecordTypeSchema = {
required: Object.freeze(['id', 'captured-at', 'session', 'cwd', 'summary']),
optional: Object.freeze(['repo', 'skill', 'model', 'tags', 'correction']),
required: Object.freeze(['captured-at', 'cwd', 'id', 'session', 'summary']),
optional: Object.freeze(['correction', 'model', 'repo', 'skill', 'tags']),
recall: 'recurrence-recency',
immutable: true,
};
Expand Down
Loading