@cleocode/contracts 2026.5.108 → 2026.5.109

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.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Contract tests for the CLEO database inventory SSoT.
3
+ *
4
+ * Asserts the structural invariants the inventory MUST hold:
5
+ *
6
+ * 1. Every {@link DbInventoryEntry.role} is unique across the array.
7
+ * 2. Every {@link DbInventoryEntry.tier} is a valid member of the
8
+ * {@link DbTier} union.
9
+ * 3. Every non-null {@link DbInventoryEntry.drizzleSchemaPath} resolves
10
+ * to a real file on disk relative to the monorepo root.
11
+ * 4. Every non-null {@link DbInventoryEntry.migrationsDir} resolves to a
12
+ * real directory on disk relative to the monorepo root.
13
+ * 5. The list is non-empty and covers the AC1-mandated role set.
14
+ *
15
+ * These invariants are the gating contract for downstream saga tasks
16
+ * (T10307 fleet survey, T10310 pragma drift, T10311 migration coverage,
17
+ * T10312 doctor integrity, T10320 cross-DB invariants). If this suite
18
+ * fails, the inventory has drifted from disk reality and CI MUST block.
19
+ *
20
+ * @task T10305
21
+ * @epic T10282
22
+ * @saga T10281
23
+ */
24
+ export {};
25
+ //# sourceMappingURL=db-inventory.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-inventory.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/db-inventory.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Contract tests for the CLEO database inventory SSoT.
3
+ *
4
+ * Asserts the structural invariants the inventory MUST hold:
5
+ *
6
+ * 1. Every {@link DbInventoryEntry.role} is unique across the array.
7
+ * 2. Every {@link DbInventoryEntry.tier} is a valid member of the
8
+ * {@link DbTier} union.
9
+ * 3. Every non-null {@link DbInventoryEntry.drizzleSchemaPath} resolves
10
+ * to a real file on disk relative to the monorepo root.
11
+ * 4. Every non-null {@link DbInventoryEntry.migrationsDir} resolves to a
12
+ * real directory on disk relative to the monorepo root.
13
+ * 5. The list is non-empty and covers the AC1-mandated role set.
14
+ *
15
+ * These invariants are the gating contract for downstream saga tasks
16
+ * (T10307 fleet survey, T10310 pragma drift, T10311 migration coverage,
17
+ * T10312 doctor integrity, T10320 cross-DB invariants). If this suite
18
+ * fails, the inventory has drifted from disk reality and CI MUST block.
19
+ *
20
+ * @task T10305
21
+ * @epic T10282
22
+ * @saga T10281
23
+ */
24
+ import { existsSync, statSync } from 'node:fs';
25
+ import { dirname, resolve } from 'node:path';
26
+ import { fileURLToPath } from 'node:url';
27
+ import { describe, expect, it } from 'vitest';
28
+ import { DB_INVENTORY } from '../db-inventory.js';
29
+ /**
30
+ * Resolve the monorepo root from this test file.
31
+ *
32
+ * `__tests__/db-inventory.test.ts` lives at
33
+ * `packages/contracts/src/__tests__/` — four levels above the repo root.
34
+ */
35
+ const THIS_FILE = fileURLToPath(import.meta.url);
36
+ const REPO_ROOT = resolve(dirname(THIS_FILE), '..', '..', '..', '..');
37
+ const VALID_TIERS = new Set(['project', 'global', 'derived']);
38
+ /**
39
+ * Roles AC1 of T10305 explicitly requires the inventory to enumerate.
40
+ * The set must be covered exactly; extras are acceptable when documented.
41
+ */
42
+ const REQUIRED_ROLES = [
43
+ 'tasks',
44
+ 'brain',
45
+ 'conduit',
46
+ 'manifest',
47
+ 'llmtxt',
48
+ 'nexus',
49
+ 'signaldock-project',
50
+ 'signaldock-global',
51
+ 'telemetry',
52
+ 'skills',
53
+ 'global-brain',
54
+ 'global-tasks',
55
+ ];
56
+ describe('CLEO database inventory (T10305 SSoT)', () => {
57
+ it('is non-empty', () => {
58
+ expect(DB_INVENTORY.length).toBeGreaterThan(0);
59
+ });
60
+ it('covers every role required by T10305 AC1', () => {
61
+ const seen = new Set(DB_INVENTORY.map((e) => e.role));
62
+ for (const role of REQUIRED_ROLES) {
63
+ expect(seen.has(role), `inventory missing role '${role}'`).toBe(true);
64
+ }
65
+ });
66
+ it('has unique role IDs across all entries', () => {
67
+ const roles = DB_INVENTORY.map((e) => e.role);
68
+ const unique = new Set(roles);
69
+ expect(unique.size).toBe(roles.length);
70
+ });
71
+ it('uses only valid tier literals', () => {
72
+ for (const entry of DB_INVENTORY) {
73
+ expect(VALID_TIERS.has(entry.tier), `role '${entry.role}' has invalid tier '${entry.tier}'`).toBe(true);
74
+ }
75
+ });
76
+ it('uses valid path tokens in filePathTemplate', () => {
77
+ // Project tier MUST use <projectRoot>/ prefix; global tier MUST use
78
+ // $XDG_DATA_HOME/cleo/ prefix. Derived tier may use either.
79
+ for (const entry of DB_INVENTORY) {
80
+ const t = entry.filePathTemplate;
81
+ if (entry.tier === 'project') {
82
+ expect(t.startsWith('<projectRoot>/'), `project-tier entry '${entry.role}' uses non-canonical path '${t}'`).toBe(true);
83
+ }
84
+ else if (entry.tier === 'global') {
85
+ expect(t.startsWith('$XDG_DATA_HOME/cleo/'), `global-tier entry '${entry.role}' uses non-canonical path '${t}'`).toBe(true);
86
+ }
87
+ }
88
+ });
89
+ it('resolves every non-null drizzleSchemaPath to a real file', () => {
90
+ for (const entry of DB_INVENTORY) {
91
+ if (entry.drizzleSchemaPath === null)
92
+ continue;
93
+ const absolutePath = resolve(REPO_ROOT, entry.drizzleSchemaPath);
94
+ expect(existsSync(absolutePath), `role '${entry.role}' schema path missing: ${entry.drizzleSchemaPath}`).toBe(true);
95
+ expect(statSync(absolutePath).isFile(), `role '${entry.role}' schema path is not a file: ${entry.drizzleSchemaPath}`).toBe(true);
96
+ }
97
+ });
98
+ it('resolves every non-null migrationsDir to a real directory', () => {
99
+ for (const entry of DB_INVENTORY) {
100
+ if (entry.migrationsDir === null)
101
+ continue;
102
+ const absolutePath = resolve(REPO_ROOT, entry.migrationsDir);
103
+ expect(existsSync(absolutePath), `role '${entry.role}' migrations dir missing: ${entry.migrationsDir}`).toBe(true);
104
+ expect(statSync(absolutePath).isDirectory(), `role '${entry.role}' migrations path is not a directory: ${entry.migrationsDir}`).toBe(true);
105
+ }
106
+ });
107
+ it('omits migrationsDir only for derived or reserved roles', () => {
108
+ // A null migrationsDir is only valid for:
109
+ // - derived tier (schema owned by upstream lib — e.g. manifest)
110
+ // - reserved roles whose opener throws not-yet-implemented (e.g. llmtxt)
111
+ for (const entry of DB_INVENTORY) {
112
+ if (entry.migrationsDir !== null)
113
+ continue;
114
+ const isDerived = entry.tier === 'derived';
115
+ const isReserved = /reserved|not yet implemented/i.test(entry.openedVia);
116
+ expect(isDerived || isReserved, `role '${entry.role}' has null migrationsDir but is neither derived nor reserved`).toBe(true);
117
+ }
118
+ });
119
+ it('exposes a readonly array type at compile time', () => {
120
+ // Compile-time check: assigning to an index must be rejected.
121
+ // Runtime check: Object.isFrozen is not guaranteed by `readonly` but the
122
+ // type-system reject is the primary defence. We only assert the runtime
123
+ // shape is array-like here.
124
+ expect(Array.isArray(DB_INVENTORY)).toBe(true);
125
+ });
126
+ it('keeps each entry self-consistent (sample-fields populated)', () => {
127
+ // Sanity: every entry must populate the structural fields. The contract
128
+ // forbids `null` placeholders on non-optional fields.
129
+ const sampleRequiredKeys = [
130
+ 'role',
131
+ 'tier',
132
+ 'filePathTemplate',
133
+ 'ownerPackage',
134
+ 'openedVia',
135
+ 'concurrency',
136
+ 'privacy',
137
+ 'backupPath',
138
+ 'documentedIn',
139
+ ];
140
+ for (const entry of DB_INVENTORY) {
141
+ for (const key of sampleRequiredKeys) {
142
+ const value = entry[key];
143
+ expect(typeof value === 'string' && value.length > 0, `role '${entry.role}' field '${String(key)}' is empty or non-string`).toBe(true);
144
+ }
145
+ }
146
+ });
147
+ });
148
+ //# sourceMappingURL=db-inventory.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-inventory.test.js","sourceRoot":"","sources":["../../src/__tests__/db-inventory.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TaskType discriminator narrowing tests.
3
+ *
4
+ * Pins the post-ADR-083 §2.5 union shape (`'saga' | 'epic' | 'task' |
5
+ * 'subtask'`) so that:
6
+ * - Adding/removing a tier in the canonical {@link TaskType} union breaks
7
+ * this test loudly (caught at compile time AND runtime).
8
+ * - Discriminated-union narrowing on `task.type === 'saga'` keeps working
9
+ * for downstream consumers.
10
+ *
11
+ * @since SAGA T10326 · Epic T10277 · Task T10328 (W1.A)
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=task-type-narrowing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-type-narrowing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/task-type-narrowing.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * TaskType discriminator narrowing tests.
3
+ *
4
+ * Pins the post-ADR-083 §2.5 union shape (`'saga' | 'epic' | 'task' |
5
+ * 'subtask'`) so that:
6
+ * - Adding/removing a tier in the canonical {@link TaskType} union breaks
7
+ * this test loudly (caught at compile time AND runtime).
8
+ * - Discriminated-union narrowing on `task.type === 'saga'` keeps working
9
+ * for downstream consumers.
10
+ *
11
+ * @since SAGA T10326 · Epic T10277 · Task T10328 (W1.A)
12
+ */
13
+ import { describe, expectTypeOf, it } from 'vitest';
14
+ describe('TaskType discriminator', () => {
15
+ it('narrows when type === "saga"', () => {
16
+ const t = {
17
+ id: 'T1',
18
+ title: 'demo',
19
+ description: 'demo task',
20
+ status: 'pending',
21
+ priority: 'medium',
22
+ type: 'saga',
23
+ createdAt: '2026-01-01T00:00:00.000Z',
24
+ };
25
+ if (t.type === 'saga') {
26
+ expectTypeOf(t.type).toEqualTypeOf();
27
+ }
28
+ });
29
+ it('narrows when type === "epic"', () => {
30
+ const t = {
31
+ id: 'T2',
32
+ title: 'demo',
33
+ description: 'demo task',
34
+ status: 'pending',
35
+ priority: 'medium',
36
+ type: 'epic',
37
+ createdAt: '2026-01-01T00:00:00.000Z',
38
+ };
39
+ if (t.type === 'epic') {
40
+ expectTypeOf(t.type).toEqualTypeOf();
41
+ }
42
+ });
43
+ it('accepts all 4 tier values', () => {
44
+ const types = ['saga', 'epic', 'task', 'subtask'];
45
+ expectTypeOf(types).toEqualTypeOf();
46
+ });
47
+ it('TaskType is the 4-element union per ADR-083 §2.5', () => {
48
+ expectTypeOf().toEqualTypeOf();
49
+ });
50
+ });
51
+ //# sourceMappingURL=task-type-narrowing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-type-narrowing.test.js","sourceRoot":"","sources":["../../src/__tests__/task-type-narrowing.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAGpD,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAS;YACd,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,MAAM;YACb,WAAW,EAAE,WAAW;YACxB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,0BAA0B;SACtC,CAAC;QACF,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACtB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAU,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAS;YACd,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,MAAM;YACb,WAAW,EAAE,WAAW;YACxB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,0BAA0B;SACtC,CAAC;QACF,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACtB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAU,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,KAAK,GAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAC9D,YAAY,CAAC,KAAK,CAAC,CAAC,aAAa,EAAc,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,YAAY,EAAY,CAAC,aAAa,EAAwC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/brain.d.ts CHANGED
@@ -85,4 +85,107 @@ export interface SupersededEntry {
85
85
  /** Topic or category grouping these entries together. */
86
86
  grouping: string;
87
87
  }
88
+ /**
89
+ * Result of a brain.db auto-recovery attempt.
90
+ *
91
+ * Returned by `recoverMalformedBrainDb()` (T10303) when the chokepoint
92
+ * detects malformation via `ERR_SQLITE_ERROR errcode=11` or a failing
93
+ * `PRAGMA integrity_check`/`PRAGMA quick_check`. The corrupt DB has been
94
+ * moved to a quarantine directory and the freshest validated snapshot has
95
+ * been copied to `.cleo/brain.db`.
96
+ *
97
+ * Consumers (the brain.db open chokepoint, telemetry, the upcoming T10302
98
+ * regression test) read this structure to decide whether to re-attempt the
99
+ * open and to emit user-facing diagnostics with the data-loss window.
100
+ */
101
+ export interface BrainRecoveryResult {
102
+ /** Absolute path to the snapshot that was restored, or null if recovery failed. */
103
+ restoredFrom: string | null;
104
+ /**
105
+ * Approximate hours between the snapshot's timestamp and the recovery
106
+ * event. `null` when the snapshot timestamp could not be parsed.
107
+ * Used in the recovery warning to make the data-loss window legible.
108
+ */
109
+ dataLossWindowHours: number | null;
110
+ /**
111
+ * Number of `brain_observations` rows in the restored DB. Best-effort —
112
+ * `null` when the count query failed (table missing, FK violation, …).
113
+ */
114
+ observationsRecovered: number | null;
115
+ /** `true` if the restored DB passes `PRAGMA quick_check`. */
116
+ integrityOK: boolean;
117
+ /**
118
+ * Absolute path to the quarantine directory where the corrupt DB plus
119
+ * its `-wal`/`-shm` sidecars were moved before restore.
120
+ */
121
+ quarantineDir: string | null;
122
+ }
123
+ /**
124
+ * Per-table row counts probed from the restored brain.db.
125
+ *
126
+ * Best-effort — any individual count may be `null` when the table is
127
+ * missing (very old snapshot predating that schema rev) or when the count
128
+ * query throws. The values feed both the `cleo backup recover brain`
129
+ * envelope and the recovery runbook's user-facing diagnostics.
130
+ *
131
+ * @task T10304
132
+ * @epic T10286
133
+ * @saga T10281
134
+ */
135
+ export interface BrainRecoveredRowCounts {
136
+ /** `brain_observations` row count, or `null` when the count failed. */
137
+ observations: number | null;
138
+ /** `brain_decisions` row count, or `null` when the count failed. */
139
+ decisions: number | null;
140
+ /** `brain_learnings` row count, or `null` when the count failed. */
141
+ learnings: number | null;
142
+ }
143
+ /**
144
+ * Envelope payload returned by `cleo backup recover brain`.
145
+ *
146
+ * The CLI verb (T10304) wraps {@link BrainRecoveryResult} from
147
+ * {@link recoverMalformedBrainDb} (T10303) and enriches it with per-table
148
+ * row counts plus the operator-friendly snapshot/quarantine paths required
149
+ * by the AC envelope shape.
150
+ *
151
+ * Surfaces:
152
+ * - `--dry-run` plan envelopes (with `restoredFrom` being the snapshot that
153
+ * *would* be restored and `quarantinedTo` being the directory the corrupt
154
+ * DB *would* be moved to).
155
+ * - Real-recovery envelopes after the pipeline has executed.
156
+ *
157
+ * @task T10304
158
+ * @epic T10286
159
+ * @saga T10281
160
+ */
161
+ export interface BackupRecoverBrainResult {
162
+ /**
163
+ * Absolute path to the snapshot that was (or would be) restored. Empty
164
+ * string when no snapshot was available — the envelope's caller surfaces
165
+ * that as a failure mode.
166
+ */
167
+ restoredFrom: string;
168
+ /** Per-table row counts probed from the restored DB. */
169
+ rowsRecovered: BrainRecoveredRowCounts;
170
+ /**
171
+ * Approximate hours between the snapshot's timestamp and the recovery
172
+ * event. `null` when the snapshot timestamp could not be parsed (e.g.
173
+ * legacy `brain.db.PRE-DUP-FIX-*` fallback artifact).
174
+ */
175
+ dataLossWindowHours: number | null;
176
+ /** `true` when the restored DB passes `PRAGMA quick_check`. */
177
+ integrityOK: boolean;
178
+ /**
179
+ * Absolute path to the quarantine directory where the corrupt DB plus
180
+ * its `-wal`/`-shm` sidecars were moved. Empty string in `--dry-run`
181
+ * mode where no files were touched.
182
+ */
183
+ quarantinedTo: string;
184
+ /**
185
+ * `true` when invoked with `--dry-run` — indicates the envelope is a
186
+ * plan, NOT a record of mutations performed. Consumers MUST check this
187
+ * before treating `restoredFrom` as a post-condition.
188
+ */
189
+ dryRun: boolean;
190
+ }
88
191
  //# sourceMappingURL=brain.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"brain.d.ts","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1D;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,GAAG,aAAa,CAAC;AAEvF,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,sDAAsD;AACtD,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,MAAM,EAAE,aAAa,CAAC;IACtB,8CAA8C;IAC9C,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,iDAAiD;IACjD,WAAW,EAAE,iBAAiB,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"brain.d.ts","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1D;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,GAAG,aAAa,CAAC;AAEvF,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,sDAAsD;AACtD,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,MAAM,EAAE,aAAa,CAAC;IACtB,8CAA8C;IAC9C,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,iDAAiD;IACjD,WAAW,EAAE,iBAAiB,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAMD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAuB;IACtC,uEAAuE;IACvE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,+DAA+D;IAC/D,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * CLEO Database Inventory — SSoT type contract + immutable constant.
3
+ *
4
+ * @remarks
5
+ * This module exports the typed shape and the runtime constant for every
6
+ * SQLite database that CLEO manages. The runtime data is sourced from the
7
+ * canonical JSON inventory at `packages/core/src/store/db-inventory.json`
8
+ * via ESM JSON import (`with { type: 'json' }`). The JSON file is the
9
+ * single source of truth; this module re-exposes it with a typed contract.
10
+ *
11
+ * Downstream consumers:
12
+ *
13
+ * - **T10307 — Fleet survey** (`cleo doctor db-substrate`) iterates `DB_INVENTORY`
14
+ * to enumerate every DB on disk across project + global tiers.
15
+ * - **T10310 — Pragma drift** validates that every open handle for each role
16
+ * applies the pragma SSoT (`specs/sqlite-pragmas.json`).
17
+ * - **T10311 — Migration coverage** asserts that each entry's
18
+ * `migrationsDir` exists and contains a `0000_*` baseline.
19
+ * - **T10312 — Doctor integrity** runs `PRAGMA integrity_check` against
20
+ * every entry whose tier resolves to a present file on disk.
21
+ * - **T10320 — Cross-DB invariants** uses `ownerPackage` + `tier` to
22
+ * classify which DBs must agree on shared identifiers (project_id,
23
+ * agent_id, session_id, ...).
24
+ *
25
+ * Adding a new entry to the inventory is a charter amendment — update
26
+ * `db-inventory.json` AND `.cleo/adrs/ADR-068-cleo-database-charter.md`
27
+ * in the same PR (gated by `cleo check arch` Gate-4 SSoT-EXEMPT lint
28
+ * once T10282 ships its drift check).
29
+ *
30
+ * @see ADR-068 — CLEO Database Charter (canonical narrative)
31
+ * @see Saga T10281 — SG-BRAIN-DB-RESILIENCE (provenance)
32
+ * @see Epic T10282 — E1-DB-INVENTORY (this artifact)
33
+ * @see Research note `sg-brain-db-resilience-deep-audit-2026-05-23`
34
+ *
35
+ * @task T10305
36
+ * @epic T10282
37
+ * @saga T10281
38
+ */
39
+ /**
40
+ * Canonical role names for every SQLite database in the CLEO charter.
41
+ *
42
+ * @remarks
43
+ * Mirrors the `openCleoDb('<role>', cwd)` chokepoint (ADR-068 §3) plus the
44
+ * three audit-discovered roles (`global-brain`, `global-tasks`, `manifest`)
45
+ * that exist on disk today but do not yet have a registered opener.
46
+ *
47
+ * - `tasks` — project-tier task engine DB
48
+ * - `brain` — project-tier memory DB (PII)
49
+ * - `conduit` — project-tier agent message transport
50
+ * - `manifest` — project-tier derived blob index (rebuildable)
51
+ * - `llmtxt` — reserved project-tier llmtxt session store
52
+ * - `nexus` — global-tier cross-project knowledge graph (PII)
53
+ * - `signaldock-project` — historical project-tier signaldock (post-ADR-037, merged into conduit)
54
+ * - `signaldock-global` — global-tier canonical agent identity registry
55
+ * - `telemetry` — global-tier opt-in command telemetry
56
+ * - `skills` — global-tier per-user skill registry
57
+ * - `global-brain` — global-tier brain.db observed on disk (audit §1.2 — provenance under investigation)
58
+ * - `global-tasks` — global-tier tasks.db observed on disk (audit §1.2 — provenance under investigation)
59
+ *
60
+ * @public
61
+ */
62
+ export type DbRole = 'tasks' | 'brain' | 'conduit' | 'manifest' | 'llmtxt' | 'nexus' | 'signaldock-project' | 'signaldock-global' | 'telemetry' | 'skills' | 'global-brain' | 'global-tasks';
63
+ /**
64
+ * Lifecycle scope of a CLEO database.
65
+ *
66
+ * @remarks
67
+ * - `project` — file lives under `<projectRoot>/.cleo/`; lifecycle bound to one CLEO project.
68
+ * - `global` — file lives under `$XDG_DATA_HOME/cleo/` (env-paths via `getCleoHome()`).
69
+ * - `derived` — file lives under the project tier but is rebuildable from a
70
+ * non-DB source-of-truth (e.g. content-addressable blob store).
71
+ * MAY be excluded from backup-pack.
72
+ *
73
+ * @public
74
+ */
75
+ export type DbTier = 'project' | 'global' | 'derived';
76
+ /**
77
+ * Privacy classification governing backup + cloud-export rules.
78
+ *
79
+ * @remarks
80
+ * - `local-only` — never cloud-exported.
81
+ * - `local-only-pii` — never cloud-exported; PII-class — requires
82
+ * explicit `cleo backup export --include-pii`.
83
+ * - `cloud-exportable-opt-in` — may be exported only after explicit opt-in
84
+ * (e.g. `cleo diagnostics enable`).
85
+ *
86
+ * @public
87
+ */
88
+ export type DbPrivacy = 'local-only' | 'local-only-pii' | 'cloud-exportable-opt-in';
89
+ /**
90
+ * Concurrency model for the database.
91
+ *
92
+ * @remarks
93
+ * Every CLEO database today is `single-writer` (WAL mode with in-process
94
+ * serialization via the `openCleoDb` singleton). The field is enumerated so
95
+ * a future read-replica or multi-writer DB MUST be declared explicitly.
96
+ *
97
+ * @public
98
+ */
99
+ export type DbConcurrency = 'single-writer' | 'multi-writer';
100
+ /**
101
+ * One row in the CLEO database charter.
102
+ *
103
+ * @remarks
104
+ * Every field is required (no `null` placeholders) EXCEPT `drizzleSchemaPath`
105
+ * and `migrationsDir` — those MAY be `null` for:
106
+ *
107
+ * - `derived` databases whose schema is owned by an upstream library (e.g.
108
+ * `manifest.db` is owned by `llmtxt/blob`'s `BlobFsAdapter` contract).
109
+ * - `reserved` roles whose opener throws `not yet implemented` (e.g.
110
+ * `llmtxt.db`).
111
+ *
112
+ * Path templates use the substitution tokens:
113
+ *
114
+ * - `<projectRoot>` — resolved at runtime from `CLEO_ROOT` env var or
115
+ * `process.cwd()` via `getCleoProjectDir()`.
116
+ * - `$XDG_DATA_HOME` — resolved via env-paths through `getCleoHome()`.
117
+ * Linux: `~/.local/share/cleo/`; macOS:
118
+ * `~/Library/Application Support/cleo/`.
119
+ *
120
+ * @public
121
+ */
122
+ export interface DbInventoryEntry {
123
+ /** Canonical role identifier used by `openCleoDb` and audit tooling. */
124
+ readonly role: DbRole;
125
+ /** Lifecycle scope — project, global, or derived. */
126
+ readonly tier: DbTier;
127
+ /**
128
+ * Filesystem path template with `<projectRoot>` / `$XDG_DATA_HOME` tokens.
129
+ * Substitution convention is documented on {@link DbInventoryEntry}.
130
+ */
131
+ readonly filePathTemplate: string;
132
+ /**
133
+ * Repo-relative path to the Drizzle schema TypeScript file. `null` when
134
+ * the schema is owned by an upstream library or the role is reserved.
135
+ */
136
+ readonly drizzleSchemaPath: string | null;
137
+ /**
138
+ * Repo-relative path to the Drizzle migrations directory (with trailing
139
+ * slash). `null` for `derived` rows or reserved roles. The path MUST
140
+ * exist on disk when non-null — enforced by the contracts test suite.
141
+ */
142
+ readonly migrationsDir: string | null;
143
+ /** npm package that owns the open + lifecycle for this database. */
144
+ readonly ownerPackage: string;
145
+ /**
146
+ * Human-readable description of HOW the database is opened. Typically
147
+ * a code excerpt like `openCleoDb('tasks', cwd)`. For databases without
148
+ * a registered opener, describes provenance / status.
149
+ */
150
+ readonly openedVia: string;
151
+ /** Concurrency model — see {@link DbConcurrency}. */
152
+ readonly concurrency: DbConcurrency;
153
+ /** Privacy classification — see {@link DbPrivacy}. */
154
+ readonly privacy: DbPrivacy;
155
+ /**
156
+ * Canonical backup path template. For `derived` rows this is the
157
+ * sentinel string `rebuildable-from-blob-store` (or similar) and the
158
+ * row is excluded from backup-pack staging.
159
+ */
160
+ readonly backupPath: string;
161
+ /**
162
+ * Provenance pointers — ADR row, related task IDs, audit section
163
+ * references. Comma-or-semicolon separated string of references.
164
+ */
165
+ readonly documentedIn: string;
166
+ }
167
+ /**
168
+ * Immutable canonical inventory of every CLEO SQLite database.
169
+ *
170
+ * @remarks
171
+ * Sourced from `packages/core/src/store/db-inventory.json` — the SSoT.
172
+ * Adding a new entry is a charter amendment per ADR-068 §"How to add a
173
+ * new database". The {@link db-inventory.test.ts} suite asserts:
174
+ *
175
+ * 1. Every `role` is unique across the array.
176
+ * 2. Every `drizzleSchemaPath` (when non-null) exists on disk.
177
+ * 3. Every `migrationsDir` (when non-null) exists on disk.
178
+ * 4. Every `tier` is a member of the {@link DbTier} union.
179
+ *
180
+ * @example Iterate every project-tier database
181
+ * ```typescript
182
+ * import { DB_INVENTORY } from '@cleocode/contracts';
183
+ *
184
+ * const projectDbs = DB_INVENTORY.filter((entry) => entry.tier === 'project');
185
+ * for (const entry of projectDbs) {
186
+ * console.log(entry.role, entry.filePathTemplate);
187
+ * }
188
+ * ```
189
+ *
190
+ * @public
191
+ */
192
+ export declare const DB_INVENTORY: readonly DbInventoryEntry[];
193
+ //# sourceMappingURL=db-inventory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-inventory.d.ts","sourceRoot":"","sources":["../src/db-inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,MAAM,GACd,OAAO,GACP,OAAO,GACP,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,GACP,oBAAoB,GACpB,mBAAmB,GACnB,WAAW,GACX,QAAQ,GACR,cAAc,GACd,cAAc,CAAC;AAEnB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,gBAAgB,GAAG,yBAAyB,CAAC;AAEpF;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,cAAc,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,oEAAoE;IACpE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC;IACpC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,gBAAgB,EAAyB,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * CLEO Database Inventory — SSoT type contract + immutable constant.
3
+ *
4
+ * @remarks
5
+ * This module exports the typed shape and the runtime constant for every
6
+ * SQLite database that CLEO manages. The runtime data is sourced from the
7
+ * canonical JSON inventory at `packages/core/src/store/db-inventory.json`
8
+ * via ESM JSON import (`with { type: 'json' }`). The JSON file is the
9
+ * single source of truth; this module re-exposes it with a typed contract.
10
+ *
11
+ * Downstream consumers:
12
+ *
13
+ * - **T10307 — Fleet survey** (`cleo doctor db-substrate`) iterates `DB_INVENTORY`
14
+ * to enumerate every DB on disk across project + global tiers.
15
+ * - **T10310 — Pragma drift** validates that every open handle for each role
16
+ * applies the pragma SSoT (`specs/sqlite-pragmas.json`).
17
+ * - **T10311 — Migration coverage** asserts that each entry's
18
+ * `migrationsDir` exists and contains a `0000_*` baseline.
19
+ * - **T10312 — Doctor integrity** runs `PRAGMA integrity_check` against
20
+ * every entry whose tier resolves to a present file on disk.
21
+ * - **T10320 — Cross-DB invariants** uses `ownerPackage` + `tier` to
22
+ * classify which DBs must agree on shared identifiers (project_id,
23
+ * agent_id, session_id, ...).
24
+ *
25
+ * Adding a new entry to the inventory is a charter amendment — update
26
+ * `db-inventory.json` AND `.cleo/adrs/ADR-068-cleo-database-charter.md`
27
+ * in the same PR (gated by `cleo check arch` Gate-4 SSoT-EXEMPT lint
28
+ * once T10282 ships its drift check).
29
+ *
30
+ * @see ADR-068 — CLEO Database Charter (canonical narrative)
31
+ * @see Saga T10281 — SG-BRAIN-DB-RESILIENCE (provenance)
32
+ * @see Epic T10282 — E1-DB-INVENTORY (this artifact)
33
+ * @see Research note `sg-brain-db-resilience-deep-audit-2026-05-23`
34
+ *
35
+ * @task T10305
36
+ * @epic T10282
37
+ * @saga T10281
38
+ */
39
+ import dbInventoryData from '../../core/src/store/db-inventory.json' with { type: 'json' };
40
+ // Narrow the raw JSON to the typed shape. The runtime parity test
41
+ // (`db-inventory.test.ts`) asserts every field is valid for every entry.
42
+ const rawInventory = dbInventoryData;
43
+ /**
44
+ * Immutable canonical inventory of every CLEO SQLite database.
45
+ *
46
+ * @remarks
47
+ * Sourced from `packages/core/src/store/db-inventory.json` — the SSoT.
48
+ * Adding a new entry is a charter amendment per ADR-068 §"How to add a
49
+ * new database". The {@link db-inventory.test.ts} suite asserts:
50
+ *
51
+ * 1. Every `role` is unique across the array.
52
+ * 2. Every `drizzleSchemaPath` (when non-null) exists on disk.
53
+ * 3. Every `migrationsDir` (when non-null) exists on disk.
54
+ * 4. Every `tier` is a member of the {@link DbTier} union.
55
+ *
56
+ * @example Iterate every project-tier database
57
+ * ```typescript
58
+ * import { DB_INVENTORY } from '@cleocode/contracts';
59
+ *
60
+ * const projectDbs = DB_INVENTORY.filter((entry) => entry.tier === 'project');
61
+ * for (const entry of projectDbs) {
62
+ * console.log(entry.role, entry.filePathTemplate);
63
+ * }
64
+ * ```
65
+ *
66
+ * @public
67
+ */
68
+ export const DB_INVENTORY = rawInventory.entries;
69
+ //# sourceMappingURL=db-inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-inventory.js","sourceRoot":"","sources":["../src/db-inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,eAAe,MAAM,wCAAwC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AA8J3F,kEAAkE;AAClE,yEAAyE;AACzE,MAAM,YAAY,GAAG,eAAkC,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,YAAY,CAAC,OAAO,CAAC"}