Files
xinmi/scripts/weknora_business_etl.py
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

470 lines
28 KiB
Python

"""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}$;
"""