diff --git a/design-docs/00-文档大纲.md b/design-docs/00-文档大纲.md
index e209ddd5..21b4863e 100644
--- a/design-docs/00-文档大纲.md
+++ b/design-docs/00-文档大纲.md
@@ -106,7 +106,8 @@
- [临时-01-AI流SSE长任务超时修复方案](临时-01-AI流SSE长任务超时修复方案.md)(评审版)——AI 真生成"长任务候选丢失"的 SSE 协议/时序 bug 修复方案对比,待人类 review 后执行;配套人读图 `.html`。SSE 接口语义归属仍属 `后端-05`,本件不重定义概念。
- [临时-02-market-install下游物化方案](临时-02-market-install下游物化方案.md)(评审版)——市场安装的 agent/kb 到“可真用”的两个物化断点(知识库检索 `no_dataset` 门 + 智能体 runtime 实体缺失)诊断与 C/B'/B/暂缓 四方案对比,待人类拍板物化深度/时机/数据集共享;配套人读图 `.html`。owner 边界与表结构归 `架构-02`/`后端-04`,handoff 边界与 ADR-016/017/020 只引用不重定义。
-- [临时-03-market-install-KB物化执行plan](临时-03-market-install-KB物化执行plan.md)(执行版)——承临时-02 拍板(B' installed_ref + KB 先行),把 KB 物化拆成 U0–U4 可独立验证实现单元;一手代码核验揪出四条硬事实(kb_id 被 assetId 污染、跨 BC 反查链断需新 `MarketAssetSourceApi`、**多租户共享同一 RAGFlow dataset 必越权→U0 转为“共享前先补 chunk 级隔离”硬门**、`muse_source_propagation_target` 表不存在);物化落点在 knowledge 绑定路径(非 install)。待人类拍 D1(共享 vs 复制 vs 暂缓)后执行;配套人读图 `.html`。owner 边界引 临时-02/架构-02/专题-03/ADR-020,不重定义。
+- [临时-03-market-install-KB物化执行plan](临时-03-market-install-KB物化执行plan.md)(执行版,**已被临时-04 supersede**)——承临时-02 拍板(B' installed_ref + KB 先行),把 KB 物化拆成 U0–U4 可独立验证实现单元;一手代码核验揪出四条硬事实(kb_id 被 assetId 污染、跨 BC 反查链断需新 `MarketAssetSourceApi`、检索链对返回 chunk 无二次过滤、`muse_source_propagation_target` 表不存在);物化落点在 knowledge 绑定路径(非 install)。当时方向是"多租户共享 dataset → 共享前补 chunk 级隔离",**D1 澄清后被临时-04 D0-fork 取代**(保留作决策演进史);配套人读图 `.html`。owner 边界引 临时-02/架构-02/专题-03/ADR-020,不重定义。
+- [临时-04-market-KB物化-D0fork执行plan](临时-04-market-KB物化-D0fork执行plan.md)(执行版)——**supersede 临时-03**。D1 澄清坐实真越权 =「安装者读到**发布者私有**内容」(market 对 knowledge/ragflow 零依赖→上架不 fork→安装者共享发布者活 dataset→上架后 KB 仍可加私有文档),用户拍板 **D0-fork**:知识库上架时在发布侧 fork 一份**只含公开文档的专用 dataset**(公开副本),安装者只读共享它 → **物理隔离**发布者私有、副本仅 1 份、**无需运行时 chunk 隔离**、`metadata_filter` 字段 bug 降级潜伏。拆成 U-fork(发布侧 fork 公开副本,全新核心工程:建副本 dataset+逐文档复制+重索引+异步重活)/ U-materialize(安装侧物化去隔离)/ U-retrieve(检索打通)/ U-verify(含发布者私有不泄露验证,复用临时-03 U0 反向基线)四单元;含 **fork 时机推荐(上架时 fork)+ 接线推荐(事件驱动,打破 market→knowledge 零依赖,契合 ADR-017)+ DDL 判定(初版不需新迁移)**。待人类拍 fork 时机/接线/副本更新等决策点后执行;配套人读图 `.html`。owner 边界引 临时-02/03/架构-02/专题-03/ADR-017/020,不重定义。
## 输入 / 输出闭环(你写的东西要能被别人用)
diff --git a/design-docs/临时-03-market-install-KB物化执行plan.md b/design-docs/临时-03-market-install-KB物化执行plan.md
index de7c0870..52544799 100644
--- a/design-docs/临时-03-market-install-KB物化执行plan.md
+++ b/design-docs/临时-03-market-install-KB物化执行plan.md
@@ -1,5 +1,7 @@
# 临时-03 · Market Install KB 下游物化执行 Plan(HOW,供 review 后执行)
+> ⚠️ **已被 [`临时-04-market-KB物化-D0fork执行plan.md`](临时-04-market-KB物化-D0fork执行plan.md) supersede(2026-06-26)**:D1 澄清坐实真越权是「安装者读到**发布者私有**内容」(非本稿假设的安装者间互读),用户拍板改走 **D0-fork(发布侧 fork 纯公开副本、物理隔离)**,去掉本稿 S 分支的运行时 chunk 隔离、`metadata_filter`→`metadata_condition` 字段修复降级为潜伏 bug。**本稿保留作决策演进史**,新执行依据以临时-04 为准;本稿的 U0 spike 证据与四条硬事实仍有效(被临时-04 继承)。
+
- 版本:v1(执行版,待人类 review/拍板后执行;本稿只读出文档,不改任何代码)
- 更新日期:2026-06-26
- 目标读者:后端 / 架构 / PR reviewer
diff --git a/design-docs/临时-04-market-KB物化-D0fork执行plan.html b/design-docs/临时-04-market-KB物化-D0fork执行plan.html
new file mode 100644
index 00000000..6cc84f6d
--- /dev/null
+++ b/design-docs/临时-04-market-KB物化-D0fork执行plan.html
@@ -0,0 +1,291 @@
+
+
+
+
+
临时-04 · Market KB 物化 D0-fork 执行 Plan
+
发布侧 fork 纯公开副本 · v1(执行版,待人类 review 后执行,本稿只读出文档)· 2026-06-26
+
配套正文:临时-04-market-KB物化-D0fork执行plan.md | 上一版 临时-03(共享+运行时隔离)已被本稿 supersede
+
+
+ 一句话:知识库上架时,在发布侧 fork 一份只含公开文档的专用 dataset("公开副本"),所有安装者只读共享这一份。
+ 从物理上把发布者私有内容隔在副本之外,从根消除"安装者读到发布者私有内容"的越权——
+ 不需要运行时 chunk 隔离、不依赖那个 metadata_filter 字段 bug。代价是新增一块发布侧 fork 工程(建副本+复制文档+重索引,异步重活)+ 打破 market→knowledge 零依赖接线。
+
+
+
+
越权解法:从"私有泄露"到"物理不可见"
+
+
+
+
✗ 现状 / 共享活 dataset(会越权)
+
+ - market 对 knowledge/ragflow 零依赖:上架审核只翻 market 自有资产状态,从不 fork 任何 dataset
+ - 安装者绑定后指向发布者那一份活 dataset
+ - 发布者上架后仍可继续加私有文档(whole-KB 上架、KB 不冻结)
+ - 检索链对返回 chunk 无任何二次过滤:dataset 进检索即整库返回 → 安装者读到上架时不存在、发布者事后才加的私有内容
+ - 租户拦截器拦不住:两边 binding 指向同一个 RAGFlow dataset_id
+
+
+
+
✓ D0-fork(物理隔离)
+
+ - 上架时 fork 出只含上架时刻公开快照的副本 dataset
+ - 安装者只读副本,发布者私有/上架后新增文档物理不在副本内
+ - "整库返回"在这里是安全的——整库 = 纯公开
+ - 无需运行时 chunk 隔离、无需 metadata 过滤
+ - 副本仅 1 份,N 个安装者共享只读
+
+
+
+
+ 与临时-03 的差异:临时-03 把越权理解为"安装者之间互读(多租户共享 dataset)",方向是"共享前补 chunk 级隔离";
+ D1 澄清坐实真越权是安装者读到发布者私有内容,故改走物理隔离(fork 公开副本)。
+ 临时-03 的 U0 spike 证据("整库无 chunk 过滤")仍有效,本稿转作 U-verify 的反向基线(证"私有不泄露")。
+
+
+
+
+
物理隔离:发布侧 vs 安装侧
+
+
+
+
发布者域(owner = 发布者)
+
+
发布者活 dataset kb-{发布者kbId}-v{ver}
+
含公开文档 + 上架后新增的私有文档(持续变化)
+
+
+
⭐ 公开副本 dataset fork-asset-{assetId}-public
+
只含上架时刻的公开快照文档(fork 后不随活 dataset 变)
+
+
↑ U-fork:上架时逐文档复制内容 + 重索引(异步重活)
+
+
+
+
+
+
安装者域(owner = 各安装者)
+
+
installed_ref kb 行(每安装者一行)
+
kb_type=installed_ref · source_market_asset_id=assetId · license_snapshot_id=授权快照
+
+
+
ragflow_binding(去污染后)
+
kb_id=本地 installed_ref 主键(不再是 assetId)· ragflow_dataset_id=公开副本
+
+
+
检索 selectActiveDatasetByKbId → 公开副本
+
RAGFlow 整库返回 = 🟢 纯公开,发布者私有物理不可见
+
+
+
+
+ 越权根除点:安装者 binding 指向的 dataset_id 是公开副本而非发布者活 dataset。
+ 即使检索链"整库返回 + 无二次过滤"的事实不变,整库里也只有上架时刻的公开内容——发布者私有从源头不在这份 dataset 里。
+
+
+
+
+
四个实现单元(各一句话)
+
+
+
+
U-fork 全新·最重
+
上架事件触发 knowledge 异步 fork:建副本 dataset + 逐文档复制 + 重索引 + 幂等/重试/部分成功;whole-KB 公开集 = 上架时刻全部可检索文档。
+
+
→
+
+
U-materialize
+
绑定路径建 installed_ref kb 行 + binding 指向公开副本;kb_id 去污染(assetId→本地主键)+ 新 MarketAssetSourceApi 跨 BC 读带回副本 dataset + forkStatus + 幂等。
+
+
→
+
+
U-retrieve
+
物化后第四门返非空→命中;无运行时隔离(副本纯公开);授权快照沿用 ADR-020 VARCHAR。代码几乎不改。
+
+
→
+
+
U-verify
+
真 PG IT(fork→安装→检索命中)+ studio e2e + 发布者私有不泄露(复用 U0 反向基线)+ 召回/下架回滚。
+
+
+
+ 相对临时-03:U-materialize/U-retrieve = 原 U2/U3 简化去隔离;U-fork 是全新核心工程;U0 spike 的 2 个 case 复用 作 U-verify 反向基线,不重写。
+
+
+
+
+
fork 时序(上架触发 + 事件驱动 + 异步,含失败/重试/幂等)
+
+
1
管理员审核
approvePublishRequest(含 markListed)
+
2
market 审核服务
资产/版本 listed(market 自有事实,同事务)
+
3
market 审核服务
落上架事件 listed{assetId, 发布者kbId, version}(同事务) · 不等 fork,审核到此提交,不被 fork 成败绑架
+
4
knowledge 消费者
异步消费上架事件 → forkPublicSnapshot(assetId, 发布者kbId, version)
+
5
knowledge fork
幂等检查(该 assetId+version 已 fork?命中跳过)→ createDataset(副本)
+
6
knowledge fork
对每个上架时刻公开文档:uploadDocuments(副本) + startParseDocuments(副本重索引)
+
7
knowledge fork
全成功 → forkStatus=ready + 记副本 datasetId(供 MarketAssetSourceApi 带回)
部分失败/502 → forkStatus=partial/failed + 标可重试(不删已建部分、不重复传已成功文档)
+
无现成 RAGFlow "copy dataset" API → fork 必须重走 createDataset + 逐文档 upload + startParse(重索引)。这是异步长任务重活,是 D0-fork 相对临时-03 最大的新增成本。
+
+
+
+
关键决策点(待人类拍板)
+
+
+ | 决策 | 选项 | 倾向 + 理由 |
+
+
+ | fork 时机 |
+ 上架 markListed 时 fork / 首次安装懒 fork |
+ 上架时 fork:版本快照语义干净(副本=上架那刻公开集)+ 安装侧轻(无异步等待)+ 浪费可控;懒 fork 破坏快照语义 + 首装延迟 + 并发抢锁。 |
+
+
+ 接线 (打破零依赖) |
+ 事件驱动 / market 调 knowledge facade 同步 |
+ 事件驱动:审核不被 fork 成败绑架 + 契合 ADR-017 + 保 BC 边界(market 不反向依赖 knowledge);facade 同步会让审核挂在 RAGFlow 多次调用上、失败回滚审核。 |
+
+
+ | 副本更新 |
+ 重新上架才更新 / 不更新 / 实时跟随 |
+ 重新上架才更新:与"市场资产=发布快照"模型一致;实时跟随会重新引入私有泄露。 |
+
+
+ fork 未就绪 时安装 |
+ 绑定阶段拒(fail-closed)/ 绑定但检索 no_dataset |
+ 绑定阶段拒:避免"绑了用不了"迷惑态;实现时定夺回填。 |
+
+
+ 召回/下架 回滚 |
+ 复用现有传播 / 本期标开放项手动停用 |
+ 现状 market→目标 owner 传播是 fail-closed blocked 记录式(TARGET_OWNER_UNAVAILABLE),knowledge 无消费入口 → 倾向本期标开放项,不假装闭环。 |
+
+
+ DDL / 副本存放 |
+ 复用 JSONB 不加列 / 新增列或表(V32) |
+ 复用现有结构 + JSONB 承载 fork 状态/副本映射 → 不需要新迁移;仅评审坚持强类型列时才走 V32(_test 库铁律)。 |
+
+
+
+
+
+
+
风险与边界(诚实呈现)
+
+
+
主要风险
+
+ - R1 私有泄露:fork 公开集界定错 / 副本"实时跟随"→私有重新泄露。缓解:严格按上架时刻 active 文档 + U-verify 真验私有不泄露。
+ - R2 fork 异步重活复杂度(不掩盖):建 dataset+N 文档逐个 upload+重索引,失败/重试/幂等/部分成功——比临时-03"共享+运行时隔离"重。诚实:安全模型更干净(物理隔离),但发布侧工程更重。
+ - R3 打破 market→knowledge 零依赖:影响面集中在"上架落事件"+knowledge fork 消费链,不改 market 审核主体;需架构 review(ADR-017 为据)。
+ - R6 metadata_filter 字段 bug 潜伏·留待修:发的 metadata_filter 被 RAGFlow 静默忽略(应为 metadata_condition)。D0-fork 不依赖它,降级潜伏 bug 单记。
+
+
+
+
本期不做(Scope)
+
+ - agent 物化(下一阶段,不碰 ai 模块)
+ - install 侧物化(维持只记账 targetFactsWritten=false)
+ - 运行时 chunk 隔离(D0-fork 用物理隔离替代)
+ - metadata_filter 字段 bug 修复(潜伏单记)
+ - 副本资源回收(下架/无安装清理副本,开放)
+ - 召回/下架回滚自动化(开放项,不假装闭环)
+ - market 两列 BIGINT 契约议题
+
+
DDL 判定:初版不需要新 Flyway 迁移(installed_ref 落 V5/V14 已有列 + fork 状态走 JSONB);仅评审坚持强类型列才走 V32。
+
+
+
+
+
+
+
diff --git a/design-docs/临时-04-market-KB物化-D0fork执行plan.md b/design-docs/临时-04-market-KB物化-D0fork执行plan.md
new file mode 100644
index 00000000..5b1404b2
--- /dev/null
+++ b/design-docs/临时-04-market-KB物化-D0fork执行plan.md
@@ -0,0 +1,397 @@
+# 临时-04 · Market KB 物化 D0-fork(发布侧 fork 纯公开副本)执行 Plan
+
+- 版本:v1(执行版,待人类 review/拍板后执行;本稿只读出文档,不改任何代码)
+- 更新日期:2026-06-26
+- 目标读者:后端 / 架构 / PR reviewer
+- 阅读时间:30–40 分钟
+- 文档性质:**临时件**(执行依据,落定后归并入正式分册或删除,不作长期 SSOT)。本稿只给"怎么做",不重定义概念:方案演进与 C/B'/暂缓权衡见 [`临时-02-market-install下游物化方案.md`](临时-02-market-install下游物化方案.md);上一版(共享发布者活 dataset + 运行时 chunk 隔离)见 [`临时-03-market-install-KB物化执行plan.md`](临时-03-market-install-KB物化执行plan.md)(**已被本稿 supersede**,保留作决策演进史);术语与 owner 边界以 [`架构-02-核心数据结构与双轨模型.md`](架构-02-核心数据结构与双轨模型.md) 为准(§6 市场资产、§11.2 绑定安装授权、授权快照"引用对象必须保存快照 id");表结构归 `后端-04`;检索合同归 [`专题-03`](专题-03-AI编排上下文与质量评测实现规范.md) §5;授权快照字符串承载归 ADR-020;Source 传播事件驱动归 ADR-017;BC 边界规则归 [`.agents/rules/bc-boundaries.md`](../.agents/rules/bc-boundaries.md)。
+- 配套人读图:[`临时-04-market-KB物化-D0fork执行plan.html`](临时-04-market-KB物化-D0fork执行plan.html)
+
+> **一句话**:拍板已定——做 **D0-fork**:知识库上架时,在**发布侧** fork 出一份**只含公开文档的专用 dataset**("公开副本"),所有安装者只读共享这一份副本。这从物理上把发布者的私有内容隔在副本之外,从根上消除"安装者读到发布者私有内容"的越权,**不需要运行时 chunk 隔离、不依赖那个 `metadata_filter` 字段 bug**。代价是新增一块发布侧的 fork 工程(建副本 dataset + 逐文档复制 + 重索引,异步重活),并要打破"market 对 knowledge 零依赖"的现状接线。本 plan 把 D0-fork 拆成 **U-fork / U-materialize / U-retrieve / U-verify 四个可独立验证的实现单元**。
+>
+> **越权真因(D1 澄清坐实,区别于临时-03 的假设)**:临时-03 当时把越权理解为"多租户共享同一 dataset → 安装者**之间**互读",方向定在"共享前补 chunk 级隔离"。D1 澄清重新坐实了更要命的一条:真越权是**安装者读到发布者的私有内容**。链条是——market 对 knowledge/ragflow **零依赖**(上架审核 `markListed` 只翻 market 自有资产状态,从不 fork 任何 dataset)→ 安装者绑定后若走"共享"必然指向**发布者那一份活 dataset**→ 而发布者**上架后仍可往自己 KB 继续加私有文档**(whole-KB 上架、KB 生命周期不冻结)→ 安装者检索这份活 dataset 就会读到上架时根本不存在、发布者事后才加的私有内容。**这不是租户拦截器能拦的**(两边 binding 指向同一个 RAGFlow dataset_id,检索链对返回 chunk 无任何二次过滤,见 §1 事实 1)。D0-fork 用"复制一份只含公开快照的独立 dataset"把这条链从物理上斩断。
+
+---
+
+## 0. 与临时-03 的差异(读过临时-03 的人只需看这一节就能对齐)
+
+| 维度 | 临时-03(共享发布者活 dataset,superseded) | 临时-04(D0-fork,本稿) |
+|---|---|---|
+| 越权模型 | 安装者**之间**越权(多租户共享 dataset) | 安装者读到**发布者私有**内容(上架后新增/未公开文档) |
+| 隔离手段 | 运行时 chunk 隔离(`metadata_filter`/`document_ids` 把 chunk 限到本授权子集) | **物理隔离**:fork 一份只含公开文档的专用 dataset,安装者只读它 |
+| 检索时 dataset | 发布者活 dataset(共享) | **公开副本 dataset**(与发布者活 dataset 物理分离) |
+| `metadata_filter` 字段 bug | U3 隔离前置必须先修(`metadata_filter`→`metadata_condition`) | **降级为潜伏 bug**:不在 D0-fork 关键路径(公开副本纯公开、检索不靠它过滤);单独记、留待修 |
+| 核心新增工程 | chunk 级隔离 + 物化时给文档打安装维度元数据 | **发布侧 fork 公开副本**(建 dataset + 复制文档 + 重索引,异步重活)+ 打破 market→knowledge 零依赖接线 |
+| 复制方向 | 否决了"每安装者各复制一份"(C 分支) | fork **一份**公开副本、N 个安装者共享只读(副本仅 1 份,非每安装者一份) |
+
+**临时-03 哪些资产被本稿继承**:
+- **U0 spike 的 2 个 spike case 保留**:机制事实"检索链对返回 chunk 无 chunk 级过滤"(混入他源 magic chunk 原样返回 + `RetrieveChunksCommand` 的 `documentIds`/`metadataFilter` 均 null = 整库扫描)仍然成立、仍是 D0-fork 必须斩断越权的根因证据;它在本稿转作 **U-verify 的反向基线**——用来证明"发布者私有不泄露"(fork 后安装者检索副本,混入副本之外的发布者私有 magic chunk 应**检索不到**)。spike 测试已落 `MuseKnowledgeRetrievalApiImplTest`(+69 行,零业务代码),不必重写。
+- **临时-03 的四条硬事实**(kb_id 被 assetId 污染、跨 BC 反查链断需新 `MarketAssetSourceApi`、`muse_source_propagation_target` 表不存在、检索链无 chunk 二次过滤)**全部仍然有效**,是本稿 U-materialize/U-retrieve 的地基,§1 复述。
+
+---
+
+## 1. 执行前必读:把工作量钉死的硬事实(基于真实代码,行号为只读核验所得)
+
+**事实 1 — 检索链对返回 chunk 无任何二次过滤,"谁能进检索、就看到该 dataset 整库"。这是 D0-fork 必须做物理隔离、而非运行时隔离的根因。**
+RAGFlow 检索 HTTP body(`HttpRagFlowKnowledgeRuntimeClient.retrieveChunks:144-157`)只发 `dataset_ids + question + top_k + similarity_threshold + metadata_filter`,`tenantId/ownerUserId/kbId` **不进 RAGFlow**。检索链 `MuseKnowledgeRetrievalApiImpl.retrieveForWork`:双门 + `selectActiveDatasetByKbId` 只控制"能否拿到这个 dataset_id",一旦 dataset_id 进入检索,`document_ids` 传 null(`:149` 第五个参数 null)→ **整库返回**;`parseChunks:171-198` 回来只按 dataset_id 贴归因元数据,**对 chunk 无任何按授权子集的二次过滤**。**结论**:只要安装者 binding 指向发布者活 dataset,就能读到该 dataset 里发布者后加的私有 chunk。D0-fork 让安装者 binding 指向的是**只含公开快照的副本 dataset**,从源头让"整库返回"返回的也只有公开内容。
+
+**事实 2 — 那个 `metadata_filter` 字段在 RAGFlow 侧被静默忽略(潜伏 bug,D0-fork 下不在关键路径)。**
+检索发 `body.put("metadata_filter", ...)`(`HttpRagFlowKnowledgeRuntimeClient.retrieveChunks:155`),但 RAGFlow `/api/v1/retrieval` 官方契约字段是 `metadata_condition`(context7 `/infiniflow/ragflow` 核对 + 临时-03 活体对照:乱值条件仍返 baseline),故当前 `metadata_filter` 被 RAGFlow 静默忽略、根本不过滤。**结论**:临时-03 的共享分支要靠它做隔离,所以必须先修;**D0-fork 不靠它**(公开副本纯公开,检索不需要再按维度过滤),故此 bug 在本期**降级为潜伏 bug**——`§7 风险 R6` 单独记、留待后续修,不进 D0-fork 关键路径。
+
+**事实 3 — `kb_id` 字段当前被污染:存的是 market assetId,不是真实 `muse_knowledge_base.id`。**
+`MuseKnowledgeBindingService.createKnowledgeBindingPrecheck:110` `precheck.setKbId(parseLong(reqVO.getSourceId()))`,studio 传入的 `sourceId` 实为 market **assetId**;`createKnowledgeBinding:148` `binding.setKbId(precheck.getKbId())` 原样进 `muse_knowledge_binding.kb_id`。**结论**:物化要把 `kb_id` 从 assetId 改写成新建本地 installed_ref kb 行的真实主键,并保证检索/读回端口跟着改对。这是 U-materialize 的核心难点。
+
+**事实 4 — `assetId → 发布者 kbId` 反查链数据上通、跨 BC 上断;market 对外 API 包当前只有 `MarketHandoffTokenApi`。**
+`muse_market_asset.source_id`(`V6:10` BIGINT)在审核物化资产时写入发布者本地 kbId(`AdminMarketReviewServiceImpl.resolveApprovedAssetBinding:454` `asset.setSourceId(longValue(draftSnapshot.get("sourceId")))`)。但 knowledge 不能直读 market 的 `.dal`(ArchUnit `BcBoundaryArchTest`),market `api` 包下**目前只有 `MarketHandoffTokenApi`(verify/consume)**,没有"按 assetId 查源对象/查公开副本 dataset"的读接口。**结论**:D0-fork 下安装侧物化要拿到"公开副本 dataset id",必须**新增跨 BC 读端口**(`MarketAssetSourceApi.getAssetSource(assetId) → {sourceType, sourceId=发布者kbId, publisherUserId, publicForkDatasetId, forkStatus}`,本地进程内 Bean,与 `MarketHandoffTokenApi` 同范式、不加 Feign)。**注意 handoff token 不带这个信息**:token snapshot(`MarketHandoffServiceImpl.handoffSnapshot:450`)只含 assetId/authorizationSnapshotId/targetWorkId/targetPage,没有发布者 kbId/dataset,故拿不到副本 dataset,必须走这个新读端口。
+
+**事实 5 — 发布快照 `muse_knowledge_publish_snapshot` 不含文档子集,印证"上架时刻 KB 全部文档 = 公开集"。**
+`MuseKnowledgePublishService.createKBPublishSnapshot:140-159` 写入的快照只有 `sourceSnapshotId`/`authorizationSnapshotId`/`packageHash` 等字符串,**没有"哪些文档算公开"的文档清单**(DO `MuseKnowledgePublishSnapshotDO` 也无文档子集字段)。**结论**:因为 draft/上架没有"公开文档子集"概念,**whole-KB 上架时刻 KB 的全部文档即公开集**(U-fork §3.3 据此界定)。这也意味着 fork 的"公开快照"= 上架审核那一刻 KB 的全部文档版本,发布者**上架后新增的文档不属于这个快照、不进副本**——这正是隔离发布者私有的语义支点。
+
+**事实 6 — dataset 与文档复制无现成 RAGFlow "copy" API;fork 必须重走 createDataset + 逐文档 upload + startParse(重索引)。**
+`RagFlowKnowledgeRuntimeClient` 接口(11 个操作)有 `createDataset`/`uploadDocuments`/`startParseDocuments`,**没有 copyDataset/copyDocument**。现有上传链路 `MuseKnowledgeDocumentService.continueRagflowIfMaterialized:248-298` 的形态是:`ensureDatasetBinding`(懒建 dataset)→ `uploadDocuments`(带 `fileRef`/`content` byte[])→ `startParseDocuments`(触发解析/索引)。**结论**:fork 一份副本 = 新建一个副本 dataset(`createDataset`)+ 把发布者每个公开文档的物化文件(`muse_knowledge_document_version.storageRef` + 物化内容)逐个 `uploadDocuments` 到副本 + 逐个 `startParseDocuments` 重索引。这是 **异步长任务重活**(多次外部调用、可能失败/部分成功),是 D0-fork 相对临时-03 最大的新增成本,U-fork §3.5 据此设计。
+
+**事实 7 — market 召回/下架对目标 owner 的传播当前是 fail-closed blocked 记录式,knowledge 侧无消费入口。**
+`AdminMarketGovernanceServiceImpl.writeSourceStatusBlocked:361` 把召回/下架的目标 owner 传播落成 `propagationStatus=blocked / reason=target_owner_unavailable / errorCode=TARGET_OWNER_UNAVAILABLE`,注释自证"Market Task 9 未接入目标 owner 传播"。**结论**:召回/下架回滚到 knowledge installed_ref + 副本 dataset 的自动化,本期是**开放项**(U-verify §回滚 + 决策点 D5 如实标,不假装已闭环;也不引用临时-03 已证伪的 `muse_source_propagation_target` 表)。
+
+**事实 8 — installed_ref 落点的列与唯一键已就绪,B' 共享/D0-fork 初版均不需要新 DDL(除可选 fork 状态列,见 §6)。**
+`muse_knowledge_base`(`V5:4-28`)已备 `kb_type`/`source_market_asset_id`(BIGINT)/`license_snapshot_id`(BIGINT);`muse_knowledge_ragflow_binding`(`V14`)唯一键 `uk_..._active = (tenant_id, kb_id) WHERE status='active' AND document_id IS NULL AND deleted=FALSE`——副本 dataset binding 挂在**新建本地 installed_ref kbId** 上不撞发布者 kb 的键。**结论**:安装侧物化(U-materialize)落在 V5/V14 已有列,**不需要新迁移**;唯一可能需要 DDL 的是发布侧"副本 dataset id + fork 状态"的存放(§6 给两种落点,倾向复用 JSONB 不加列 → 仍不需要迁移)。
+
+> 这八条把 D0-fork 的真实成本钉死:**核心增量 = 发布侧 fork 公开副本(事实 5/6,异步重活,全新)+ 打破 market→knowledge 零依赖接线(事实 4/7)+ kb_id 去污染 + 新跨 BC 读端口(事实 3/4)**;运行时隔离与 `metadata_filter` 修复(临时-03 的核心增量)在 D0-fork 下**不需要**。
+
+---
+
+## 2. 总览:实现单元、数据流与 fork 时序
+
+### 2.1 实现单元依赖图
+
+```mermaid
+flowchart TD
+ UFORK["U-fork(发布侧 fork 公开副本,核心新工程)