# 架构与数据契约 本文是 `dsh-research-kit` 的架构参考:模块职责、运行时数据流、DSH 宿主边界、目录数据契约与扩展点。需要改动代码或新增资产时以此为准。 文档索引见 [`README.md`](README.md);手工验收方式见 [`MANUAL-QA.md`](MANUAL-QA.md);方法工坊与草稿增强器的嵌入细节见 [`METHOD-WORKSHOP.md`](METHOD-WORKSHOP.md)。 ## 1. 架构决策 ### 1.1 一句话架构 `dsh-research-kit` 是一个 **浏览器侧 DSH 插件**:它维护科研资源目录、把工作流和用户参数组装成可编辑 Prompt,并由 DSH 当前会话负责实际发送与执行。 ```text ┌────────────────────────────────────────────────────────────────────┐ │ DSH 宿主 │ │ conversation.view conversation.input.* inputActions │ │ (视图槽位) (左入口/浮层/右增强) setDraft / submit │ └───────▲───────────────────────────▲───────────────────▲────────────┘ │ │ │ 注册统一视图 注册输入槽位 写入 / 发送最终 Prompt │ │ │ ┌───────┴───────────────────────────┴───────────────────┴────────────┐ │ DSH Research Kit(浏览器侧) │ │ │ │ ResearchConsole(统一容器 + 两级吸顶) │ │ ├─ ①「资源与工作流」 catalog.js ──► catalog/*/index.js │ │ ├─ ②「方法工坊」 vendored 工件 + prompt-studio-glue │ │ ├─ ③「研究资产库」 research-vault.js ◄─► vault-core.js │ │ └─ ④「研究证据图谱」 evidence-store.js ◄─► evidence-graph-core │ │ │ │ 所有分区共享同一出口:setDraft() / submit(),缺失时降级为复制 Prompt │ └───────▲─────────────────────────────────────────────────────────────┘ │ 仅四条受控路由(index.js,Node half) │ /query(公开数据源直查,经 ctx.web.fetch) · /semantic-enhance*(草稿增强) │ /host-capabilities(装配与 MCP 连接事实) · /memory-search(Memory Center 检索) └───────┴──── DSH 受控 web 服务 / 当前会话模型路由 ``` ![全局架构:DSH 工作台将 Prompt 交回宿主执行;同包 MCP Server 提供跨宿主的受控研究工具](assets/architecture.svg) ### 1.2 不引入独立后端的原因 第一期不需要沙箱、数据库代理或任务队列。它们会重复 DSH 已经承担的能力,并带来权限、保密、成本和状态同步问题。 **例外:Node half 只保留四条无法在浏览器侧完成的受控路由**(`index.js`,见 §2.1): 1. `/dsh-research-kit/query` —— 公开数据源直查。浏览器无法直接跨域访问这些 API,且需要进程内缓存与限流;出网一律经 DSH `ctx.web.fetch()`,插件自身不持有凭据。 2. `/dsh-research-kit/semantic-enhance`(含 `/stream`)—— 草稿语义增强。复用当前会话已建立的模型路由(`sessionId → provider/model`),不持有任何 API Key。 3. `/dsh-research-kit/host-capabilities` —— 宿主能力探测(ROADMAP §6)。从工具注册表解析 `mcp____` 得到「已连接 MCP 服务器」事实,并报告 Web/Shell/文件系统/模型路由装配事实;只读、无副作用、不改写目录标注。 4. `/dsh-research-kit/memory-search` —— Memory Center 项目记忆检索(ROADMAP §5)。按已连接 MCP 的工具 Schema 合成参数后代为执行 `mcp__` 前缀检索工具;无法可靠合成参数时明确拒绝。结果只作增强候选上下文,是否注入由用户在面板显式勾选。 这四条不构成 DSH 插件自己的后端:无凭据、无模型选择权,宿主卸载插件后不残留。另有 `mcp/server.js` stdio 入口,可被兼容宿主独立启动;它将证据、运行护照、检查点与调用日志保存到本地可配置目录,不启动后台队列或独立模型服务。 | 能力 | 所有者 | 本插件职责 | | --- | --- | --- | | 模型路由与调用 | DSH | 不读取密钥,不自行调用模型。 | | 当前对话与发送 | DSH | 通过 `inputActions` 写入或提交。 | | 文件、`@` 提及与文件内容注入 | DSH | 只在 UI 中提示用户使用原生能力。 | | MCP、Web、数据库工具 | DSH / 已安装插件 | 只如实标注工作流的接入前提。 | | 工作流资产与 Prompt 组装 | Research Kit | 维护 JSON 目录、表单、校验与预览。 | | 科研结论的责任 | 研究者 | 产物必须标为草案/待核验,不自动升级为事实。 | ### 1.3 已知宿主兼容性原则 同级 `dsh-promptkit` 已验证 DSH 的 `conversation.view` 与 `inputActions` 集成方式,但 DSH 的槽位 props 曾在版本间演变。因此: - 首次接入必须在真实 DSH profile 启动验证,而不是只依赖单元测试; - 所有访问 `inputActions` 的代码必须允许其暂时不存在,展示可理解的错误,不得使视图崩溃; - 仅在用户点击“发送到当前会话”时调用 `submit()`; - 不截获 Enter,不改变原生输入框行为; - 不重新实现 `@文件` 自动补全、上传或文件解析。 ## 2. 目录与模块职责 ```text dsh-research-kit/ ├── catalog/ # 人工审核的科研资产,纯数据;三个 index.js 是唯一数据入口 │ ├── workflows/ # 参数化 Prompt 工作流,按流程族分片(349 条 / 28 个类目) │ │ ├── index.js # 唯一聚合入口:按固定顺序导出数组,新增分片必须在此登记 │ │ └── <流程族>.json # 每个分类一个分片(paper-manuscript、genomics、ecology…) │ ├── skills/ # 技能,按稳定用途分片(core 43 / crop-breeding 2 / bioinformatics 1 / host-capabilities 63,共 109 条) │ ├── resources/ # 数据源,按稳定用途分片(chinese-academic / crop-breeding / literature / genomics / omics / general-science,共 129 条) │ │ ├── index.js # 唯一聚合入口,并导出 database-metadata.json 的分组展示元数据 │ │ └── database-metadata.json # 数据源分组等展示元数据(对象型配置,不是条目分片) ├── src/ │ ├── catalog.js # 资源读取、搜索、查询、Prompt 组装(纯函数) │ ├── catalog-storage.js # 收藏与使用历史的 CatalogStorage 接口 │ ├── research-selection-store.js # 会话级资源选择(仅存于当前会话) │ ├── research-context-store.js # 跨分区研究上下文:当前项目 + 最小研究运行元数据(不保存 Prompt 或原始内容) │ ├── evidence-store.js # 本会话证据索引(只读汇总) │ ├── evidence-vault-store.js # 证据库持久化:IndexedDB schema v2(entries + 资产-证据 link 表,守卫式升级)+ 内存降级 + 项目隔离 / 去重 / 备份 │ ├── knowledge-store.js # 自动沉淀知识库持久化:节点/关系双 store,稳定 id 去重合并、冲突并列(IndexedDB + 内存降级) │ ├── knowledge-deposition.js # 自动沉淀编排:开关、assistant/message 事件接线、水位线、联动灵感资产与证据库 │ ├── theme.js # 视觉令牌单一真源(--rk-* 明暗双源 + 交互反馈) │ ├── ui.js # 统一基础组件层(按钮/卡片/输入/标签/空态/弹窗…) │ ├── catalog-category-filter.js # 工作台与弹层共用的分类筛选组件(快捷分类与颜色集中在此) │ ├── research-console.js # 统一视图容器:分区调度 + 两级吸顶偏移实测 │ ├── research-workbench.js # 分区①「资源与工作流」:目录检索 + Prompt 组装 + 内嵌组装回放 │ ├── route-replay.js # 组装回放:trace 分段、引用块预览、独立 viewer 弹窗(§3.2) │ ├── research-vault.js # 分区③「研究资产库」:灵感资产增删改 / 版本 / 验证状态 + 证据库子模块切换 │ ├── research-evidence-vault.js # 证据库面板(项目切换 / 删除 / 导入导出 / Agent 批量初判)与保存表单 │ ├── research-evidence-graph.js # 分区④「研究证据图谱」:关系图渲染(缩放平移/迷你地图/范围模式/导出)+ 已保存证据接入 + 方向性锚点 + 自动沉淀开关与结论追溯面板 │ ├── database-query-panel.js # 公开数据源直查面板(工作台详情内嵌) │ ├── composer-launcher.js # 输入框工具行「资源/工作流程」入口 │ ├── composer-overlay.js # 输入框 overlay 资源选择器与启动弹窗 │ ├── composer-deposit-button.js # 手动沉淀伴生钮:贴靠增强器浮动按钮、位置解算(纯函数)与临时状态条 │ ├── host-capabilities-client.js # 宿主能力摘要:事实汇总(纯函数)+ 进程级 5 分钟缓存取数 │ └── lib/ │ ├── icons.js # 图标 path │ ├── enhance-output.js # 模型输出协议解析(Node half 与浏览器共用) │ ├── vault-core.js # 灵感资产纯逻辑与隐私边界 │ ├── knowledge-extract.js # 自动沉淀结构化提取器(纯逻辑):知识节点/关系/引用来源,确定性与有界性契约 │ ├── evidence-graph-core.js # 证据图谱节点与边纯逻辑(含已保存证据与自动沉淀知识接入) │ ├── evidence-vault-core.js # 证据条目纯逻辑:标识符识别、规范化、隐私校验、去重键、备份格式 │ ├── asset-evidence-links.js # 资产-证据互链纯逻辑:稳定 link id、候选推导(项目/标签/知识链种子)、图谱边转换 │ ├── console-sections.js # 统一容器的分区契约(名称/定位/用途/边界/独占数据) │ ├── overlay-anchor.js # 输入卡片浮层的锚定与可用高度解算(纯函数) │ └── archify-adapter.js # IR / trace → archify data-* 契约 + 哨兵槽位替换(纯函数,衔接 vendor/archify) ├── mcp/ # MCP Server:36 个 research_* 工具的注册、实现与执行层 │ ├── server.js # MCP 进程入口:注册工具与 annotations、统一错误语义、转发调用 │ ├── tool-registry.js # 工具元数据唯一事实源(名称/分类/层级/访问级/帮助路由/中文名),表格与活动面板由此派生 │ ├── paths.js # MCP 本地数据根目录解析(DSH_RESEARCH_KIT_HOME 可配置) │ ├── tools/ │ │ ├── index.js # 对外注册入口:聚合工具数组并保持稳定导出 │ │ ├── catalog.js # 目录检索与工作流 Prompt 组装 │ │ ├── discovery.js # 工具发现路由与 research_help(只读) │ │ ├── evidence.js # 证据保存、盘点、人工评估、写回与资产关联 │ │ ├── figures.js # 论文图表脚本生成与风格查询 │ │ ├── literature.js # 单源检索与稳定标识符存在性核验 │ │ ├── literature-search.js # 多源检索编排、互引分析与 OpenAlex 元数据 │ │ ├── observability.js # 脱敏工具调用统计与链路中断观测 │ │ ├── review.js # 草稿审阅、限制语检查与 AI 使用披露 │ │ ├── runs.js # 研究运行、护照与人工检查点 │ │ └── shared.js # 证据字段投影与多源文献去重(跨工具共享) │ ├── state/ # 运行状态与产物 │ │ ├── checkpoint-manager.js # 管道检查点与人工审批 │ │ ├── claim-ledger.js # 显式科研 Claim 台账:认识论状态与证据引用,不存正文 │ │ ├── material-passport.js # 跨会话状态快照(护照 YAML) │ │ ├── research-context-pack.js # Claim/证据/验证回执的有界只读上下文包 │ │ └── run-overview.js # 运行总览聚合(阶段/检查点/证据/最近产物/下一步) │ └── execution/ # 审阅与生成执行层(纯逻辑 + 外呼适配器) │ ├── anomaly-detector.js # 冗余/矛盾/缺失异常检测 │ ├── call-logger.js # 工具调用日志(活动面板与用法统计数据源) │ ├── citation-verifier.js # DOI/PMID/arXiv 存在性与关键词线索,声明支持性待人工核验 │ ├── claim-auditor.js # 文本级 claim-source 对齐审计 │ ├── contract.js # 执行层契约(输入输出形状) │ ├── disclosure-generator.js # 期刊 AI 披露声明生成(15 个期刊政策) │ ├── evidence-grader.js # 来源缺失检查;有来源则未分级,证据强度需人工核验 │ ├── evidence-inventory.js # 证据盘点汇总 │ ├── evidence-store.js # 证据条目持久化(文件系统为真源) │ ├── figure-generator.js # 多面板 matplotlib 图表脚本生成(8 个风格) │ ├── figure-styles/index.js # 图表风格模板(精确 rcParams) │ ├── hedging-phrases.js # 限制语词典 │ ├── http-client.js # 共享外呼客户端:User-Agent、Retry-After、指数退避与短时熔断 │ ├── identifiers.js # 稳定标识符归一化(DOI / PMID / arXiv / OpenAlex) │ ├── literature-linker.js # 证据互引关系发现 │ ├── openalex-fetcher.js # OpenAlex 元数据获取 │ ├── source-querier.js # 多数据源直查适配器 │ ├── writing-quality.js # 学术写作质量检查 │ └── wrapper.js # 执行层统一包装(计时/错误/日志) ├── dsh/ │ ├── standalone-glue.js # DSH 槽位注册唯一入口(view + input.left + input.overlay + input.right) │ ├── slot-registry.js # 四个槽位的 id/order/label 单一事实源(纯数据) │ ├── prompt-studio-glue.js # 分区②「方法工坊」宿主与 provider 实例化 │ ├── prompt-enhancer-glue.js # 草稿增强器宿主:研究上下文桥接 + SSE 客户端 │ ├── database-query.js # 公开数据源直查适配器、缓存与限流(Node half) │ ├── semantic-enhance.js # 语义增强 system 指令与两条路由(Node half) │ ├── host-capabilities.js # 宿主能力探测:装配事实 + MCP 连接清单(Node half,只读) │ ├── memory-search.js # Memory Center 检索:工具挑选、Schema 参数合成、代执行 mcp__ 工具(Node half) │ ├── catalog-data.js # 目录 JSON 同源延迟路由 │ ├── promptkit-client.js # PromptKit 同源延迟脚本路由 │ ├── archify-template.js # Archify viewer 同源延迟模板路由 │ ├── agent-activity.js # Agent 活动面板:调用轨迹聚合、运行 ID 自动捕获与检查点确认桥接(HTTP handler) │ ├── evidence-sync.js # 证据库文件同步:IndexedDB ↔ 文件系统真源双向同步(HTTP handler) │ └── evidence-agent-assess.js # 当前会话模型的证据元数据批量初判(不读取全文、不改人工状态) ├── ui/ │ ├── package.json # 浏览器子包元数据 │ ├── client.js # 构建生成的 DSH ModuleLoader 主包(勿手改) │ ├── catalog-data.json # 构建生成的目录延迟工件(勿手改) │ └── promptkit.js # 构建生成的 PromptKit 延迟工件(勿手改) ├── vendor/ │ ├── promptkit-embed.js # vendored 界面工件(SHA-256 锁定,勿手改) │ ├── archify/ │ │ ├── template.html # vendored 交互 viewer 模板(SHA-256 锁定;整段注入为全局字符串) │ │ ├── i18n.mjs # vendored viewer 文案(SHA-256 锁定;ESM 源码,参与 strip 与拼接) │ │ └── LICENSE # 上游许可证原文 │ └── vendor-manifest.json # 工件来源 commit 与校验和清单(当前 3 个工件) ├── scripts/ │ ├── build-client.mjs # 生成主包与两份延迟工件(含符号顺序与顶层重名断言) │ ├── check-vendor.mjs # 校验 vendored 工件未被篡改 │ ├── check-doc-stats.mjs # 校验对外文档的规模数字与 catalog/ / 工具注册表实测一致(--verbose 列看守范围) │ ├── check-doc-assets.mjs # 校验 docs/assets/ 的图与文档引用双向一致(死资产 / 断链,--verbose 列引用处) │ ├── validate-catalog*.mjs # 目录契约校验(CLI 与测试共用纯逻辑库) │ ├── sync-tool-docs.mjs # 从工具注册表生成 MCP-SETUP 的工具表与最短路径(--check 入 npm run check) │ ├── render-diagrams.mjs # diagram IR → 单文件交互 HTML(--html);结果文件 → IR 脚手架(--from-files) │ ├── validate-diagrams.mjs # diagram IR 诊断(规则码 + supportedFixes),--repo 已入 npm run check │ ├── add-agent-fields.mjs # 一次性迁移脚本:为工作流条目批量补 tool_mode / input_schema 字段 │ ├── browser-regression.cjs # 真实 Chromium 交互回归(npm run test:browser) │ └── lib/ │ └── catalog-entries.mjs # 分片与聚合入口的两路读取(目录校验与文档统计校验共用) ├── test/ # 429 项测试(62 个测试文件 + helpers 下的 IndexedDB 与 DOM 桩:纯逻辑 + 渲染级降级断言 + 源码/产物文本断言) ├── docs/ # 读者文档,索引见 docs/README.md ├── index.js # Node half:仅注册受控路由 ├── package.json └── cordis.patch.yml # DSH bundle 注册补丁 ``` > 本树是**受控清单**:新增模块、脚本或 vendored 工件必须同步登记本节。它与「新增源码模块登记两处」是同一条纪律的三个落点——本树(人读)/ `scripts/build-client.mjs` 的 `files`(产物)/ `package.json` 的 `check`(单文件语法)。目录分片只按目录粒度登记,不逐条列出资源。 ### 2.1 分层规则 | 层 | 可以做什么 | 不可以做什么 | | --- | --- | --- | | `catalog/` | 声明研究流程、文本、字段、关联、限制 | 放可执行 JS、密钥、未核验结论。 | | `src/catalog.js` | 纯函数、数据校验、搜索、Prompt 组装 | 访问 DOM、网络、`localStorage`。 | | `src/catalog-storage.js` | 收藏/历史读写、变更通知,隔离 localStorage | 存参数值或完整 Prompt;网络访问。 | | `src/research-selection-store.js` | 会话级资源选择的读写与广播 | 跨会话持久化。 | | `src/research-context-store.js` | 跨分区的当前项目与研究运行元数据;只保存工作流身份、阶段、状态和时间,不保存 Prompt、检索词、文件或模型输出。运行 id 可作为 MCP passport / checkpoint / 证据 / 活动日志的可选关联键 | 替代证据、资产、知识或 MCP 的领域存储;声称某个运行已执行工具,或改变证据去重。 | | `src/evidence-store.js` | 在当前页面内存中汇总本会话已选资源、已启动工作流与直查来源的**索引**,并向各视图实时广播 | 执行查询、持久化、保存原始文件或检索词、生成结论。 | | `src/evidence-vault-store.js` | 证据库持久化:IndexedDB schema v2(条目 + 资产-证据 link 表,守卫式升级)、按项目隔离与去重、备份序列化,并提供内存降级;link 的建立/解除/端点删除联动 | 触碰 DOM;在降级时伪装成已持久化;保存未经用户确认的条目或自动建立 link。 | | `src/lib/asset-evidence-links.js` | 资产-证据互链纯逻辑:稳定 link id、候选推导(同项目 / 共同标签 / 知识链种子)、图谱边转换 | 自动建立 link;把候选当成已确认事实;在候选里携带笔记或全文。 | | `src/knowledge-store.js` | 自动沉淀知识库持久化:节点/关系双 store、稳定 id 去重合并、冲突并列保留,并提供内存降级 | 触碰 DOM;在降级时伪装成已持久化;改写用户推进过的核验状态。 | | `src/knowledge-deposition.js` | 自动沉淀编排:读写开关与处理水位线、**增量扫描** DSH 会话事件流(`sessions.binding().eventSource`,每次通知只扫上次扫过的尾部之后的新增段)、调用提取器并联动三个库;另提供手动沉淀入口(沉淀当前会话最近一条回答,图谱页与增强器伴生钮共用) | 在开关关闭时自动提取内容;发送任何网络请求;回放开关关闭期间的历史消息;让沉淀失败冒泡到宿主。 | | `src/lib/knowledge-extract.js` | 规则化结构提取:知识节点/关系/引用来源,确定性与有界性输出 | 访问 DOM、网络或存储;把无法核验的提取结果标为已核验。 | | `src/theme.js` | 主题 CSS 变量与 GlobalStyle 注入 | 读取宿主私有主题 API。 | | `src/ui.js` | 无业务状态的基础组件与图标 | 持有业务逻辑或读取目录数据。 | | `src/research-console.js` | 分区调度、分区导航、两级吸顶偏移实测 | 持有任何分区的业务逻辑,或读写分区的数据。 | | `src/research-workbench.js` / `research-vault.js` / `research-evidence-graph.js` / `research-evidence-vault.js` | React 状态、渲染、调用注入的宿主动作 | 直接依赖 DSH 私有全局或发网络请求。 | | `src/lib/*` | 与 DOM 解耦的纯逻辑(协议解析、布局解算、隐私边界、稳定性标识符识别、备份格式、分区契约) | 触碰 DOM 或宿主 API。 | | `src/route-replay.js` / `src/lib/archify-adapter.js` | 把 `composeWorkflow` 的 `trace` 渲染为可核对的组装回放(详情内嵌 + 独立 viewer 窗口);IR / trace → archify `data-*` 契约与哨兵槽位替换 | 预测执行结果;改写 vendored 模板;把回放当作执行证据。 | | `src/composer-launcher.js` / `composer-overlay.js` | 输入框入口、overlay 选择器、启动弹窗 | 绕过 `inputActions` 直接发送或读取文件。 | | `dsh/standalone-glue.js` | 将 DSH props 映射为组件 props、注册槽位(返回统一释放函数) | 处理领域业务、拼 Prompt。 | | `dsh/slot-registry.js` | 槽位 id / order / label 的纯数据声明 | 执行注册本身。 | | `dsh/prompt-studio-glue.js` / `prompt-enhancer-glue.js` | 为 vendored 组件与增强器提供宿主装配 | 修改 vendored 工件本身。 | | `dsh/*.js` 路由模块 | Node half 的查询、增强、同步、活动与延迟工件路由 | 持久化状态、持有凭据、自行选择模型、代执行 `mcp__` 前缀之外的原生工具。 | | `vendor/` | 存放经审查、SHA 锁定的工件快照 | 手工编辑;运行时从相邻目录加载。 | | `ui/client.js` / `catalog-data.json` / `promptkit.js` | 仅为构建产物 | 手工编辑。 | | `index.js` | 保持插件 Node half 可被加载;集中注册受控路由 | 持久化状态、持有凭据、自行选择模型或注册未经需求确认的路由。 | ### 2.2 统一视图的分区契约 三个并列视图(科研工作台 / 研究方法工坊 / 研究灵感库——后者即今天的「研究资产库」)已合并为单一 `conversation.view`(`dsh-research-kit-console`),内部按「发现 → 构造 → 沉淀 → 证据」的科研闭环做四个二级分区。证据图谱是 Research Kit 自有分区,汇总本会话资源、工作流、查询来源、资产与**已保存证据**的关系;其余三个分区组件继续以 `embedded` 模式复用。 | 分区 | 定位 | 核心用途 | 职责边界 | 独占数据 | | --- | --- | --- | --- | --- | | 资源与工作流 | 发现层 | 目录检索、按参数与技能组装 Prompt、公开数据源直查 | 不生产知识、不沉淀资产、不直接出网 | 目录收藏与使用历史 | | 方法工坊 | 构造层 | 方法卡库、变量填充生成可编辑 Prompt、从当前对话提取草稿并写回输入框 | 不管理资产正文、不检索项目记忆或最近会话、不替工作流决定领域参数 | 方法卡与工坊资产 | | 研究资产库(含「灵感资产 / 证据库 / Claim 审阅」子模块) | 沉淀层 | 灵感资产增删改与版本对比;证据库按项目保存可追溯来源;Claim 审阅逐条记录人工判断、理由和证据关联 | 不生成 Prompt、不存原始数据与完整查询结果、不静默注入;Claim 确认必须关联本课题已保存证据 | 灵感资产(PromptKit asset provider);证据条目(IndexedDB 与文件证据库);科研 Claim(MCP 文件台账) | | 研究证据图谱 | 证据层 | 可视化本会话已选资源、已启动工作流、直查来源、资产、已保存证据与自动沉淀知识之间的关系(节点与边见 §3.5);承载自动沉淀开关与结论追溯面板 | 不执行查询、不生成结论、不保存原始文件与检索词;对证据库只读接入,不写入、不携带笔记与全文 | 本会话证据索引(`evidence-store`);自动沉淀知识库(IndexedDB `dsh-research-kit-knowledge`);对证据库只读 | 契约由 `src/lib/console-sections.js` 声明、`test/research-console.test.js` 守护: - 每个分区必须声明名称、定位、核心用途、职责边界与独占数据五项; - 职责边界必须显式包含否定项("不做什么"),数据归属必须互斥,避免合并后功能重叠; - 分区 id 必须与 `src/research-console.js` 的组件映射表一一对应,不允许出现"有导航无内容"的空分区。 合并过渡期的「原「旧标签」」提示徽标已移除:三个分区的旧位置映射在合并后已稳定,徽标只是常驻噪声,且它会随窗口变窄折行、反过来改变导航高度(而导航高度正是二级吸顶的偏移量来源)。因此 `formerLabel` 一并不再作为契约字段保留,避免留下无消费方的死数据。 **分区宽度一致性**:四个分区必须铺满内容区,水平内边距统一引用流式令牌 `--rk-gutter: clamp(16px, 3vw, 34px)`(`src/theme.js` 唯一定义处,容器导航条与四个分区五处共同消费):视口 ≥1133px 时取上限 34px(与既有视觉刻度一致),其间随窗口线性收缩,880px 以下由媒体查询锁定 16px。宽度方向一律用 `100%` 相对父容器解算,不得出现固定像素宽度。方法工坊复用 vendored `PromptStudio`,其根 `
` 内联了 `width: min(1240px, max(100%, calc(100vw - 280px)))` 与 `margin: 0 auto`——这是「独立插件页 + 为宿主侧栏预留 280px」场景的写法。嵌入统一容器后父容器已是扣除侧栏后的可视区,叠加该上限会使本分区收成居中窄栏(宽屏留白、窄容器横向溢出),与另外三个铺满分区视觉割裂。 vendor 为 SHA 锁定工件不可改,因此由 `dsh/prompt-studio-glue.js` 的宿主包装提供锚点 `.rk-studio-host`,`src/theme.js` 以 author 级 `!important` 规则覆盖内联宽度(内联声明非 `!important` 时可被覆盖),只解绑宽度、内边距与 `overflow`,不改动组件其他样式。真实 Chromium 实测(视口 1280px): | 父容器宽 | 解绑前 main 宽 | 解绑后 main 宽 | | --- | --- | --- | | 1440px | 1240px(左右各留白 100px) | 1440px(铺满) | | 900px | 1000px(横向溢出 100px) | 900px(贴合) | 流式令牌四档视口实测(方法工坊分区,`--rk-gutter` 解算值): | 视口宽 | `--rk-gutter` 解算值 | main 宽 | 横向溢出 | | --- | --- | --- | --- | | 600px | 16px(媒体查询锁定) | 铺满 | 无 | | 880px | 16px(媒体查询锁定) | 铺满 | 无 | | 1000px | 30px(3vw) | 铺满 | 无 | | 1440px | 34px(上限) | 铺满 | 无 | 契约由 `test/research-console.test.js` 守护:vendor 宽度写法漂移检测 + 宿主锚点存在 + 覆盖规则齐备(宽度 / 居中边距 / `overflow`)+ 流式令牌定义(上下限与视口项)+ 四分区内边距同刻度。 其中 `overflow` 解绑是吸顶生效的前提,原因见 §2.3:`S.page` 里的 `overflow: auto` 会在嵌入场景下变成一个不再滚动的内层滚动盒,把 `
` 内所有 `position: sticky` 的参照系锁死在它自己身上。 ### 2.3 顶部吸顶分层 统一视图的可滚动内容很长(分区①详情栏、分区③资产列表都能把页面撑到数千像素),而检索、筛选与模式切换是复用频率最高的动作。顶部因此采用**两层吸顶 + 一条分层原则**,而不是把所有头部一把吸住: > **吸顶只放「随时要用的操作」,不放「读一次就够的内容」。** | 层级 | 元素 | 是否吸顶 | 理由 | | --- | --- | --- | --- | | 一级 | `.rk-console-nav`(分区导航 + 说明块) | 是 | 回答"我在哪个分区",跨分区切换不应需要回滚 | | — | 分区封面 `PageHead`(kicker / 标题 / 导语 / 低频动作) | 否 | 定位是"封面":标题与一级导航的当前标签重复,导语是读一次的介绍;吸住会白占约 87px 并放大重复感 | | 二级 | `.rk-sticky-toolbar`(该分区的常驻操作行) | 是 | 高频控件。资源 587 项、资产与方法库持续增长,滚走意味着每次操作都要先回顶部 | 四个分区的二级吸顶带按同一口径组装(检索 + 筛选 + 该分区的模式/主操作): | 分区 | 二级吸顶带内容 | 实现 | | --- | --- | --- | | 资源与工作流 | 科研模式 · 检索框 · 类型筛选(全部/工作流程/技能/数据库/收藏/历史);选择工作流程、技能或数据库后显示该类型的分类筛选(高频快捷项 + “全部”下拉) | `Toolbar sticky` | | 方法工坊 | 方法检索框 · 分类下拉 | vendored 组件的筛选块(宿主侧解绑,见下) | | 研究资产库 | 灵感资产:检索框 · 状态筛选 · 项目筛选 · 新建资产;证据库:检索框 · 核验状态筛选 · 项目选择 · 导出 / 导入 / 清空;Claim 审阅:草稿登记 · 逐条判断 · 证据关联 | 灵感资产和证据库各一条 `Toolbar sticky`;Claim 审阅按卡片逐条操作 | | 研究证据图谱 | 节点计数 · 关系计数 · 图例 | `Toolbar sticky` | **操作下沉而非封面吸顶**:`科研模式` 原挂在分区封面右侧、`新建资产` 原挂在封面动作区,都会随页面滚走(实测 `科研模式` 滚 800px 后 top = −555),每次切换都要先回顶部。两者都是常驻控件,因此下沉进二级吸顶带;而导出/恢复备份是一次性维护动作,留在封面即可,不占用常驻高度。 **折行顺序有意为「模式 → 检索 → 筛选」**:三者放不下一行时按 DOM 顺序折行,把最宽的筛选项留在最后折行才能占满整行;若把「科研模式」放末尾,被挤到第二行的就是它一个窄控件,会留下一整行空白(实测 1180px 窗口即触发)。检索框的 flex 基准(`1 1 200px`)也是按"三者同占一行"倒推的:922px 内容宽下 模式 176 + 检索 200 + 筛选 495 + 间距 20 = 891 ≤ 922。 **偏移量必须实测,不得写死像素**:二级吸顶的 `top` 取 `var(--rk-console-nav-h)`,由 `ResearchConsole` 用 `ResizeObserver` 观察一级导航并写入;挂载时先写一次,卸载时清理。写死必然错位——导航高度随窗口变窄换行(说明块变 4–5 行)而变化,实测在 1280px 宽下为 149px、780px 宽下为 180px。 三个关键约束: - **观察 `box: 'border-box'`**:`ResizeObserver` 默认只观察 content-box,因此"内边距/边框把导航撑高而内容框不变"的变化不会触发回调,二级吸顶会停在旧位置、压进导航底下。此缺陷只有在真实宿主里扰动导航高度才暴露得出来。 - **吸顶带必须有背景**,且垂直节奏由内边距而非外边距承接——外边距区域不绘制背景,吸顶后滚动内容会从缝隙透出(故 `Toolbar` 在 `sticky` 态把 `margin` 置零,由 `.rk-sticky-toolbar` 的 `padding` 接管)。 - **`overflow` 必须解绑**(方法工坊专属,见下):任何祖先建立滚动盒都会夺走后代 sticky 的参照系。 **方法工坊的两条 vendor 解绑**(这是四个分区里唯一不由本仓库实现的区块,两条都只有真实宿主才暴露): 1. **vendored 左列的死 sticky**。组件把筛选块与整个方法列表放进同一列 `