/** * `cleo doctor malformed-ids` — find and remove task rows the CLI cannot address. * * ## Why a doctor command rather than a normal delete * * A task id was written that no read path accepts. Found in a live store: * * id = '/mnt/projects/cleocode' * title = 'Task /mnt/projects/cleocode' * type = null * * The row is **immortal**. `cleo list` enumerates it, but `cleo show`, * `cleo update` and `cleo delete` all reject the id as malformed *before* they * reach the store, so the ordinary way to remove a bad row cannot be used on * precisely the rows that need removing. The validators that should have * prevented the write are what make the result unfixable. * * T12128 closed the write path, so no new such row can be created. This closes * the other half: the ones already there. * * ## Why deletion is the right repair * * A row whose id is not an id has no identity — nothing can reference it, * `depends` cannot name it, and no evidence atom can cite it. Re-iding would * invent an identity the row never had and silently change what any existing * reference means. Deletion is honest, and the report prints the full row * first so the operator sees exactly what is being discarded. * * Read-only by default. `--fix` is required to delete anything. * * @module * @task T12128 */ /** Rows in one table that reference a malformed id. */ export interface DependentRows { /** Table holding the references. */ readonly table: string; /** Column holding them. */ readonly column: string; /** How many rows reference the malformed id. */ readonly count: number; } /** A task row whose id does not match the canonical shape. */ export interface MalformedTaskRow { /** The malformed id, verbatim. */ readonly id: string; /** The row's title, for operator recognition. */ readonly title: string | null; /** The row's status. */ readonly status: string | null; /** The row's type, frequently `null` on these rows. */ readonly type: string | null; /** Rows in `tasks_task_dependencies` that name this id on either side. */ readonly dependencyRows: number; /** * Every reference to this id anywhere in the store, per table and column. * * The repair refuses while this is non-empty — see {@link scanMalformedTaskIds}. */ readonly dependents: readonly DependentRows[]; } /** Outcome of a {@link scanMalformedTaskIds} run. */ export interface MalformedTaskIdReport { /** Every row whose id fails {@link isStorableTaskId}. */ readonly rows: readonly MalformedTaskRow[]; /** `true` when `--fix` ran and rows were deleted. */ readonly deleted: boolean; /** * Ids `--fix` REFUSED to delete because other tables reference them. * * Deleting a malformed row while leaving its references behind manufactures * exactly the violation `cleo doctor fk-check` exists to detect — one doctor * creating work for another. Found on real data: the single malformed row in * this repository's own store has a dependent row in * `tasks_lifecycle_pipelines`, a table with no declared foreign key. * * A blanket cascade is not the answer either: 18 tables hold a task id, and * they include `tasks_audit_log` and `tasks_task_work_history`, which are * evidence. Deleting the audit trail of a bad row destroys the record of how * it got there. Which references are safe to remove is an operator judgement, * so the repair reports them and stops. */ readonly refused: readonly string[]; } /** * Find task rows whose id could not be an identifier at all. * * Uses {@link isStorableTaskId}, NOT the canonical {@link isTaskId}. That * distinction is load-bearing: CLEO deliberately mints structured ids such as * `T-RECONCILE-FOLLOWUP-v2026.5.63-6` (see `archive-reason-invariant.ts`) which * the canonical pattern rejects. Reporting those here would be wrong, and * `--fix` would DELETE working release follow-up tasks. * * @param cwd - project root. * @param opts - `fix: true` deletes rows that nothing references; default is * read-only. Rows WITH references are never deleted — see * {@link MalformedTaskIdReport.refused}. * @returns the rows found, their references, and what was deleted or refused. * * @example * ```ts * const report = await scanMalformedTaskIds(projectRoot); * if (report.rows.length > 0) console.error('unaddressable rows present'); * ``` * * @task T12128 */ export declare function scanMalformedTaskIds(cwd: string, opts?: { fix?: boolean; }): Promise; //# sourceMappingURL=malformed-task-ids.d.ts.map