"""Plan historical workbench resources and emit acceptance-only, insert-only SQL. The caller supplies a consistent_snapshot() connection and durable identity, Agent and knowledge-base mappings. No target SQL or model calls are executed. Plans contain private historical text. Only safe_business_summary is reportable. """ from __future__ import annotations import base64 import copy import hashlib import json import re import sqlite3 import uuid from pathlib import Path from weknora_asset_etl import LEDGER as ASSET_LEDGER, _mapping from weknora_identity_etl import ADMIN_TARGET_ID, IDENTITY_LEDGER SOURCE = "yawan-workbench" TARGET_DATABASE = "yawan_native_acceptance_20260915" TARGET_TENANT = 10059 LEDGER = "yawan_legacy_business_mappings" NAMESPACE = uuid.UUID("5eb4773e-f972-4cfa-b6aa-84118b82e7c2") RESOURCE_KINDS = {"canvas": "flows", "trainingmap": "training-maps", "campaign": "content-tasks"} HISTORY_TABLES = ("segment", "qcreport", "campaignrun", "runevent", "agentsession", "artifact", "llmcall", "taskqueueitem", "canvasgrant", "resourcerevision", "resourcefork") JSON_FIELDS = { "canvas": ("nodes", "edges"), "trainingmap": ("kb_ids", "kb_category_ids", "plan", "evidence", "coverage", "maps"), "campaign": ("canvas_snapshot", "task_spec", "pending_confirms", "notes"), "segment": ("generation_history", "fusion_agent_ids", "runtime_snapshot", "anchor_card", "qc_reports", "failure", "references", "kb_category_ids", "kb_category_recommendation"), "qcreport": ("checks", "runtime_snapshot"), "campaignrun": ("checkpoint", "config_snapshot"), "runevent": ("payload",), "agentsession": ("messages", "tool_state", "result_meta"), "artifact": ("compose_report", "runtime_snapshot"), "taskqueueitem": ("payload",), "resourcerevision": ("payload",), } POLICY = "historical_read_only_no_jobs_no_events_no_inferred_grants" def business_id(kind: str, source_id: int, suffix: str = "") -> str: if kind not in (*RESOURCE_KINDS, *HISTORY_TABLES) or type(source_id) is not int or source_id <= 0: raise ValueError("Invalid historical business identity") return str(uuid.uuid5(NAMESPACE, f"{SOURCE}:tenant:{TARGET_TENANT}:organization:1:{kind}:{source_id}:{suffix}")) def _read(db: sqlite3.Connection, table: str) -> list[dict]: if table not in (*RESOURCE_KINDS, *HISTORY_TABLES): raise ValueError("Unreviewed source table") query = db.execute(f'SELECT * FROM "{table}" ORDER BY id') columns = [c[0] for c in query.description] result = [] for values in query: row = dict(zip(columns, values)) for field in JSON_FIELDS.get(table, ()): if field in row and row[field] is not None: row[field] = json.loads(row[field]) if type(row.get("id")) is not int or row["id"] <= 0: raise ValueError("Invalid source row identity") result.append(row) return result def _canonical(value) -> str: return json.dumps(value, ensure_ascii=True, sort_keys=True, separators=(",", ":"), allow_nan=False) def archive_text(value): """Losslessly retain SQLite text that PostgreSQL JSONB cannot represent.""" if isinstance(value, str) and any(c == "\x00" or 0xd800 <= ord(c) <= 0xdfff for c in value): return {"legacy_text_encoding": "utf-8-surrogatepass/base64", "body": base64.b64encode(value.encode("utf-8", errors="surrogatepass")).decode("ascii")} if isinstance(value, dict): return {k: archive_text(v) for k, v in value.items()} if isinstance(value, list): return [archive_text(v) for v in value] return value def postgres_plan(plan): result = copy.deepcopy(plan) for item in [*result["resources"], *result["history"]]: item["source"] = archive_text(item["source"]) if "target" in item: data = item["target"]["data"] data["legacy_history"] = archive_text(data["legacy_history"]) return result def _owner(source: dict, identities: dict) -> str: if source.get("organization_id") != 1 or type(source.get("owner_user_id")) is not int: raise ValueError("Business owner organization differs") owner = source["owner_user_id"] or 1 if str(owner) not in identities: raise ValueError(f"Business owner {owner} has no durable identity mapping") return identities[str(owner)] def _resolve(mapping: dict, source_id, missing: list[str], field: str) -> str: if source_id in (0, None, ""): missing.append(field) return "" if type(source_id) is not int or source_id < 1: raise ValueError("Malformed historical foreign identity") if str(source_id) not in mapping: missing.append(field) return "" return mapping[str(source_id)] def _marker(kind: str, source: dict, missing: list[str]) -> dict: return {"source_system": SOURCE, "source_kind": kind, "source_id": source["id"], "source_status": source.get("status", ""), "source_owner_user_id": source["owner_user_id"], "source_visibility": source.get("visibility", "private"), "read_only": True, "requires_review": True, "needs_configuration": bool(missing), "missing_configuration": sorted(set(missing)), "review_reasons": ["legacy_execution_contract_not_equivalent", "historical_import_does_not_resume_ai"]} def _file(path: str, root: Path) -> dict: resolved = Path(path).resolve() if not resolved.is_relative_to(root.resolve()) or resolved.suffix.lower() not in (".md", ".docx"): raise ValueError("Historical artifact path is outside the allowed artifacts directory") if not resolved.is_file(): return {"source_path": path, "status": "missing"} before = resolved.stat() if before.st_size > 20 * 1024 * 1024: raise ValueError("Historical artifact exceeds reviewed size limit") body = resolved.read_bytes() after = resolved.stat() if (before.st_size, before.st_mtime_ns) != (after.st_size, after.st_mtime_ns): raise ValueError("Historical artifact changed during read") encoding = "utf-8" if resolved.suffix.lower() == ".md" else "base64" return {"source_path": path, "status": "preserved", "size": len(body), "sha256": hashlib.sha256(body).hexdigest(), "encoding": encoding, "body": body.decode("utf-8") if encoding == "utf-8" else base64.b64encode(body).decode("ascii")} def _tree(source: dict, source_id: int, path: str) -> dict: if not isinstance(source, dict) or not isinstance(source.get("title"), str): raise ValueError("Historical map tree is malformed") children = source.get("children", []) if not isinstance(children, list): raise ValueError("Historical map children are malformed") return {"id": business_id("trainingmap", source_id, path), "label": source["title"], "children": [_tree(n, source_id, f"{path}.{i}") for i, n in enumerate(children)]} def _framework(source: dict, depth=1) -> str: parts = ["#" * min(depth, 6) + " " + source["title"]] for field in ("content", "hook"): if source.get(field): parts.append(source[field]) parts.extend(_framework(child, depth + 1) for child in source.get("children", [])) return "\n\n".join(parts) def _review(reports: list[dict]) -> str: # Formatting exposes original verdicts and checks; it does not run or pass QC. return "\n\n".join("```json\n" + json.dumps({k: r.get(k) for k in ("id", "gate", "verdict", "checks", "created_at")}, ensure_ascii=False, indent=2) + "\n```" for r in reports) def _target(kind: str, source: dict, plan: dict) -> dict: identities, agents, kbs = (plan[k] for k in ("identity_mapping", "agent_mapping", "kb_mapping")) missing = [] if kind == "canvas": nodes, edges = [], [] seen = set() for node in source["nodes"]: nid = node.get("node_id") if not isinstance(nid, str) or not nid or nid in seen: raise ValueError("Canvas node identity is missing or duplicated") seen.add(nid) nodes.append({"id": nid, "agent_id": _resolve(agents, node.get("agent_id"), missing, "node_agent"), "label": node.get("label", nid)}) for edge in source["edges"]: start, end = edge.get("from", edge.get("from_node")), edge.get("to", edge.get("to_node")) if start not in seen or end not in seen: raise ValueError("Canvas edge has a missing node") edges.append({"source": start, "target": end}) if not nodes: missing.append("flow_nodes") data = {"nodes": nodes, "edges": edges, "description": "", "legacy_history": {"nodes": source["nodes"], "edges": source["edges"], "supervisor_agent_id": source.get("supervisor_agent_id"), "supervisor_mode": source.get("supervisor_mode")}} elif kind == "trainingmap": days = [] candidates = source["plan"].get("days", []) if not isinstance(candidates, list): raise ValueError("Historical training plan days must be an array") for candidate in candidates: day = candidate["day"] if type(day) is not int or day != len(days) + 1: raise ValueError("Historical training plan day ordering differs") generated = source["maps"].get(str(day)) nodes = [_tree(n, source["id"], f"{day}.{i}") for i, n in enumerate(generated.get("children", []))] if generated else [] days.append({"day": day, "title": candidate["title"], "prerequisite": candidate.get("prerequisite", ""), "hook": generated.get("hook", "") if generated else "", "nodes": nodes, "framework": _framework(generated) if generated else "", "confirmed": False}) count = source["plan"].get("recommended_days", source.get("requested_days") or 0) if count != len(days): raise ValueError("Historical training plan day count differs") kb_ids = [_resolve(kbs, k, missing, "knowledge_base") for k in source["kb_ids"]] if source["kb_category_ids"]: missing.append("knowledge_category_scope") data = {"topic": source["topic"], "days_count": count, "agent_id": _resolve(agents, source.get("agent_id"), missing, "agent_id"), "knowledge_base_ids": [k for k in kb_ids if k], "knowledge_ids": [], "days": days, "legacy_history": {k: source[k] for k in ("plan", "maps", "evidence", "coverage", "error", "confirmed_version")}} else: # Legacy campaigns contain a frozen canvas and free-form map text, not # reliable foreign keys to a map/day/live canvas. Never infer by title. missing.extend(["map_id", "map_day", "flow_id", "task_agent_id"]) segments = [] for item in plan["history"]: s = item["source"] if item["source_kind"] != "segment" or s["campaign_id"] != source["id"]: continue reports = [r["source"] for r in plan["history"] if r["source_kind"] == "qcreport" and r["source"]["segment_id"] == s["id"] and not r["relation_review"]] artifact = plan["artifacts"].get(s["artifact_path"], {}) if s["artifact_path"] and artifact.get("status") != "preserved": missing.append("segment_artifact") segments.append({"id": business_id("segment", s["id"]), "title": s["title"], "agent_id": _resolve(agents, s["agent_id"], missing, "segment_agent"), "status": s["status"], "content": artifact.get("body", "") if artifact.get("encoding") == "utf-8" else "", "review": _review(reports), "source_ids": []}) cross = [r["source"] for r in plan["history"] if r["source_kind"] == "qcreport" and r["parent_resource_id"] == business_id(kind, source["id"]) and r["source"]["gate"] == "cross" and not r["relation_review"]] data = {"map_id": "", "day": 0, "flow_id": "", "agent_id": "", "knowledge_base_ids": [], "knowledge_ids": [], "segments": segments, "review": _review(cross), "composed": "", "legacy_history": {"mindmap_text": source["mindmap_text"], "canvas_snapshot": source["canvas_snapshot"], "canvas_name": source["canvas_name"], "task_spec": source["task_spec"], "pending_confirms": source["pending_confirms"], "notes": source["notes"], "segments": [{k: s["source"][k] for k in ("id", "node_id", "time_range", "status", "round", "references", "failure", "generation_history")} for s in plan["history"] if s["source_kind"] == "segment" and s["source"]["campaign_id"] == source["id"]]}} data["legacy_import"] = _marker(kind, source, missing) name = source["topic"] if kind == "trainingmap" else source["name"] if not isinstance(name, str) or not name.strip() or "\x00" in name: raise ValueError("Historical resource name is invalid") return {"id": business_id(kind, source["id"]), "tenant_id": TARGET_TENANT, "owner_id": _owner(source, identities), "owner_name": "", "kind": RESOURCE_KINDS[kind], "name": name, "status": source.get("status", "draft"), "version": source.get("version", 1), "created_at": source.get("created_at") or None, "updated_at": source.get("finished_at") or source.get("created_at") or None, "data": data} def business_plan(db: sqlite3.Connection, identity_mapping: dict, agent_mapping: dict, kb_mapping: dict, artifact_root: Path) -> dict: """Read an online-backup snapshot; never pass the live SQLite connection.""" if db.execute("PRAGMA query_only").fetchone()[0] != 1: raise ValueError("Business plan requires the read-only consistent snapshot") identities, agents, kbs = (_mapping(m) for m in (identity_mapping, agent_mapping, kb_mapping)) if identities.get("1") != ADMIN_TARGET_ID: raise ValueError("Pinned source administrator identity differs") sources = {table: _read(db, table) for table in RESOURCE_KINDS} campaigns = {r["id"] for r in sources["campaign"]} canvases = {r["id"] for r in sources["canvas"]} history = {table: _read(db, table) for table in HISTORY_TABLES} segments = {r["id"]: r["campaign_id"] for r in history["segment"]} if any(cid not in campaigns for cid in segments.values()): raise ValueError("Historical segment has a missing campaign") runs = {r["id"]: r["campaign_id"] for r in history["campaignrun"]} plan = {"schema_version": 1, "source": SOURCE, "target_database": TARGET_DATABASE, "target_tenant_id": TARGET_TENANT, "identity_mapping": identities, "agent_mapping": agents, "kb_mapping": kbs, "resources": [], "history": [], "artifacts": {}, "policy": POLICY, "excluded_history_counts": {}, "timestamp_policy": "source_timestamp_else_import_time", "mapping_ledger": LEDGER} for table, rows in history.items(): for row in rows: parent = "" relation_review = [] if table in ("canvasgrant", "resourcerevision", "resourcefork"): if table != "canvasgrant" and row["resource_type"] != "canvas": continue cid = row.get("canvas_id", row.get("resource_id", row.get("source_id"))) if cid not in canvases: raise ValueError("Canvas history has no source resource") parent = business_id("canvas", cid) else: cid = row.get("campaign_id") if table == "qcreport": cid = segments.get(row["segment_id"]) if table == "taskqueueitem": payload = row["payload"] cid = payload.get("campaign_id") or runs.get(payload.get("run_id")) if not cid: continue if not cid and row.get("run_id"): cid = runs.get(row["run_id"]) if cid not in campaigns: if table in ("llmcall", "agentsession", "taskqueueitem"): plan["excluded_history_counts"][table] = plan["excluded_history_counts"].get(table, 0) + 1 continue raise ValueError(f"Historical {table} {row['id']} has no source campaign") if row.get("segment_id") and segments.get(row["segment_id"]) != cid: relation_review.append("source_segment_campaign_mismatch_ledger_only") if row.get("run_id") and runs.get(row["run_id"]) != cid: relation_review.append("source_run_campaign_mismatch_ledger_only") parent = business_id("campaign", cid) if row.get("organization_id", 1) != 1: raise ValueError("Historical row belongs to another organization") plan["history"].append({"source_kind": table, "source_id": row["id"], "source": row, "target_id": business_id(table, row["id"]), "parent_resource_id": parent, "relation_review": relation_review}) paths = [] if table == "segment": paths = [row["artifact_path"], *(v.get("artifact_path", "") for v in row["generation_history"])] elif table == "artifact": paths = [row["docx_path"]] for path in paths: if path and path not in plan["artifacts"]: plan["artifacts"][path] = _file(path, artifact_root) for kind, rows in sources.items(): for source in rows: plan["resources"].append({"source_kind": kind, "source_id": source["id"], "source": source, "target": _target(kind, source, plan)}) _validate_plan(plan) return plan def _validate_plan(plan: dict) -> None: if (plan.get("schema_version") != 1 or plan.get("source") != SOURCE or plan.get("target_database") != TARGET_DATABASE or plan.get("target_tenant_id") != TARGET_TENANT or plan.get("policy") != POLICY or plan.get("mapping_ledger") != LEDGER): raise ValueError("Historical migration scope differs") for key in ("identity_mapping", "agent_mapping", "kb_mapping"): _mapping(plan[key]) if plan["identity_mapping"].get("1") != ADMIN_TARGET_ID: raise ValueError("Pinned source administrator identity differs") parents = {business_id(r["source_kind"], r["source_id"]) for r in plan["resources"]} seen = set() for item in [*plan["resources"], *plan["history"]]: key = (item["source_kind"], item["source_id"]) if key in seen or item["source"]["id"] != item["source_id"]: raise ValueError("Historical identity is duplicated or changed") seen.add(key) if "target" in item: if item["target"] != _target(item["source_kind"], item["source"], plan): raise ValueError("Historical native projection differs") elif (item["target_id"] != business_id(*key) or item["parent_resource_id"] not in parents): raise ValueError("Historical parent mapping differs") for path, artifact in plan["artifacts"].items(): if artifact["source_path"] != path or artifact["status"] not in ("preserved", "missing"): raise ValueError("Historical artifact identity differs") if artifact["status"] == "preserved": raw = artifact["body"].encode("utf-8") if artifact["encoding"] == "utf-8" else base64.b64decode(artifact["body"], validate=True) if len(raw) != artifact["size"] or hashlib.sha256(raw).hexdigest() != artifact["sha256"]: raise ValueError("Historical artifact fingerprint differs") def safe_business_summary(plan: dict) -> dict: _validate_plan(plan) return {"target_database": TARGET_DATABASE, "target_tenant_id": TARGET_TENANT, "counts": {kind: sum(i["source_kind"] == kind for i in [*plan["resources"], *plan["history"]]) for kind in (*RESOURCE_KINDS, *HISTORY_TABLES)}, "resource_map": {kind: {str(i["source_id"]): i["target"]["id"] for i in plan["resources"] if i["source_kind"] == kind} for kind in RESOURCE_KINDS}, "artifacts_preserved": sum(f["status"] == "preserved" for f in plan["artifacts"].values()), "artifacts_missing": sum(f["status"] == "missing" for f in plan["artifacts"].values()), "historical_read_only": len(plan["resources"]), "jobs_created": 0, "events_created": 0, "excluded_outside_campaign_scope": plan["excluded_history_counts"], "history_relation_reviews": [{"kind": i["source_kind"], "source_id": i["source_id"], "review": i["relation_review"]} for i in plan["history"] if i["relation_review"]], "needs_configuration": [{"kind": i["source_kind"], "source_id": i["source_id"], "missing": i["target"]["data"]["legacy_import"]["missing_configuration"]} for i in plan["resources"] if i["target"]["data"]["legacy_import"]["needs_configuration"]]} def business_sql(plan: dict) -> str: """Return transaction-body SQL; no target writes happen in this function.""" _validate_plan(plan) if not re.fullmatch(r"[a-f0-9]{64}", str(plan.get("source_snapshot_sha256", ""))): raise ValueError("Business SQL requires a source snapshot fingerprint") payload = _canonical(postgres_plan(plan)) literal = "'" + payload.replace("'", "''") + "'::jsonb" tag = "business_" + hashlib.sha256(payload.encode()).hexdigest()[:16] return f"""SET LOCAL standard_conforming_strings = on; SET LOCAL log_statement = 'none'; SET LOCAL log_min_error_statement = 'panic'; DO ${tag}$ DECLARE migration jsonb := {literal}; item jsonb; target jsonb; source_data jsonb; saved record; artifact jsonb; native_id text; parent_id text; owner_name text; BEGIN IF current_database() <> '{TARGET_DATABASE}' THEN RAISE EXCEPTION 'Business target database mismatch'; END IF; PERFORM pg_advisory_xact_lock({TARGET_TENANT},11904); PERFORM 1 FROM tenants WHERE id={TARGET_TENANT} AND status='active' AND deleted_at IS NULL FOR SHARE; IF NOT FOUND THEN RAISE EXCEPTION 'Business migration requires active target tenant'; END IF; LOCK TABLE workbench_resources IN SHARE ROW EXCLUSIVE MODE; CREATE TABLE IF NOT EXISTS {LEDGER} ( source_system text NOT NULL, source_organization_id bigint NOT NULL, source_kind text NOT NULL, source_id bigint NOT NULL, target_tenant_id integer NOT NULL, target_id varchar(36) NOT NULL, parent_resource_id varchar(36), source_snapshot jsonb NOT NULL, native_snapshot jsonb NOT NULL, relation_review jsonb NOT NULL DEFAULT '[]', artifact_snapshot jsonb NOT NULL DEFAULT '{{}}', source_snapshot_sha256 varchar(64) NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY(source_system,source_organization_id,source_kind,source_id), UNIQUE(target_tenant_id,source_kind,target_id), CHECK(source_snapshot_sha256 ~ '^[a-f0-9]{{64}}$') ); LOCK TABLE {LEDGER} IN SHARE ROW EXCLUSIVE MODE; IF EXISTS (SELECT 1 FROM jsonb_each_text(migration->'identity_mapping') i LEFT JOIN {IDENTITY_LEDGER} m ON m.source_system='{SOURCE}' AND m.source_organization_id=1 AND m.source_user_id=i.key::bigint AND m.target_tenant_id={TARGET_TENANT} AND m.target_user_id=i.value LEFT JOIN users u ON u.id=i.value LEFT JOIN tenant_members tm ON tm.user_id=i.value AND tm.tenant_id={TARGET_TENANT} WHERE m.target_user_id IS NULL OR u.id IS NULL OR u.deleted_at IS NOT NULL OR tm.id IS NULL OR tm.deleted_at IS NOT NULL) THEN RAISE EXCEPTION 'Business owner durable identity or membership mismatch'; END IF; IF EXISTS (SELECT 1 FROM jsonb_each_text(migration->'agent_mapping') i LEFT JOIN {ASSET_LEDGER} m ON m.source_system='{SOURCE}' AND m.source_organization_id=1 AND m.source_kind='agent' AND m.source_id=i.key::bigint AND m.target_tenant_id={TARGET_TENANT} AND m.target_id=i.value LEFT JOIN custom_agents a ON a.id=i.value AND a.tenant_id={TARGET_TENANT} WHERE m.target_id IS NULL OR a.id IS NULL) THEN RAISE EXCEPTION 'Business Agent durable mapping mismatch'; END IF; IF EXISTS (SELECT 1 FROM jsonb_each_text(migration->'kb_mapping') i LEFT JOIN knowledge_bases k ON k.id=i.value AND k.tenant_id={TARGET_TENANT} AND k.deleted_at IS NULL WHERE k.id IS NULL) THEN RAISE EXCEPTION 'Business knowledge base scope mismatch'; END IF; FOR item IN SELECT value FROM jsonb_array_elements((migration->'resources') || (migration->'history')) LOOP source_data := item->'source'; target := coalesce(item->'target','{{}}'); native_id := coalesce(target->>'id',item->>'target_id'); parent_id := item->>'parent_resource_id'; artifact := '{{}}'; IF item->>'source_kind'='segment' THEN SELECT coalesce(jsonb_object_agg(a.key,a.value),'{{}}') INTO artifact FROM jsonb_each(migration->'artifacts') a WHERE a.key=source_data->>'artifact_path' OR EXISTS (SELECT 1 FROM jsonb_array_elements(source_data->'generation_history') h WHERE h->>'artifact_path'=a.key); ELSIF item->>'source_kind'='artifact' THEN artifact := coalesce(migration->'artifacts'->(source_data->>'docx_path'),'{{}}'); END IF; SELECT * INTO saved FROM {LEDGER} WHERE source_system='{SOURCE}' AND source_organization_id=1 AND source_kind=item->>'source_kind' AND source_id=(item->>'source_id')::bigint; IF FOUND THEN IF saved.target_tenant_id IS DISTINCT FROM {TARGET_TENANT} OR saved.target_id IS DISTINCT FROM native_id OR saved.parent_resource_id IS DISTINCT FROM parent_id OR saved.source_snapshot IS DISTINCT FROM source_data OR saved.native_snapshot IS DISTINCT FROM target OR saved.artifact_snapshot IS DISTINCT FROM artifact OR saved.relation_review IS DISTINCT FROM coalesce(item->'relation_review','[]') THEN RAISE EXCEPTION 'Business durable mapping conflict'; END IF; IF item ? 'target' THEN PERFORM 1 FROM workbench_resources WHERE id=native_id AND tenant_id={TARGET_TENANT} AND owner_id=target->>'owner_id' AND kind=target->>'kind'; IF NOT FOUND THEN RAISE EXCEPTION 'Mapped business resource removed; refusing recreation'; END IF; END IF; ELSE IF item ? 'target' THEN IF EXISTS (SELECT 1 FROM workbench_resources r WHERE r.id=native_id OR (r.tenant_id={TARGET_TENANT} AND r.owner_id=target->>'owner_id' AND r.kind=target->>'kind' AND r.name=target->>'name' AND NOT EXISTS (SELECT 1 FROM jsonb_array_elements(migration->'resources') p WHERE p->'target'->>'id'=r.id))) THEN RAISE EXCEPTION 'Native business ID or owner/name collision'; END IF; SELECT username INTO owner_name FROM users WHERE id=target->>'owner_id'; INSERT INTO workbench_resources(id,tenant_id,owner_id,owner_name,kind,name,status,version,data,created_at,updated_at) VALUES(native_id,{TARGET_TENANT},target->>'owner_id',owner_name,target->>'kind',target->>'name',target->>'status', (target->>'version')::integer,target->'data',coalesce((target->>'created_at')::timestamptz,now()), coalesce((target->>'updated_at')::timestamptz,now())); ELSE PERFORM 1 FROM workbench_resources WHERE id=parent_id AND tenant_id={TARGET_TENANT}; IF NOT FOUND THEN RAISE EXCEPTION 'Historical parent resource missing'; END IF; END IF; INSERT INTO {LEDGER}(source_system,source_organization_id,source_kind,source_id,target_tenant_id,target_id, parent_resource_id,source_snapshot,native_snapshot,artifact_snapshot,relation_review,source_snapshot_sha256) VALUES('{SOURCE}',1,item->>'source_kind',(item->>'source_id')::bigint,{TARGET_TENANT},native_id, parent_id,source_data,target,artifact,coalesce(item->'relation_review','[]'),migration->>'source_snapshot_sha256'); END IF; END LOOP; END ${tag}$; """