# Changelog
> shoucang 更新日志。基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。
## [Unreleased]
### Changed
- **🎯 v9 全面对齐(第十二轮 · 验收基建固化 + 六页结构对齐)(2026-09-13)**
**① 先修「看不见」的根因(本轮最大产出)**:此前「整页长图」与「DOM 骨架实测」都是**一次性脚本**,
随 `_tmp-*` 清理出仓 ⇒ 逐页核对只剩 860px 首屏,而原型每页真实高度 4800–6000px,
**每页只看得到约 15%**(第十一轮误判「总览只有 2 张卡」正是这么来的)。本轮把两者**固化进
`scripts/ui-geo-regress.mjs`**:`--full-shots
`(面板 + 原型各 8 张整页长图,先实测高度再截图)·
`--skeleton `(两侧同一套选择器的块树 + 路径编号 + 类计数,落 txt 供程序化 diff)。
三个坑一并记录在案:截图输出路径必须**绝对**(相对路径会静默落到别处,表现为「✗」)·
目标目录须先 `mkdir -p` · 骨架递归深度要 ≥8(卡在 `wa-tab-panel` 之下会被截断,误判成"结构缺失")。
**② 设置页**:6 个折叠组 → **一张卡平铺 10 行** + 「快捷键」卡(键位 pill 改中性色)+ 「恢复默认」动作行
—— 原型的层级只有「页头 → 卡 → 行」,折叠组是面板自造的一层;页头改「设置」+ 加「导出快照」
(真实动作:导出配置原文 + 界面偏好为 JSON);补 **导航分组显示 / 页脚健康条** 两枚开关
(两项功能本就在渲染,此前只是没暴露 —— 不是假开关)。
**③ 参数页**:4 个 pane 各自**包进一张卡**(原型 `div.card.plain`)—— 此前 18 个控件裸平铺,整页少一层容器。
**④ 运行观测页**:KPI 去掉状态点与进度条(原型卡高 104,面板 110)· 执行进度由折叠块改**卡** + 路由 chip ·
日志行改原型形态「级别图标 + 方法 + 端点 + 耗时 + 状态码」(耗时与状态码是 `api()` 写入 `ctx` 的**真实值**,
不是解析 message 文本);`UI.kpi` 因此新增 `plain` 变体(容量类 KPI 仍带条,不用"改一处、别处跟着走样"的做法)。
**⑤ 插件集合页**:夹具补 3 条成员(此前 `members:[]` ⇒ 成员网格恒只有「添加卡」,卡片形态无法核对)。
**⑥ 记忆库页**:容量区排版与标准 KPI **收敛为同一组值**(值字号 `clamp(22px,2.05vw,26px)` + `min-height:34px`
+ 条 `margin-top:auto` 沉底共线;此前固定 22px/88 高 vs 原型 26px/110)· 归档区 Tab 回填计数(原型「归档区 4」)。
**⑦ 深度睡眠页 14 块 → 6 块**(对齐原型 DOM):移除 判据与对账 / 认知环(总览页已有同源卡)·
账本对账(迁运行观测页「关键指标」Tab)· 会话徽章与计时条(信息已在分布卡图例与状态机水位里)·
控制小节(触发并入「睡眠状态分布」卡头右侧的执行位)· 阈值小节(4 项迁设置页 › 高级,与「配置原文」同处);
补 **本轮产出回执(7 张 KPI)**、**下轮材料预估(3 行)**、「最近会话」卡(pill 状态 + 描述;
原型的「查看」按钮**不放** —— 面板没有会话详情视图,不做点不动的控件)。CSS 侧 12 条死规则随之删除。
**⑧ 夹具三补(不补则出图缺块,属"假页")**:`/cognition/report` 缺 `ok` ⇒ 回执与材料**整块不渲染**
(`renderCognitionReport` 首行 `if(!r.ok)return`);再补 `sleeps[]`;`/deepsleep` 补 `sessions[]`。
**⑨ 出图管线自身的两个 bug 一并修**:`group()` 单游标会把握手卡**嵌进上一张卡的卡体**(第二次调用把游标推成卡体)
⇒ 拆成「卡挂容器 / 内容挂卡体」两个游标;异步卡(回执 / 材料)必须在**同步阶段占位**,否则晚到的卡落到页面末尾。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` **42 pass · 1 xfail · 0 skip** ·
`ui-geo-regress` **99 PASS / 0 FAIL** · 8 视图整页出图逐页复核(`deliverables/v9-compare/w9/`)。
**⚠ 仍未对齐(如实记录,接手点见 `deliverables/v9-full-change-plan.md` §11)**:记忆库各 Tab 的「pane → 卡」
层级 · 画像页指针行的成熟度数值列(后端未上报该字段)· 设置/参数页行高(原型 65 / 面板 ~94)·
深睡页「待执行结构操作」块(无数据源)与「自检卡 ↔ 最近会话卡」顺序 · 插件集合「N 工具」字段。
- **🎯 v9 全面对齐(第十一轮 · 运行总览页 · v9 原型 = 最终标准)(2026-09-13)**
**① 对齐方法先修根**:此前"逐页复核"用的出图只有 860px 首屏,而原型每页真实高度 **4826–5968px**
⇒ 每页**只看过约 15%**,滚动下方的卡片从未进过图。本轮改为**整页长图**(原型放开 `.frame` 的 720px 上限;
面板放开模态的 `height:min(900px,92vh)`),并加 `--shots` 之外的整页出图能力;核对改为 **DOM 同口径实测**
(直接量骨架 / KPI 条顶边 / 卡片计数),不再靠肉眼。
**② 总览页两栏 2 卡 → 6 卡**(原型 DOM 实测 card 6),补齐 4 张:
· **晨起摘要**(`delta` / `weekDiff`,数据本就在 `/memory/overview` 响应里,此前只是没渲染)
· **最近动态**(`.tl` 时间线;原型未标端点 ⇒ 按 v9 标准用现有端点聚合**真实**动态,不编造事件流)
· **判据与重排门**(`GET /criteria`;**从深度睡眠页迁来**——原型总览有、深睡页无)
· **快捷操作**(4 个运维动作)
**③ 恢复系统状态卡被误删的 3 行**(MCL 认知环 / 注入统计 / 嵌入服务)—— 上一轮删除依据是
**方案文档正文**「该卡只有一行」,而**原型 DOM 实为 4 行**(各带右侧 pill)。**对齐依据必须是 DOM,不是文档描述。**
**④ badges 文案统一为「标签 · 状态词」**(`蒸馏 · 2 分钟前` / `判据台账 · 已就绪` / `库版本 · 已启用`);
「向量 **fusion**」是 provider 标识,**不再中文化**(旧实现译成"融合")。
**⑤ 告警条**改原型结构:`N 项待处理 —— 描述` + 「前往处理」可点击直达(旧实现是裸 `⚠ 文本`)。
**⑥ 操作卡端点**由灰字改 **`.sc-src` chip**(等宽 + 边框 + 底色);页头补 `.proto-note` 标注本页唯一执行位。
**⑦ 新增端点 `POST /maturation/scan`**(与 `/reconcile` **同构**的运维脚本端点)——
v9 原型「快捷操作」卡有「成熟度扫描」按钮,而插件运行时无该能力(实现是 `scripts/maturation-scan.mjs`)
⇒ 端点化,不留假按钮。契约路由 **34 → 35 条**。
**⑧ 测试基建同步**:`ui-geo-regress` 的契约条数**改从产物读**(`lib/panel-contract.json` 的 `routeCount`),
不再写死数字(加一个端点就要改测试是纯噪音);`test-panel-wiring` 的 `ROUTES` 登记新路由。
**⑨ 夹具三修(不修则出图/核对失真)**:索引行由字符串 `'[x]'` 改**对象数组** `{tag,subject,pointer}`
(格式不符会让 `renderIndexRows` **整块跳过**,记忆库/画像页列表全空);补 `delta`(晨起摘要)、
`criteria.health.notesWarn`(判据卡)、`/deepsleep.active`(状态机整块跳过渲染)。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` **42 pass · 1 xfail · 0 skip** ·
骨架实测 **card 6 / card 6**(原型 ↔ 面板一致)· 整页出图逐块复核。
**⚠ 仍未做**:其余 7 页按同一流程逐页推进(差异清单见 `deliverables/v9-full-change-plan.md`)。
- **🎯 v9 严格对齐(第三轮 · 挂账两项收口)(2026-09-13 · 收掉下一条"第二轮"遗留挂账)**
上一轮挂了三项,本轮收两项、第三项附明确不做的理由。
**① 画像页「成熟度分布」接通真实数据**(此前 5 根柱**恒 0** ⇒ 视觉上等于坏图,卡内还写着"数据未上报"):
`/memory/overview` 新增 `maturity` 字段 = **库内** `audit/maturation.jsonl` 按 A 值 0.2 五档的**小节数**
(与 `deepsleep-apply` 同一台账,**不新增端点**);前端柱高按最大值归一化,并标注升格线与空台账文案。
真机实测分布 `0 / 35 / 8 / 4 / 14`(共 61 节,坏行 0)。
**② 「压缩画像」按钮从假按钮改为真实动作**:上一轮那枚按钮**没有 onclick**(点了没反应,title 还写着"占位")
⇒ 现接 `/deepsleep/trigger`(画像压缩在插件内**无独立端点**,唯一实现路径是深睡归纳的树整理),
confirm/title 明写这层依赖,不留"看得见点不动"的控件。
**③ 深度睡眠页补「状态机」卡**(原型第 1 张卡,此前整块缺失):三节点 = 插件真实的**三段停滞时间轴**
(清醒 → 判定中 ≥ probeAfterMs → 可入睡 ≥ idleMs),当前阶段由 `now` 与两个阈值比较直接得出,
水位条 = 停滞时长 / 阈值。**零新端点、零自造状态**。
**④ 运行观测页:6 个叠放折叠块 → 4 组 Tab**(原型为「4 KPI + 执行进度卡 + 3 组 Tab」):
调用日志 / 错误定位 / 运维操作,另加「关键指标」(原型无此组但为真实功能,独立成枚,不删功能);
「高级:行级编辑 / 删除」并入运维操作。Tab 态经 `Cfg('tab:observe')` 持久化,与参数页/记忆库页同一 `UI.tabs` 实现。
**⑤ 出图集 5 → 8 视图**:`ui-geo-regress --shots` 补画像 / 插件集合 / 深度睡眠 —— 这三页正是
**"几何断言天然失明"**的地方(柱高全 0、状态机整块缺失,门禁照样全绿,只有出图肉眼可见)。
**⑥ 夹具修正(否则出图是假的)**:`/deepsleep` 补 `active`(缺它 ⇒ 端点判定未激活、整块跳过渲染,
出图得到"未激活"空页)与 `lastActivityAt`/`probeAfterMs`(状态机判据);
`/memory/overview` 补 `maturity`,用**真机实测分布**而非编造柱形。
**⑦ 工具链坑(新踩)**:`FIX` 是**模板字符串**,其注释里写反引号会**提前终止字符串** ⇒
`SyntaxError: Unexpected token '!'`;注释内引用标识符一律不加反引号。
**⑧ 协作坑(新踩,已入 skill)**:同一条消息里**并行发多个 Edit 改同一个文件**会产生写竞态 ——
本轮 5 个 Edit 只有 3 个落盘,两个静默丢失(表现为"日志面板进了 Tab、错误定位却还在页级")。
**改同一文件必须串行**。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` 42 pass · 1 xfail · 0 skip ·
`ui-geo-regress` 99 PASS / 0 FAIL · 8 视图出图逐页肉眼复核。
**⚠ 仍未对齐(如实记录,附理由)**:
· 插件集合成员卡的「N 工具」—— 插件**未上报工具数**,无采集口径;且原型那三张卡
(managing-memory / shoucang-core / scheduler)本身是**三包合并前**的旧结构,真机为单成员,
**不宜按原型数量硬对齐**;
· 画像页「USER / AGENT 构成」出图为空——夹具 `lines` 是无 tag 的占位字符串,真机有 tag 即正常显示。
- **🎯 v9 严格对齐(第二轮 · 剩余四页)(2026-09-13 · 承接上一条)**
**⑤ 画像页**:页标题「画像板块」→「画像」、页头描述与 chip 对齐原型;容量网格改为**本页专用 2×2**
(新增 `.sc-kpis-2`),并**补齐原型的第 3、4 格**——「USER 构成 / AGENT 构成」两张卡(数据纯前端从指针行
的 tag 统计得出,**零新端点**);容量数字改 `Derive.num()` 千分位(对齐原型 `2,340 / 3,000`)。
**⑥ 全站 KPI 网格**:`.sc-kpis` 由 `repeat(auto-fit,minmax(160px,1fr))` 改为**固定 4 列** `repeat(4,minmax(0,1fr))`
——vfiff 实测 auto-fit 在 946px 下算出 **5 列**(多一个 0 宽轨道),与原型的 `repeat(4,1fr)` 不符;
≤900px 断点收敛 2 列(与原型同)。
**⑦ 插件集合页**:成员卡状态文案对齐原型——原型 `.pmeta` 右 span 是「已装配」纯文字,**不暴露内部基准口径**
(`✓ 注入器` / `✓ profile` / `✓✓ 双基准`)⇒ 改回「已装配 / 未装配」,口径差异移入 `title`(悬浮可见,信息不丢)。
**⑧ 深度睡眠页**:**补「睡眠状态分布」卡**(原型第 2 张卡)——分段条 + 图例(五态语义色与徽章同源),
数据是同一份五态计数,只是**形态**从徽章改成比例条。**落地时踩了一个作用域坑**:把整块移到
`renderRunExtras` 之前 ⇒ 代码离开 `/deepsleep` 回调作用域、引用局部 `r` 未定义 ⇒ **整页渲染中断**(截图空页);
正确做法 = **占位容器**(`distSlot` 在原型位置提前插入,异步回调内把卡挂到占位)——代码不离开作用域,
DOM 顺序仍符合 v9。这个坑与前端拆分的「父函数局部名子函数拿不到」同根:**跨作用域搬代码前先查引用**。
**⑨ 运行观测页**:**补 4 张观测 KPI**(请求总数 / 成功率 / 平均耗时 / 错误)——纯前端从本地 Store 统计
(logs 的 `"N ms"` 字样 + errors),**零新端点**;页头右侧补**「导出」(JSON 下载)与「清空日志」(danger)**;
路由 chip 对齐原型(`/cognition/report · /selfcheck · /reconcile · /embed/test`)。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` 全绿 · 8 视图出图逐页复核。
**⚠ 仍未对齐(如实记录,均有明确理由)**:
· 运行观测页的分区容器仍是**折叠条**(原型是 tabs 胶囊:调用日志/错误定位/运维操作)——改造要把延迟渲染
的折叠内容搬进 tabs,结构风险较大,**单独立项**;
· 画像页的「成熟度分布」卡与「压缩画像」按钮——现有 34 条路由**无此数据源**,需新增后端端点;
· 插件集合成员卡的「N 工具」——需后端在 `/suite` 增加 per-member 工具数字段。
**⚠ 需重启 DSH** 前端才生效。
- **🎯 v9 严格对齐(第一轮 · 视觉形态)(2026-09-13 · 用户拍板「从视觉看统一对齐,组件样式和展示效果」)**
**① 页面底色令牌**:原型 v9 的层级是 `--bg #131315` < `--panel2 #171719` < `--panel #1b1b1e` < `--panel3 #2a2a2f`;
面板此前把 `--panel` 的值(#1b1b1e)当成了**页面底** ⇒ 比原型**亮一档**(vfiff 实测 `--bg DIFF`)。
不直接改 `--sc-bg1`(它还服务按钮/输入/胶囊等部件,改了会连锁引入新差异),而是**新增页面级令牌**
`--sc-bg-page`,只让 `.sc-main` / `.sc-headslot` 使用 ⇒ `--bg` 对齐。
**② 记忆库页形态收敛**(删掉原型没有的两大块 + 对齐口径):
· 删**状态徽章行**(7 枚)——原型记忆库页无此块(它是运行总览页的组成);
· 删**「运行态」Tab** 及其内容(蒸馏运行 / 记忆库状态 KPI)——同属运行总览页;
· 删**「向量召回」区块**——原型无;且它写的 `pane('run')` 随 Tab 删除后返回 null,
使页面报 `Cannot read properties of null (reading 'appendChild')`(已修);
· 三列容量口径改原型:`MEMORY.md 容量 / notes · 笔记 / pending 候选`(原第 2 列是「待归档会话」);
· Tab 文案改原型样式**带计数**(知识索引 66 / 候选区 N / 笔记 N 类 / 统计),默认落「知识索引」;
· 导航脚状态同步(`refs.navHealth`)从被删段迁到 `fillCap` 之后,**不丢功能**。
**③ 运行总览页形态对齐**:`系统状态` 卡由 5 行收敛为原型的**一行**(当前根目录)——另 4 行
(MCL / 判据版本 / 库版本 / 注入统计)与顶部徽章行重复且原型没有;操作卡按原型**加线框图标**
(蒸馏 ✦ / 深睡 ☾ / 自检 ✓);页头路由 chip 对齐原型(`/memory/overview · /cognition/report · /mcl/status`)。
**④ 连带清理(均为门禁抓出的真问题)**:删段后 `Derive.vecRecall` 失去唯一调用点(D7c 死代码断言翻红)⇒
连同 `VEC_RECALL` 表、导出项与测试金标准一并删除;`.sc-danger` 成孤立样式(CSS 审计门禁翻红)⇒ 删除。
**⑤ 工具链修假绿**:出图脚本 `.internal/panel-shots.mjs` 原先 `catch(e){}` 吞错误 + 用 `existsSync` 判成功 ⇒
Chrome 全失败时仍报 ok,且**把图写进了 Chrome 自己的 cwd**(出图目录传的是相对路径)——
我据此误判「删了两块但图没变」。已修为:出图目录**解析为绝对路径** + 先删目标文件 + 打印 stderr。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` 全绿 · 契约基线按新形态更新(记忆库 16 → 7 项)·
`ui-geo-regress` 的 TABBED 记忆库 5 → 4 同步 · 8 视图出图复核。
**⚠ 仍未对齐(如实记录)**:原型记忆库 tabs 第 4 项「归档区」面板无独立数据源,未造;
画像 / 插件集合 / 深度睡眠 / 运行观测 四页的形态逐页对照尚未做。
**⚠ 需重启 DSH** 前端才生效。
- **🎛 P0-1 组件库收尾:接入进度条组件 + 清掉 6 个零使用 import(产物 −150KB / −20%)(2026-09-13)**
**① 接入 `wa-progress-bar`**(`UI.progress` 内部换实现,**调用点零改动**):条体改由组件承载,
外壳 `div.sc-prog` 保留(承载行间距与下方文字),`value` 属性驱动进度。
**关键在尺寸接管**——组件自带 `--track-height:1rem`(=16px) 与 `min-height`/`padding`/`margin`,
比方案 6px 高 10px;**首版直接替换(不接管尺寸)实测 `ui-geo-regress` 93 → 70 PASS**(整页网格位移,故被回滚)。
本轮先读组件源码 `progress-bar.styles.ts` 拿到变量名,再用 `--track-height`/`--track-color`/`--indicator-color`
显式接管 ⇒ **99 PASS / 0 FAIL**。
配套**常驻渲染断言**(`ui-geo-regress`):① 组件已注册;② `--track-height` 计算值 = 6px。
**判据为何用计算样式而非几何**:组件是 LitElement,插入 DOM 后需等一个 microtask 才渲染,
同步读几何只能拿到 `h=0`、shadow 里仅注释(**实测踩到**);而 CSS 变量解析是同步的,
且「变量是否被接管」正是本项要守的靶点。
**② 清掉 6 个「import 了却零使用」的组件**(`vendor.js` 13 → 7 import):card / badge / spinner / tooltip / select / option。
逐项评估(口径 = 产物里有无 `document.createElement('wa-*')`):`UI.card` 有 8 个调用点,但
`.sc-card-hd/.sc-card-bd` 与 wa-card 的 slot **不同构**、替换会叠加两层卡片(须重写整个卡片层 CSS,
风险高而观感无收益);`UI.badge` **零调用点 = 死代码**;`spinner` 无加载态需求(走 `busyText`);
`tooltip` 现有走原生 `title`;`select/option` 二度回滚后维持原生(图标虽已解锁,但填充/宽度还需接管
4–5 个 `--wa-form-control-*` 变量,且验证手段只有出图目视 ⇒ 风险/收益比不佳)。
**实测收益:产物 756,334 → 602,328 字节(−154KB / **−20%**)**——「import 未用」的代价比预估大得多。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` 全绿 · `ui-geo-regress` **99 PASS / 0 FAIL** ·
`test-css-usage-gate` PASS(删 `.sc-prog-fill` 后无孤立样式)· 已安装副本特性标记 14 项齐全。
**⚠ 需重启 DSH** 前端才生效。
- **✅ P1-2 + P1-1 收尾:记忆库页与模型页全部拆净,前端函数跨度全线 ≤200(2026-09-13 · 承接下一条)**
**① 契约件泛化**:`test-panel-toggles-contract.mjs` → **`test-panel-view-contract.mjs`**(一件覆盖**参数页 + 记忆库页**两视图;
旧件与旧基线删除)。迁移已证伪等价:新件参数页 34 项与旧件**逐项相同**。记忆库页的契约对象是**结构骨架**
(`.sc-mem-group-title` 小节标题 / `.sc-cap-top` 容量列 / `.sc-mem-stat-label` 统计卡,**16 项**)——该页本来就没有表单控件。
**② P1-1 收尾**:`renderTogglesModel` 270 → 父 14 行 + `renderTogglesModelVec`(192) + `renderTogglesModelLlm`(72)。
两个板块(向量链路 / LLM 模型选择)之间**无共享状态**,是零风险的一刀。
**③ P1-2**:`renderMemoryExpanded` **321 行** → 父 69 行 + **9 个语义段子函数**(run 主段 72 / 月度成长 26 / 记忆库状态 27 /
索引 24 / pending 32 / notes 24 / 本地知识区 32 / 向量召回 16 / 成长增量 28)+ 模块级 `mkStat`。
**④ 前端函数跨度全线 ≤200**(实测最大 **192** = `renderTogglesModelVec`;原 615 / 321 两块巨石均已拆净)。
**验收**:`typecheck` 0 错 · `build` 成功 · `check-runner` **42 pass · 1 xfail · 0 skip** ·
契约 **参数页 34/34 + 记忆库页 16/16** 逐项一致 · `ui-geo-regress` PASS · 差异件已部署(安装副本 140/140 sha 一致)。
**⚠ 需重启 DSH** 前端才生效(热重载只换 host 侧 `lib/*.js`)。
**⚠ 关键设计约束(决定了唯一安全的切法)**:记忆库页的 Tab 内容**是交织的**(run 出现 3 次、growth 3 次、index 2 次)。
故**不能**按 Tab 聚合重排——重排会改变各 pane 内元素的 DOM 顺序(= 视觉顺序),而契约测试只比对**清单**、
不含顺序 ⇒ **顺序漂移它抓不到**。因此按**原顺序**切段(零重排),每段一个语义化函数名。
**⚠ 踩坑记录(与 P1-1 同型,第三次出现)**:子函数只接 `ctx` 而**不解构**段内用到的父级名(`data` / `view` / `cap`)时,
段内原样使用这些名字会 ReferenceError ⇒ 父函数中断 ⇒ **全部段落不渲染**(契约实测 16 项全缺)。
口径固化:**子函数开头必须解构 ctx 里用到的每一个名字**(`host` / `data` / `view` / `memoryFile` / `cap`)。
- **✅ P1-1 前端函数跨度债务归零:`renderViewToggles` 615 行 → 父 21 行 + 4 个 pane 子函数(2026-09-13 · 方案档 `deliverables/ui-implementation-plan-2026-09-13.md`)**
**① 先建安全网(方案列为不可跳过的硬前置)**:新增 `scripts/test-panel-view-contract.mjs` + 基线
`scripts/fixtures/panel-view-baseline.json`(**参数页 34 项**:cap 10 / inject 5 / model 6 / sched 13)——
真机渲染参数页,取每个 `.setting-item` 的「Tab + 名称 + 控件类型」,**拆分前固化、拆分后逐项比对**,
**清单不变 = 行为等价**。为什么不用静态扫源码:`SWITCH_KEYS` 有数据驱动的整体跳过、`UI.item` 的控件形态由
children 决定、部分项在异步回调里追加 ⇒ 只有真机渲染的清单才作数。已**反向证伪**(篡改基线任一 ctl ⇒
FAIL 漂移 2 项;还原 ⇒ PASS),已登记 `check-runner` 的 `CHECKS`。
**② 拆分**:`body.js:1964–2578`(615 行)按配置域切成 `renderTogglesInject`(91) / `renderTogglesCap`(90) /
`renderTogglesModel`(270) / `renderTogglesSched`(149) + **模块级** `numSetting`(16);父函数只做页头 + 页签装配
(**21 行**)。切片用一次性脚本按行号机械搬运(28 处边界断言 + 花括号自平衡校验 + 关键锚点自检),零手工重打。
子函数必须放**模块级**而非嵌在父函数里——否则父函数仍是 600+ 行,拆分只换位置、跨度门禁照样红。
**③ 棘轮收紧**:`audit-fnspan --client --gate --debt` **1 → 0**,实测 `> 400 行的函数: 0`。
**验收**:`typecheck` 0 错 · `build`(host+client)成功 · `check-runner` **42 pass · 1 xfail · 0 skip** ·
`ui-geo-regress` **93 PASS / 0 FAIL**(与拆分前基线一致)· 契约测试 34/34 一致 ·
差异件已部署(安装副本 **140/140 sha 一致**)· 参数页真机出图核对无回归。
**⚠ 需重启 DSH**:前端 bundle 变了,热重载只换 host 侧 `lib/*.js`。
**(首轮遗留,同日已收尾)**:拆完 `renderTogglesModel` 仍是 **270 行**(> 方案「子函数各 ≤200」的目标,但 < 400 不触发门禁);
当天第二轮已拆净 —— 见下一条。
**教训留痕(两个坑都值钱)**:
(a)首版把 `gVal` 定义在父函数里、以为「作为参数传下去就够」——但子函数**直接引用 `g`** 的地方
(cap 的 `(g && g.actual)`)拿不到父函数局部变量 ⇒ ReferenceError ⇒ 父函数中断 ⇒ **后面的 pane 一个都不渲染**
(契约测试实测:34 项只剩 5 项)。口径改为「**传 `g`,各子函数自建 `gVal`**」——`g` 只留一条传递路径。
(b)契约测试当时只报「缺失 29 项」给不出根因,白折腾一轮;现补 `error` / `unhandledrejection` 捕获并
**顶到「缺失 N 项」之前**报出——**根因优先于症状**。
- **🔧 UI 落地三项(P0-2 / P0-3 / P2 · 2026-09-13 · 方案档 `deliverables/ui-implementation-plan-2026-09-13.md` + `ui-audit-report-2026-09-13.md`)**
**① P0-3 `renderIndexRows` 健壮性防御**(`src-client/body.js`):索引行元素若退化为非对象(如纯字符串占位),
原实现对 `tag/subject/pointer` 解构全得 `undefined` ⇒ 渲染出「空 pill + 空文本」的行,**静默丢数据且看不出来**
(实测:USER.md 容量卡声称 24 条但只渲染 17 行、AGENT.md 19 条整卡失踪)。现**跳过退化元素并把跳过数回显**
(`⚠ N 条索引行数据格式异常已跳过`)+ `Log.warn` 留痕。真机数据正常时零影响。
**② P0-2 前端纳入函数跨度门禁**(`scripts/audit-fnspan.mjs` 扩展 `--client`、`scripts/test-fnspan-wrapper.mjs` 新增):
此前 `audit-fnspan` **只扫 `src/*.ts`**,前端 `src-client/`(4523 行)完全无门禁守 —— 后端已把 >400 行函数清零,
而前端 `renderViewToggles` 615 行从未被度量。新增 `--client` 模式(TS AST + `ScriptKind.JS`,实测解析 0 诊断)
并内置**包装函数排除规则**(`非声明形态 && 嵌套深度≤2 && 跨度占比>0.8`,应对 `body.js` 的
`__ModuleLoader__` 自注册 IIFE 双层包装);阈值 `--soft 400 --hard 800 --debt 1`(实测值,棘轮只许收紧)。
配套 7 个反向证伪用例(含改名绕过 / 纯 ESM / 「3 个 500 行函数塞进大闭包仍判 3 个」的**反向激励**测试)。
**③ P2 `` 可渲染性取证**(`scripts/ui-geo-regress.mjs` 新增 `--icon-check`):挂离屏探针按
**渲染尺寸**判定(此前只验 shadow DOM 里「有没有元素」⇒ 假绿)。**实测 `rendered=true size=20x16`**
—— `vendor.js` 旧注释「渲染尺寸为 0」已不成立(主题令牌层展平后即可渲染),
**解锁 `wa-tooltip` / `wa-option` / `wa-select` 的采用**(此前 `wa-select` 因该问题回滚为原生 select)。
**验收**:`typecheck` 零错 · `build`(host+client)零错 · `scripts/check-runner.mjs` **41 pass · 1 xfail · 0 skip**(xfail 为既有 `test-treeops-rm`)。
**回滚**:三处改动互相独立,`git checkout` 对应文件即可。
**⚠ 已知未做**:P0-1 组件库收尾(`wa-card`/`wa-badge`/`wa-spinner`/`wa-tooltip`/`wa-option` 仍 import 未用)
—— 试做 `UI.progress → wa-progress-bar` 时 `ui-geo-regress` 由 93 PASS/0 FAIL 跌至 70/23 FAIL
(wa 组件自带 `min-height`/`padding`/`margin` 与手写 `.sc-prog-*` 不同 ⇒ 整页网格位移),
已回滚;**每个组件需单独一轮适配 + 回归**,不可批量替换。
- **🧩 上下文供给落地(P0 / P1 / P2 / 局部 P5 · 2026-09-13 · 方案档 `docs/context-supply-plan.md` v3)**
**① P0 即时项**:`panel-inject.ts` 注入 query 取值补 `data.source.kind === 'user'` 来源过滤——此前宿主注入块(运行态快照 / MCL 慢通道材料 / 后台回执)也会被当成"最近用户消息",导致**用注入物去召回记忆**(实测旁证:两个不同问题召回出同一批 6 行);口径现与 `mcl.ts`、`distill-activation.ts`(ACT-024 结构性去污染)一致。
`panel-shared.ts` 画像行配额由「全局最近 N 条」改为「**按标签各留最近 1 条**再取 N 条」并**截断可见化**(被挡下行留痕提示),修掉"新写的 `[性格]`/`[认知]` 把 `[边界]` 静默挤出注入面"。
引导词补人格两面:`skill/engine/criteria.json` 的 Q2 判据与 `deepsleep-core.ts` 双画像段加入**表达风格(`[性格]`)/ 思维模式(`[认知]`)**——六类 P 标签长期零实存的主因是引导词只列"做法/边界/教训"(结构性排除);注册表 `surface.injection.carriers.profile` 3→4。
**② P1 供给台账**(新增 `src/supply-ledger.ts`):会话级注入台账(行指纹 × 会话,**生命周期独立于轮级 state**)——修掉"`state.delete(sid)` 在每条用户消息自删去重信息 ⇒ 同一会话逐字重复注入"(实测 8 次注入 2,955 字符中 **782 字符 = 26%** 为重复);候选全已给过时**本步零注入**并记 `dupSkipped`;三张会话 Map 加硬上界(此前 `taskText`/`ready` 从无清理)。
**③ P2 三层预算 + 稳定面缓存**:热记忆注入引入**总预算 + 三层分档**(一次性 11% / 稳定面 56% / 变动面 33%;总预算由注册表 `surface.injection.budgetChars` 驱动并 **3000 → 1800**),超预算**留痕不静默**;画像两段(query 无关)单独缓存、以**索引文件尺寸签名**失效,免掉"新用户消息 ⇒ 全量重读三文件 + 解析 activity.jsonl"。
**④ P5 口径收口**:定位统一为**长期记忆底座**(`README.md` / `skill/memory-whitelist-spec.md` / `docs/memory-core-model.md` / `docs/assistant-focus-plan.md` 四处);「守藏不设任何人为边界」主语错位修正为「**agent** 不设人为边界,**守藏**只供给底座」;§8「明确不做」增「伙伴关系与人设实现(归另一插件)」;`D:\FF\modules\shoucang.md` 标注 S01 装配检测 / S05 人化执行循环 / `assistant_capabilities` 为**自检附属 · 非记忆职能**。
**验收**:`typecheck` 零错 · `build`(host+client)零错 · `scripts/check-runner.mjs` 全绿。**回滚开关**:`injectProfileRows=0`(画像行不注入)· `budgetChars` 调大(回到无总预算行为)· 台账纯内存态(重载即清空)。
- **🐞 运行态修复:预算裁切把 USER 画像整段挤掉(2026-09-13 · 重启验证发现并当场修)**
重启后系统化验证发现:三层预算原实现对「agent 画像 + 用户画像**合并后**的稳定面数组」做一次 `clamp`
⇒ agent 画像一超预算,**USER.md 画像整段消失**(`GET /inject/preview` 实测 `含用户画像段 = false`),
违反方案自身不变量 **I2a「恒定面每步必在」**。**修法**:稳定面**按块各自配额**(agent 55% / user 45%,各自下限 120 字符)——
**块内裁行、不丢块**,且每块各自留痕(`(agent 画像另省略 N 行…)`)。
**实测(修复后 /inject/preview)**:注入面 **1,319 字符 / 23 行**(改前 3,418 字符 ⇒ **−61%**)·
`agent 画像 = true · 用户画像 = true · 知识索引 = true · 预算留痕 = true` · 对硬顶 1,800 占比 **73%**;
本会话注入面即带 `(agent 画像另省略 9 行)`+`(用户画像另省略 5 行)` 双留痕。
落地:`typecheck`/`build` 零错、`check-runner` 全绿、差异文件已部署、**插件热重载生效(无需二次重启)**。
- **⚙️ 深层归因的五项建议全部执行并逐项验效(2026-09-13)**
**① 深睡触发松绑**:注册表 `trigger.idleMs` 3h → **45min**(实测 `TRIGGER.idleMs=2700000`;zod 缺省与深睡状态机 `deepsleep-machine` 判据同源派生)。
**② 深睡门禁留明细**:`/cognition/report` 的 `sleeps[]` 原先只透 `gate` 字符串、把审计里的 `rejectedLines` 丢掉 ⇒ 补 `gateExit/rejected/gateDetail(≤5 条)`(原始审计早已落 `[gate:原因] 行原文`,只是投影把它扔了)。
**③ 蒸馏失败留成因**:`distill-run` 审计按 fclass 落 `reason`(`dispatch failed=N`/`gate rejected=N`/`json-parse stop=…`/`agent stop=…`)——原 113 条失败行零成因、45% 失败率不可诊断。
**④ 判据收敛为单一实现**:`isRealUserEvent` 落到 `targets.ts`(同时兼容**事件** `data.source.kind` 与 **消息** `source.kind` 两形态),`distill-chunks`(re-export)/ `distill-activation` / `mcl`×2 / `panel-inject` **四处改为 import 同一函数**;核验旧副本写法清零(消除"同一语义判据四处实现必然漂移"的结构)。
**⑤ 验收**:`typecheck`/`build` 零错 · `check-runner` **PASS(39 pass · 1 xfail · 0 skip)**(含新增来源过滤回归 9 断言)· 部署 lib 20 件 + engine 3 件 · 热重载生效(未要求重启)。
**效果实证(本轮亲自触发并核对)**:**手动触发深睡跑通** —— `stop=completed · profiles=3 · pointers=1 · otherDone=4 · landed=true`,记忆库 git 新增提交 **`3b96e67 memory: deep-sleep @ 2026-09-13T04:32:55`**(改动 AGENT.md / MEMORY.md / activity.jsonl / maturation.jsonl / access-real.jsonl / criteria-gate.json)⇒ **巩固域从"停摆"恢复运转**;**AGENT.md 首次产出 `[认知]` 行**(「架构优先 · 先定承载节点再动手」)+ 新 `[边界]` 行(「子代理权限固定」)⇒ P0 补的"表达风格/思维模式"引导词**实证生效**;深睡写入后 **悬空指针仍 0 · 整档写门 `exit=0 允许写入` PASS**。
**本轮未验到的两项(如实记录)**:`reason` 字段(今日 `dispatch-failed=0`、无失败样本)与 episode 去污(蒸馏触发成功 `sessions:2` 但**零新增** episode ⇒ 无新样本可判)——均留待下次真实失败 / 新会话被蒸馏时复核。
- **🔬 深层归因:来源过滤的「第二副本」被修,转正链数据源去污 75%(2026-09-13)**
顺着"写侧归类与读侧可得性断裂"往下挖,用原始数据定位到**同一个根因的第二个副本**:
**① 病灶**:`src/distill-chunks.ts` 的 `textPartsOfEvent` 只按**事件类型**取文本、**不看 `data.source.kind`** ⇒ 宿主注入块
(`Current runtime context` 运行态快照 / MCL 慢通道材料 / ``)被当作 `[user]` 文本进入**蒸馏材料**,
并进一步成为 `episode.intent`。实测 **`episodes.jsonl` 255 条里 190 条(75%)intent 是宿主样板** ⇒
「同型判定 / 成功计数 / 跨会话计数」的判据基础是脏数据 ⇒ **转正链空转**(`flow-candidates` 无有效候选)。
而 `distill-activation.ts`(ACT-024)的来源过滤**只作用于采样判定**,不作用于文本化 ⇒ 同一根因两个副本、口径不一致。
**② 修法(四处统一为同一口径)**:新增 `isRealUserEvent()`(`kind` 缺失=旧格式/夹具 ⇒ 收;`==='user'` ⇒ 收;其余 ⇒ 丢),
`textPartsOfEvent` 首行调用 ⇒ 蒸馏材料与 episode.intent 同时去污。与 `distill-activation.ts`(ACT-024)、
`mcl.ts#captureFromEvent`、`panel-inject.ts#taskTextOf` 判据**完全同源**。
**③ 新增回归门** `scripts/test-distill-source-filter.mjs`(9 条断言:三类注入 kind 全丢 / 旧格式与真实用户全收 /
**判据是结构字段而非内容**(注入块即使写用户口吻也丢)/ assistant 不受影响 / **水位仍推进到窗口末事件——丢文本不丢 seq**)。
已登记 `check-runner` 的 `CHECKS`;`check-runner` **PASS(39 pass · 1 xfail · 0 skip)**。
**④ 同轮查出的链条实况(写入本档备查)**:深睡 20 次运行里 **gate=no-op/空 12 次 · 失败门 4 次(指针悬空/行格式违规/all-rejected×2)· pass 仅 5 次**(成功率 ≈25%),且 **09-11 21:00 之后零运行**(会话持续活跃 ⇒ 3h 全会话停滞门槛不满足);`ledger` 300 行里 **摄取 234 / 巩固 66(其中 53 是每日自检,真正 consolidate 决策仅 8)** ⇒ 树整编/指针维护/遗忘/[原则]-[路径] 归纳**全部依赖的深睡处于饥饿+低成功率**,这正是先前查出的 13 处超 R 大节、同名主题、67 个零召回主题**无人处理**的原因。
- **🧪 蒸馏链 / 睡眠链 / 职能归类审查 + R1–R3 收口(2026-09-13)**
**① 库内归类与指针卫生(硬错,走门禁修复)**:写门把**真实库**判为 exit=2——6 条悬空指针(`§node 与包管理`/`§包版本探测`/`§协作与文档治理`/`§视觉还原度验收`/`§ui 布局弹性化`/`§Node`)⇒ 整档编辑被拒;3 行标签越白名单(MEMORY.md 内 `[教训]`×2、`[环境]`)。逐条重指向真实小节 + 标签归位,**经 `memory_write_gate` 校验后落盘**(备份 `~/.dsh/backups/MEMORY.md.bak-*`)⇒ 门禁 PASS、越界 0。
**② 睡眠链自检的调用口径(真缺陷)**:`sleep-selfcheck.mjs` 的 `run()` 原为 `stdio:'ignore'` 且**不设 cwd** ⇒ 仓侧 `check-criteria`/`check-carriers` 按调用方 cwd 解析相对路径而**恒 fail**,且失败无明细(只落 `exit≠0`)。改 `cwd=仓根` + 捕获输出尾部作 `detail` ⇒ 带 `--repo` 复测 **6/6 全绿(裁决 ok)**。
**③ 被自检抓出的自身缺陷**:`criteria.json` 的 note 内用直引号 ⇒ **非法 JSON**,`gen-criteria` 静默失败而 `check-runner` 全绿(该轮跑在改动前)——睡眠自检是第一个发现它的门。改用「」并加 `JSON.parse` 决定性验证。
**④ R2 快通道恒 0(已解)**:`sim` 用 `rows[0]` 测、`hasHighConf` 用 `some(∈高置信集)` 判 ⇒ 两条件锚在不同行。探针改用高置信行 ⇒ 审计首现 `channel=fast · sim=0.662 · hit=[原则]`。
**⑤ R3 画像行配额(已解)**:`carriers.profile` 4→6(zod 上限);实测被挡行由 3 降到 1。
**⑥ R1 词法地板弱(已解)**:真实自然语言提问**词法 0 命中**,与 `criteria-audit ①「判跨任务可复用条目 7 天零真实读命中 = 0%」`是**同一断裂的两面**。实现**预热通道**——MCL 的 async 融合召回(dense 0.7+lexical 0.3,实测 `sim≈0.66` 证明嵌入可用)写 `audit/warm-recall.json`,注入面按 `recallKeyOf` 键复用,**零新增嵌入开销**;离线验证"键匹配则生效、键不匹配不串话"。
**⑦ R4 存储解耦**:`record-export` 往返闸常绿,但**不执行切换**(数据安全级;单写向与开关已定义,等显式拍板)。
**门禁**:`typecheck`/`build` 零错 · `check-runner` **PASS(38 pass · 1 xfail · 0 skip)** · 睡眠自检 6/6 · 部署面 140/140 一致 · 插件热重载生效。
- **🔍 质量回归评估(2026-09-13 · 用户要求排查"改动后是否降级")——查出 4 处真风险并全部修掉**
以**实证**逐项核(不靠推断):① 转录里 62 条 `user/message` 的 source 分布 = **user:17 · plugin:43** ⇒ P0 的来源过滤**正确**(真实提问都带 `kind='user'`);
② 直调 `recallIndex` 实测**真实自然语言提问词法召回 0 命中** ⇒ P0 只是**揭穿**了"改前看着有 6–8 行"的真相——那是 query 被宿主注入块顶掉、用自己的注入物召回自己的**回声**。
**修掉的 4 项**:**(a) 恒定面被裁**(AGENT 15 条索引行 1,138 字符 vs 分档 554 ⇒ 裁掉一半以上,违 I2a)→ 改「**恒定面免裁 + 安全带 4,000**」,变动面 ≤600 / 一次性 ≤200 各有硬顶;
**(b) 画像行按块配额**(原合并后一次 clamp ⇒ agent 画像一超预算就把 **USER 画像整段挤掉**,preview 实测 `含用户画像段=false`)→ 按块 55%/45%、**块内裁行不丢块**;
**(c) 位置式回填池用错集合**(分层过滤后 `allMem` 只剩 P 层 ⇒ 新鲜度槽/基线**恒空**,源码自认"回退=回退到空")→ `q && relOn` 分支内改用 **MEMORY.md 全层行**(有查询才铺,载体契约 A7-1 仍守)⇒ 知识索引 **1 行 → 9 行**(本会话实测);
**(d) 台账 v1 是整会话永久去重**(材料被压缩掉后仍记"给过" ⇒ 该记忆对会话失效;被忽略的经验永不再提)→ 改 **轮次窗口去重**(`DEDUP_WINDOW_TURNS=3`,覆盖实测的相邻轮重复形态)。
另修两处**既有**缺陷:`profileCap` 兜底硬编码 `?? 3` 使注册表 `carriers.profile` 改动**对运行时零效果**(改读注册表)· 画像行择优改为**标签行优先**(`[边界] 宿主服务免动` 位于文件首位、在旧 `slice(-N)` 下**从未被注入过**,现已常驻可见)。
**附带发现**:`src-client/body.js` 的 `#scpanl-root .sc-pagehead` **顶层重复定义**(v9 UI 未提交工作遗留,被本轮重构建 + CSS 门禁暴露)已合并为唯一规则。
**验收**:`typecheck`/`build` 零错 · `check-runner` **PASS(38 pass · 1 xfail · 0 skip)** · 差异件已部署 · 插件热重载生效(无需重启)。
- **🎯 v9 视觉对齐(2026-09-13)—— 对照 `deliverables/ui-redesign-v9-2026-09-13.html` 做渲染级复核,修掉一批走样**
**① 复核方法**(无法看图时的实证通道):临时件 `.internal/vdiff.mjs` 把**原型页面**与**真实 `client.js`**
放进同一个无头 Chrome 各自渲染,对语义等价元素取 `computedStyle` + 几何并排比对;颜色再用
`.internal/tmp-png-sample.mjs`(自写 PNG 解码)**直接采样渲染像素**。两条**计量纪律**先立:
· 无头虚拟时间下 **CSS transition 不推进**(实测 `getAnimations()` 恒 `currentTime=0`)——首轮读数把
「选中态导航」误判成透明(像素也读成 `#171719`),实为**测量假象**;两侧统一关动效后复测才为真值。
· 夹具语法错会让**依赖数据的视图整片空白**(`Unexpected token ']'`),空视图会被误读成「UI 缺块」。
**② 修掉的走样(改前 → 改后 = 原型值)**:
· 导航宽 **200 → 216**(`Cfg` 缺省 `navWidth:200` 与方案 `--nav-w:216` 打架,令牌被内联变量压过)
· 导航内距 12/8 → **14/10/10**;标题字重 400 → **700**、内距 → **0/10/6**(`.nav-title` 规格)
· 导航项 **34 → 37px**(行高 1.35 → 1.6)、内距 8/12 → **8/10**、间距 8 → **10**
· 选中态底:`color-mix` 派生(合成 ≈`#2e293d`)→ **实色 `#251f3a`**(新增 `--sc-accent-soft`,两套皮肤各给方案实色)
· 页头:**随内容滚动 → 固定**(新增 `.sc-headslot`,页头移出滚动容器;实测滚动 156px 后页头 y 恒为 33),
内距 → **18/24/14**、底分隔线 → `--sc-border2`;`h1` 15 → **17px**、`desc` 12 → **12.5px**、根字号 16 → **13px**
· KPI:内距 12/14 → **13/14**、`k-top` 12 → **11.5px**、`k-val` clamp 20.2 → **26px**、`k-sub` 12 → **11px**、
进度条 4px/`#232327`/pill 圆角 → **6px/`#33333a`/3px**(新增 `--sc-border2` 令牌),KPI 行间距 24 → **16px**
· 内容区内距 18.9/25.2/31.6 → **18.3/24.0/25.2**(≈方案 18/24/26),同级块统一 **16px** 节奏
· **凸卡体系回归修复**:`.sc-fold` 与 `.sc-mem-stat` 各有**后置 `background:var(--sc-bg1)` 覆盖**,
把卡面压回页面色(v7 一致性补丁点名过的「大面积发平像线框图」)⇒ 去掉覆盖,卡面回 **`#2a2a2f`**
· 徽标:31 → **29px**(内距 4/11 → 4/10、字号 13 → 12、边框 → `--sc-border2`)
· 日志:折叠条 47 → **≤44px**(级别下拉/清空按钮在折叠态隐藏 —— 方案里它们属日志正文工具),
日志行改**定宽三列**(时间 78 / 级别 54 / 正文 1fr,v7 补丁第 9 条)
**③ 仍存差异(本轮未动,须用户拍板,不在「已完成」之列)**:① 分段控件仍走组件库 `wa-tab-group`
(tab 高 43px、下划线式)vs 方案 `.tabs`(28px 胶囊分段)——S3 的组件库决策,改需同步改门禁断言;
② 概览页**信息组成**不同:方案概览含 6 张内容卡(成长/delta/时间线/运行态/判据/快捷操作),
面板概览是「3 操作卡 + 4 KPI + 徽章行」,其余信息分散在记忆/画像/观测页;③ 页头 `acts`(路由 chip + 指南按钮)面板无。
**验证**:`typecheck` 0 错 · `build` 成功 · `check-runner` **37 pass · 1 xfail** · `ui-geo-regress` **93 PASS / 0 FAIL** ·
已安装副本 `client.js` sha256 与仓内一致(改前已备份 `.bak-<时间戳>`)· 出图 8 视图 + 原型对照存
`.dsh-vision-toolkit/artifacts/v9cmp/`。
- **👁 视觉通道打通 + v9 第二轮(结构/层级)对齐(2026-09-13)**
**① 先修「看不见」这件事**(比 UI 本身更关键):`read_image` 一直报 `model "deepseek-flash" does not declare
image input`,我据此判断"没法看图"——**判断错了**。多模态冒烟(合成 640×400 探针图:数字 7391 + 红绿蓝方块 +
底行英文,直发 `opencode-go-custom` 端点)实测:**当前模型 `deepseek-flash` 全部读对**。真因是
`~/.dsh/settings.yaml` 该模型条目**缺 `input: [text, image]` 声明**(provider 的 `/models` 不返回模态元数据
⇒ DSH 默认按纯文本处理)。⇒ 增量补声明(先备份 `settings.yaml.bak-visioninput-<时间戳>`),**无需重启即生效**。
与 GOAT 条目 `deepseek/deepseek-v4.1-flash` 的既有注释同因同解。
**② 出图夹具的解析缺陷**(污染过证据,已修):`client.js` 含 `