oh-my-muse/design-docs/临时-03-market-install-KB物化执行plan.html
lili 76a7e0d312 docs(market): KB 物化执行版 plan(临时-03、待 D1 拍板后执行)
承临时-02 拍板(B' installed_ref + KB 先行)出 KB 物化执行版 plan,拆 U0-U4 可独立验证实现单元。出 plan 时一手代码核验揪出四条改变工作量/性质的硬事实(均 spot-check 坐实):①kb_id 当前被 market assetId 污染(KnowledgeHandoffLanding sourceId=assetId)→物化须去污染改写;②assetId→发布者 dataset 反查链跨 BC 断(market.api 仅 HandoffTokenApi)→需新增 MarketAssetSourceApi 本地读端口;③多租户共享同一 RAGFlow dataset 必越权(retrieveChunks body 不含 tenant+document_ids=null 全量返回、parseChunks 无 chunk 租户二次过滤)=安全红线→U0 从"验证能否共享"转为"共享前先补 chunk 级隔离"硬门;④muse_source_propagation_target 表零命中→U4 回滚改基于真实 source_event 机制。

物化落点严格在 knowledge 绑定路径(非 install、handoff 非物化桥、安装解耦不动)。初版判定不需新 Flyway 迁移(V5/V14 已备列)。决策点 D1(共享 S/复制 C/暂缓 H)待人类先看 U0 spike 证据再拍。两图文(text+mermaid + html 人读图)+大纲注册。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:33:41 -07:00

122 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>临时-03 · Market Install KB 下游物化执行 Plan</title>
<style>
:root{--bg:#0d1117;--card:#161b22;--ink:#e6edf3;--mut:#8b949e;--red:#f85149;--grn:#3fb950;--yel:#d29922;--blu:#58a6ff;--pur:#bc8cff;--bd:#30363d}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--ink);font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;padding:48px 24px;max-width:1080px;margin:0 auto}
h1{font-size:27px;margin-bottom:8px;letter-spacing:.3px}
.meta{color:var(--mut);font-size:13px;margin-bottom:24px}
.lead{background:linear-gradient(135deg,#1c2230,#161b22);border-left:4px solid var(--yel);padding:18px 22px;border-radius:10px;margin-bottom:32px}
.lead b{color:var(--yel)}
h2{font-size:18px;margin:36px 0 16px;color:var(--blu);display:flex;align-items:center;gap:10px}
h2::before{content:"";width:4px;height:18px;background:var(--blu);border-radius:2px}
.facts{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:720px){.facts{grid-template-columns:1fr}}
.fact{background:var(--card);border-radius:12px;padding:16px 18px;border:1px solid var(--bd)}
.fact.danger{border-color:var(--red);background:linear-gradient(135deg,#2a1518,#161b22)}
.fact .t{font-weight:600;margin-bottom:8px;display:flex;align-items:center;gap:10px;font-size:15px}
.fact .n{width:26px;height:26px;line-height:26px;text-align:center;border-radius:7px;background:var(--bd);font-size:13px;font-weight:700;flex-shrink:0}
.fact.danger .n{background:var(--red);color:#000}
.fact .d{color:var(--mut);font-size:13.5px}
.fact code{background:#0d1117;padding:1px 6px;border-radius:4px;font-size:12px;color:var(--pur)}
.tag{display:inline-block;font-size:11px;padding:2px 9px;border-radius:5px;font-weight:700}
.tag.sec{background:var(--red);color:#000}
.gate{background:var(--card);border:1px solid var(--bd);border-radius:12px;padding:20px}
.gate .q{text-align:center;background:linear-gradient(135deg,#2a1518,#1a1f27);border:2px solid var(--red);border-radius:10px;padding:14px;font-weight:600;margin-bottom:18px}
.gate .q span{font-size:13px;color:var(--mut);font-weight:400}
.branches{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
@media(max-width:720px){.branches{grid-template-columns:1fr}}
.br{border-radius:10px;padding:14px;font-size:13.5px}
.br.s{background:#2a2410;border:1px solid var(--yel)}
.br.c{background:#11261a;border:1px solid var(--grn)}
.br.h{background:#16202e;border:1px solid var(--blu)}
.br .bt{font-weight:700;margin-bottom:6px}
.br.s .bt{color:var(--yel)}.br.c .bt{color:var(--grn)}.br.h .bt{color:var(--blu)}
.br .bd2{color:var(--mut);font-size:12.5px}
.flow{display:flex;flex-direction:column;gap:8px}
.step{background:var(--card);border:1px solid var(--bd);border-radius:10px;padding:14px 18px;display:flex;gap:14px;align-items:flex-start}
.step .u{font-weight:700;color:var(--blu);flex-shrink:0;width:38px;font-size:16px}
.step .sc{flex:1}
.step .st{font-weight:600;margin-bottom:3px}
.step .sd{color:var(--mut);font-size:13px}
.step.u0{border-color:var(--red)}
.step.u0 .u{color:var(--red)}
.arrow{text-align:center;color:var(--bd);font-size:14px;line-height:.4}
table{width:100%;border-collapse:collapse;font-size:13.5px;background:var(--card);border-radius:10px;overflow:hidden}
th,td{padding:10px 14px;text-align:left;border-bottom:1px solid var(--bd);vertical-align:top}
th{background:#1c2230;color:var(--blu);font-size:13px}
td .dk{font-weight:700}
.lean{color:var(--grn);font-weight:600}
.scope{display:grid;gap:8px}
.sc-item{background:var(--card);border:1px solid var(--bd);border-left:3px solid var(--mut);border-radius:8px;padding:10px 14px;font-size:13.5px}
.sc-item b{color:var(--ink)}
.foot{margin-top:40px;padding-top:16px;border-top:1px solid var(--bd);color:var(--mut);font-size:12.5px}
.foot code{color:var(--pur)}
</style>
</head>
<body>
<h1>临时-03 · Market Install KB 下游物化执行 Plan</h1>
<div class="meta">执行版 v1 · 2026-06-26 · 后端/架构/PR reviewer · 承临时-02 拍板B' installed_ref + KB 先行)· 待人类拍 D1 后执行</div>
<div class="lead">
拍板已定——做 <b>B'installed_ref 最小留痕)+ KB 先行</b>。本 plan 把它拆成 <b>U0…U4 五个可独立验证单元</b>,物化落点在<b>知识库绑定路径</b>(非 install。但一手代码核验坐实一个比评审版更硬的事实<b>按当前代码,多租户"共享发布者同一 RAGFlow dataset"必然越权</b>。所以 U0 不是"验证隔得住吗",而是<b>"共享落地前先把 chunk 级隔离补上"</b>的真前置硬门。
</div>
<h2>执行前四条硬事实(一手代码核验,非推断)</h2>
<div class="facts">
<div class="fact"><div class="t"><span class="n">1</span>kb_id 当前被污染</div><div class="d">绑定存的 <code>kb_id</code> 是 market <b>assetId</b><code>sourceId: assetId</code>),不是真实 <code>muse_knowledge_base.id</code>。物化要把 kb_id <b>去污染改写</b>成新建 installed_ref 主键,并改对所有读回端口。</div></div>
<div class="fact"><div class="t"><span class="n">2</span>跨 BC 反查链断</div><div class="d"><code>assetId→发布者 kbId→dataset</code> 数据通、跨 BC 断market.api 只有 HandoffToken、无按 assetId 查源接口)。需新增 <b>MarketAssetSourceApi</b> 本地读端口。</div></div>
<div class="fact danger"><div class="t"><span class="n">3</span>共享必越权 <span class="tag sec">安全红线</span></div><div class="d">RAGFlow 检索 body <b>不含 tenant</b>、document_ids=null 时 dataset <b>全量返回</b><code>parseChunks</code> 对返回 chunk <b>无租户二次过滤</b>。两租户 binding 指同一 dataset → A 读到 B 全部 chunk。<b>U0 转为"共享前先补 chunk 级隔离"硬门。</b></div></div>
<div class="fact"><div class="t"><span class="n">4</span>回滚表不存在</div><div class="d"><code>muse_source_propagation_target</code> 全仓零命中。U4 回滚必须基于真实机制(<code>muse_knowledge_source_event</code> + projection不得引用它。</div></div>
</div>
<h2>U0 决策门dataset 隔离硬前置D1</h2>
<div class="gate">
<div class="q">⚠ U0 spike共享发布者同一 RAGFlow dataset 能否做到租户隔离?<br><span>(已知当前必越权 → 真问题是"补隔离手段能否落地"</span></div>
<div class="branches">
<div class="br s"><div class="bt">分支 S · 补隔离后共享</div><div class="bd2">metadata_filter / document_ids 把 chunk 限到本安装授权子集,验证生效 → 共享发布者 dataset存储不放大<b>需先投入隔离工程</b></div></div>
<div class="br c"><div class="bt">分支 C · 每安装者复制</div><div class="bd2">独立复制 dataset隔离天然干净。但文档复制+重解析是异步重活另起子任务。U0 红时兜底。</div></div>
<div class="br h"><div class="bt">分支 H · 暂缓</div><div class="bd2">只做诚实标注"市场资产暂未开放直接用",消除静默 no_dataset 骗用户。成本最低。</div></div>
</div>
</div>
<h2>实现单元 U0 → U4</h2>
<div class="flow">
<div class="step u0"><div class="u">U0</div><div class="sc"><div class="st">spikechunk 级隔离硬前置门</div><div class="sd">单测层证伪租户过滤 + 活体层证 RAGFlow 整库返回 + 验证补隔离手段metadata_filter/document_ids→ 输出 S/C/H 三选一给人类拍。不产业务代码。</div></div></div>
<div class="arrow">▾▾▾</div>
<div class="step"><div class="u">U1</div><div class="sc"><div class="st">数据模型 + 迁移判定</div><div class="sd">installed_ref kb 行字段映射kb_type/source_market_asset_id/license_snapshot_idV5 已备列复用)+ dataset 关联策略。<b>初版判定:不需新 Flyway 迁移</b></div></div></div>
<div class="arrow">▾▾▾</div>
<div class="step"><div class="u">U2</div><div class="sc"><div class="st">物化落点:绑定路径建实体</div><div class="sd">在 knowledge 绑定路径(非 install建本地 kb 行 + dataset 关联kb_id 去污染 + 新增 MarketAssetSourceApi 跨 BC 读 + 幂等 + kbId 存在性校验。<b>核心工程量在此</b></div></div></div>
<div class="arrow">▾▾▾</div>
<div class="step"><div class="u">U3</div><div class="sc"><div class="st">检索打通:消除 no_dataset</div><div class="sd">U2 数据正确后第四门自然返非空→命中(共享分支 RetrievalApiImpl 多半无需改)。授权快照沿用 ADR-020 VARCHAR不回退 parseLong。</div></div></div>
<div class="arrow">▾▾▾</div>
<div class="step"><div class="u">U4</div><div class="sc"><div class="st">验证:真 PG IT + e2e + 回滚 + 隔离回归</div><div class="sd">真 PG+真 RAGFlow 端到端命中 + studio e2e + 幂等 + 跨租户隔离回归(承 U0+ 召回/下架回滚(基于真实 source event 机制)。</div></div></div>
</div>
<h2>决策点(待人类拍板)</h2>
<table>
<tr><th>#</th><th>决策</th><th>选项</th><th>倾向</th></tr>
<tr><td><span class="dk">D1</span></td><td>dataset 共享 vs 复制最硬·U0 门)</td><td>S 补隔离后共享 / C 每安装者复制 / H 暂缓</td><td>先看 U0 证据再拍</td></tr>
<tr><td><span class="dk">D2</span></td><td>物化时机</td><td>绑定同步 / 惰性首用</td><td class="lean">绑定同步</td></tr>
<tr><td><span class="dk">D3</span></td><td>license_snapshot_id 承载</td><td>数值主键 / 字符串 envelope(需 V32)</td><td class="lean">数值主键</td></tr>
<tr><td><span class="dk">D4</span></td><td>跨 BC 读发布者 dataset 路径</td><td>API 带回 / knowledge 内部受控查</td><td>U2 实现时定夺</td></tr>
<tr><td><span class="dk">D5</span></td><td>召回/下架回滚自动化</td><td>复用现有传播 / 本期标开放项</td><td>先验现状是否触达</td></tr>
</table>
<h2>Scope 边界(明确不做)</h2>
<div class="scope">
<div class="sc-item"><b>KB 限定</b>——只做知识库物化agentmuse_agent market_installed + runtime 放行)是独立下一阶段,本 plan 不碰 ai 模块。</div>
<div class="sc-item"><b>install 解耦不动</b>——installMarketplaceAsset 维持"只记账",物化落点严格在 knowledge 绑定路径。</div>
<div class="sc-item"><b>handoff 非物化桥</b>——token 只负责跳转+被消费,不负责物化。</div>
<div class="sc-item"><b>复制分支(C)细节不展开</b>——仅作 U0 红兜底标注,异步复制实现另起子任务。</div>
<div class="sc-item"><b>market 两列 BIGINT 议题不纳入</b>——独立契约议题,本 plan 不处理。</div>
</div>
<div class="foot">配套工程/AI 读本:<code>临时-03-market-install-KB物化执行plan.md</code>(含 mermaid 依赖图与实现单元全文)· 方案 WHAT 见临时-02 · 概念边界归 架构-02 / 专题-03 / ADR-020</div>
</body>
</html>