@cleocode/contracts 2026.5.108 → 2026.5.110

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.
Files changed (51) hide show
  1. package/dist/__tests__/db-inventory.test.d.ts +25 -0
  2. package/dist/__tests__/db-inventory.test.d.ts.map +1 -0
  3. package/dist/__tests__/db-inventory.test.js +148 -0
  4. package/dist/__tests__/db-inventory.test.js.map +1 -0
  5. package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
  6. package/dist/__tests__/task-type-narrowing.test.d.ts +14 -0
  7. package/dist/__tests__/task-type-narrowing.test.d.ts.map +1 -0
  8. package/dist/__tests__/task-type-narrowing.test.js +51 -0
  9. package/dist/__tests__/task-type-narrowing.test.js.map +1 -0
  10. package/dist/backup-verify.d.ts +136 -0
  11. package/dist/backup-verify.d.ts.map +1 -0
  12. package/dist/backup-verify.js +29 -0
  13. package/dist/backup-verify.js.map +1 -0
  14. package/dist/brain.d.ts +103 -0
  15. package/dist/brain.d.ts.map +1 -1
  16. package/dist/db-inventory.d.ts +200 -0
  17. package/dist/db-inventory.d.ts.map +1 -0
  18. package/dist/db-inventory.js +76 -0
  19. package/dist/db-inventory.js.map +1 -0
  20. package/dist/db-inventory.json +165 -0
  21. package/dist/db-recovery.d.ts +141 -0
  22. package/dist/db-recovery.d.ts.map +1 -0
  23. package/dist/db-recovery.js +29 -0
  24. package/dist/db-recovery.js.map +1 -0
  25. package/dist/doctor.d.ts +605 -0
  26. package/dist/doctor.d.ts.map +1 -1
  27. package/dist/index.d.ts +6 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/memory/observe.d.ts +8 -0
  32. package/dist/memory/observe.d.ts.map +1 -1
  33. package/dist/operations/tasks.d.ts +4 -4
  34. package/dist/operations/tasks.d.ts.map +1 -1
  35. package/dist/task.d.ts +13 -2
  36. package/dist/task.d.ts.map +1 -1
  37. package/dist/task.js.map +1 -1
  38. package/package.json +5 -4
  39. package/src/__tests__/db-inventory.test.ts +184 -0
  40. package/src/__tests__/memory-wire-shapes.test.ts +1 -0
  41. package/src/__tests__/task-type-narrowing.test.ts +56 -0
  42. package/src/backup-verify.ts +140 -0
  43. package/src/brain.ts +114 -0
  44. package/src/db-inventory.json +165 -0
  45. package/src/db-inventory.ts +234 -0
  46. package/src/db-recovery.ts +144 -0
  47. package/src/doctor.ts +634 -0
  48. package/src/index.ts +46 -0
  49. package/src/memory/observe.ts +8 -0
  50. package/src/operations/tasks.ts +4 -4
  51. package/src/task.ts +13 -2
@@ -0,0 +1,200 @@
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/contracts/src/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
+ * The JSON file is co-located in this package (rather than referencing a
12
+ * sibling-package `src/` path) so that the built `dist/db-inventory.js`
13
+ * resolves the JSON via a relative `./db-inventory.json` import that
14
+ * works inside the published `@cleocode/contracts` npm tarball — sibling
15
+ * package `src/` directories are not shipped to consumers.
16
+ *
17
+ * Downstream consumers:
18
+ *
19
+ * - **T10307 — Fleet survey** (`cleo doctor db-substrate`) iterates `DB_INVENTORY`
20
+ * to enumerate every DB on disk across project + global tiers.
21
+ * - **T10310 — Pragma drift** validates that every open handle for each role
22
+ * applies the pragma SSoT (`specs/sqlite-pragmas.json`).
23
+ * - **T10311 — Migration coverage** asserts that each entry's
24
+ * `migrationsDir` exists and contains a `0000_*` baseline.
25
+ * - **T10312 — Doctor integrity** runs `PRAGMA integrity_check` against
26
+ * every entry whose tier resolves to a present file on disk.
27
+ * - **T10320 — Cross-DB invariants** uses `ownerPackage` + `tier` to
28
+ * classify which DBs must agree on shared identifiers (project_id,
29
+ * agent_id, session_id, ...).
30
+ *
31
+ * Adding a new entry to the inventory is a charter amendment — update
32
+ * `packages/contracts/src/db-inventory.json` AND
33
+ * `.cleo/adrs/ADR-068-cleo-database-charter.md` in the same PR (gated by
34
+ * `cleo check arch` Gate-4 SSoT-EXEMPT lint once T10282 ships its drift
35
+ * check).
36
+ *
37
+ * @see ADR-068 — CLEO Database Charter (canonical narrative)
38
+ * @see Saga T10281 — SG-BRAIN-DB-RESILIENCE (provenance)
39
+ * @see Epic T10282 — E1-DB-INVENTORY (this artifact)
40
+ * @see Research note `sg-brain-db-resilience-deep-audit-2026-05-23`
41
+ *
42
+ * @task T10305
43
+ * @epic T10282
44
+ * @saga T10281
45
+ */
46
+ /**
47
+ * Canonical role names for every SQLite database in the CLEO charter.
48
+ *
49
+ * @remarks
50
+ * Mirrors the `openCleoDb('<role>', cwd)` chokepoint (ADR-068 §3) plus the
51
+ * three audit-discovered roles (`global-brain`, `global-tasks`, `manifest`)
52
+ * that exist on disk today but do not yet have a registered opener.
53
+ *
54
+ * - `tasks` — project-tier task engine DB
55
+ * - `brain` — project-tier memory DB (PII)
56
+ * - `conduit` — project-tier agent message transport
57
+ * - `manifest` — project-tier derived blob index (rebuildable)
58
+ * - `llmtxt` — reserved project-tier llmtxt session store
59
+ * - `nexus` — global-tier cross-project knowledge graph (PII)
60
+ * - `signaldock-project` — historical project-tier signaldock (post-ADR-037, merged into conduit)
61
+ * - `signaldock-global` — global-tier canonical agent identity registry
62
+ * - `telemetry` — global-tier opt-in command telemetry
63
+ * - `skills` — global-tier per-user skill registry
64
+ * - `global-brain` — global-tier brain.db observed on disk (audit §1.2 — provenance under investigation)
65
+ * - `global-tasks` — global-tier tasks.db observed on disk (audit §1.2 — provenance under investigation)
66
+ *
67
+ * @public
68
+ */
69
+ export type DbRole = 'tasks' | 'brain' | 'conduit' | 'manifest' | 'llmtxt' | 'nexus' | 'signaldock-project' | 'signaldock-global' | 'telemetry' | 'skills' | 'global-brain' | 'global-tasks';
70
+ /**
71
+ * Lifecycle scope of a CLEO database.
72
+ *
73
+ * @remarks
74
+ * - `project` — file lives under `<projectRoot>/.cleo/`; lifecycle bound to one CLEO project.
75
+ * - `global` — file lives under `$XDG_DATA_HOME/cleo/` (env-paths via `getCleoHome()`).
76
+ * - `derived` — file lives under the project tier but is rebuildable from a
77
+ * non-DB source-of-truth (e.g. content-addressable blob store).
78
+ * MAY be excluded from backup-pack.
79
+ *
80
+ * @public
81
+ */
82
+ export type DbTier = 'project' | 'global' | 'derived';
83
+ /**
84
+ * Privacy classification governing backup + cloud-export rules.
85
+ *
86
+ * @remarks
87
+ * - `local-only` — never cloud-exported.
88
+ * - `local-only-pii` — never cloud-exported; PII-class — requires
89
+ * explicit `cleo backup export --include-pii`.
90
+ * - `cloud-exportable-opt-in` — may be exported only after explicit opt-in
91
+ * (e.g. `cleo diagnostics enable`).
92
+ *
93
+ * @public
94
+ */
95
+ export type DbPrivacy = 'local-only' | 'local-only-pii' | 'cloud-exportable-opt-in';
96
+ /**
97
+ * Concurrency model for the database.
98
+ *
99
+ * @remarks
100
+ * Every CLEO database today is `single-writer` (WAL mode with in-process
101
+ * serialization via the `openCleoDb` singleton). The field is enumerated so
102
+ * a future read-replica or multi-writer DB MUST be declared explicitly.
103
+ *
104
+ * @public
105
+ */
106
+ export type DbConcurrency = 'single-writer' | 'multi-writer';
107
+ /**
108
+ * One row in the CLEO database charter.
109
+ *
110
+ * @remarks
111
+ * Every field is required (no `null` placeholders) EXCEPT `drizzleSchemaPath`
112
+ * and `migrationsDir` — those MAY be `null` for:
113
+ *
114
+ * - `derived` databases whose schema is owned by an upstream library (e.g.
115
+ * `manifest.db` is owned by `llmtxt/blob`'s `BlobFsAdapter` contract).
116
+ * - `reserved` roles whose opener throws `not yet implemented` (e.g.
117
+ * `llmtxt.db`).
118
+ *
119
+ * Path templates use the substitution tokens:
120
+ *
121
+ * - `<projectRoot>` — resolved at runtime from `CLEO_ROOT` env var or
122
+ * `process.cwd()` via `getCleoProjectDir()`.
123
+ * - `$XDG_DATA_HOME` — resolved via env-paths through `getCleoHome()`.
124
+ * Linux: `~/.local/share/cleo/`; macOS:
125
+ * `~/Library/Application Support/cleo/`.
126
+ *
127
+ * @public
128
+ */
129
+ export interface DbInventoryEntry {
130
+ /** Canonical role identifier used by `openCleoDb` and audit tooling. */
131
+ readonly role: DbRole;
132
+ /** Lifecycle scope — project, global, or derived. */
133
+ readonly tier: DbTier;
134
+ /**
135
+ * Filesystem path template with `<projectRoot>` / `$XDG_DATA_HOME` tokens.
136
+ * Substitution convention is documented on {@link DbInventoryEntry}.
137
+ */
138
+ readonly filePathTemplate: string;
139
+ /**
140
+ * Repo-relative path to the Drizzle schema TypeScript file. `null` when
141
+ * the schema is owned by an upstream library or the role is reserved.
142
+ */
143
+ readonly drizzleSchemaPath: string | null;
144
+ /**
145
+ * Repo-relative path to the Drizzle migrations directory (with trailing
146
+ * slash). `null` for `derived` rows or reserved roles. The path MUST
147
+ * exist on disk when non-null — enforced by the contracts test suite.
148
+ */
149
+ readonly migrationsDir: string | null;
150
+ /** npm package that owns the open + lifecycle for this database. */
151
+ readonly ownerPackage: string;
152
+ /**
153
+ * Human-readable description of HOW the database is opened. Typically
154
+ * a code excerpt like `openCleoDb('tasks', cwd)`. For databases without
155
+ * a registered opener, describes provenance / status.
156
+ */
157
+ readonly openedVia: string;
158
+ /** Concurrency model — see {@link DbConcurrency}. */
159
+ readonly concurrency: DbConcurrency;
160
+ /** Privacy classification — see {@link DbPrivacy}. */
161
+ readonly privacy: DbPrivacy;
162
+ /**
163
+ * Canonical backup path template. For `derived` rows this is the
164
+ * sentinel string `rebuildable-from-blob-store` (or similar) and the
165
+ * row is excluded from backup-pack staging.
166
+ */
167
+ readonly backupPath: string;
168
+ /**
169
+ * Provenance pointers — ADR row, related task IDs, audit section
170
+ * references. Comma-or-semicolon separated string of references.
171
+ */
172
+ readonly documentedIn: string;
173
+ }
174
+ /**
175
+ * Immutable canonical inventory of every CLEO SQLite database.
176
+ *
177
+ * @remarks
178
+ * Sourced from `packages/contracts/src/db-inventory.json` — the SSoT.
179
+ * Adding a new entry is a charter amendment per ADR-068 §"How to add a
180
+ * new database". The {@link db-inventory.test.ts} suite asserts:
181
+ *
182
+ * 1. Every `role` is unique across the array.
183
+ * 2. Every `drizzleSchemaPath` (when non-null) exists on disk.
184
+ * 3. Every `migrationsDir` (when non-null) exists on disk.
185
+ * 4. Every `tier` is a member of the {@link DbTier} union.
186
+ *
187
+ * @example Iterate every project-tier database
188
+ * ```typescript
189
+ * import { DB_INVENTORY } from '@cleocode/contracts';
190
+ *
191
+ * const projectDbs = DB_INVENTORY.filter((entry) => entry.tier === 'project');
192
+ * for (const entry of projectDbs) {
193
+ * console.log(entry.role, entry.filePathTemplate);
194
+ * }
195
+ * ```
196
+ *
197
+ * @public
198
+ */
199
+ export declare const DB_INVENTORY: readonly DbInventoryEntry[];
200
+ //# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;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,76 @@
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/contracts/src/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
+ * The JSON file is co-located in this package (rather than referencing a
12
+ * sibling-package `src/` path) so that the built `dist/db-inventory.js`
13
+ * resolves the JSON via a relative `./db-inventory.json` import that
14
+ * works inside the published `@cleocode/contracts` npm tarball — sibling
15
+ * package `src/` directories are not shipped to consumers.
16
+ *
17
+ * Downstream consumers:
18
+ *
19
+ * - **T10307 — Fleet survey** (`cleo doctor db-substrate`) iterates `DB_INVENTORY`
20
+ * to enumerate every DB on disk across project + global tiers.
21
+ * - **T10310 — Pragma drift** validates that every open handle for each role
22
+ * applies the pragma SSoT (`specs/sqlite-pragmas.json`).
23
+ * - **T10311 — Migration coverage** asserts that each entry's
24
+ * `migrationsDir` exists and contains a `0000_*` baseline.
25
+ * - **T10312 — Doctor integrity** runs `PRAGMA integrity_check` against
26
+ * every entry whose tier resolves to a present file on disk.
27
+ * - **T10320 — Cross-DB invariants** uses `ownerPackage` + `tier` to
28
+ * classify which DBs must agree on shared identifiers (project_id,
29
+ * agent_id, session_id, ...).
30
+ *
31
+ * Adding a new entry to the inventory is a charter amendment — update
32
+ * `packages/contracts/src/db-inventory.json` AND
33
+ * `.cleo/adrs/ADR-068-cleo-database-charter.md` in the same PR (gated by
34
+ * `cleo check arch` Gate-4 SSoT-EXEMPT lint once T10282 ships its drift
35
+ * check).
36
+ *
37
+ * @see ADR-068 — CLEO Database Charter (canonical narrative)
38
+ * @see Saga T10281 — SG-BRAIN-DB-RESILIENCE (provenance)
39
+ * @see Epic T10282 — E1-DB-INVENTORY (this artifact)
40
+ * @see Research note `sg-brain-db-resilience-deep-audit-2026-05-23`
41
+ *
42
+ * @task T10305
43
+ * @epic T10282
44
+ * @saga T10281
45
+ */
46
+ import dbInventoryData from './db-inventory.json' with { type: 'json' };
47
+ // Narrow the raw JSON to the typed shape. The runtime parity test
48
+ // (`db-inventory.test.ts`) asserts every field is valid for every entry.
49
+ const rawInventory = dbInventoryData;
50
+ /**
51
+ * Immutable canonical inventory of every CLEO SQLite database.
52
+ *
53
+ * @remarks
54
+ * Sourced from `packages/contracts/src/db-inventory.json` — the SSoT.
55
+ * Adding a new entry is a charter amendment per ADR-068 §"How to add a
56
+ * new database". The {@link db-inventory.test.ts} suite asserts:
57
+ *
58
+ * 1. Every `role` is unique across the array.
59
+ * 2. Every `drizzleSchemaPath` (when non-null) exists on disk.
60
+ * 3. Every `migrationsDir` (when non-null) exists on disk.
61
+ * 4. Every `tier` is a member of the {@link DbTier} union.
62
+ *
63
+ * @example Iterate every project-tier database
64
+ * ```typescript
65
+ * import { DB_INVENTORY } from '@cleocode/contracts';
66
+ *
67
+ * const projectDbs = DB_INVENTORY.filter((entry) => entry.tier === 'project');
68
+ * for (const entry of projectDbs) {
69
+ * console.log(entry.role, entry.filePathTemplate);
70
+ * }
71
+ * ```
72
+ *
73
+ * @public
74
+ */
75
+ export const DB_INVENTORY = rawInventory.entries;
76
+ //# sourceMappingURL=db-inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-inventory.js","sourceRoot":"","sources":["../src/db-inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,eAAe,MAAM,qBAAqB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AA8JxE,kEAAkE;AAClE,yEAAyE;AACzE,MAAM,YAAY,GAAG,eAAkC,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,YAAY,CAAC,OAAO,CAAC"}
@@ -0,0 +1,165 @@
1
+ {
2
+ "$schemaNote": "SSoT machine-readable inventory of every CLEO SQLite database. Consumed by T10307 fleet survey, T10310 pragma drift, T10311 migration coverage, T10312 doctor integrity, T10320 cross-DB invariants. Owned by Saga T10281 SG-BRAIN-DB-RESILIENCE / Epic T10282 E1-DB-INVENTORY (task T10305). Amend together with ADR-068 charter; the CI drift gate (forthcoming under E1) compares entries to disk reality.",
3
+ "$pathTokens": {
4
+ "<projectRoot>": "Resolved at runtime from CLEO_ROOT env var or process.cwd(). Substituted by SSoT helpers `getCleoProjectDir()` in packages/brain/src/cleo-home.ts.",
5
+ "$XDG_DATA_HOME": "Resolved via env-paths through `getCleoHome()` in @cleocode/paths. Linux: ~/.local/share/cleo/, macOS: ~/Library/Application Support/cleo/."
6
+ },
7
+ "entries": [
8
+ {
9
+ "role": "tasks",
10
+ "tier": "project",
11
+ "filePathTemplate": "<projectRoot>/.cleo/tasks.db",
12
+ "drizzleSchemaPath": "packages/core/src/store/tasks-schema.ts",
13
+ "migrationsDir": "packages/core/migrations/drizzle-tasks/",
14
+ "ownerPackage": "@cleocode/core",
15
+ "openedVia": "openCleoDb('tasks', cwd)",
16
+ "concurrency": "single-writer",
17
+ "privacy": "local-only",
18
+ "backupPath": ".cleo/backups/sqlite/tasks-YYYYMMDD-HHmmss.db",
19
+ "documentedIn": "ADR-068 row 1; ADR-013 §9"
20
+ },
21
+ {
22
+ "role": "brain",
23
+ "tier": "project",
24
+ "filePathTemplate": "<projectRoot>/.cleo/brain.db",
25
+ "drizzleSchemaPath": "packages/core/src/store/memory-schema.ts",
26
+ "migrationsDir": "packages/core/migrations/drizzle-brain/",
27
+ "ownerPackage": "@cleocode/brain",
28
+ "openedVia": "openCleoDb('brain', cwd)",
29
+ "concurrency": "single-writer",
30
+ "privacy": "local-only-pii",
31
+ "backupPath": ".cleo/backups/sqlite/brain-YYYYMMDD-HHmmss.db",
32
+ "documentedIn": "ADR-068 row 2; ADR-013 §9; audit §2 (P0 malformed 2026-05-23)"
33
+ },
34
+ {
35
+ "role": "conduit",
36
+ "tier": "project",
37
+ "filePathTemplate": "<projectRoot>/.cleo/conduit.db",
38
+ "drizzleSchemaPath": "packages/core/src/store/conduit-schema.ts",
39
+ "migrationsDir": "packages/core/migrations/drizzle-conduit/",
40
+ "ownerPackage": "@cleocode/core",
41
+ "openedVia": "openCleoDb('conduit', cwd)",
42
+ "concurrency": "single-writer",
43
+ "privacy": "local-only",
44
+ "backupPath": ".cleo/backups/sqlite/conduit-YYYYMMDD-HHmmss.db",
45
+ "documentedIn": "ADR-068 row 3; ADR-037 (signaldock→conduit split)"
46
+ },
47
+ {
48
+ "role": "manifest",
49
+ "tier": "derived",
50
+ "filePathTemplate": "<projectRoot>/.cleo/blobs/manifest.db",
51
+ "drizzleSchemaPath": "packages/core/src/store/llmtxt-blob-adapter.ts",
52
+ "migrationsDir": null,
53
+ "ownerPackage": "@cleocode/core",
54
+ "openedVia": "CleoBlobStore via llmtxt/blob BlobFsAdapter (no openCleoDb role registered)",
55
+ "concurrency": "single-writer",
56
+ "privacy": "local-only",
57
+ "backupPath": "rebuildable-from-blob-store",
58
+ "documentedIn": "ADR-068 row 7 (derived); schema owned by llmtxt/blob BlobFsAdapter contract"
59
+ },
60
+ {
61
+ "role": "llmtxt",
62
+ "tier": "project",
63
+ "filePathTemplate": "<projectRoot>/.cleo/llmtxt/llmtxt.db",
64
+ "drizzleSchemaPath": null,
65
+ "migrationsDir": null,
66
+ "ownerPackage": "@cleocode/llmtxt-core",
67
+ "openedVia": "openCleoDb('llmtxt', cwd) — RESERVED; opener throws 'not yet implemented' (see open-cleo-db.ts L138)",
68
+ "concurrency": "single-writer",
69
+ "privacy": "local-only-pii",
70
+ "backupPath": ".cleo/backups/sqlite/llmtxt-YYYYMMDD-HHmmss.db",
71
+ "documentedIn": "ADR-068 row 8 (reserved); audit §1.1 row 4 (live at .cleo/llmtxt/llmtxt.db)"
72
+ },
73
+ {
74
+ "role": "nexus",
75
+ "tier": "global",
76
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/nexus.db",
77
+ "drizzleSchemaPath": "packages/core/src/store/nexus-schema.ts",
78
+ "migrationsDir": "packages/core/migrations/drizzle-nexus/",
79
+ "ownerPackage": "@cleocode/core",
80
+ "openedVia": "openCleoDb('nexus')",
81
+ "concurrency": "single-writer",
82
+ "privacy": "local-only-pii",
83
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/nexus-YYYYMMDD-HHmmss.db",
84
+ "documentedIn": "ADR-068 row 5"
85
+ },
86
+ {
87
+ "role": "signaldock-project",
88
+ "tier": "project",
89
+ "filePathTemplate": "<projectRoot>/.cleo/signaldock.db",
90
+ "drizzleSchemaPath": "packages/core/src/store/signaldock-schema.ts",
91
+ "migrationsDir": "packages/core/migrations/drizzle-signaldock/",
92
+ "ownerPackage": "@cleocode/core",
93
+ "openedVia": "HISTORICAL — project-tier signaldock.db was migrated into conduit.db post-T310/ADR-037. No live opener; charter row retained for migration provenance and legacy backup detection.",
94
+ "concurrency": "single-writer",
95
+ "privacy": "local-only",
96
+ "backupPath": ".cleo/backups/sqlite/signaldock-project-YYYYMMDD-HHmmss.db",
97
+ "documentedIn": "ADR-068 row 4 (stale — superseded by ADR-037); audit §1.1 (not in live project DB list)"
98
+ },
99
+ {
100
+ "role": "signaldock-global",
101
+ "tier": "global",
102
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/signaldock.db",
103
+ "drizzleSchemaPath": "packages/core/src/store/signaldock-schema.ts",
104
+ "migrationsDir": "packages/core/migrations/drizzle-signaldock/",
105
+ "ownerPackage": "@cleocode/core",
106
+ "openedVia": "openCleoDb('signaldock')",
107
+ "concurrency": "single-writer",
108
+ "privacy": "local-only",
109
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/signaldock-global-YYYYMMDD-HHmmss.db",
110
+ "documentedIn": "ADR-068 row 9; ADR-037 (post-split global identity registry)"
111
+ },
112
+ {
113
+ "role": "telemetry",
114
+ "tier": "global",
115
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/telemetry.db",
116
+ "drizzleSchemaPath": "packages/core/src/telemetry/schema.ts",
117
+ "migrationsDir": "packages/core/migrations/drizzle-telemetry/",
118
+ "ownerPackage": "@cleocode/core",
119
+ "openedVia": "@cleocode/core telemetry/sqlite.ts — lazy open on first event when opted-in; not yet registered as openCleoDb role",
120
+ "concurrency": "single-writer",
121
+ "privacy": "cloud-exportable-opt-in",
122
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/telemetry-YYYYMMDD-HHmmss.db",
123
+ "documentedIn": "ADR-068 row 6; T624"
124
+ },
125
+ {
126
+ "role": "skills",
127
+ "tier": "global",
128
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/skills.db",
129
+ "drizzleSchemaPath": "packages/core/src/store/skills-schema.ts",
130
+ "migrationsDir": "packages/core/migrations/drizzle-skills/",
131
+ "ownerPackage": "@cleocode/core",
132
+ "openedVia": "openCleoDb('skills')",
133
+ "concurrency": "single-writer",
134
+ "privacy": "local-only",
135
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/skills-YYYYMMDD-HHmmss.db",
136
+ "documentedIn": "T9651 (initial skills.db migration); audit §1.2 row 4 — NOT yet in ADR-068 table"
137
+ },
138
+ {
139
+ "role": "global-brain",
140
+ "tier": "global",
141
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/brain.db",
142
+ "drizzleSchemaPath": "packages/core/src/store/memory-schema.ts",
143
+ "migrationsDir": "packages/core/migrations/drizzle-brain/",
144
+ "ownerPackage": "@cleocode/brain",
145
+ "openedVia": "UNREGISTERED — file exists on disk (audit §1.2 row 3) but no live opener. Provenance unclear; likely orphan from a getCleoHome()-vs-project-resolution path bug. Tracked for cleanup decision under T10282/T10307.",
146
+ "concurrency": "single-writer",
147
+ "privacy": "local-only-pii",
148
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/global-brain-YYYYMMDD-HHmmss.db",
149
+ "documentedIn": "audit §1.2 row 3 — NEW per saga T10281; not in ADR-068"
150
+ },
151
+ {
152
+ "role": "global-tasks",
153
+ "tier": "global",
154
+ "filePathTemplate": "$XDG_DATA_HOME/cleo/tasks.db",
155
+ "drizzleSchemaPath": "packages/core/src/store/tasks-schema.ts",
156
+ "migrationsDir": "packages/core/migrations/drizzle-tasks/",
157
+ "ownerPackage": "@cleocode/core",
158
+ "openedVia": "UNREGISTERED — file exists on disk (audit §1.2 row 5, 4 KB) but no live opener. Provenance unclear; likely orphan from a cwd-cascade bug (T9550 class). Tracked for cleanup decision under T10282/T10307.",
159
+ "concurrency": "single-writer",
160
+ "privacy": "local-only",
161
+ "backupPath": "$XDG_DATA_HOME/cleo/backups/sqlite/global-tasks-YYYYMMDD-HHmmss.db",
162
+ "documentedIn": "audit §1.2 row 5 — NEW per saga T10281; not in ADR-068"
163
+ }
164
+ ]
165
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Generic CLEO database recovery contracts — generalised from the brain-only
3
+ * T10303/T10304 shapes so the same envelope works for every role declared in
4
+ * {@link DB_INVENTORY}.
5
+ *
6
+ * These types mirror {@link BrainRecoveryResult} + {@link BackupRecoverBrainResult}
7
+ * almost verbatim, with two adjustments:
8
+ *
9
+ * 1. `observationsRecovered: number | null` is generalised to
10
+ * `rowCounts: DbRecoveredRowCounts` — a `Record<tableName, number | null>`
11
+ * keyed by the user tables discovered in the restored DB via
12
+ * `sqlite_master`. Tables that fail to count surface as `null`.
13
+ * 2. Every envelope carries the `role: DbRole` it pertains to so envelopes from
14
+ * `cleo backup recover <role>` are self-describing across tools that may
15
+ * fan recovery out across multiple DBs.
16
+ *
17
+ * The brain-specific shapes ({@link BrainRecoveryResult},
18
+ * {@link BackupRecoverBrainResult}, {@link BrainRecoveredRowCounts}) remain in
19
+ * {@link brain.ts} as the backward-compatible surface — the brain CLI verb
20
+ * (`cleo backup recover brain`) still emits the same envelope it did before
21
+ * T10318 generalised the pipeline.
22
+ *
23
+ * @task T10318
24
+ * @epic T10284
25
+ * @saga T10281
26
+ * @adr ADR-068
27
+ */
28
+ import type { DbRole } from './db-inventory.js';
29
+ /**
30
+ * Best-effort per-table row counts probed from a recovered CLEO database.
31
+ *
32
+ * @remarks
33
+ * The recovery pipeline enumerates user tables in the restored DB via
34
+ * `sqlite_master` (excluding internal `sqlite_*` and Drizzle journal tables)
35
+ * and runs `SELECT COUNT(*)` on each. Tables that fail to count — for
36
+ * example, a missing table in a very old snapshot, or a schema/version
37
+ * mismatch — surface as `null` instead of throwing so the envelope always
38
+ * serialises cleanly.
39
+ *
40
+ * Keys are exact SQLite table names (case-sensitive). Values are non-negative
41
+ * integers or `null`.
42
+ *
43
+ * @public
44
+ */
45
+ export type DbRecoveredRowCounts = Readonly<Record<string, number | null>>;
46
+ /**
47
+ * Result of a generic CLEO DB auto-recovery attempt.
48
+ *
49
+ * @remarks
50
+ * Returned by `recoverMalformedDb({ role, ... })` (T10318) when the chokepoint
51
+ * (or an operator invoking `cleo backup recover <role>`) detects malformation
52
+ * via `ERR_SQLITE_ERROR errcode=11` or a failing `PRAGMA integrity_check` /
53
+ * `PRAGMA quick_check`. The corrupt DB has been moved to a quarantine
54
+ * directory and the freshest validated snapshot has been copied to the
55
+ * canonical role path.
56
+ *
57
+ * Consumers read this structure to decide whether to re-attempt the open and
58
+ * to emit user-facing diagnostics with the data-loss window.
59
+ *
60
+ * @public
61
+ */
62
+ export interface DbRecoveryResult {
63
+ /** Canonical role of the database that was recovered. */
64
+ role: DbRole;
65
+ /** Absolute path to the snapshot that was restored, or `null` if recovery failed. */
66
+ restoredFrom: string | null;
67
+ /**
68
+ * Approximate hours between the snapshot's timestamp and the recovery
69
+ * event. `null` when the snapshot timestamp could not be parsed.
70
+ * Used in the recovery warning to make the data-loss window legible.
71
+ */
72
+ dataLossWindowHours: number | null;
73
+ /**
74
+ * Per-table row counts probed from the restored DB. Each key is a user
75
+ * table name; each value is the row count, or `null` on count failure.
76
+ * Empty record `{}` when the restored DB has no user tables (or when
77
+ * the probe itself failed to open the DB).
78
+ */
79
+ rowCounts: DbRecoveredRowCounts;
80
+ /** `true` if the restored DB passes `PRAGMA quick_check`. */
81
+ integrityOK: boolean;
82
+ /**
83
+ * Absolute path to the quarantine directory where the corrupt DB plus
84
+ * its `-wal`/`-shm` sidecars were moved before restore. `null` when no
85
+ * corrupt DB existed at the canonical path (recovery into an empty slot).
86
+ */
87
+ quarantineDir: string | null;
88
+ }
89
+ /**
90
+ * Envelope payload returned by `cleo backup recover <role>`.
91
+ *
92
+ * @remarks
93
+ * Wraps {@link DbRecoveryResult} with three CLI-only additions:
94
+ *
95
+ * - `rowsRecovered` aliases `rowCounts` to keep the envelope shape compatible
96
+ * with the brain-specific {@link BackupRecoverBrainResult}.
97
+ * - `quarantinedTo: string` is the non-nullable string form (empty string in
98
+ * `--dry-run` mode where no files were touched) — easier for shell scripts
99
+ * that pipe the envelope into `jq` and then path operations.
100
+ * - `dryRun: boolean` records whether the envelope is a *plan* (would-do)
101
+ * versus a *record* (already-done). Consumers MUST check this before
102
+ * treating `restoredFrom` as a post-condition.
103
+ *
104
+ * @task T10318
105
+ * @epic T10284
106
+ * @saga T10281
107
+ * @public
108
+ */
109
+ export interface BackupRecoverResult {
110
+ /** Canonical role of the database that was (or would be) recovered. */
111
+ role: DbRole;
112
+ /**
113
+ * Absolute path to the snapshot that was (or would be) restored. Empty
114
+ * string when no snapshot was available — the envelope's caller surfaces
115
+ * that as a failure mode via a structured error.
116
+ */
117
+ restoredFrom: string;
118
+ /** Per-table row counts probed from the restored DB (or the plan target). */
119
+ rowsRecovered: DbRecoveredRowCounts;
120
+ /**
121
+ * Approximate hours between the snapshot's timestamp and the recovery
122
+ * event. `null` when the snapshot timestamp could not be parsed (e.g.
123
+ * legacy `<role>.db.PRE-DUP-FIX-*` fallback artifact).
124
+ */
125
+ dataLossWindowHours: number | null;
126
+ /** `true` when the restored DB passes `PRAGMA quick_check`. */
127
+ integrityOK: boolean;
128
+ /**
129
+ * Absolute path to the quarantine directory where the corrupt DB plus
130
+ * its `-wal`/`-shm` sidecars were moved. Empty string in `--dry-run`
131
+ * mode where no files were touched.
132
+ */
133
+ quarantinedTo: string;
134
+ /**
135
+ * `true` when invoked with `--dry-run` — indicates the envelope is a
136
+ * plan, NOT a record of mutations performed. Consumers MUST check this
137
+ * before treating `restoredFrom` as a post-condition.
138
+ */
139
+ dryRun: boolean;
140
+ }
141
+ //# sourceMappingURL=db-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-recovery.d.ts","sourceRoot":"","sources":["../src/db-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;;OAKG;IACH,SAAS,EAAE,oBAAoB,CAAC;IAChC,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,aAAa,EAAE,oBAAoB,CAAC;IACpC;;;;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,29 @@
1
+ /**
2
+ * Generic CLEO database recovery contracts — generalised from the brain-only
3
+ * T10303/T10304 shapes so the same envelope works for every role declared in
4
+ * {@link DB_INVENTORY}.
5
+ *
6
+ * These types mirror {@link BrainRecoveryResult} + {@link BackupRecoverBrainResult}
7
+ * almost verbatim, with two adjustments:
8
+ *
9
+ * 1. `observationsRecovered: number | null` is generalised to
10
+ * `rowCounts: DbRecoveredRowCounts` — a `Record<tableName, number | null>`
11
+ * keyed by the user tables discovered in the restored DB via
12
+ * `sqlite_master`. Tables that fail to count surface as `null`.
13
+ * 2. Every envelope carries the `role: DbRole` it pertains to so envelopes from
14
+ * `cleo backup recover <role>` are self-describing across tools that may
15
+ * fan recovery out across multiple DBs.
16
+ *
17
+ * The brain-specific shapes ({@link BrainRecoveryResult},
18
+ * {@link BackupRecoverBrainResult}, {@link BrainRecoveredRowCounts}) remain in
19
+ * {@link brain.ts} as the backward-compatible surface — the brain CLI verb
20
+ * (`cleo backup recover brain`) still emits the same envelope it did before
21
+ * T10318 generalised the pipeline.
22
+ *
23
+ * @task T10318
24
+ * @epic T10284
25
+ * @saga T10281
26
+ * @adr ADR-068
27
+ */
28
+ export {};
29
+ //# sourceMappingURL=db-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-recovery.js","sourceRoot":"","sources":["../src/db-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG"}