/** * `cleo provenance backfill --since ` — Phase 2 of T9493 (T9528). * * Walks historical git tags from a starting version forward and populates the * 11 provenance tables (commits, task_commits, commit_files, pull_requests, * pr_commits, pr_tasks, releases, release_commits, release_changes, * release_artifacts, brain_release_links) for every release in the range. * * Design: * * - Enumerates tags via `git tag --list --sort=creatordate` (handles both * annotated and lightweight tags — `committerdate` silently drops * annotated tags because they have no committerdate of their own). * - For each tag, synthesises a minimal release plan (T#### tokens extracted * from `git log`, tasks resolved against `tasks.db`) when no plan file * already exists, then invokes {@link releaseReconcileV2} with the * `backfill: true` flag (skips the ADR-051 staleness gate per T9528 design). * - Restartable via `.cleo/release/backfill-state.json` checkpoint — every * successfully-reconciled tag is appended to `completedTags[]` before the * next iteration starts. On Ctrl-C the next invocation resumes from where * the previous one left off. * - Idempotent: re-running over already-reconciled tags is a no-op because * reconcile's `releases.status='reconciled'` short-circuit applies. * - `--force-overwrite` clears the checkpoint AND signals downstream * reconcile to UPDATE existing rows (current SQL is UPSERT, so the effect * is informational + audit-logged). * - `--dry-run` enumerates the tag set and returns it without writing to DB * or disk. * * @task T9528 * @epic T9493 * @adr ADR-T9345 (IVTR-release-overhaul) * @spec .cleo/rcasd/T9345/research/SPEC-T9345-release-pipeline-v2.md §8.3 * @spec .cleo/rcasd/T9345/research/provenance-graph-design.md §4.4 */ import { type EngineResult } from '../engine-result.js'; /** * Options for {@link provenanceBackfill}. * * `since` is the lower-bound version (exclusive — matches `git log A..B` * range semantics). Tags whose committer date is strictly greater than * `since` are enumerated forward to HEAD. */ export interface BackfillOptions { /** Starting version (exclusive). Empty string = walk every reachable tag. */ since: string; /** Project root override (defaults to CLEO_ROOT or cwd). */ projectRoot?: string; /** When true, signals downstream reconcile to UPDATE existing rows. */ forceOverwrite?: boolean; /** When true, enumerates tags and returns the plan without DB writes. */ dryRun?: boolean; /** When true, clears any existing checkpoint before starting. */ resetCheckpoint?: boolean; } /** * Per-tag outcome — captured in the {@link BackfillResult.results} array so * callers can surface per-tag success / failure detail without re-loading the * checkpoint file. */ export interface BackfillTagResult { tag: string; status: 'reconciled' | 'skipped' | 'failed'; durationMs?: number; errorCode?: string; errorMessage?: string; } /** Result envelope for {@link provenanceBackfill}. */ export interface BackfillResult { /** Lower-bound version that was passed in via `--since`. */ since: string; /** All historical tags discovered in the `since..HEAD` range. */ totalTags: string[]; /** Tags successfully reconciled (one row per tag). */ completedTags: string[]; /** Tags that failed reconcile (re-runnable). */ failedTags: { tag: string; errorCode: string; errorMessage: string; }[]; /** Per-tag detailed results. */ results: BackfillTagResult[]; /** True when `--dry-run` skipped DB writes. */ dryRun?: boolean; /** Path to the checkpoint file (relative or absolute). Null when dry-run. */ checkpointPath: string | null; /** Total wall-clock duration in ms. */ durationMs?: number; } /** * On-disk shape of `.cleo/release/backfill-state.json`. Holds enough state * for a fresh process to resume mid-walk after Ctrl-C / crash. */ interface CheckpointState { /** Lower-bound version passed via `--since` for the original invocation. */ since: string; /** Tag list captured up-front (so resume sees the same plan). */ totalTags: string[]; /** Tags successfully reconciled so far. */ completedTags: string[]; /** Tags that failed (re-runnable). */ failedTags: { tag: string; errorCode: string; errorMessage: string; }[]; /** Last tag attempted (success or failure). Null before first iteration. */ lastProcessedTag: string | null; /** ISO-8601 timestamp the original walk started. */ startedAt: string; /** ISO-8601 timestamp of the most recent checkpoint save. */ lastSavedAt: string; /** Forced-overwrite flag carried through across resume. */ forceOverwrite: boolean; } /** * Enumerate all git tags newer than `since` in creator-date order * (oldest-first). When `since` is the empty string the full tag list is * returned. * * Implementation: `git tag --list --sort=creatordate` — `creatordate` * returns the tagger date for annotated tags and the committer date for * lightweight tags, so the same sort order applies uniformly. Using * `committerdate` silently drops every annotated tag from the result * because annotated tags have no committerdate of their own (the empty * string sorts ahead of every real timestamp). */ export declare function enumerateHistoricalTags(since: string, projectRoot: string): string[]; /** * Load the checkpoint state from disk, or null when the file does not exist. * Returns null (not throws) on parse errors so the caller can fall back to a * fresh walk; the corrupt file is logged at warn level. */ export declare function loadCheckpoint(projectRoot: string): CheckpointState | null; /** * Atomically write the checkpoint state to disk via tmp-then-rename. The * directory is created on demand. */ export declare function saveCheckpoint(state: CheckpointState, projectRoot: string): void; /** Remove the checkpoint file on successful completion. Idempotent. */ export declare function clearCheckpoint(projectRoot: string): void; /** * Synthesise a minimal release plan for a historical tag and write it to * `.cleo/release/.plan.json` so {@link releaseReconcileV2} can consume * it. The plan is bare-bones — non-empty `tasks[]` derived from T#### tokens * in the `prevTag..tag` git log, intersected with valid task IDs in tasks.db. * * Returns the absolute path to the plan file written (or already on disk). * When `prevTag` is null, walks from the beginning of history. */ export declare function synthesizePlanFromTag(tag: string, prevTag: string | null, projectRoot: string): Promise; /** * Walk historical git tags from `opts.since` forward and populate the 11 * provenance tables for every release in the range. * * On success returns `engineSuccess(BackfillResult)`. On structural failure * (e.g. git repo missing) returns `engineError(, ...)`. Per-tag * reconcile failures are aggregated into `BackfillResult.failedTags` — the * verb itself still returns success when at least one tag completed. * * @param opts — see {@link BackfillOptions}. * @returns EngineResult envelope. */ export declare function provenanceBackfill(opts: BackfillOptions): Promise>; export {}; //# sourceMappingURL=backfill.d.ts.map