#!/usr/bin/env python3 """A3:23 型结构本体 YAML → meta 表行(W1 种子演练,幂等可重跑)。 映射约定(详见 db/表映射.md 与本次收口记录): - muse_meta_schema 一型一行;schema_key=target_type;状态 启用→active / 待启用→inactive - muse_meta_schema_version 每型 v1,active_flag=TRUE;field_contract_snapshot=完整 YAML(判据/说明/设计发现全在) - muse_meta_field 规范化投影行:基础字段 sort_order 1–9,特有字段 11 起(段位即基础/特有约定) - muse_meta_visibility_policy 版本级一行:ai_context=是否存在 AI 可见字段; 字段级细则进 policy_snapshot.fieldAiContext(主仓无字段级列——设计发现,待回填) - 幂等:schema/version/policy upsert;field 行重跑=删旧插新(meta 种子行豁免软删约定,见表映射.md) """ import json import pathlib import sys import psycopg import yaml from psycopg.types.json import Jsonb DSN = "postgresql://root:f6710e2d0294eb1c10e26a805a64bc54@100.64.0.8:5433/muse-example" SCHEMA_DIR = pathlib.Path(__file__).resolve().parents[4] / "meta" / "schemas" TENANT, ACTOR = 1, "1" # 实验写入约定:系统主账号 # 基础字段(所有型共有,README §使用规则;aiContext 为实验设计判断,可在 B4 优化环调整): # 名称/别名/摘要/标签全用途可见;来源(出处)生成不可见防抄袭腔;状态是系统轨道值不进上下文(授权过滤在查询层) BASE_FIELDS = [ ("名称", "text", True, None, True), ("别名", "array", False, None, True), ("一句话摘要", "text", True, None, True), ("标签", "array", False, None, True), ("来源", "text", False, None, ["planning", "detection", "extraction"]), ("状态", "enum", True, ["草稿", "已确认"], False), ] def seed_one(conn, doc: dict, src_name: str): """单型入库:schema → version(v1) → fields → visibility_policy;返回审查摘要。""" key = doc["target_type"] status = "active" if doc.get("状态", "启用") == "启用" else "inactive" # 1) schema 行 upsert(uk: tenant_id+domain+scope+target_type+schema_key) row = conn.execute( """INSERT INTO muse_meta_schema (schema_key, domain, scope, target_type, display_name, status, creator, updater, tenant_id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) ON CONFLICT (tenant_id, domain, scope, target_type, schema_key) DO UPDATE SET display_name=EXCLUDED.display_name, status=EXCLUDED.status, updater=EXCLUDED.updater RETURNING id""", (key, doc["domain"], doc["scope"], key, doc.get("中文名", key), status, ACTOR, ACTOR, TENANT)).fetchone() schema_id = row[0] # 2) version v1 upsert(uk: tenant_id+schema_key+version_no);快照=完整 YAML row = conn.execute( """INSERT INTO muse_meta_schema_version (schema_id, schema_key, version_no, status, active_flag, field_contract_snapshot, change_note, published_by, activated_by, creator, updater, tenant_id) VALUES (%s,%s,1,'published',TRUE,%s,%s,%s,%s,%s,%s,%s) ON CONFLICT (tenant_id, schema_key, version_no) DO UPDATE SET field_contract_snapshot=EXCLUDED.field_contract_snapshot, change_note=EXCLUDED.change_note, updater=EXCLUDED.updater RETURNING id""", (schema_id, key, Jsonb(doc), f"A3 种子入库(源:{src_name})", ACTOR, ACTOR, ACTOR, ACTOR, TENANT)).fetchone() version_id = row[0] conn.execute("UPDATE muse_meta_schema SET active_version_id=%s WHERE id=%s", (version_id, schema_id)) # 3) field 行:删旧插新(幂等重建) conn.execute("DELETE FROM muse_meta_field WHERE tenant_id=%s AND schema_version_id=%s", (TENANT, version_id)) ai_map = {} n_special = 0 for i, (fk, ftype, req, enum, ai) in enumerate(BASE_FIELDS, start=1): conn.execute( """INSERT INTO muse_meta_field (schema_version_id, field_key, display_name, field_type, is_required, enum_values, sort_order, creator, updater, tenant_id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)""", (version_id, fk, fk, ftype, req, Jsonb(enum) if enum else None, i, ACTOR, ACTOR, TENANT)) ai_map[fk] = ai for i, f in enumerate(doc.get("特有字段") or [], start=11): conn.execute( """INSERT INTO muse_meta_field (schema_version_id, field_key, display_name, field_type, is_required, sort_order, creator, updater, tenant_id) VALUES (%s,%s,%s,'text',FALSE,%s,%s,%s,%s)""", (version_id, f["key"], f["key"], i, ACTOR, ACTOR, TENANT)) ai_map[f["key"]] = f.get("aiContext", True) n_special += 1 # 4) visibility_policy:版本级一行 upsert(无 uk,先查后写);字段级细则进 policy_snapshot any_ai = any(v is not False for v in ai_map.values()) snap = Jsonb({"fieldAiContext": ai_map, "用途枚举": ["planning", "generation", "detection", "extraction"], "语义": "true=任何用途可入AI上下文;false=一律不入;[用途]=仅列出的用途可入"}) exist = conn.execute( "SELECT id FROM muse_meta_visibility_policy WHERE tenant_id=%s AND schema_version_id=%s", (TENANT, version_id)).fetchone() if exist: conn.execute("UPDATE muse_meta_visibility_policy SET ai_context=%s, policy_snapshot=%s, updater=%s WHERE id=%s", (any_ai, snap, ACTOR, exist[0])) else: conn.execute( """INSERT INTO muse_meta_visibility_policy (schema_version_id, ui_visible, ai_context, user_editable, user_searchable, exportable, policy_snapshot, creator, updater, tenant_id) VALUES (%s,TRUE,%s,TRUE,FALSE,FALSE,%s,%s,%s,%s)""", (version_id, any_ai, snap, ACTOR, ACTOR, TENANT)) full_open = sum(1 for v in ai_map.values() if v is True) scoped = sum(1 for v in ai_map.values() if isinstance(v, list)) closed = sum(1 for v in ai_map.values() if v is False) return (key, doc.get("中文名", ""), doc["domain"], doc["scope"], status, len(BASE_FIELDS) + n_special, full_open, scoped, closed) def main(): files = sorted(p for p in SCHEMA_DIR.glob("*.yaml")) if not files: sys.exit(f"未找到 schema YAML: {SCHEMA_DIR}") rows = [] with psycopg.connect(DSN) as conn: for p in files: doc = yaml.safe_load(p.read_text()) rows.append(seed_one(conn, doc, p.name)) conn.commit() # 审查面:逐型卡片行 print(f"{'型':<20}{'中文名':<10}{'domain':<11}{'scope':<10}{'状态':<9}{'字段':<5}{'AI全开':<7}{'限用途':<7}{'关闭'}") for r in rows: print(f"{r[0]:<20}{r[1]:<10}{r[2]:<11}{r[3]:<10}{r[4]:<9}{r[5]:<5}{r[6]:<7}{r[7]:<7}{r[8]}") print(f"\n共 {len(rows)} 型入库(基础字段 {len(BASE_FIELDS)} + 各型特有;快照含判据/说明/设计发现全文)") if __name__ == "__main__": main()