import { type Database as DatabaseType } from "better-sqlite3"; export { CORRUPT_SESSIONS_DATABASE, UNSUPPORTED_PRERELEASE_TODO_DATA } from "./migrate-refusals.js"; /** File-copy backup suffix written next to the registry before a v1→v2 rebuild. */ export declare const WORK_ITEMS_BACKUP_SUFFIX = ".pre-todos-v2"; /** v2 (Todos v2 slice 1): per-department prefixes + sub-task tree columns. */ export declare const WORK_ITEMS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_items (\n id TEXT PRIMARY KEY CHECK (\n id GLOB '[A-Z][A-Z][A-Z]-[1-9]*'\n AND substr(id, 5) NOT GLOB '*[^0-9]*'\n AND CAST(substr(id, 5) AS INTEGER) BETWEEN 1 AND 9007199254740991\n AND printf('%lld', CAST(substr(id, 5) AS INTEGER)) = substr(id, 5)\n),\n title TEXT NOT NULL,\n body TEXT,\n status TEXT NOT NULL DEFAULT 'backlog' CHECK (status IN ('backlog','assigned','executing','in_review','done','blocked','escalated','cancelled')),\n department TEXT,\n assignee TEXT,\n created_by TEXT NOT NULL,\n parent_id TEXT REFERENCES work_items(id),\n root_id TEXT NOT NULL,\n depth INTEGER NOT NULL DEFAULT 0 CHECK ((parent_id IS NULL AND depth = 0) OR (parent_id IS NOT NULL AND depth BETWEEN 1 AND 3)),\n due_at TEXT,\n priority INTEGER NOT NULL DEFAULT 2 CHECK (priority BETWEEN 0 AND 3),\n rank REAL,\n version INTEGER NOT NULL DEFAULT 1 CHECK (version >= 1),\n source TEXT NOT NULL DEFAULT 'human' CHECK (source IN ('human','delegation','cron','workflow','session','connector','goal')),\n source_ref TEXT,\n acceptance TEXT,\n verify_policy TEXT,\n rounds INTEGER NOT NULL DEFAULT 0,\n budget_usd REAL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n closed_at TEXT\n)"; export declare const WORK_ITEMS_INDEX_DDL = "\nCREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_department ON work_items(department);\nCREATE UNIQUE INDEX IF NOT EXISTS uq_work_items_source_ref\n ON work_items(source, source_ref) WHERE source_ref IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_work_items_recent ON work_items(updated_at DESC, created_at DESC);\nCREATE INDEX IF NOT EXISTS idx_work_items_default_order\n ON work_items((rank IS NULL), rank, updated_at DESC, created_at DESC, id ASC);\nCREATE INDEX IF NOT EXISTS idx_work_items_manual_order\n ON work_items(status, (rank IS NULL), rank, updated_at DESC, created_at DESC, id ASC);\nCREATE INDEX IF NOT EXISTS idx_work_items_parent ON work_items(parent_id) WHERE parent_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_work_items_root ON work_items(root_id);\nCREATE INDEX IF NOT EXISTS idx_work_items_created_by ON work_items(created_by, (parent_id IS NULL), updated_at DESC);\nCREATE INDEX IF NOT EXISTS idx_work_items_due ON work_items(due_at) WHERE due_at IS NOT NULL;\n"; export declare const WORK_ITEM_EVENTS_TABLE_DDL: string; export declare const WORK_ITEM_EVENTS_DDL: string; /** Todos v2 slice 2: threaded, mutable discussion layer. Delete = tombstone * (body cleared, row retained) so thread shape survives; `work_item_events` * stays the pure machine audit and records comment activity separately. */ export declare const WORK_ITEM_COMMENTS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_comments (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wic_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n parent_comment_id TEXT REFERENCES work_item_comments(id),\n author_kind TEXT NOT NULL CHECK (author_kind IN ('operator','employee','system')),\n author TEXT NOT NULL,\n body TEXT NOT NULL,\n created_at TEXT NOT NULL,\n edited_at TEXT,\n deleted_at TEXT\n)"; export declare const WORK_ITEM_COMMENTS_DDL = "\n\nCREATE TABLE IF NOT EXISTS work_item_comments (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wic_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n parent_comment_id TEXT REFERENCES work_item_comments(id),\n author_kind TEXT NOT NULL CHECK (author_kind IN ('operator','employee','system')),\n author TEXT NOT NULL,\n body TEXT NOT NULL,\n created_at TEXT NOT NULL,\n edited_at TEXT,\n deleted_at TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_wi_comments_item ON work_item_comments(work_item_id, created_at);\n"; /** Todos v2 slice 3: typed item-to-item relations. `blocks`/`duplicates` are * directional; `relates` is symmetric and stored ONCE in canonical order * (lexicographically smaller Todo id as src_id). The DAG guarantee on `blocks` * is enforced by the write path's in-transaction cycle check and re-verified * at boot. */ export declare const WORK_ITEM_RELATIONS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_relations (\n src_id TEXT NOT NULL REFERENCES work_items(id),\n dst_id TEXT NOT NULL REFERENCES work_items(id),\n kind TEXT NOT NULL CHECK (kind IN ('blocks','relates','duplicates')),\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (src_id, dst_id, kind),\n CHECK (src_id <> dst_id)\n)"; export declare const WORK_ITEM_RELATIONS_DDL = "\n\nCREATE TABLE IF NOT EXISTS work_item_relations (\n src_id TEXT NOT NULL REFERENCES work_items(id),\n dst_id TEXT NOT NULL REFERENCES work_items(id),\n kind TEXT NOT NULL CHECK (kind IN ('blocks','relates','duplicates')),\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (src_id, dst_id, kind),\n CHECK (src_id <> dst_id)\n);\nCREATE INDEX IF NOT EXISTS idx_wi_relations_dst ON work_item_relations(dst_id, kind);\n"; /** Todos v2 slice 3: shared label registry. `name` is normalized lowercase * kebab-case; `department` NULL = company-wide. */ export declare const LABELS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS labels (\n id TEXT PRIMARY KEY CHECK (id GLOB 'lbl_[0-9a-f]*' AND length(id) = 16),\n name TEXT NOT NULL UNIQUE,\n color TEXT CHECK (color IS NULL OR color GLOB '#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]'),\n department TEXT,\n created_at TEXT NOT NULL\n)"; export declare const LABELS_DDL = "\nCREATE TABLE IF NOT EXISTS labels (\n id TEXT PRIMARY KEY CHECK (id GLOB 'lbl_[0-9a-f]*' AND length(id) = 16),\n name TEXT NOT NULL UNIQUE,\n color TEXT CHECK (color IS NULL OR color GLOB '#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]'),\n department TEXT,\n created_at TEXT NOT NULL\n);"; export declare const WORK_ITEM_LABELS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_labels (\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n label_id TEXT NOT NULL REFERENCES labels(id),\n PRIMARY KEY (work_item_id, label_id)\n)"; export declare const WORK_ITEM_LABELS_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_labels (\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n label_id TEXT NOT NULL REFERENCES labels(id),\n PRIMARY KEY (work_item_id, label_id)\n);"; /** Todos v2 slice 5: content-addressed file attachments on Todos and comments. * Bytes live at `/attachments//` (dedup by * content); `storage_path` stores the RELATIVE form. `comment_id` NULL = * attached to the Todo itself; set = attached to that comment (which must * belong to the same item — enforced in the store write and re-proven by the * verifier). The sha256 hex shape is a verifier concern (the DDL pins only the * length, matching spec §3.2). */ export declare const WORK_ITEM_ATTACHMENTS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_attachments (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wia_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n comment_id TEXT REFERENCES work_item_comments(id),\n filename TEXT NOT NULL,\n mime TEXT NOT NULL,\n bytes INTEGER NOT NULL CHECK (bytes > 0),\n sha256 TEXT NOT NULL CHECK (length(sha256) = 64),\n storage_path TEXT NOT NULL,\n uploaded_by TEXT NOT NULL,\n created_at TEXT NOT NULL\n)"; export declare const WORK_ITEM_ATTACHMENTS_DDL = "\n\nCREATE TABLE IF NOT EXISTS work_item_attachments (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wia_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n comment_id TEXT REFERENCES work_item_comments(id),\n filename TEXT NOT NULL,\n mime TEXT NOT NULL,\n bytes INTEGER NOT NULL CHECK (bytes > 0),\n sha256 TEXT NOT NULL CHECK (length(sha256) = 64),\n storage_path TEXT NOT NULL,\n uploaded_by TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_wia_item ON work_item_attachments(work_item_id, created_at);\nCREATE INDEX IF NOT EXISTS idx_wia_comment ON work_item_attachments(comment_id) WHERE comment_id IS NOT NULL;\n"; /** Todos v2 slice 4: approvals leave the fat work_items row. The SOLE storage * owner since PLA-48 — full history, one row per requested gate; the partial * unique index makes "at most one PENDING approval per item" a DB guarantee. * `ref` is the opaque correlation reference the request contract has always * carried (kept here so the `approvalRef` payload field stays byte-identical). */ export declare const WORK_ITEM_APPROVALS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_approvals (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wap_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n state TEXT NOT NULL CHECK (state IN ('pending','approved','rejected')),\n request TEXT NOT NULL,\n ref TEXT,\n target TEXT,\n target_kind TEXT CHECK (target_kind IN ('employee','virtual','none')),\n requested_by TEXT NOT NULL,\n requested_at TEXT NOT NULL,\n escalated_at TEXT,\n decided_by TEXT,\n decided_at TEXT,\n note TEXT\n)"; export declare const WORK_ITEM_APPROVALS_DDL = "\n\nCREATE TABLE IF NOT EXISTS work_item_approvals (\n id TEXT PRIMARY KEY CHECK (id GLOB 'wap_[0-9a-f]*' AND length(id) = 16),\n work_item_id TEXT NOT NULL REFERENCES work_items(id),\n state TEXT NOT NULL CHECK (state IN ('pending','approved','rejected')),\n request TEXT NOT NULL,\n ref TEXT,\n target TEXT,\n target_kind TEXT CHECK (target_kind IN ('employee','virtual','none')),\n requested_by TEXT NOT NULL,\n requested_at TEXT NOT NULL,\n escalated_at TEXT,\n decided_by TEXT,\n decided_at TEXT,\n note TEXT\n);\nCREATE UNIQUE INDEX IF NOT EXISTS uq_wap_pending ON work_item_approvals(work_item_id) WHERE state = 'pending';\nCREATE INDEX IF NOT EXISTS idx_wap_item ON work_item_approvals(work_item_id, requested_at);\n"; /** Variant-picking approvals: the offered options and the picked one, 1:1 with * an approval row. A separate table rather than two `work_item_approvals` * columns because `verifyCurrentWorkItemSchema` refuses ANY shape drift on an * existing table, while a MISSING additive table heals cleanly on boot — so a * new table is the only backward-compatible way to extend an approval. * `options` is a JSON array of labels; `choice` is null until a pick lands. */ export declare const WORK_ITEM_APPROVAL_CHOICES_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_approval_choices (\n approval_id TEXT PRIMARY KEY REFERENCES work_item_approvals(id) ON DELETE CASCADE,\n options TEXT NOT NULL,\n choice TEXT\n)"; /** Gates reserved for the human operator: a row here means NO employee may * decide this approval, not the COO and not through escalation. Presence IS the * reservation, so there is no value to drift. A separate table for the same * reason as `work_item_approval_choices`: `work_item_approvals.target_kind` * carries a CHECK constraint the exact-shape preflight covers, so adding a * value there would make every existing database refuse to boot. */ export declare const WORK_ITEM_APPROVAL_OPERATOR_ONLY_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_approval_operator_only (\n approval_id TEXT PRIMARY KEY REFERENCES work_item_approvals(id) ON DELETE CASCADE\n)"; export declare const WORK_ITEM_EDIT_RECEIPTS_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_edit_receipts (\n key_digest TEXT PRIMARY KEY CHECK (length(key_digest) = 64),\n request_fingerprint TEXT NOT NULL,\n result_version INTEGER NOT NULL CHECK (result_version >= 1),\n created_at TEXT NOT NULL\n);\n"; export declare const WORK_ITEM_ID_ALLOCATOR_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_id_allocator (\n prefix TEXT PRIMARY KEY CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n high_water INTEGER NOT NULL CHECK (high_water BETWEEN 0 AND 9007199254740991)\n)"; export declare const WORK_ITEM_ID_BURNS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_id_burns (\n prefix TEXT NOT NULL CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n ordinal INTEGER NOT NULL CHECK (ordinal BETWEEN 1 AND 9007199254740991),\n claim_digest TEXT NOT NULL UNIQUE CHECK (length(claim_digest) = 64 AND claim_digest NOT GLOB '*[^0-9a-f]*'),\n burned_at TEXT NOT NULL,\n PRIMARY KEY (prefix, ordinal)\n)"; export declare const WORK_ITEM_ID_ISSUANCES_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS work_item_id_issuances (\n prefix TEXT NOT NULL CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n ordinal INTEGER NOT NULL CHECK (ordinal BETWEEN 1 AND 9007199254740991),\n issued_at TEXT NOT NULL,\n PRIMARY KEY (prefix, ordinal)\n)"; export declare const DEPARTMENTS_TABLE_DDL = "\nCREATE TABLE IF NOT EXISTS departments (\n slug TEXT PRIMARY KEY,\n prefix TEXT NOT NULL UNIQUE CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n created_at TEXT NOT NULL\n)"; export declare const WORK_ITEM_IDENTITY_TABLES_DDL = "\n\nCREATE TABLE IF NOT EXISTS work_item_id_allocator (\n prefix TEXT PRIMARY KEY CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n high_water INTEGER NOT NULL CHECK (high_water BETWEEN 0 AND 9007199254740991)\n);\n\nCREATE TABLE IF NOT EXISTS work_item_id_burns (\n prefix TEXT NOT NULL CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n ordinal INTEGER NOT NULL CHECK (ordinal BETWEEN 1 AND 9007199254740991),\n claim_digest TEXT NOT NULL UNIQUE CHECK (length(claim_digest) = 64 AND claim_digest NOT GLOB '*[^0-9a-f]*'),\n burned_at TEXT NOT NULL,\n PRIMARY KEY (prefix, ordinal)\n);\n\nCREATE TABLE IF NOT EXISTS work_item_id_issuances (\n prefix TEXT NOT NULL CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n ordinal INTEGER NOT NULL CHECK (ordinal BETWEEN 1 AND 9007199254740991),\n issued_at TEXT NOT NULL,\n PRIMARY KEY (prefix, ordinal)\n);\n\nCREATE TABLE IF NOT EXISTS departments (\n slug TEXT PRIMARY KEY,\n prefix TEXT NOT NULL UNIQUE CHECK (length(prefix) = 3 AND prefix GLOB '[A-Z][A-Z][A-Z]'),\n created_at TEXT NOT NULL\n);\n"; export declare const WORK_ITEM_ID_IMMUTABLE_TRIGGER_SQL = "CREATE TRIGGER IF NOT EXISTS work_items_id_immutable\nBEFORE UPDATE OF id ON work_items\nBEGIN\n SELECT RAISE(ABORT, 'Todo ID is immutable');\nEND"; export declare const V1_WORK_ITEM_IDENTITY_TRIGGERS_DDL: string; export declare const WORK_ITEM_IDENTITY_TRIGGERS_DDL: string; /** The runtime half of Todo identity lives in id-allocator.ts; re-exported so * the schema module stays the one import every caller already had. */ export { allocateWorkItemId, allocateWorkItemIdV1ForTest, registerWorkItemIdentityFunctions, useWorkItemAllocationClaim, type WorkItemAllocationClaim } from "./id-allocator.js"; export type WorkItemSchemaPreflight = "absent" | "empty-prerelease" | "v1" | "current"; /** * Register any department that holds Todos but is missing from the registry * (review F2). Department-changing writes now mint the row in their own * transaction; this reconciles rows written BEFORE that fix (move-only * departments). Idempotent — runs on every boot. */ export declare function reconcileDepartmentRegistry(db: DatabaseType): number; export declare function verifyCurrentWorkItemSchema(db: DatabaseType): void; /** Read-only and side-effect free. It runs before WAL mode or any schema write. */ export declare function preflightWorkItemsDatabase(filename: string): WorkItemSchemaPreflight; export interface WorkItemsMigrationResult { rebuilt: boolean; rows: number; } /** Create the clean v2 model, replace a previously classified empty prerelease * shape, or rebuild a recognized v1 database in place (per-prefix allocator + * tree columns, data preserved). */ export declare function migrateWorkItemsSchema(db: DatabaseType, _preflight?: WorkItemSchemaPreflight): WorkItemsMigrationResult; //# sourceMappingURL=migrate.d.ts.map