import type { Db } from "./db-postgres.js"; /** 02-store §4. v3 (block-actions design §C, ENG-263) historically added the Vendo-owned org tables (`vendo_orgs` + `vendo_org_members`); those tables are cut under the simplify-v2 kill-list (§A5) — orgs live on the Vendo-hosted side now. Existing dev databases that already have `vendo_orgs`/ `vendo_org_members` keep those orphaned tables — erasing them is not required and this migration does not attempt it. v4 (kill-list §B3) added `vendo_sessions`, the guest-session registry. Guest sessions are gone; the table's CREATE is removed here and ADDITIVE_DDL now drops the orphan left behind on databases that already had it. v5 (ENG-356, knowledge design v2 (2026-07-22) R1) adds the dedicated knowledge record collections `vendo_knowledge_docs` / `vendo_knowledge_chunks`. Bumping the version is load-bearing, not cosmetic (review fix F1): the DDL loop runs only while `version < SCHEMA_VERSION`, so appending the tables WITHOUT this bump would leave every existing v4 database on 4 forever and the new tables would never be created. v6 (the embedded-agent build contract) is ONE bump carrying all four new tables — wave-1 lanes B and D landed together, so a database moves to v6 once and gets the whole set: · `vendo_workspace_files` / `vendo_workspace_history` (§3.3) — the agent's filesystem as a façade over rows (documents are files, records stay tables), with a revision and an append-only history trail per path. · `vendo_thread_messages` (§6) — one row per transcript message, so a turn writes O(messages) instead of rewriting the whole array. `vendo_threads` LOSES `messages`; the v6 backfill splits every existing array into rows before dropping the column. · `vendo_effects` (§7) — the effect ledger that makes fail-and-re-run correct, keyed per (run, turn, tool, input, ordinal) and subject-scoped so it joins the erase cascade. Same load-bearing bump as v5 — the DDL loop only runs while version < SCHEMA_VERSION. v7 (build contract §9.2, wave 3) adds `vendo_app_grants`: app → principal → level, the ONLY multi-party rows Vendo stores. Memberships are asserted per request by the host's own identity system and are never persisted (§9.1), so this one table is the whole sharing model. Same load-bearing bump. v8 adds `vendo_idempotency_ledger` (01 §12 `IdempotencyLedger`): what a keyed request already answered, so a replayed `Idempotency-Key` gives that answer back instead of applying the mutation a second time. It is a table in THIS database rather than a store of its own because the ledger must commit with the mutation it gates — one that lives elsewhere can commit while its mutation rolls back, and the replay then confidently returns a result for work that never happened. Same load-bearing bump. v9 adds `vendo_quarantine` (01 §12 `StoreOps.retention`): where a retention sweep puts the rows it lifts out of a live collection, so the window between `quarantine` and `purge` is recoverable instead of a delete with a nicer name. The engine OWNS this table — no caller names it, no collection maps to it, and `purge` is the only way back out. It is a table of its own rather than a column on every collection because the rows come from thirty-odd tables with nothing in common but their id, and a `quarantined_at` column apiece would mean every read in the store growing a `WHERE quarantined_at IS NULL` it can never be trusted to remember. Same load-bearing bump. v10 adds `vendo_usage` (01 §12 `StoreOps.usage`): the meter a host's `LimitsCallback` decides on. One row per metered action, keeping its own instant — never a pre-bucketed count, because a policy authors its own window ("20 messages an hour", "3 generations today") and a bucket can only answer the periods whoever chose it happened to pick. It is engine-owned like `vendo_quarantine`: no collection maps to it and no door lists it, so a meter row is only ever counted. Same load-bearing bump. v11 makes the AUTOMATION the first-class record and takes the app's place in the two tables that assumed one. `vendo_automations` is the new drawer: one principal-owned record per row, `subject` (the owner) the erase-cascade selector — a row carries a live webhook signing key, so a record that outlived its owner's erasure would be a hole, not an untidiness — and `revision` the optimistic-concurrency counter the row's atomic verbs turn. No caller claims a fire through it: the tick arbitrates on the schedule cursor instead (packages/vendo/src/automations/ingestion-surface.ts). `vendo_runs` re-keys `app_id` to `automation_id`, because a run belongs to the record that fired it and an automation holds no app reference at all; `vendo_grants` re-keys `trigger_id` to `automation_id` for the same reason — the trigger it named lived inside an app document that no longer has triggers. Stored run rows are DROPPED rather than migrated: an app-keyed run cannot be read by the new path and no selector reaches it, so ADDITIVE_DDL empties the table ONCE, guarded on the old column's existence. Same load-bearing bump as v5 — the DDL loop only runs while version < SCHEMA_VERSION, so without it no existing database would ever create the new table. v12 moves harness continuity onto the thread row and DELETES `vendo_state`. The bookmark a session-owning harness resumes on (its native-session ref) rode `vendo_state` under a synthetic `app_id` of `harness_state:`, which bought "no new table" at the price of a slot that no table cascade covered: thread deletion swept it by hand in two places (ops.ts, helpers/threads.ts), a retention sweep needed a fence to keep the app-state door from seeing it, and the erase cascade reached it only through a second selector. It is one nullable `harness_state jsonb` column on `vendo_threads` now — ONE slot per thread, on the row that already carries the thread's owner — so every one of those hand-wired cascades is simply the row going away. `vendo_state`'s OTHER tenant, an app's per-user state, is dropped rather than migrated: an app's own data lives in the app's own SQL database, so nothing has written this table in a long time and the table's only live rows were the harness slots the backfill below relocates. The v2 backfill goes with it — it relocated legacy rows INTO this table, and there is no longer anywhere to put them. Any legacy `vendo_records` row under collection `vendo_state` simply stays where it is, unread, rather than being moved into a table that is about to be dropped. */ export declare const SCHEMA_VERSION = 12; /** 02-store §2 */ export declare const DDL: readonly ["CREATE TABLE IF NOT EXISTS vendo_apps (\n id text PRIMARY KEY, subject text NOT NULL, enabled boolean NOT NULL DEFAULT true,\n doc jsonb NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_apps_subject_idx ON vendo_apps (subject)", "CREATE TABLE IF NOT EXISTS vendo_records (\n collection text NOT NULL, id text NOT NULL, data jsonb NOT NULL, refs jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL,\n revision bigint NOT NULL DEFAULT 1,\n PRIMARY KEY (collection, id)\n )", "CREATE INDEX IF NOT EXISTS vendo_records_refs_idx ON vendo_records USING GIN (refs jsonb_path_ops)", "CREATE TABLE IF NOT EXISTS vendo_blobs (\n namespace text NOT NULL, key text NOT NULL, bytes bytea NOT NULL, content_type text,\n created_at timestamptz NOT NULL, PRIMARY KEY (namespace, key)\n )", "CREATE TABLE IF NOT EXISTS vendo_threads (\n id text PRIMARY KEY, subject text NOT NULL,\n harness_state jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_threads_subject_idx ON vendo_threads (subject)", "CREATE TABLE IF NOT EXISTS vendo_thread_messages (\n thread_id text NOT NULL, id text NOT NULL, seq integer NOT NULL,\n message jsonb NOT NULL, revision integer NOT NULL DEFAULT 1,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (thread_id, id)\n )", "CREATE INDEX IF NOT EXISTS vendo_thread_messages_thread_seq_idx ON vendo_thread_messages (thread_id, seq)", "CREATE TABLE IF NOT EXISTS vendo_effects (\n key text PRIMARY KEY, subject text NOT NULL, outcome jsonb NOT NULL,\n at timestamptz NOT NULL DEFAULT now()\n )", "CREATE INDEX IF NOT EXISTS vendo_effects_subject_idx ON vendo_effects (subject)", "CREATE TABLE IF NOT EXISTS vendo_grants (\n id text PRIMARY KEY, subject text NOT NULL, tool text NOT NULL, descriptor_hash text NOT NULL,\n scope jsonb NOT NULL, duration text NOT NULL, context_key text, app_id text, source text NOT NULL,\n granted_at timestamptz NOT NULL, expires_at timestamptz, revoked_at timestamptz\n )", "CREATE INDEX IF NOT EXISTS vendo_grants_subject_tool_idx ON vendo_grants (subject, tool)", "CREATE TABLE IF NOT EXISTS vendo_approvals (\n id text PRIMARY KEY, subject text NOT NULL, request jsonb NOT NULL,\n status text NOT NULL DEFAULT 'pending', decided_at timestamptz, session_id text,\n consumed_at timestamptz, created_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_approvals_subject_status_idx ON vendo_approvals (subject, status)", "CREATE TABLE IF NOT EXISTS vendo_audit (\n id text PRIMARY KEY, at timestamptz NOT NULL, kind text NOT NULL, subject text NOT NULL,\n venue text NOT NULL, presence text NOT NULL, app_id text, tool text, event jsonb NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_audit_subject_at_idx ON vendo_audit (subject, at)", "CREATE INDEX IF NOT EXISTS vendo_audit_at_idx ON vendo_audit (at)", "CREATE TABLE IF NOT EXISTS vendo_automations (\n id text PRIMARY KEY, subject text NOT NULL, armed boolean NOT NULL DEFAULT true,\n data jsonb NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL,\n revision bigint NOT NULL DEFAULT 1,\n when_kind text GENERATED ALWAYS AS (data->'when'->>'kind') STORED\n )", "CREATE INDEX IF NOT EXISTS vendo_automations_subject_idx ON vendo_automations (subject)", "CREATE INDEX IF NOT EXISTS vendo_automations_when_kind_idx ON vendo_automations (when_kind)", "CREATE INDEX IF NOT EXISTS vendo_automations_subject_when_kind_idx ON vendo_automations (subject, when_kind)", "CREATE TABLE IF NOT EXISTS vendo_runs (\n id text PRIMARY KEY, automation_id text NOT NULL, trigger jsonb NOT NULL, status text NOT NULL,\n record jsonb NOT NULL, started_at timestamptz NOT NULL, finished_at timestamptz\n )", "CREATE TABLE IF NOT EXISTS vendo_secrets (\n name text PRIMARY KEY, ciphertext text NOT NULL, created_at timestamptz NOT NULL,\n updated_at timestamptz\n )", "CREATE TABLE IF NOT EXISTS vendo_mcp_clients (\n id text PRIMARY KEY, data jsonb NOT NULL, refs jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_mcp_clients_refs_idx ON vendo_mcp_clients USING GIN (refs jsonb_path_ops)", "CREATE TABLE IF NOT EXISTS vendo_mcp_grants (\n id text PRIMARY KEY, data jsonb NOT NULL, refs jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_mcp_grants_refs_idx ON vendo_mcp_grants USING GIN (refs jsonb_path_ops)", "CREATE TABLE IF NOT EXISTS vendo_knowledge_docs (\n id text PRIMARY KEY, data jsonb NOT NULL, refs jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_knowledge_docs_refs_idx ON vendo_knowledge_docs USING GIN (refs jsonb_path_ops)", "CREATE TABLE IF NOT EXISTS vendo_knowledge_chunks (\n id text PRIMARY KEY, data jsonb NOT NULL, refs jsonb,\n created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL\n )", "CREATE INDEX IF NOT EXISTS vendo_knowledge_chunks_refs_idx ON vendo_knowledge_chunks USING GIN (refs jsonb_path_ops)", "CREATE TABLE IF NOT EXISTS vendo_workspace_files (\n path text NOT NULL, owner text NOT NULL, content text, blob_ref text,\n bytes integer NOT NULL, revision integer NOT NULL DEFAULT 1,\n created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (path, owner)\n )", "CREATE INDEX IF NOT EXISTS vendo_workspace_files_owner_idx ON vendo_workspace_files (owner)", "CREATE TABLE IF NOT EXISTS vendo_workspace_history (\n id text PRIMARY KEY, path text NOT NULL, owner text NOT NULL, revision integer NOT NULL,\n content text, blob_ref text, intent text, at timestamptz NOT NULL DEFAULT now()\n )", "CREATE INDEX IF NOT EXISTS vendo_workspace_history_path_idx ON vendo_workspace_history (path, owner, revision DESC)", "CREATE TABLE IF NOT EXISTS vendo_app_grants (\n id text PRIMARY KEY, app_id text NOT NULL, org_id text NOT NULL,\n principal text NOT NULL, level text NOT NULL, created_by text NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (app_id, principal)\n )", "CREATE INDEX IF NOT EXISTS vendo_app_grants_app_idx ON vendo_app_grants (app_id)", "CREATE INDEX IF NOT EXISTS vendo_app_grants_principal_idx ON vendo_app_grants (principal)", "CREATE TABLE IF NOT EXISTS vendo_idempotency_ledger (\n tenant text NOT NULL, op text NOT NULL, key text NOT NULL,\n request_hash text NOT NULL, status int NOT NULL, result jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant, op, key)\n )", "CREATE TABLE IF NOT EXISTS vendo_quarantine (\n collection text NOT NULL, id text NOT NULL, data jsonb NOT NULL,\n subject text, app_id text,\n quarantined_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (collection, id, quarantined_at)\n )", "CREATE INDEX IF NOT EXISTS vendo_quarantine_collection_at_idx ON vendo_quarantine (collection, quarantined_at)", "CREATE INDEX IF NOT EXISTS vendo_quarantine_subject_idx ON vendo_quarantine (subject)", "CREATE INDEX IF NOT EXISTS vendo_quarantine_app_idx ON vendo_quarantine (app_id)", "CREATE TABLE IF NOT EXISTS vendo_usage (\n id text PRIMARY KEY, subject text NOT NULL, action text NOT NULL,\n at timestamptz NOT NULL, pool_keys text[]\n )", "CREATE INDEX IF NOT EXISTS vendo_usage_subject_action_at_idx ON vendo_usage (subject, action, at)", "CREATE INDEX IF NOT EXISTS vendo_usage_pool_keys_idx ON vendo_usage USING GIN (pool_keys)"]; /** 02-store §4 */ export declare function ensureSchema(db: Db): Promise; //# sourceMappingURL=schema.d.ts.map