承临时-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>
122 lines
11 KiB
HTML
122 lines
11 KiB
HTML
<!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">spike:chunk 级隔离硬前置门</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_id,V5 已备列复用)+ 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>——只做知识库物化,agent(muse_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>
|