/** * T10165 — One-shot backfill: migrate `.cleo/adrs/adr-index.jsonl` rows into * the `attachments` table provenance columns shipped by T10158. * * The JSONL is a denormalised portability export historically regenerated by * `syncAdrsToDb` in `packages/core/src/adrs/sync.ts`. After this migration the * primary store for the same metadata is the `attachments` table (with the * T10158-introduced columns `lifecycle_status`, `supersedes`, `superseded_by`, * `summary`, `keywords`, `topics`, `related_tasks`), reachable from the docs * SSoT graph (T10162 supersede verb, T10164 graph CLI). * * ## Behaviour * * For every ADR row in `adr-index.jsonl`: * 1. Resolve the on-disk `.cleo/adrs/` and compute its `sha256`. * 2. Look up — or insert — an `attachments` row keyed on the sha. The * attachment payload is a minimal `BlobAttachment` discriminator so the * record is identical in shape to what `cleo docs add --type adr` would * have produced if invoked directly. * 3. Populate the seven provenance columns from the JSONL fields: * - `lifecycle_status` ← JSONL `status` (mapped to the * {@link ATTACHMENT_LIFECYCLE_STATUSES} enum) * - `supersedes` ← attachment id of the JSONL `supersedes` * target (ADR-NNN → resolved via slug lookup) * - `superseded_by` ← attachment id of the JSONL `supersededBy` * target (resolved via slug lookup) * - `summary` ← JSONL `summary` * - `keywords` ← JSON-encoded `keywords[]` * - `topics` ← JSON-encoded `topics[]` * - `related_tasks` ← JSON-encoded `relatedTasks[]` * 4. Set `slug = ` (e.g. `adr-003`) and `type = 'adr'` * so the row is reachable from `cleo docs fetch adr-003` exactly like * any other doc kind. * * Two passes are required because the supersession edges form a graph: the * first pass inserts/updates every attachment row, the second pass resolves * the `supersedes` / `superseded_by` FKs once every slug exists. * * ## Idempotency * * The script is safe to re-run. A row already populated for the same `sha256` * is updated in place (no duplicate insert) and the `slug` UNIQUE INDEX is * pre-checked outside the transaction window to surface a friendly error if * a non-ADR row already owns the target slug. * * ## Usage * * ```bash * # Dry-run (default) — reports what would change without writing * pnpm --filter @cleocode/core exec tsx \ * packages/core/src/migration/manual/T10165-backfill-adr-index.ts --dry-run * * # Apply — writes to tasks.db * pnpm --filter @cleocode/core exec tsx \ * packages/core/src/migration/manual/T10165-backfill-adr-index.ts --apply * ``` * * The exported {@link backfillAdrIndex} function is the same code path used * by the tests. * * @task T10165 * @epic T10157 (C-DOCS-SSOT) * @saga T9855 (SG-TEMPLATE-CONFIG-SSOT) */ /** * Shape of one line in `.cleo/adrs/adr-index.jsonl`. * * Fields are optional because the historical writer omits them when blank; * the backfill treats missing/blank fields as `null`. */ export interface AdrIndexRow { /** ADR identifier, e.g. `"ADR-003"`. */ id: string; /** Path of the ADR markdown file relative to the project root. */ file: string; /** Human-readable ADR title. */ title: string; /** Lifecycle status — `"proposed" | "accepted" | "superseded" | "deprecated" | ...`. */ status?: string; /** ISO date when the ADR was authored. */ date?: string; /** ISO date when the ADR transitioned to `accepted` (if any). */ accepted?: string; /** Free-form reference to the ADR this one supersedes, e.g. `"ADR-001"`. */ supersedes?: string; /** Free-form reference to the ADR that supersedes this one. */ supersededBy?: string; /** Comma-split list of related task IDs (`T####`). */ relatedTasks?: string[]; /** Human-readable summary sentence. */ summary?: string; /** Free-form keywords. */ keywords?: string[]; /** Higher-signal topic slugs. */ topics?: string[]; } /** Outcome of a single backfill run. */ export interface BackfillResult { /** ADR rows that were newly inserted into `attachments`. */ inserted: number; /** ADR rows whose `attachments` row was updated in place. */ updated: number; /** ADR rows whose row already matched the target state — no write needed. */ unchanged: number; /** ADR rows that referenced a missing or unreadable markdown file. */ fileMissing: number; /** ADR rows whose `supersedes` / `supersededBy` target could not be resolved. */ unresolvedEdges: number; /** Non-fatal warnings — one line per concern. */ warnings: string[]; } /** * Parse the JSONL file at `path` into a typed list of {@link AdrIndexRow}. * * Lines that fail to parse are skipped with a warning so a single malformed * entry never blocks the entire backfill (mirrors the T9780 lesson). */ export declare function parseAdrIndexJsonl(path: string, warnings: string[]): AdrIndexRow[]; /** * One-shot backfill entry point. * * Reads `/.cleo/adrs/adr-index.jsonl`, populates the * `attachments` table provenance columns for every ADR row, then resolves * `supersedes` / `superseded_by` edges on a second pass once every slug * exists. * * @param projectRoot - Absolute project root containing the `.cleo/` directory. * @param opts.dryRun - When `true`, no rows are written; returns the would-be * counts instead. */ export declare function backfillAdrIndex(projectRoot: string, opts?: { dryRun?: boolean; }): Promise; //# sourceMappingURL=T10165-backfill-adr-index.d.ts.map