WeData 敏感数据分类与脱敏标签打标
Skill 概述
本 skill 提供敏感数据分类、字段自动识别与脱敏标签打标能力。WeData 中数据表采用三级结构 Catalog / Schema / Table,用户可以对一个或多个 Catalog 下的表字段进行敏感数据扫描,AI 根据字段名称、类型、描述以及(如有)字段采样值自动识别敏感字段并推荐脱敏标签,经用户确认后完成打标。
ℹ️ 关于字段采样数据:
SearchAsset返回的FieldInfo.SampleValues为字段实际数据采样值列表,可能存在也可能不存在。当SampleValues非空时,必须将其纳入识别判断作为元数据的有力佐证;当为空时,仅基于元数据(表名、表描述、字段名、字段类型、字段描述)和脱敏标签信息进行识别。不要把「是否使用采样数据」作为选项询问用户——有就用,没有就只用元数据,识别策略由 skill 自动决定。
WeData 的脱敏标签(LabelType=4)可以绑定脱敏策略,当字段被打上脱敏标签后,系统内部会自动对该字段下发已绑定的脱敏策略。用户也可以单独管理脱敏标签与脱敏策略的绑定关系。
核心能力
| 能力 | 说明 |
|---|---|
| 敏感字段扫描 | 对指定 Catalog 下的表进行字段级敏感数据识别 |
| AI 智能打标 | 根据字段元数据(名称、类型、描述)+ 字段采样值(如有)+ 脱敏标签列表,自动推荐匹配的脱敏标签 |
| 脱敏标签打标 | 调用接口为字段打上脱敏标签,系统自动关联脱敏策略 |
| 脱敏策略管理 | 查询、绑定、解绑脱敏标签与脱敏策略的关联关系;创建、更新、删除脱敏策略 |
| AI 打标排除管理 | 对不希望被 AI 打上敏感标签的字段进行排除,后续 AI 扫描时自动跳过;也可恢复已排除的字段 |
不适用场景
- 用户询问治理标签 / 自定义标签 / 属性标签(LabelType=1 或 2 或 3)的管理 → 这些不是脱敏标签
- 用户询问表 / 字段 / 血缘等通用资产检索(不涉及脱敏标签) → 使用
knowledge/semantic-meta-search - 用户询问数据质量规则的创建和执行 → 使用
data-quality - 用户询问数据开发任务的管理 → 使用
data-engineer
必需输入
- Catalog 范围:敏感扫描时需要用户指定要扫描的 Catalog 名称(一个或多个)
- 写操作确认:打标和脱敏策略绑定属于写操作,必须经用户明确确认后执行
实体模型
Catalog(数据目录)
└── Schema(数据库)
└── Table(数据表)
└── Field(字段)
├── Name: 字段名称
├── Type: 字段类型(string, int, ...)
├── Comment: 字段描述
├── SampleValues: 字段采样值列表(可选,可能为空)
└── Tags: 已有标签列表
脱敏标签(BizLabel, LabelType=4)
├── Name: 标签名称(如"手机号"、"身份证号"、"银行卡号")
├── Description: 标签描述(含用途说明、合规要求等)
├── SecurityTypes: 安全类型列表(如 PII、GDPR、HIPAA 等)
├── ⚠️ 脱敏标签的标签值非必填(Values 可为空),与治理标签/自定义标签不同
└── 脱敏策略绑定(LabelMaskPolicyRelInfo)
├── PolicyId: 脱敏策略 ID
└── PolicyName: 脱敏策略名称
意图路由(第一步 MUST)
收到用户问题后,第一步必须判定意图属于下列哪类,然后进入对应工作流。
| 意图类别 | 触发词 | 工作流 |
|---|---|---|
| A. 敏感字段扫描与打标 | "扫描 / 识别 / 敏感字段 / 安全扫描 / 字段打标 / PII / 分类分级" | 工作流 A:扫描与打标 |
| B. 脱敏标签查询 | "脱敏标签 / 安全标签 / 标签列表 / 有哪些脱敏标签 / 查看标签" | 工作流 B:标签查询 |
| C. 脱敏策略管理 | "脱敏策略 / 绑定策略 / 解绑 / 策略关联 / 脱敏绑定 / 创建策略 / 新建策略 / 删除策略 / 修改策略 / 更新策略 / 脱敏方法 / 用户组" | 工作流 C:脱敏策略管理 |
| D. 已有标签查询 | "字段标签 / 表的标签 / 哪些字段打了标" | 工作流 D:资产标签查询 |
| E. AI 打标排除管理 | "排除 / 不要打标 / 忽略字段 / 恢复排除 / 排除列表 / 跳过字段" | 工作流 E:AI 打标排除管理 |
⚠️ 若同一句话含多个类别触发词(如"扫描敏感字段并绑定脱敏策略"),按顺序拆分执行,先完成 A 再处理 C。
工作流 A:敏感字段扫描与打标(核心流程)
这是本 skill 的核心场景,完整流程分为 5 个阶段:
阶段 1:确定扫描范围
⚠️ 强制要求:必须先与用户确认扫描的 Catalog 范围后才能开始扫描,绝不能在用户未明确指定的情况下自动扫描所有 Catalog。 即使用户说"帮我扫描敏感字段"但未指定 Catalog,也必须先询问用户要扫描哪些 Catalog。
- 用户指定要扫描的 Catalog 名称(一个或多个)→ 直接进入阶段 2
- 如果用户未指定或不确定自己有哪些 Catalog,通过
Skill("asset-discovery")查询可用 Catalog 列表,展示给用户选择后再开始扫描
将查询到的 Catalog 列表展示给用户,等待用户选择要扫描的范围后再继续,不要自动选择全部。
阶段 2:获取表和字段信息
本阶段分两步:先通过 Skill("asset-discovery") 检索目标范围内的表列表,再通过 SearchAsset 获取字段详情(采样值、已有标签等)。
步骤 2.1:检索表列表(通过 asset-discovery)
⚠️ 所有平台资产的检索/浏览操作统一走
Skill("asset-discovery")。包括但不限于:查 Catalog 列表、查 Schema 列表、获取表列表、搜索表名等。不要直接用SearchAsset做全量翻页扫描。🔴 直连分析型 Catalog 标记:在获取表列表时,同时记录每个 Catalog 是否为直连分析型(
connection_id非空)。此信息将在阶段 4 输出格式和阶段 5 中用于能力降级判断。直连分析型 Catalog 的表支持敏感识别和打标,但不支持脱敏策略下发。
步骤 2.2:获取字段及标签信息(SearchAsset)
拿到表名列表后,调用 SearchAsset 获取每个表的字段信息(名称、类型、描述、采样值)和已有标签信息(FieldTags)。这是 SearchAsset 在本 skill 中的唯一用途——提供字段级元数据,而非用于检索/浏览资产。
⚠️ 必须循环分页:每次最多返回 50 条,必须检查
NextPageToken直到为空。 详细参数见 api_reference.md。
关键字段提取:FullName(表路径)、AssetGuid(打标时的 PropertyId)、AssetName、Comment、FieldInfo(字段名/类型/描述/采样值 SampleValues)、FieldTags(已有标签)。
ℹ️
FieldInfo.SampleValues为该字段的实际数据采样列表(如有),将作为阶段 4 敏感识别的辅助输入。该字段可能为空(采样未开启、数据为空、无访问权限等场景),为空时跳过采样维度判断即可。 ℹ️ 从SearchAsset结果中按FullName(catalog.schema.table)过滤出步骤 2.1 获取的目标表,忽略不在范围内的结果。
阶段 3:获取脱敏标签列表
调用 ListLabels(Types=[4],必传 WorkspaceId + Shared=true,PageSize=100)。响应 BizLabel.MaskPolicy 已直接回填关联策略,无需 N+1 调 ListMaskPoliciesByLabel。
💡 可选过滤(仅 Type=4 有效):
SecurityTypes、PolicyBindStatus(1=已关联/2=未关联)、SourceTypes([2]=仅自定义)
# 首页(根据 TotalCount 决定是否需要继续翻页);响应 BizLabel.MaskPolicy 已直接给出关联策略
wedatacli ListLabels '{"WorkspaceId":"<ws_id>","Shared":true,"Types":[4],"Page":{"PageNumber":1,"PageSize":100}}'
# 例:只想要"已绑定策略 + 命中 PII/GDPR"的脱敏标签
wedatacli ListLabels '{"WorkspaceId":"<ws_id>","Shared":true,"Types":[4],"SecurityTypes":["PII","GDPR"],"PolicyBindStatus":1,"Page":{"PageNumber":1,"PageSize":100}}'
⛔ 不要再走旧 N+1 写法:
ListLabels拿到 N 个脱敏标签后逐个调ListMaskPoliciesByLabel的写法已过时,请直接读BizLabel.MaskPolicy。仅当需要查看完整历史关联记录(含已 unbind 的)时才走ListMaskPoliciesByLabel。
阶段 4:AI 敏感数据识别
基于以下信息进行智能识别:
输入(以下数据源):
- 表元数据:表全名(FullName,即 catalog.schema.table)、表名称(AssetName)、表描述(Comment)
- 字段元数据:名称(Name)、类型(Type)、描述(Comment)
- 字段采样值(如有):
FieldInfo.SampleValues,字段的实际数据采样列表,可能为空 - 脱敏标签列表:名称、描述、安全类型(SecurityTypes)、已绑定的脱敏策略(如有)
⚠️ 脱敏标签的标签值非必填,识别时只需匹配到脱敏标签本身即可,不需要匹配标签值。 ℹ️ 采样数据是可选辅助输入,不是必需输入。 当
SampleValues非空时把它作为有力佐证(用真实值格式特征佐证或推翻元数据匹配结论);为空时仅基于元数据识别即可。不要把「是否使用采样数据」作为可选项让用户选择——有就用,没有就基于元数据识别,由 skill 自动决定。
核心原则:不漏报,减少误报。 漏报意味着敏感数据未被保护,是安全风险;误报可通过排除机制(工作流 E)修正。当存在歧义时,倾向于纳入识别结果并交给用户确认,而非直接跳过。
识别采用两阶段框架:先降噪排除 → 再按标签匹配。
第一阶段:降噪排除(仅排除明确不可能是敏感数据的字段,宁可放过不可错杀)
排除纯标识符(_id/_uid/_uuid)、枚举/状态(_type/_status)、度量/统计(count/amount)、时间(_at/_ts)、布尔(is_/has_)、技术配置(version/config)等明确非敏感字段。含 name/phone/email/address/card 等敏感关键词的字段不排除。
详细排除规则表见 recognition_rules.md。
第二阶段:按标签匹配(基于 ListLabels 实际返回的标签,动态匹配)
对每个通过第一阶段的字段,遍历 ListLabels 返回的所有脱敏标签,利用标签 Name(提取 . 后的语义关键词)和 Description 进行语义匹配。需注意区分系统对象名(file_name/table_name)与自然人姓名、技术地址(mac_address)与地理位置等易误报场景。
详细误报场景处理规则见 recognition_rules.md。
采样值交叉验证(当 SampleValues 非空时启用)
- 元数据匹配 + 采样值符合 → 强匹配,识别依据标注「字段名+采样值」
- 元数据匹配 + 采样值明显不符 → 推翻匹配,作为误报排除
- 元数据匹配 + 采样值缺失 → 维持元数据匹配结论
- 元数据未匹配 + 采样值强烈指向某敏感类型 → 纳入候选,标注置信度较低
详细采样值校验规则见 recognition_rules.md。
⚠️ 匹配优先级:字段 Comment > 字段名关键词 > 采样值特征 > 表名上下文。描述中明确提及敏感含义时,即使字段名不含关键词也应纳入;采样值用于交叉验证以减少误报。已有相同标签的字段跳过。 ⚠️ 排除字段跳过:识别前先调用
ListAssetTagExclusions查询已排除字段,已排除字段自动跳过。
输出格式(展示给用户确认):
结果按 Catalog / Schema / Table 分组展示。每个字段列出:字段名、类型、描述、推荐脱敏标签、安全类型、识别依据、采样佐证(脱敏后,如 138****1234)、已绑定脱敏策略状态(✅/❌)。末尾汇总扫描表数、识别字段数、未绑定策略的标签数。
⚠️ 严禁明文展示采样真实值,必须先脱敏处理。标记 ❌ 的脱敏标签需提醒用户打标后不会自动脱敏。
🔴 直连分析型 Catalog 展示调整:若目标表属于外部数据目录(直连分析型),"已绑定脱敏策略状态"列展示
N/A(外部表不支持下发),而非 ✅/❌;汇总信息中不统计"未绑定策略的标签数"(因为绑定了也不生效)。
阶段 5:执行打标与脱敏策略处理
用户确认后,执行以下操作:
5.1 批量打标
⚠️ FieldTags 按
FieldName增量覆盖:传入的 FieldName 会完全替换该字段的已有标签,未传入的 FieldName 保持不变。详见 api_reference.md。
打标决策:
- 只动 FieldTags,不传 Tags(避免误改资产级标签)
- 仅包含本次要打标的字段;未涉及字段不传
- 每个字段需合并已有标签 + 新增脱敏标签后一并传入
wedatacli BatchVoteAssetTag '{"Votes":[{"PropertyType":"TABLE","PropertyId":"<table_asset_guid>","Creator":"<user>","FieldTags":[{"LabelId":"<label_id>","LabelName":"<name>","LabelType":4,"FieldName":"<field>","FieldType":"<type>"}]}]}'
5.2 处理未绑定脱敏策略的脱敏标签
🔴 直连分析型 Catalog 能力降级:若目标表属于外部数据目录(直连分析型 Linked Catalog,
connection_id非空),跳过本阶段,改为输出提示:"已完成敏感字段打标。当前表属于外部数据目录(直连分析型),暂不支持动态脱敏策略下发,标签仅作为分类标记使用。"
仅对内部 Catalog 的表执行以下策略绑定建议流程。
打标完成后,对标记"❌ 未绑定"的脱敏标签:调用 ListDataMaskStrategies 匹配推荐策略,展示给用户选择绑定(→ 工作流 C.2)、创建策略(→ 工作流 C.5)或跳过。
5.3 查询并汇报脱敏策略下发结果
🔴 直连分析型 Catalog 能力降级:若目标表属于外部数据目录(直连分析型),整体跳过本阶段(外部表不支持脱敏策略下发,无下发结果可查)。
仅当打标涉及已绑定策略的脱敏标签时执行。调用 ListMaskPolicyDispatchLogs(LabelId 必填 + 四元组缩小结果集)。
状态判定:DispatchStatus=1→✅ 成功;=2→❌ 失败(读 FailReason);查不到→⏳ 处理中(提示 30 秒后重试)。
工作流 B:脱敏标签查询(只读)
调用 ListLabels(Types=[4],必传 WorkspaceId + Shared=true,PageSize=100)查询脱敏标签。响应 BizLabel.MaskPolicy 已直接回填关联策略,⛔ 不要走旧 N+1 写法。
wedatacli ListLabels '{"WorkspaceId":"<ws_id>","Shared":true,"Types":[4],"Page":{"PageNumber":1,"PageSize":100}}'
整合输出:标签名称、描述、安全类型、已绑定脱敏策略。
工作流 C:脱敏策略管理(含确认闭环)
工作流 C 覆盖脱敏策略的完整生命周期:查询绑定关系、绑定/解绑、查询策略列表、创建/更新/删除策略。
C.1 查询脱敏策略绑定(只读)
优先:直接读 ListLabels 响应的 BizLabel.MaskPolicy 字段。仅当需要完整历史关联记录时才走 ListMaskPoliciesByLabel。
ℹ️ 策略视角反查(PolicyId → labels)无云 API 暴露,可在
ListLabels(Types=[4])结果中按MaskPolicy.PolicyId客户端过滤。
C.2 关联/更换/解绑脱敏策略(写操作,需确认)
推荐:UpdatePolicyLabelBindings(声明式 PUT 语义,一次调用覆盖新增/修改/删除):
wedatacli UpdatePolicyLabelBindings '{"PolicyId":"<policy_id>","LabelIds":[1,2,3],"WorkspaceId":"<ws_id>","Operator":"<user>"}'
- LabelIds 为最终全集,服务端自动 diff;
LabelIds:[]= 解绑全部 - 全成全败;LabelIds ≤ 200
标签侧替代方案:通过 UpdateLabels.PolicyBindingUpdate(三态)调整关联:
- 不传
PolicyBindingUpdate= 保持不动 PolicyId="<id>"= 关联或更换PolicyId=""= 解除关联
wedatacli UpdateLabels '{"WorkspaceId":"<ws_id>","Shared":true,"Labels":[{"LabelId":1,"Modifier":"<user>","PolicyBindingUpdate":{"PolicyId":"<policy_id>","WorkspaceId":"<ws_id>"}}]}'
C.4 查询脱敏策略列表(只读)
调用 ListDataMaskStrategies 展示策略列表。一个脱敏策略下可以包含多个脱敏方法,每个脱敏方法针对一个用户组生效。
wedatacli ListDataMaskStrategies '{"WorkspaceId":"<workspace_id>","Offset":0,"Limit":100}'
⚠️ 展示策略详情时必须同时给出
GroupId与GroupName。名称优先取接口返回的Groups[].GroupName;为空时收集缺失的GroupId一次性调用ListConsoleGroups补查,严禁编造。
C.5~C.7 创建 / 删除 / 更新脱敏策略(写操作,需确认)
| 操作 | 关键接口 | 要点 |
|---|---|---|
| 创建 | CreateDataMaskStrategy |
不同用户组配不同脱敏方法;确认计划需展示 GroupId + GroupName;创建后询问是否绑定标签 |
| 删除 | DeleteDataMaskStrategy |
不可恢复;需列出影响范围(脱敏方法+用户组);建议先检查标签绑定 |
| 更新 | UpdateDataMaskStrategy |
Groups 为全量替换,必须传入完整规则列表 |
详细交互流程与示例见 strategy_lifecycle.md。
工作流 D:资产标签查询(只读)
通过 SearchAsset(FieldTags)或 ListTagsByAsset 查询指定表/字段已有的脱敏标签。
如用户进一步追问「这个字段的脱敏策略下发是否成功?为什么没生效?」之类的问题,调用 ListMaskPolicyDispatchLogs 按 LabelId + 四元组(CatalogName/SchemaName/TableName/FieldName)精确查询,参考工作流 A 阶段 5.3 的结果解读和展示模板。
工作流 E:AI 打标排除管理
用户对 AI 识别的敏感标签不认可时,可将字段排除(后续扫描自动跳过);也可恢复已排除字段。
E.1 排除字段(写操作,需确认)
⚠️ 排除 = 保存排除记录 + 移除字段标签,是原子操作,确认排除即同时移除标签,严禁拆开询问。
展示排除计划(表名、字段名、当前脱敏标签、排除原因)等待确认后,连续执行:
- 保存排除记录:
UpdateAssetTagExclusions(ExclusionAction=1) - 移除字段标签:
BatchVoteAssetTag(LabelId="-1"清除,或传保留标签列表走增量覆盖)
wedatacli UpdateAssetTagExclusions '{"ExclusionAction":1,"Items":[{"PropertyType":"TABLE","PropertyId":"<guid>","ColumnName":"<field>","LabelId":"<id>","LabelName":"<name>","Reason":"<原因>","CatalogName":"<c>","SchemaName":"<s>","TableName":"<t>"}]}'
E.2 恢复排除字段(写操作,需确认)
先查询排除记录(ListAssetTagExclusions),展示恢复计划等待确认后,调用 UpdateAssetTagExclusions(ExclusionAction=2)。
E.3 查询排除记录(只读)
调用 ListAssetTagExclusions,支持按 Catalog、表、标签等维度过滤。
API 速查表
所有接口通过 wedatacli <Action> '<JSON_Params>' 调用。详细参数见 api_reference.md。
| 场景 | Action | 关键约束 |
|---|---|---|
| 平台资产检索(Catalog/Schema/表列表/搜索) | Skill("asset-discovery") |
所有检索/浏览操作统一走 asset-discovery(get catalogs / get schemas / get tables / search table) |
| 获取字段及标签信息 | SearchAsset |
获取表的字段元数据(名称/类型/描述/采样值)和已有标签;必须循环分页(检查 NextPageToken) |
| 查询脱敏标签列表 | ListLabels |
必传 WorkspaceId + Shared=true;Types=[4];PageSize=100;响应 BizLabel.MaskPolicy 已回填关联策略 |
| 批量字段打标 | BatchVoteAssetTag |
FieldTags 按 FieldName 增量覆盖;LabelId="-1" 清除全部标签 |
| 策略侧批量关联标签 | UpdatePolicyLabelBindings |
声明式 PUT 语义,LabelIds 为最终全集;全成全败 |
| 修改脱敏标签关联策略 | UpdateLabels |
用 PolicyBindingUpdate wrapper(三态) |
| 查询脱敏策略列表 | ListDataMaskStrategies |
— |
| 创建/更新/删除脱敏策略 | CreateDataMaskStrategy / UpdateDataMaskStrategy / DeleteDataMaskStrategy |
Groups 为全量替换;详见 strategy_lifecycle.md |
| 查询脱敏策略下发流水 | ListMaskPolicyDispatchLogs |
LabelId 必填;DispatchStatus: 1=成功 2=失败 |
| 排除/恢复字段打标 | UpdateAssetTagExclusions |
ExclusionAction: 1=排除 2=恢复 |
| 查询排除记录 | ListAssetTagExclusions |
支持按 Catalog、表、标签过滤 |
ℹ️
WorkspaceId由 wedatacli 从~/.wedata/config.json自动注入,命令示例无需显式传入。
全局安全约束
- 写操作需显式确认:打标、策略绑定/解绑/创建/更新/删除、排除/恢复必须经用户确认
- 打标确认闭环:AI 识别结果必须展示给用户确认后才执行
- 不编造 ID:所有 ID 必须从 API 查询结果获取。PropertyId =
AssetGuid,PropertyType ="TABLE" - 打标增量合并:FieldTags 按 FieldName 增量覆盖,需合并已有标签 + 新增标签;清除用
LabelId="-1" - 跳过已打标字段:字段已有相同脱敏标签时默认跳过
- 分页处理:SearchAsset 必须循环检查
NextPageToken直到为空 - 扫描范围确认:必须先与用户确认 Catalog 范围,绝不能自动扫描所有 Catalog
- 检索能力收拢:所有平台资产的检索/浏览操作(查 Catalog、查 Schema、获取表列表、搜索表)统一走
Skill("asset-discovery");本 skill 不直接调用ListCatalogNames等检索类 API;SearchAsset仅用于获取表的字段信息和标签信息 - 脱敏标签标签值非必填:打标时
LabelValueId="0",LabelValue="" - 采样数据自动决策:非空时必须作为交叉验证依据;为空时仅基于元数据识别。不要询问用户。严禁明文展示采样真实值
- 排除字段跳过:AI 扫描前先查询排除记录,已排除字段自动跳过
- 排除即移除标签:排除 = 保存排除记录 + 移除字段标签,是原子操作,严禁拆开询问
- 脱敏策略 Groups 全量替换:更新时必须传入完整的用户组规则列表
- 脱敏策略删除不可恢复:删除前必须提醒用户,建议先检查标签绑定
- 脱敏策略用户组展示必须含名称:必须同时给出
GroupId+GroupName;名称优先取接口返回值,为空时一次性调ListConsoleGroups补查,严禁编造 - 🔴 直连分析型 Catalog 能力降级:目标表属于外部数据目录(直连分析型 Linked Catalog,
connection_id非空)时,敏感识别和打标本身支持,但动态脱敏策略下发不支持。具体处理:- 工作流 A 阶段 5.1(打标):✅ 正常执行
- 工作流 A 阶段 5.2(处理未绑定策略的标签):🔴 跳过策略绑定建议,改为输出提示:
"已完成敏感字段打标。当前表属于外部数据目录(直连分析型),暂不支持动态脱敏策略下发,标签仅作为分类标记使用。"
- 工作流 A 阶段 5.3(查询下发结果):🔴 外部表场景下整体跳过
- 工作流 C.2(绑定/解绑脱敏策略):依赖后端
BindLabelMaskPolicy/UpdatePolicyLabelBindings返回错误码UnsupportedOperationForLinkedCatalog,捕获后提示:"外部数据目录(直连分析型)的表暂不支持动态脱敏策略下发。"
- 识别结果展示调整:外部表的扫描结果中,"已绑定脱敏策略状态"列展示
N/A(外部表不支持下发),而非 ✅/❌;汇总信息中不统计"未绑定策略的标签数"
Reference 文件索引
reference/api_reference.md— 各 API 的请求/响应参数详细说明reference/strategy_lifecycle.md— 脱敏策略创建/删除/更新的详细流程与示例reference/recognition_rules.md— AI 敏感数据识别的降噪排除规则、误报场景处理、采样值校验规则
最终产物处理
敏感字段扫描清单、脱敏打标变更记录、脱敏策略变更摘要等结构化产物,通过 Skill("artifact-uploader") 上传到 databuddy/governance/。
关键约束:domain="governance" → 仅 Markdown 且单文件 ≤ 5MB → 多文件用 op="upload_batch" 合并 → 回显 studio_link,失败时展示 errors[]。采样真实值必须脱敏后再写入产物,严禁明文。