Skip to content

feat: Callout Live 形态收口——BlockWrapper 容器与引用内完整渲染(T04–T07) - #678

Merged
ONEGAYI merged 28 commits into
mainfrom
feat/callout-live-refinement
Nov 1, 2026
Merged

ONEGAYI merged 28 commits into
mainfrom
feat/callout-live-refinement

Conversation

@ONEGAYI

@ONEGAYI ONEGAYI commented Oct 31, 2026

Copy link
Copy Markdown
Owner

概述

#668 Callout Live 形态收口批次主体:Live 嵌套 callout 改由 CM6 原生 BlockWrapper 承载容器视觉(间距/边框/圆角/类型色),引用内围栏代码块与多行公式达成完整渲染(代码卡全功能 + KaTeX),不采用降级方案。

提交链

  • ebdec116/928f6685/80fda0e9 BlockWrapper 路线探针报告(含懒延续归属勘误)
  • 212091bd T04 BlockWrapper 容器结构(区间消费解析器节点区间、rank 60−10×深度、根正文独占装配)
  • 0a75a8c6 T05 容器视觉迁移(.callout/data-callout/data-callout-depth 迁 wrapper、行级让位 + facet 嵌入保护、公开样式契约重锚)
  • 5da4d111 T06 扫描器前缀剥离(scanFencesDetailed/scanMathRanges 块模式前缀感知、ContentLineMapEntry 逐行映射、增量对拍)
  • e77ece63 T04/T05 评审修复(让位规则 :not 防雷、契约台账坐实、wrapper margin:0、A86 登记)
  • f5bd1070 T07 消费端收口(mapContentOffsetToDoc token 逐行折算、组合验证)
  • 02bc0935 T07 评审微修

流程与质量

implement-spec 后台编排:每票实施后双轴 code-review(Standards + Spec,钉死提交区间只读评审),发现全部闭环——评审净捕获 1 契约台账登记失实(补断言坐实)、1 特异性雷(让位规则将在引用内代码卡上复现行号甩出盒外,修复有前后取证)、1 增量坐标残留真缺陷;登记不修项均有理由留档。

验证

  • 全量单测 10180 用例 + node --test 196 绿
  • callout 族 + codeCardChrome/codeCardClickOffset/mermaidPaint 浏览器套件绿(含 wrapper 组合场景:行号入盒、token 对位、20 同坐标点击、折叠往返、复制剥前缀内容、增量编辑)
  • check:stylecontract 八项零失败(target token 只增、免重锚)
  • 人工验收:manual-verification.md 新增 A86(组合观感存疑四点)

遗留(不随本 PR)

#676(calloutFold 九段 re-init 根因)、#677(双主题截图 + 热更新测量刷新)、P2(引用内列表/表格/图片/嵌入 wrapper 回归,未开票)。

Close #669
Close #670
Close #672
Close #673
Close #674
Close #675

用户发布后观感复核提出四项 Live 形态差距,本轮完成方案探查与开票,
不含生产代码变更。

## 探查结论(真实 Chromium + 生产控制器 + 产物 CSS)

- **行级垂直 padding 落点竞态**:给 callout 标题行注入真实
  padding-top/bottom 后行盒高度 21px→39px,同一坐标的点击落点在两次
  独立运行中分别命中第 3 行与第 4 行。CM6 按真实 DOM 高度记账,
  浏览器异步布局造成高度表与 posAtCoords 之间的窗口期。据此否证
  「把 --callout-padding 上下分量直接落到 .cm-line」的直觉方案。
- **引用内围栏/公式块零加工**:围栏行有 .vsidian-code-line 底色但无
  语言标签/高亮/行号;公式块完全不渲染。成因是 mermaid.ts 的
  indentColumns 只计空格与 Tab、math.ts 用 trim 后 startsWith('$$')。
  进一步查明「剥前缀即可」不成立——会触发 replace 区间重叠、block
  widget 定位到引用前缀、缩进列对齐三处冲突。
- **嵌套 callout 无层次**:data-callout 取最内层导致外层正文行被染成
  内层类型色,各层 padding-left 同为 24px 无深度区分。
- **两项待决策**(整标题点击折叠、光标进入退化引用块)经核对与
  callout.md §4.1 既有决策直接冲突,按用户要求本轮不动。

## 开票

批次总票 #668,子票 V01/#669、V02/#670、T02/#671。V01 与 V02 为有
明确退出条件的验证票,不以票关闭代替结论通过。

## 文件树

docs/research/callout-live-refinement-probe.md 经 file-tree 技能登记
(tree_tool.py add + check --strict)。check --strict 残留三项告警
(codeCardClickOffset.mjs / codeCardClickOffsetFixture.ts /
calloutCommands.test.ts)为 main 基线已有漏登记,见
docs/specs/integration-test-groups.md,不在本次范围扩大修复。
不同类型 callout 的标题此前与正文同色,只靠图标形状区分。原因是标题行
只读 --callout-title-color(默认 inherit),缺「标题容器取类型色」一层。

## 实现

按 Obsidian 1.14.4 app.css 的两层分工对齐:
- 标题层 `.callout-title` 取 `--callout-color`(类型色)
- 内层 `.callout-title-inner` 取 `--callout-title-color`(保持 inherit)

关键取舍:**不把 --callout-title-color 的默认值改成类型色**。该变量是
用户片段覆盖标题文字的入口,改默认会破坏其语义;两层各司其职,覆盖
前者只改标题文字、不动类型色。Live 与阅读两侧同款结构,同一
data-callout 值两端计算色一致。

## 联动生效

`calloutMenuPreview.paintTypeRow` 本已有「标题色 ≠ 基准色才落菜单文案」
的分支,因两者此前恒等而从未走到;本票后自动点亮。

## 测试

TDD 先红后绿:
- `calloutCssContract` 扩 3 例(标题层类型色 / 内层保 inherit 语义 /
  阅读侧两层结构),改前 3 红、改后 21/21 绿
- `calloutTypes` 浏览器套件扩绘制层断言(27 类型标题计算色各自等于类型色、
  内层继承、至少 6 种不同色、片段覆盖 --callout-title-color 只作用于内层
  而标题层不变、Live 与阅读两端同值一致)

其间修了两处自引入的测试缺陷:变量名与文件既有 `overrideStyle` 重名;
Live 侧复检后未切回阅读模式,破坏后续依赖阅读态的嵌套用例。

## 验证

- 全量 vitest 10113 例:10109 通过,4 例 i18nBundleBytes 失败为
  「构建产物缺失」——`npm run compile` 后复验 8/8 通过
- `check:stylecontract` 八项零失败;样式指南 234 条目重新生成
- 浏览器 `calloutTypes` 全绿(27 类型 × 明暗 × 图标 × 嵌套/列表编辑 ×
  malformed × 阅读侧)

## 文档

styleContract 的 callout 条目 states 与 var-callout-color 条目 purpose
补标题着色语义;CHANGELOG Unreleased 记用户可见变更;人工验证清单登记
A85(明暗主题下 13 类型标题色可辨度、富标题链接可读性、片段覆盖观感)。
代理自检不等于人工验收。
V02(#670)验证完成:完整卡片形态在引用容器内不可行,降级形态可行。

## 关键更正(前序报告判断有误)

前序探查报告称「卡片 replace 与 QuoteMark hideDeco 同区间重叠,CM6 严格
禁止」——**这条是错的**。本轮独立复核(裸 CM6 四种区间形态在 Chromium
实测)确认:replace 区间重叠**不抛错,静默取并集**。源码层面
`PointDecoration.range` 仅在 `from > to` 或零宽 replace 时抛
`RangeError`,与重叠无关。

前序报告对缩进偏移的归因也不准确:不是「缩进值算错」,而是 **CSS 特异性
平局**——callout 规则与卡片 edge 规则同为 (1,5,0) 且靠后胜出,抢走中间
代码行的 padding-left 而 text-indent 存活。故调 --vsidian-code-indent 修
不好(两处引用同一变量,差值恒定 14px)。

**结论不变但依据更换**:完整卡片仍不可行,真正原因是——
1. block widget 宽度由 .cm-content 决定,卡头横带在引用内必然跨出容器
   左缘(实测 x=70 vs 容器内容 x=94)
2. 上述特异性平局

## 降级形态

只发语法高亮可行且零缺陷(零 replace、零缩进计算、零行号列),代价是
丢弃卡头横带与行号。是否采用待决策。

## 公式粒度修正

「引用内公式不渲染」需分开看:行内 $x^2$ 与单行 $$x^2$$ **已正常渲染**,
只有多行 $$ 块不工作。前序报告笼统列为一项,现按实测细化。

## 文档

- 新增 docs/research/callout-live-refinement-probe2-v02.md(经 file-tree 登记)
- 更正 probe.md §3.3 第 2、3 条,加 2026-10-31 更正块并指向 V02
- perf/2026-09-mermaid-rendering.md 已知限制第 1 条改写(原文「剥前缀即可」
  不成立)
- perf/2026-09-math-rendering.md 已知差异补公式粒度说明

src/ 零变更(V02 为验证票,只产出结论)。
V01(#669)验证完成:四路线实测,选定路线 D(块级间隔 widget)。

## 关键更正:落点偏移不是竞态,是确定性失效

前序报告称行级垂直 padding 的落点偏移是「浏览器异步布局竞态」——**归因
错误**。实测同一坐标连续 20 次点击,热态下 20/20 全部错行到下一行,3 秒
内模型偏差恒为 24px 不变。这不是抖动。

真正根因是 **.cm-content 的 min-height: 100% 高度门控**:CM6 的 measure()
只在 contentDOMHeight != domRect.height 时重测行高(源码 @codemirror/view
6362 行核实)。短文档内容被钳在视口高度,给行加 padding 不改变 .cm-content
自身高度,模型永不重测。长文档超出视口反而不受影响——意味着**短笔记(
callout 主要场景)必然踩坑,而手工打字时看起来正常**(真实键入产生事务
会置 mustMeasureContent)。

生产现成的 scheduleSnippetMeasure 对该问题完全无效。

归因差异影响取路:若是竞态,等待或补重测即可;既然不是,必须换承载层。

## 四路线判定

| 路线 | 落点 | 承载间距 | 判定 |
| 真实 padding | 热态确定性 FAIL | 是 | 不通过 |
| 伪元素撑高 | 同型 FAIL(越 strut 后) | 是 | 不通过 |
| 绝对定位伪元素 / box-shadow | PASS | 否(零间距) | 不满足需求 |
| **块级间隔 widget** | **全矩阵 PASS** | **是** | **通过** |

选定 D:唯一同时满足真实间距与落点确定性,且间隔可放在标题行与正文首行
之间(实测间距 7.25→15.25px),直接对应「标题与正文无留白」这条需求。
构建成本与基线持平(2101 行/700 callout:init 119ms vs 基线 120ms)。

实施前提 5 条(widget 须经 StateField、需自备底色、间隔区不可放光标、
--callout-padding 上下分量映射、折叠时同步退场)已写入报告 §5.2。

## 顺带发现:嵌套是既有缺陷,不只是观感

data-callout 一旦被内层覆盖就不恢复,三层嵌套下外层尾段被染成最内层
类型。后果:既有片段 [data-callout='note'] 只能命中第 1、2 行,「给最外层
加样式」的片段无法达成。推荐逐层通道 data-callout-lN(零破坏既有片段且
能修复该缺陷);深度类方案给不了类型归属。

## 文档

- 新增 docs/research/callout-live-refinement-probe2-v01.md(file-tree 登记)
- 更正 probe.md §2.3 竞态归因与 §4.2 嵌套说明

src/ 零变更(验证票只产出结论)。
V01/V02 报告的 tree.json 登记已提交,但渲染产物 AGENTS.md 的简版树块
漏在暂存区外。本提交补齐,使 tree.json 与渲染结果一致。
- 验证 CM6 原生 BlockWrapper(@codemirror/view 6.43.13)在生产
  WebviewSyncController 链路上承载可编辑 callout 与完整子块
- 结论:路线条件可行;V02 两条硬约束(block widget 宽度归属、
  CSS 特异性平局)被 wrapper 结构性化解,引用内完整代码卡 +
  多行公式组合实测通过(20 次点击口径)
- 钉死机制事实:行归属两端含端点须行对齐区间、边界空间入
  heightmap 记账而垂直 margin 不入(长文档确定性错行对照实验)、
  Lezer 嵌套 Blockquote node.to 吃外层尾行(data-callout 内层
  胜出既有缺陷的根源实证)、widget 在 wrapper 内部不分裂
- 记录实施前置清单(margin 禁令、区间派生口径、扫描器前缀
  剥离蓝本、liveMath 标记锚点适配、token 逐行映射、公开契约
  迁移)与视觉缺口(公式源文泄漏、高亮错位、行号盒外定位)
- 探针件一次性已删;三轮日志与截图留存 out/test/callout-wrapper/
  (gitignored);临时扫描器补丁已回滚并复跑验证无残留
- 用户复核 s3 截图提出两点:盒内边距观感缺失、代码行号向左支出盒外
- 视觉子代理逐像素复核 + DOM 级 computed 测量(临时补丁重建 bundle
  实测后已回滚,工作树干净)双路钉死成因
- 行号支出 = 悬挂缩进塌陷:行级卡 padding-left 与 text-indent:-38px
  两式不同源(quiet/探针规则清零前者、后者存活),首行起点被拉到
  行盒外 38px,行号甩出 wrapper 盒;与 V02 特异性平局同族,
  迁移时两式必须同源消费 --vsidian-code-indent
- 内边距观感 = 两层反差:wrapper 外框留白充分(26/26/14/14),但
  行级 quiet 背景块内部左 0-1px、上 3px、下 4px 贴边——上下分量
  按现行纪律不落行(行级类不改行高),容器背景上移 wrapper 是必修项
- 两项从「样式迁移设计项」升格为实施票必修
实施前复核发现 §2.4/§5.2 的关键定性错误:嵌套 Blockquote 内层节点 to
覆盖外层尾行不是 Lezer 缺陷,是 CommonMark 懒延续(带较少 > 的行剥去
外层标记后可延续内层末段)。证据:test/unit/calloutParity.test.ts
F17/F38/F44 以 markdown-it token map 双端对拍钉住同一区间,Reading 同
渲染在内层;T01 syntax-parity.json F17 同型。

- 撤回「data-callout 内层胜出是既有缺陷」判定;V01 §4.1 真实遗留诉求
  是分层样式可达性(data-callout-lN 类提案),归样式契约票
- 撤销 §5.2「引用深度向下扫描」派生方案:它把懒延续行截到外层,与
  Reading 分叉。改为直接消费解析器节点区间(from 对齐标题行行首、to
  取尾行行尾),列表内 callout v1 不接 wrapper
- §3 S1 与 §7 同步标注勘误口径
#672(#668 批次):把探针验证的容器结构接入生产——新模块 liveCalloutWrap
以 StateField 派生 wrapper 区间,经 EditorView.blockWrappers 装配(块级
结构禁止插件发射,StateField 是 CM6 唯一合法通道)。

区间口径(探针报告 §5.1/§5.2 勘误后):
- 直接消费解析器节点区间(识别单一事实源 calloutOfBlockquote):
  from 对齐标题行行首(内层 node.from 落在第二个 > 上,直接使用会使
  内层标题行逃出内层盒——探针 S1 实证)、to 取节点尾行行尾
- 懒延续行(含带较少 > 前缀的外层行)留在内层容器,与 Reading 双端
  一致(calloutParity F17/F38/F44)
- rank = 60 − 10 × 引用深度(外层大内层小);树复用
  liveDecorationsField 增量结果,纯选区事务不重建
- 边界:列表内 callout 与引用嵌入实例不接 wrapper(v1 维持行级形态);
  frontmatter 区域 fmEnd 守卫

装配:syncController.rootOwnedViewExtensions(根正文独有);结构层只挂
内部类 vsidian-callout-wrap + data-callout-depth,公开类名与视觉迁移归
T05(#673);wrapper 禁垂直 margin 纪律见报告 §5.1。

测试:
- 单测 liveCalloutWrap.test.ts 14 例:纯函数矩阵(嵌套/懒延续/兄弟/
  列表排除/紧贴降级/fmEnd)+ 增量对拍 + 纯选区不重建 + rank
- 浏览器套件 calloutWrap:结构/嵌套/懒延续归属、4×20 同坐标点击、
  标题行首击(光标进入后标记显形改行几何,连击属显隐语义——实测钉住)、
  wrapper 内真实键入、热样式结构保持 + 模式往返冷重建后 padding 记账
  精确、长文档视口入场(先滚后等——ADR-0005 视口外不实例化)、零页面错误
- 回归:calloutPaint/Types/Fold/Plan/Icon/RefEmbed/Menu 7 套件全绿

报告同步:S1 热样式结论收窄——运行中改 wrapper padding 短文档下
coordsAtPos↔posAtCoords 不自愈(scroll/空事务/视口 resize/沉降点击实测
无效,偏移恰为新增边界空间),冷重建后恢复;片段热更新测量刷新为 T05
设计项。fixture init 版本自增(同版本 init 去重,对齐宿主协议)。

Close #672
#673(#668 批次):非列表内 callout 的容器视觉从行级拼贴迁 BlockWrapper
承载,公开契约同步迁移(探针报告 §4.4「内边距没留」的根治)。

契约迁移(style-contract 流程:修改前已固定旧契约条目,无入口删除/
降级,check:stylecontract 8 项零失败,无需基线豁免重锚):
- wrapper 挂 .callout 主类 + data-callout 类型 + data-callout-depth
  (公开分层入口:嵌套 wrapper DOM 天然承载 .callout .callout 后代
  选择器——V01 §4.2 data-callout-lN 提案免新增属性族)
- 行级让位:非列表内 callout 行不再挂 .callout 与 data-callout(防
  片段双命中/双绘制);.callout-title/.callout-content/quiet/圆角行类
  照挂(quiet 只承担紫条静默)
- 嵌入保护:calloutWrapFacet 开关驱动发射让位——引用嵌入实例不装配
  wrapper(行级全形态保留),修复首版「嵌入视图既无 wrapper 又无行级
  视觉」的裸形态缺陷
- 列表内 callout v1 维持行级全形态(边界如实登记)

CSS:wrapper 消费 --callout-padding 四向真内边距、border 三件套四边
完整(此前 Live 仅左缘近似)、圆角、双通道底色——与阅读容器同款;
wrapper 禁垂直 margin 纪律写入条目(探针 S1b/S1c);blend 仍不承诺
Live(边界登记)。热更新测量刷新边界实测(styles 变更坐标映射不自愈)
写入条目 states。

条目与指南:callout / var-callout-color / limit-callout 三条目
purpose/dom/states 修订 + 英文文案同步;gen:styleguide 产物重生成。

测试:
- 单测:liveCallout 断言迁 wrapper 契约(+嵌入形态保留用例)、
  liveCalloutWrap 补 13 类型/别名/未知类型矩阵;受影响面 165+31 例全绿
- 浏览器:7 个 callout 族套件断言迁移后全绿(行级 data-callout 断言
  改 wrapper/嵌套 DOM 承载;calloutIcon 边框断言升级为四边完整消费)
- 发现并修复 fixture 既有 bug:calloutFold/calloutWrap fixture init
  版本恒 1 被宿主协议去重(多段 re-init 一直在旧文档上跑);calloutFold
  九段随之暴露「长流程后 re-init 失效 + reading 挂载窗口依赖」——
  九段显式 SKIP(不静默降级),根因独立跟踪 #676
- 外围:codeCardClickOffset / chromeContract 零回归

Close #673(热更新测量刷新的工程接线与双主题截图对照随 T05 收尾票补,
当前边界已如实写入契约条目)
#674(Callout Live 收口批次):把 BlockWrapper 探针 S3 验证过的「剥引用
前缀识别」从临时补丁落成生产代码——引用内围栏与多行公式此前不识别
(遇 > 前缀整行跳过),是 #670 完整渲染的内容前提。

- src/shared/math.ts
  - 新增引用前缀工具单一事实源:stripQuotePrefix(剥全部层,返回裸行/
    层数/剥除长度)与 stripQuoteLayers(剥恰好 n 层,不足返回 null),
    每层 `>` + 可选一个空格(CommonMark blockquote 标记消耗口径)
  - 新增 ContentLineMapEntry:扫描产物内容段 → 原文行偏移映射条目
    (折算式 lineStart + prefixLen + (offset − contentOffset)),T07
    token 着色与装饰锚定的换算输入,随扫描产物一并产出
  - scanMathRanges 块模式前缀感知:开启判定输入裸行(from/to 折算回
    全文坐标、tex 剥前缀);内容/闭合行剥开启行层数,层数不足的断开行
    原样吃进(跨容器延续——对齐 @vscode/markdown-it-katex 的 src 级
    贪婪,实测 `> $$\nx\n> $$` 插件 content 含断开行);行内路径一行
    不动(原行原坐标),MathOccurrence 增 lineMap(行内命中为空数组)

- src/shared/mermaid.ts
  - scanFencesDetailed 前缀感知:识别输入为剥前缀裸行(缩进/围栏判定
    口径不变),from/to 保持全文坐标、code 剥前缀;开闭同容器——闭合
    行剥开启层数后须是纯闭合围栏,层数不足即容器断开、未闭合终止不产出
    (对齐 CommonMark 核心规则:markdown-it 引用内 fence 断开处自动
    闭合,live 降级显源码方向安全),断开行落回普通重扫不吞行
  - FenceSpan/OpenFence 增 lineMap,OpenFence 增 depth(跨批续扫的同
    容器判定依据);前缀工具与映射条目复用 math.ts,不建第二份

- src/webview(消费方接线)
  - liveMermaid/liveMath 增量重建的窗口外保留项携带 lineMap,且锚点
    lineStart 随编辑 mapPos 映射(与 from/to 同源——liveMath 既有
    编辑序列对拍暴露过锚点残留旧坐标的缺陷,已修并有钉子用例)
  - liveMath scanOpenIncrement 开启/闭合判定改用剥前缀裸行(增量
    延伸与全量扫描对 `> $$` 同口径)

- 测试(TDD:先红后绿,两矩阵 21 个新用例先行失败后转绿)
  - mermaidFence/mathScan:1/2/3 层与不定长前缀、> 无空格、同容器
    开闭、未闭合降级、字面 >(含顶层围栏内容行不剥钉子)、相对缩进
    0-3/4 列与 Tab、跨扫描窗口与跨容器边界续扫、lineMap 逐段锚定
  - liveMermaid/liveMath:引用内固定编辑序列(前缀加深、容器断开、
    闭合删除、行内共存)每步增量 vs 全量逐字段对拍;窗口外保留项
    lineStart 映射钉子
  - readingMath/readingMermaid:同例双端对拍一致(含容器断开延续);
    三处已知差异如实钉住不追赶——空内容块阅读渲染空公式(既有差异随
    前缀平移)、引用内 Tab 阅读出 fence(markdown-it 引用内不折算
    4 列,live 保守不识别)、容器断开围栏阅读自动闭合出空容器

Close #674
T04(#672)/T05(#673)code-review 可执行项收口,含一处防雷与两处契约
半边补实;登记不修项见正文末。

## 样式(src/webview/main.css)

- **T05-P1 让位规则排除代码卡行(防雷)**:T06 起引用内围栏被扫描器识别,
  callout 内代码卡内容行同挂 quiet + code-card-line,行级让位规则
  (1,5,0) 命中会清零卡行规则 (1,4,0) 的 padding-left 而负 text-indent
  存活——悬挂缩进塌陷、行号甩出 wrapper 盒外、卡底色一并被清(探针
  报告 §4.3 形态,一次性探针实测复现:修复前行号 x64 甩出盒左缘 x70、
  padding-left 0px / text-indent -38px)。让位规则追加
  :not(.vsidian-code-card-line) 排除后实测恢复同源对(38px/-38px)、
  行号入盒、卡底色回归;紫条回归基础引用规则,与「普通引用内代码卡行」
  同形态(T06 统一语义),观感复核点登记 A86。
- **T05-P2 wrapper 容器规则补 margin: 0**:探针 S1b/S1c 钉死的垂直
  margin 禁令此前只有契约注释半边——常见 Obsidian 片段
  `.callout { margin: 10px 0 }` (0,1,0) 命中 Live wrapper 会触发确定性
  点击错行;规则侧显式归零后片段 margin 不再进入落点记账。

## 契约(src/shared/styleContract.ts + styleContractEn.ts,指南产物再生成)

- callout 条目 purpose/dom 同步登记上述两处接缝(双语):margin 禁令的
  规则半边、让位规则的 :not 排除与卡行规则族的承载关系。条目 target
  与类名 token 未动,无需基线重锚(entry-comparison 零失败)。
- 指南产物随 compile 链再生成入库(styleGuideData.ts / style-reference.*)。

## 测试

- **T05-S1**:calloutCssContract 补 wrapper 两条规则的契约断言(容器
  margin/padding/border/radius/双通道底色 + 让位规则 :not 防雷与四项
  让位声明)——契约条目 verification 已登记的「T05 wrapper 容器视觉与
  行级让位」单元覆盖落为真实存在。
- **T04 评审四项**(liveCalloutWrap.ts):删自建 WRAP_DESCEND_NAMES 改
  import liveDecorations 导出的 CALLOUT_CONTAINER_NAMES(消除可漂移的
  第二份集合);descend else-if 分支恒真参数简化为直传 true、inList 时
  先判再识别(跳过列表内声明白扫描);calloutWrapRank 深度边界登记
  (CM6 侧 clamp [0,100] 使 >6 层饱和 0,同 rank 嵌套由区间 tie-break
  维持——rank 未写入公开契约,不预钳制);浏览器 calloutWrap 补列表内
  正文行 wrapDepth=null 直接断言(此前仅由 count=3 间接排除)。

## 文档

- **T05-P3**:manual-verification 登记 A86——探针 §4.5 存疑项(复制
  按钮图标可辨度、标题旁小蓝点成因)与修复后新形态(卡行紫条、嵌套
  观感)的人工验收条目。

## 登记不修(评审裁定,不在本提交范围)

- T05-S2 列表排除两处判定形态不同(遍历 flag vs path 数组,注释已声明
  同口径)——等列表内 callout 接 wrapper 票统一;
- T05-S3 emitForRange 16 参收拢——独立重构票;
- T04 区间换算下沉 shared——两行收益小;
- T05-P4 双主题截图 + 热更新刷新——由编排层开票。

验证:compile 零错误;定向单测 95 例全绿(calloutCssContract 23 +
liveCalloutWrap 15 + liveCallout 31 + styleContract/styleGuideGen 26);
check:stylecontract 八项零失败;浏览器 calloutPaint/calloutIcon/
calloutTypes/calloutWrap 四套件通过;防雷探针 before/after 取证落
out/test/callout-codecard-probe/(日志 t05-review-*.log)。
#675(Callout Live 收口批次末票):T06 让引用内围栏/公式被扫描识别后,
消费端 token 着色仍按「行首即裸内容起点」直加映射,第二行起错位逐行
累积(探针 §4.2 实证);math 装饰锚定经生产装配实证已被 T06 的 from/to
前缀折算顺带覆盖(探针 §4.1 泄漏系当时补丁形态),本票钉住并在 wrapper
下完成组合验证。

- src/shared/math.ts
  - 新增 mapContentOffsetToDoc:裸内容串 offset → 原文全文 offset 的
    逐段折算(ContentLineMapEntry 语义的单一消费入口),FenceSpan 与
    MathOccurrence 两族内容段共用,消费端不建第二份映射;二分查找,
    长块 token 总量 O(n log n);空 lineMap 返回 -1(调用方丢弃)

- src/webview/liveCodeCard.ts
  - token 着色改逐行前缀感知映射:seg.from/seg.to 经
    mapContentOffsetToDoc(fence.lineMap, …) 折算回原文坐标,替换
    openLine.to + 1 + tokenOffset 直加(引用内每行前缀不等长且逐行
    累积错位;顶层无前缀时折算与直加等价,零回归)

- src/webview/liveMath.ts(无实现改动,实证 + 钉住)
  - 生产装配浏览器探针实证:引用内多行公式整块被跨行 replace 覆盖、
    KaTeX 成型无源文泄漏(textContent 中的源文是 KaTeX annotation 的
    正常组成);探针 §4.1 的泄漏系当时临时补丁未折算 from/to,T06
    生产实现已正确——本票以单测钉住锚定语义,不重复实现

- 测试(TDD:token 矩阵 4 用例先红——『> con』右移与跨行累积错位,
  实现后转绿)
  - liveCodeCard.test:引用内 token 对位矩阵(一层前缀两行、> > 与
    > 无空格不定长、内容行缩进折算、空内容行零长段、顶层对照)
  - mathScan.test:mapContentOffsetToDoc 纯函数契约(段内/段尾归属、
    零长段不劫持、空表 -1、FenceSpan 同语义折算)
  - liveMath.test:引用内锚定矩阵(多行块 replace/mark 从开行 $$ 到
    闭行 $$ 尾不吞开行前缀、行内原行坐标、单行块段内折算)
  - calloutWrap 浏览器套件扩 T07 组合场景:引用内代码卡 + 多行公式 +
    嵌套 callout 单一 wrapper 承载;绘制层断言卡 chrome/行号入盒
    (T05 防雷)/token 对位/公式无泄漏/前缀全隐/尾部不吞(S3);
    20 同坐标点击、折叠展开往返、复制内容剥前缀、增量键入与删字符
    后装饰仍对;截图留证 out/test/t07-callout-combo-*.png

已知边界(如实):点击序列中光标离开代码块时围栏行由显形恢复清空、
行高变化致下方行上移是显隐语义(非 wrapper 缺陷),套件按「几何落地
后再连击」编排;公式 widget 点击定位落在块端点是 CM6 inline replace
的 posAtDOM 语义。

验证:compile 零错误;单测全量 10180+196 全绿(分支单测终检);浏览器
codeCardChrome/codeCardClickOffset/mermaidPaint/calloutWrap 四套件
通过(token 对位与公式无泄漏断言含绘制层)。

Close #675
T07(f5bd1070)code-review 三项轻微发现的处置:

- mathScan 手算注释钉正:闭行前段 lineStart 误写 16,实为 17
  (17 = 第 3 行行首 11 + 行长 5 + 换行 1;16 是第 3 行末换行符
  位置),改为正确坐标并就地注明换算依据。其余行(0/5/11)与
  FenceSpan 注释(8/22、offset 12)逐项复核无误,测试断言本身
  引用实际计算值不受影响。

- calloutWrap combo 场景补 emptyFenceRows 断言:该字段此前是
  evaluate 返回但未断言的死观测。实测取证(2026-10-31,报告
  out/test/browser-runs/run-vz15HW/)确认文档 13 行无空行时空
  文本行恰为 2——正是两个围栏行(```js / ```)被 replace 清空
  的形态。补 `equal(2)` 断言钉住:quotePrefixed 只抓 > 残留,
  围栏行 replace 失效时 ``` 残留不以 > 开头会逃过既有断言,此
  处是唯一观测点。

- 「换行」项登记为未验证、不在组合场景补断言:Live 代码卡
  chrome 只装 copy/fold 两键(liveCodeCard.ts),buildWrapButton
  仅阅读侧(readingCodeCard #191)消费——Live 引用内不存在
  「卡内换行开关」入口;且观测 wrap 需长行文本,改 T07_DOC 文
  本会波及 linenos/keywords/copy 等一串锚定断言,成本超出一个
  断言。#191 折行本体已由 codeCardChrome.mjs 顶层(阅读态
  nowrap 联动)覆盖,引用内 Live wrap 形态留待编排层在 #675
  关闭评论记录。

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 审查 · 首审 · R1

仓库/PR:#678
快照:head 02bc09351668e05eb3bc1cdf5a90584332bf77ac;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。45 文件,完整 Git 工作树;先核对 reviews/全部原线程为空,发布前仍是同 head/open。
依据:#668、#672–#675 及其修订评论,#676/#677 边界;本 head AGENTS.md、style-contract 技能、callout 规格与 ADR-0023;用户指定 PR 发布规范。

结论

已完成两轴亲审,确认两项实现问题,见本轮行内线程。全量单测通过不覆盖这两种输入边界。本 COMMENT 不是合并批准或完整宿主/视觉验收。

Spec

  • vsidianPR678-001 · P2 · exists:wrapper 的后代让位规则误清除其内部列表 Callout 的保留行级视觉。
  • vsidianPR678-002 · P3 · exists:续扫将一个空内容行当零行,新增引用围栏的增量渲染/复制丢掉首个空行。顶层同类缺口基线已有,归本次新增能力的验收遗漏,不冒称全新底层回归。
  • 容器区间消费解析器节点、行对齐、懒延续归属与 Reading 一致;不恢复已撤回的“解析器区间缺陷”判断。列表/嵌入不装 wrapper、标题文字编辑/箭头折叠与光标行为的既定边界不因本轮扩展。
  • 扫描产物随行携带映射、窗口外 lineMap 随 changes 平移;token 消费使用同一折算入口。除上述002外,原定向矩阵通过。公式跨引用边界的贪婪口径与围栏不同,按既有 Reading 引擎区分,不误合并两套规则。
  • #677 热 padding/border 更新后的坐标刷新未完成,只有冷重建后精度;不能把当前浏览器脚本的模式往返对照写成热更新直接通过。引用内 wrap 组合、列表/表格/图片/嵌入回归与 A85/A86 仍有明确未验范围。

Standards

未另登记独立新 Standards 缺陷;样式类名/变量/指南生成链有对照,检查器通过不等于 DOM 关系与绘制兼容全部成立(001即反例)。
保留以下未闭环证据边界:

  • #676 九段 re-init/挂载问题以显式 SKIP 绕过,末尾“全部通过”不表示该场景执行;旧 fixture 同版本去重造成旧文档上断言的历史不注销。这里已有独立票,不重复创造根因或宣称产品根因已知。
  • perf 文档仍包含 V02 时“完整卡不可行/只高亮待决策”和引用块未渲染的阶段性文字,应结合后续 BlockWrapper 报告与本 PR 理解,不能据旧探针宣布当前能力不可行,也不能把阶段报告当验收。
  • 未将票面“用户授权”转成新的推送、合并、重跑或发布权限。

本方验证

Linux Node24.22.1,完整精确 head 工作树:

  • compile(生成器/esbuild/tsc)通过,生成产物无跟踪文件变化;git diff --check通过。
  • Vitest 10177 passed / 3 skipped(443 pass文件、1 skip文件);Node 189 passed / 7 skipped,共196,不写“196全部通过”。
  • check:stylecontract 8项通过;本地部分新tag未获取有明确warning,未据此确认新版本发行。
  • 全量使用既有依赖目录,逐项比对 lock 所有非optional包版本无差异;随后独立临时安装锁定版本/完整性(只将下载host换为官方npm,产品lock未改),当前11个相关测试文件 363 passed,base相应10文件 293 passed。
  • 额外生产 scanner/StateField/header载荷探针确认002;原wrapper区间/行装饰输出加受控DOM与CSS层叠对照确认001。不是物理剪贴板、真实输入或浏览器绘制验证。
  • 首次依赖安装因默认cache目录不可写/下载与安装目录冲突失败保留,独立新目录与可写cache后成功;不是产品失败。自制StateField探针首次混入两份CM state报Unrecognized extension,统一同一模块后完成复现,首败保留。未改产品代码。
  • 浏览器 calloutWrap 启动首次因缺Chromium失败;官方浏览器下载得到无效/截断ZIP,安装未完成。本方未运行成功真实Chromium/VSCode/Windows、物理鼠标/IME/截图或10万行性能;作者浏览器成功记录不计入本方。
  • 精确head CI 41207424198仍在运行,已见style-contract/API/text-appearance/敏感组成功,主browser/unit/集成分片尚未全终态;继续观察,不重跑,不称全绿。

所有测试首败与基线保留。本次只发 COMMENT 与两条行内,不自动 resolve。

Comment thread src/webview/main.css Resolved
Comment thread src/shared/mermaid.ts Resolved
人工验收(2026-10-31)两项反馈修复:

- 多行选区只显光标行 `>`(Obsidian 为选区覆盖行全部显形):
  liveDecorations 新增 selectionRevealsLineMarkers 谓词——空选区
  维持 #296 端点语义(层级编辑入口不变,callout 标题 marker 保持
  整行区间),非空选区与所在行相交即显形该行源文标记;表格上下文
  刻意不随改判放宽(格内拖选跨格纳入引用符号是 #296 三轮已修缺陷,
  表格三处前缀谓词与 QuoteMark 于表格行维持纯端点语义——表格行
  形态按 GFM 树实测 nextSibling/parent 为 Table 判定,path 不含
  Table)。QuoteMark/ListMark/callout 标题 marker 三处换用。
- callout 代码块内换行不补 `> `(裸行掉出引用容器):
  listEditing 的代码上下文排除改为「仅顶层(行无引用前缀)」——
  引用内围栏行 Enter 延续完整引用前缀(嵌套 `> > ` 同理);
  顶层围栏维持 #119 字面编辑边界不动。

测试:listEditing/liveDecorations 各加 describe(红→绿:引用内
围栏延续 2 例 + 顶层不接管钉住;选区覆盖 3 例 + 空选区分寸/表格
端点/callout 标题钉住 3 例);全量单测 EXIT=0;浏览器
calloutPaint/calloutTypes/calloutWrap/blockquoteTablePaint 绿——
其中两处「拖选逐字节等于源区间」断言改覆盖语义(from 精确、
to 容差 1:拖选路径标记显形右移、释放像素映射左偏的机械伴生)。

规格:blockquote-table.md 补端点语义范围改判记录(非表格行)。

关联 #668(批次)、A86 人工验收
人工验收判定:卡行左缘紫条是双重强调——卡片自带边界视觉(底色/
边框),Obsidian 的 callout 内代码块亦无标记条。基础引用行规则
(#143 紫条/左内边距/底色)加 :not(.vsidian-code-card-line) 排除
卡行;与 T05 让位规则的 :not 防雷互为姊妹排除(卡行不受任何引用
行基础视觉作用)。

契约:quoteBar/callout/headingPaint 三处 CSS 契约断言的选择器
形态同步;check:stylecontract 八项零失败(token 只增,免重锚)。

manual-verification:A86 转「部分验证」,登记本轮处置(③移除 +
选区覆盖显形 + 围栏换行延续)与待续验项(①②④)。

关联 #668(批次)、A86-③

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R2 亲审增量

Head 66e461096f8a9e69d20449e672ffd5205efe4bbf;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。对R1的02bc0935新增2提交12文件,已核对原reviews/全部线程。

Spec

  • 新增 vsidianPR678-003 P2 exists:引用围栏内形似列表的代码被当Markdown列表续写,生产EditorView/jsdom对照复现,见本轮行内。
  • 001列表内Callout被wrapper让位规则清空、002空内容行续扫漏换行均仍exists;相关根因代码未改,范围未变,不重复原线程评论。
  • 非表格选区改为覆盖行显形、表格保持端点语义,以及代码卡移除引用紫条,与本轮更新规格/人工反馈记录相符;不把作者人工验收记录冒充本方视觉验收。A86①②④、#676/#677边界继续保留。

Standards

未确认额外独立Standards缺陷。两项浏览器拖选断言放宽为终点左偏≤1,已在规格登记,但本方未独立验证像素偏移因果或真实拖选体验,不能因此宣称真宿主回归完成。

验证

本方Node24.22.1、精确Git工作树:相关5文件Vitest 167pass;compile通过;diff --check通过。复用依赖目录,锁文件全部非optional包版本逐项相符。003追加原EditorView/jsdom探针确证自动插入列表mark,旧head不接管;另一个空代码行探针两版均返回false,不能误当新回归。
首次命令指向已不存在的旧deps目录失败;改用版本核对后的目录。首次compile被本方临时探针未使用import阻断,移出探针后原产品compile通过,首次日志保留,非产品失败/flaky。无产品代码修改。
未重跑全量、真实VSCode/Windows/IME/物理键盘/剪贴板或本机Chromium绘制;云浏览器限制保留。CI run41218289253当前12jobs成功、browser仍运行,将继续核验终态,不重跑CI。旧head13/13成功保留,不能覆盖新增问题。

本次COMMENT不表示required approval或合并批准。

Comment thread src/webview/listEditing.ts Resolved
用户验收反馈(2026-11-01):长按 backspace 删空引用/callout 正文后,
OS 自动重复会继续一层层剥掉整段引用结构,需要防护。

- 判定信号:keydown 的 repeat 属性区分长按自动重复(true)与手动
  单发(false);经 capture 阶段原生监听记录(ViewPlugin 挂
  contentDOM keydown capture),无条件先于 keymap 冒泡处理。
- 防护点(stripListLayer 前置拦截,吞键无变更):
  1) 引用前缀右端(原将一次剥层);
  2) callout 标记右端(] 或吞并尾空格处,原将由默认路径逐字符吃掉
     [!type]);标记右端不在 prefixEnd,判定置于 prefixEnd 收口之前。
- 范围限引用结构(prefix.quote 非空):纯列表行剥层节奏不变;
  正文中间的真正内容删除不拦;选区/多光标/IME 组合维持不接管。
- 手动单发语义不变:前缀剥层一次一层,callout 标记手动删除仍为
  默认逐字符(增强为一次删整段标记留待反馈)。

测试:listEditing 新 describe 六例(红→绿:拦截 3 + 手动剥层/纯
列表不防护/正文不误伤钉住 3,装配补 keymap.of(defaultKeymap) 使
默认删除路径真实在场);calloutWrap 浏览器补真长按场景——CDP
Input.dispatchKeyEvent autoRepeat 连发删空后停在前缀、手动单发
剥层清空(Playwright keyboard 不产生 repeat,真实长按语义只能经
CDP 直发)。全量单测 EXIT=0。

规格:keybindings.md #119 段补防护语义。

关联 #668(批次)
逐条修复行级评审(R1/R2 三线程):

- **PR678-001(P2)**:让位规则误伤列表内 callout 的行级保留形态
  ——外层 wrapper 后代中的列表内 callout 行被清成透明/零缩进/无条,
  行级全形态(唯一容器视觉)消失。修:让位规则追加 :not(.callout)
  (wrapper 接管行在 wrapped 分支摘除行级 .callout,排除面精准);
  契约断言同步 + liveCallout 补「外层 wrapper 内列表 callout 行挂
  .callout」装饰断言。
- **PR678-002(P3)**:续扫把「一个空内容行」误当零行(code 空串
  歧义)——增量产物与全量分叉、复制载荷少换行。修:以 lineMap 条目
  数消歧(多行全空时 code 为 '\n…' 非空不歧义);补一个空行与多空行
  跨批对拍两例(评审复现路径)。
- **PR678-003(P2)**:引用内围栏把代码字面列表标记当 Markdown 续
  写(`> - literal` 行尾 Enter 误插 `> - `)。修:围栏成员资格按
  FencedCode 区间判定(链式判定漏裸 `>` 行——其 quote 属 QuoteMark,
  实测树形态钉住),ctx 携带 inFence;Enter 只延续 quote(规范补空
  格,有序/任务形态同禁),Backspace 不做结构剥层(纯字面)、长按
  防护点前移到 quote 右端;空代码行不走空项退出。补七例红→绿
  (含普通引用列表回归钉住)。

验证:全量单测 EXIT=0(新增 10 例);compile 绿;浏览器
calloutPaint/calloutTypes/calloutWrap/blockquoteTablePaint/codeCardChrome
五套件绿;check:stylecontract 八项零失败(token 只增免重锚)。
浏览器「外层 wrapper 内列表 callout」真实绘制断言随 P2 回归票
(引用内列表 wrapper 场景 fixture 改动波及既有坐标断言,另行落地)。

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R3 亲审复审

Head 878420b0a067db24b321ce5dd362e203ab148083;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。相对已审415148a3增量1提交7文件,原reviews/三线程及作者回复已读。

Spec

vsidianPR678-001/002/003均fixed(各原触发范围),已沿原线程分别补充证据,未resolve。001排除行级.callout保留形态,002续扫保留一个空内容行及复制载荷,003围栏字面mark不再做Markdown列表续写。未发现新增独立证实问题。

Standards

未发现新增独立问题。001真实绘制断言仍待后续场景覆盖;不得因选择器/装饰层通过就称浏览器视觉验收完成。#676/#677、A86其他观感边界保留。旧quoteBarPaint拖选断言失败不由这三项修复自动注销。

本方验证

Node24.22.1、精确Git工作树;相关4文件 145pass,compile及diffcheck通过。额外2项独立探针通过:原StateField增量/全量+实际HeaderWidget.code载荷对照;生产CSS选择器的DOM.matches保留/让位/代码卡三种分类。复用版本逐项核对相符的依赖,无产品修改。
未重跑全量、实际浏览器绘制/VSCode/Windows/物理剪贴板/OS长按;作者五浏览器套件成功是作者证据。前轮66e46109与415148a3的CI均12成功1失败,quoteBarPaint实际from4/to16、预期from4/to18的首败日志和artifact保留,未称flaky。
当前CI41220290364仍运行,继续只读核验终态,不重跑CI。本次COMMENT不表示required approval或合并批准。

CI browser job 的 quoteBarPaint 在 quote-list 场景断言失败
(to=16 vs 期望 18)。根因探针定量确认:A86 选区覆盖显形
(2026-10-31 用户拍板)使拖选中 QuoteMark 显形、正文右移一个
前缀宽(14px = 2 字符位),终点像素取自显形前布局故命中
to-2;quote 场景 from 贴 QuoteMark 右端、起始即显形无偏移,
故仅 quote-list 挂红。行为符合改判语义,断言残留 #143 时代
的逐字节口径——与 calloutPaint/calloutTypes 已改两处同型,
本文件当时漏同步。

- 断言改覆盖语义:起点精确命中 + 终点容差 ≤2(探针定量的
  显形前缀宽度折算字符位),注释记录依据与场景差异
- 本地复现红(run-A1IYpW)→ 修复后全场景绿(run-YuJ36W)
用户宿主验收(A87,2026-11-01)两项反馈:

1. 显形态的 > 与 [!xx] 以转义符式透明度弱化(opacity 0.55,
   随主题前景适配明暗)。liveDecorations 新增 syntaxMarkDeco:
   QuoteMark(含表格端点显形分支)与 callout 声明(含吞并尾
   空格)显形时发射;区间只包纯语法——标题文字与正文不进灰化,
   「不伤非语法部分」由区间来源保证。隐藏态照旧渲染 widget。

2. 行内代码加 1px inset 细边线(用户拍板方案 A):固定灰底在
   部分 callout 容器底色上对比不足,边线与容器底色解耦(VSCode
   官方 Markdown 预览的 code 同为底色+边线组合)。box-shadow
   inset 不占布局;Live(--vsidian-live-code-border)与阅读
   (--vsidian-reading-code-border,链结构对齐底色变量)双模式
   同步,底色维持不动。

- 单测:liveDecorations 新 5 例(显形灰化区间/标题不挂/隐藏态
  钉住/表格端点/正文不挂)红→绿
- 浏览器绘制断言(calloutPaint):拖选覆盖态 > 与 [!note] 的
  computed opacity=0.55、标题正文不进灰化;callout 内行内代码
  双模式 1px 边线 computed 在场、底色维持
- 全量单测 10210 例 / compile / 契约八项 / calloutPaint 全绿

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R4 亲审复审

Head 0acbc5be6fc1c3facae27716e8f98c706e193b9b;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。相对已审8e23d654为1提交4文件;发布前已复核open/head及reviews无并发新增,全部3原线程已读(作者已resolve,本方未操作)。

Spec

新增 vsidianPR678-004 · P3 · exists:阅读侧新增行内代码边线同时作用于pre里的块级code,与本提交限定行内、注释声称块级已重置的边界不符,见行内证据。001–003原修复未被本增量修改。
显形QuoteMark与callout声明弱化范围独立于标题正文,新增5种区间断言通过。A87依据为本提交描述;固定head人工验收文档尚无A87,作者宿主反馈不记为本方验收。

Standards

未另建独立Standards缺陷。新增浏览器断言核对computed opacity与boxShadow,不只是DOM存在;但未覆盖块级代码负向边界。旧#676/#677与A86未验边界保留。

本方验证与边界

完整Git固定head,liveDecorations单文件100pass(含新增5例);JS语法与diff检查通过。基于两条原样生产CSS规则、相同jsdom DOM的旧head/新head对照:旧inline和pre code均无shadow,新二者均获得inset1px规则,pre reset只重置font/background/padding,未重置shadow。这是CSS适用关系和受控DOM证据,不冒充真实Chromium绘制/VSCode/Windows验收;未重跑全量业务测试。作者全量10210/浏览器成功仅作者证据。
当前CI41259429892仍运行,继续只读跟至终态,不重跑。本轮仅COMMENT与一个新独立线程,不是合并批准。

Comment thread src/webview/main.css Outdated
background-color: var(--vsidian-reading-code-background);
/* A87(2026-11-01)与 live 侧 .vsidian-inline-code 同步的 1px 边线
(callout 容器底色上的可辨性;pre 内块级 code 已重置不承边线) */
box-shadow: inset 0 0 0 1px var(--vsidian-reading-code-border, rgba(128, 128, 128, 0.4));

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-004 · P3 · Spec:行内代码边线泄漏到阅读态块级代码

本提交/A87描述限定「行内代码加1px inset边线」,注释还明确称pre内块级code已重置。但此选择器匹配所有code,包括pre code;上方4238–4242的更具体规则仅设置font-family/background/padding,没有box-shadow,因此不能覆盖本新增属性。
触发:Reading中普通围栏/缩进代码的pre>code,尤其关闭代码卡时保留的朴素产物(readingCodeCard.ts明示两开关皆关不触碰)。影响:块级代码文本也多出本应仅用于行内代码的细框;不是只有callout内inline被改变。
本方原样两条CSS+同一jsdom DOM对照:旧8e23d654 inline/pre两者shadow为空,新0acbc5be两者都为inset 0 0 0 1px var(...)。全源码未见其他pre code shadow重置;这是受控CSS/DOM证据,未冒充宿主截图。
建议将新增规则限于非pre行内code,或在pre code明确重置box-shadow;补阅读态inline正向与fenced/indented块级code负向(含代码卡开关)的computed样式断言。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-004 · 修复 e2d01f2 · 待复审

  • 修复:e2d01f25 pre code 重置规则显式补 box-shadow: none(采纳备选二:块级排除集中在既有重置点,行内选择器保持简单形态)。审查证据链确认无误——A87 一轮我加的 box-shadow 层叠进 pre>code,既有重置规则未声明该属性盖不住,块级代码被套行内细框。
  • 验证:calloutPaint 浏览器套件新增负向矩阵——fixture 增顶层缩进代码块,断言阅读态 fenced(callout 内 ```md)与缩进(顶层 4 空格)两类 pre>code 的 computed boxShadow === 'none';行内 code 正向断言同步升级(边线 alpha ≥ 0.6)。全套件绿(run-IapGf5);全量单测 10210 例 / compile / 契约八项绿。
  • 边界:审查建议的「代码卡开关两态」宿主变体未在浏览器 fixture 覆盖——fixture 走朴素 reading 渲染(无卡开关链路),朴素产物即负向断言对象;卡开启态的块级呈现走 code-card 容器(无 code 元素直挂边线路径),泄漏面不适用。人工验收随 A87 轮宿主重验覆盖。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-004 · 复审 e2d01f2 · fixed(原pre code边线泄漏范围)
既有pre code规则新增box-shadow:none,特异性高于通用code规则,块级不再继承新增行内边线。原样生产两条CSS+同一jsdom DOM对拍:旧0acbc5be inline/pre均为inset1px,新head inline仍为inset1px、pre为none。新增浏览器负向检查同时覆盖fenced/缩进两类pre code,源码已读,本方未在Chromium执行;作者run-IapGf5成功仍为作者证据。
本方精确head readingCodeCard/liveDecorations合计172pass,JS语法/diff通过。代码卡开关宿主变体未本方验收;本次确认原CSS层叠缺口修复,不扩大为全部A87视觉验收。保留首轮失败证据,不resolve。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-004 · 修复 685cce1 · 待复审

  • 处置:随行内代码边线整体撤除(用户验收澄清:三轮边线误实现在行内代码上,诉求对象是 callout 内的代码块卡片;误向实现连同本线程所述泄漏面一并移除——live/阅读 box-shadow、--vsidian-reading-code-border 变量、pre code 重置全撤,浏览器断言同步撤净)。
  • 边界:本线程问题不复存在(无泄漏源);代码卡壳边线为正确对象的新实现(卡行 inset 线 + header border,--vsidian-code-card-border),calloutPaint/codeCardChrome computed 断言在场。
  • 关联:005(整篇围栏无尾换行的折叠遗漏)同提交修复,见 005 线程。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-004 · 复审 685cce1 · fixed(泄漏源整体撤除)
本轮撤除Live/Reading行内code的新增box-shadow与变量,连同pre code重置一起回退,原泄漏源已不存在。此前e2d的限定重置修复证据仍保留;当前是需求对象从行内代码改为代码块卡壳后的撤除,不称原行内边线功能继续验收通过。新卡行inset/header/Reading卡壳边线源码与computed测试已读,本方未执行真实绘制。作者对需求澄清的记录不扩大本方操作权限。

A87 二轮验收反馈 + PR 复审 P3 一并修复:

1. 边线可见度(验收反馈「白底上灰字」):0.4 透明灰叠 14% 灰底
   同色系形同虚设——默认链改主题边框色
   --vscode-editorWidget-border(实色、亮暗自适应),末级 fallback
   提到 0.6。live(--vsidian-live-code-border)与阅读
   (--vsidian-reading-code-border)双模式同链。

2. PR678-004(P3):行内边线泄漏到阅读态块级代码——code 规则的
   box-shadow 层叠进 pre>code(既有 pre code 重置规则未声明该属性
   盖不住),围栏/缩进块级代码四周被套行内细框。pre code 重置规则
   显式补 box-shadow: none。

- 浏览器断言(calloutPaint):边线 alpha ≥ 0.6 钉住可见度;新增
  fenced 与缩进两类块级 code 的 shadow=none 负向断言(004 复审
  要求的负向矩阵)
- 全量单测 10210 例 / compile / 契约八项 / calloutPaint 全绿

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R5 亲审复审

Head e2d01f250ede0ecd644d3822c0e7489852727167;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。相对0acbc5be为1提交2文件。全部原线程/作者004回复已读,发布前复核同head/open且无并发新review。

Spec

vsidianPR678-004 fixed(原块级code细框泄漏),已沿原线程回复证据;001–003既有修复未改变。未发现新增独立证实问题。行内边线默认改为主题边框色,fallback alpha0.6;不以透明度门槛断言替代所有主题下的实际对比度/用户观感验收。

Standards

新增fenced与缩进块级code的computed boxShadow负向断言,与inline正向断言配对;未发现独立Standards问题。实际代码卡开关宿主变体未执行,作者浏览器fixture走朴素Reading产物,边界保持明确。

本方验证

Node24.22.1,固定完整Git工作树:readingCodeCard/liveDecorations两文件 172pass;原样生产CSS两规则旧/新jsdom对拍,inline保留边线、pre从inset1px变none;JS语法、git diff --check通过。未改产品代码,未重跑全量/真实Chromium/VSCode/Windows或物理输入。作者10210/compile/契约/browser记录不计作本方执行。
旧0acbc5be CI41259429892已cancelled(取消前12job成功、browser未完成),不称绿、不归flaky;新CI41259958425仍运行,继续只读核验终态,不重跑。所有旧失败证据保留。本轮仅COMMENT,不APPROVE/resolve。

用户宿主验收(A87 三轮,2026-11-01)两项:

1. 光标在代码卡内点击折叠:收起并自动旁落光标(对齐 calloutFold
   的 migrateSelectionForCalloutFold 模式)。根因:isFolded 被
   editing 判定(selectionTouchesRange 闭区间)压住——光标在卡内
   时点击折叠「块根本折不上」。codeCardState 新增
   migrateSelectionForCodeCardFold(触及语义与装饰层一致:空选区
   闭区间、非空开区间相交;落点 = 隐藏区间外紧贴卡头的块上一行
   行尾,文档首行围栏退块后);toggleFold 事务同携旁落,effect
   值归一为围栏起始位置(fold 集合标识键)。

2. 行内代码边线参照系改判(验收质询「较于全局背景还是临近
   callout」):原默认链的主题 widget token(editorWidget-border)
   不感知容器且部分主题下值不可用(实际无边框)——弃用。默认改
   不透明中灰 rgb(127,127,127):对比对象是紧贴底色(14% 灰叠容器
   底),亮底呈深线、暗底呈亮线,任何容器底上拉开至少一档。

- 单测:liveCodeCard 新 5 例(纯函数 4 + 装饰组合「事务同携折叠
  与旁落后收起真实呈现」)红→绿
- 浏览器:codeCardChrome 新真实点击场景(点代码行进卡→点折叠→
  收起在场 + 光标旁落块外 + 不被编辑态压回);calloutPaint 边线
  alpha 断言随不透明中灰保持
- 全量单测 10215 例 / compile / 契约八项 / 双浏览器套件全绿

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R6 亲审复审

Head 86bbaf62ba8c99d2388017b583b460a1a63745fd;base/merge-base仍3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。相对e2d01f25为1提交5文件,全部原线程及提交规格已读,发布前仍同head/open,无并发新review。

Spec

新增 vsidianPR678-005 · P3 · exists:折叠旁落修复遗漏「围栏占满文档且末尾无换行」输入,落点被钳到围栏闭区间内,折叠仍被editing压回。属于本次明示修复范围的遗漏,旧版卡内点击本就不能折叠,不伪称本提交首次造成。见行内实际StateField/装饰证据。001–004原修复不变。
行内边线改不透明中灰,不再依赖主题widget变量;保留用户实际明暗/容器观感验收边界,不把固定灰色当作任意背景必然有对比。

Standards

未另建独立Standards缺陷。新增浏览器用例只覆盖块前有文字的旁落场景;新增纯函数首行用例的docLength=20、fenceTo=7仍预留了块后空间,未触及005。

本方验证与边界

精确Git工作树,原liveCodeCard 112pass(包含新5例)。额外3项生产StateField/mermaidFencesField/迁移函数/CodeCardHeaderWidget组合探针:块前有文字、末尾有换行两例通过;仅整篇围栏无末尾换行一例失败,from0/to13/docLength13/landing13,fold集合已标记而header.folded=false。合计114pass/1fail,失败保留,不归flaky。JS语法/diff检查通过,未改产品代码,临时测试已移除。
未执行实际浏览器/VSCode/Windows/物理点击或全量测试;作者10215/双浏览器成功仅作者证据。旧e2d01f25 CI41259958425仍运行,新head CI41260685363待运行,继续只读核验,不重跑。本轮仅COMMENT及新独立线程,不是合并批准。

fenceTo: number,
docLength: number,
): EditorSelection | null {
const landing = fenceFrom > 0 ? fenceFrom - 1 : Math.min(fenceTo + 1, docLength)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-005 · P3 · Spec:整篇围栏无尾换行时旁落仍留在块内,折叠修复未生效

触发:文档仅为三行 js / x() / ,末尾无换行(13字符),光标位于x()后点击代码卡折叠。
本函数取Math.min(fenceTo+1,docLength)=13,但围栏是[0,13];liveCodeCard.ts550/554的selectionTouchesRange对空选区按闭区间判断,landing13仍editing=true,isFolded被压成false。用户仍看到展开态,不能完成本提交A87三轮所承诺的卡内点击折叠。
本方精确head生产EditorState、mermaidFencesField、迁移函数与codeCardDecorations组合:from0/to13/length13/landing13,fold effect已写入而CodeCardHeaderWidget.folded=false;同一探针在尾部增加换行或块前增加普通行均true。原112项liveCodeCard测试通过,但新增首行用例人为留出块后空间,没有覆盖整篇围栏。
这是已有卡内无法折叠问题的本轮修复遗漏,不说成新引入的原始问题。请为无块外合法位置定义可实现的折叠/选区策略(不应靠偷偷改源文制造空行),并补完整StateField/真实点击的EOF无换行与有换行对照。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-005 · 修复 685cce1 · 待复审

  • 修复:editing 触及右界收一位——fence.to === doc.length(整篇围栏无尾换行)时,块级 editing 判定用 [fence.from, fence.to-1]:光标恰在块尾边界(head===fence.to===docLength)物理处于收起 replace 区间 [0, fence.to) 右界外、源码可见,不算编辑抑制;块外无合法位置的文档至此可收起。selectionTouchesRange 共享谓词本体未动(其余消费点语义不变)。旁落落点公式未动(该场景 min(fenceTo+1, docLength)=fenceTo,配合触及收窄后即为合法落点)。
  • 键入安全:插入发生在边界外——回车起新行后围栏仍闭合、收起保持、新行内容在收起区间外可见(新增单测断言);直接贴闭围栏行尾打字母会破坏闭合围栏语法、卡正确退场显源码(源文语义,非隐藏输入),已在测试注释中澄清。
  • 验证:liveCodeCard 新三例(无尾换行收起 / 有尾换行对照回归 / 收起态键入安全)红→绿,115 例全过;全量单测 10218 / compile / 契约八项 / calloutPaint + codeCardChrome 浏览器全绿(codeCardChrome 含真实点击折叠旁落场景)。
  • 边界:真实点击的 EOF 无换行专用浏览器场景未单独落 fixture(现有点击场景的块前有内容、落 fenceFrom-1 路径已测;无尾换行路径由 StateField 单测钉住)——需要时随 P2 回归票补。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-005 · 复审 685cce1 · 部分修复/仍开放(边界问题转移)
已修部分:原整篇围栏无尾换行、卡内点击后空光标落EOF的案例现在能收起,本方原生产StateField组合探针转绿。
残留/转移:liveCodeCard.ts555把fence.to统一减1后,不只排除了EOF空光标,还截短了非空选区相交范围。对同一13字符文档,折叠后设置EditorSelection.single(12,13)(选中最后一个闭围栏反引号,亦可对应EOF处Shift+Left),本方原codeCardDecorations产出的header.folded仍true;实际已选中的源码字符仍被收起装饰遮住。原范围[0,13]下该非空选区与块相交,应临时展开;这是修复引出的边界转移,不另建重复ID。
精确head原115项liveCodeCard测试通过;额外原005探针通过、末字符非空选区探针失败,合计116pass/1fail。受控jsdom/生产StateField,不是真实键盘/宿主验收。建议只对空选区且head===fence.to===doc.length放宽右端点;非空选区继续使用真实[fence.from,fence.to)相交语义,并覆盖正反向选区及多光标。迁移源码:https://github.com/ONEGAYI/vsidian/blob/685cce1419a98911901bbff304d90606c00955ef/src/webview/liveCodeCard.ts#L555-L557 。不resolve。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-005 · 复审 d6808da · fixed(原EOF折叠及末字符选区转移范围)
新增blockEditingTouches只豁免空选区head===to===docLength,非空选区恢复真实[from,to)相交,其他块内空光标继续抑制折叠,未再统一截短右界。本方原生产StateField组合先执行卡内折叠旁落,再分别设置正向末字符选区、反向Shift+Left形态、真实启用allowMultipleSelections的两光标、单独EOF空光标,4例全部通过;多光标确认实际ranges.length=2,避免单光标配置吞掉场景。
原liveCodeCard与codeCardPaintCssContract两文件141pass,另4探针共145pass。原R6/R7失败保留,当前确认上述范围修复,不等于真实键盘/VSCode/浏览器观感验收;线程不resolve。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vsidianPR678-005 · 修复 d6808da · 待复审

  • 修复(边界转移收口):块级触及判定重写为 blockEditingTouches(liveCodeCard 模块级函数),放弃「fence.to 统一收窄」——唯一放行点是「空选区且 head === fence.to === doc.length」(原 005 主场景,物理在收起 replace 区间右界外);空选区其余位置维持闭区间(编辑便利语义)、非空选区维持真实开区间相交(与共享谓词一致,正反向/多光标语义不变)。选中最后闭围栏字符的源码选区恢复临时展开。
  • 验证:按复审建议补正反向选区与多光标单例(正向 [12,13] / 反向 [13,12](EOF Shift+Left 形态)/ 多光标块内空光标 → 展开;EOF 空光标单独在场 → 收起保持),liveCodeCard 116 例全过;全量单测 10219 / compile / 契约八项 / calloutPaint + codeCardChrome 全绿。
  • 另(同提交,验收截图反馈):卡壳边线统一 inset shadow 机制(header 顶/左/右与分隔线从 border 迁 shadow——border 与 shadow 拼接的接角 1px 错位是不连续观感来源);分隔线原 editorGroup-border token 不可视,换 --vsidian-code-card-border 同源色;codeCardPaintCssContract 契约同步(验收驱动变更,理由随测试注明)。main 前移(PR test: 修正真实 Ctrl 手势并补引用表格回归与文件树 #680)已 merge 跟进(tree.json 经技能两阶段合并,零待决)。

A87 三轮把 --vsidian-reading-code-border 定义处 fallback 改为
rgb(127,127,127),但使用点(.vsidian-reading-block code 的
box-shadow)仍是一轮的 rgba(128,128,128,0.4)。定义在场时使用点
fallback 是死码、无行为差异(浏览器断言核实),但两处不一致——
将来定义链变化时旧透明值会诈尸。对齐为同值并注明理由。

calloutPaint 全绿;产物重建核实边线两处均为 rgb(127,127,127)。
验收澄清(2026-11-01 四轮):用户诉求对象是 callout 内的**代码块
卡片**底色可辨性,前三轮误实现在行内代码上。本轮撤误向实现、
在正确对象上落地;另修复 PR678-005(复审 P3)。

1. 撤除行内代码边线(三轮误向):live/阅读两处 box-shadow、
   --vsidian-reading-code-border 变量、pre code 重置(004 随撤——
   泄漏源已不存在)及对应浏览器断言全撤;显形标记灰化与代码卡
   折叠旁落(真实需求)保留。

2. 代码卡壳外缘 1px 边线(用户拍板方向,正确对象):卡底色与
   callout 容器底色部分类型对比不足——行级左右线用 inset
   box-shadow(不占行高,同紫条先例),底行加底线,header 顶/
   左/右实色 border(border-box 不扩尺寸),阅读卡容器 border
   一圈。不透明中灰 rgb(127,127,127),参照系=临近容器底色
   (亮底深线/暗底亮线),变量 --vsidian-code-card-border 可调,
   双模式同步。

3. PR678-005:整篇围栏无尾换行(块外无合法位置)时旁落落点
   min(fenceTo+1, docLength) 退回块尾、闭区间触及误判 editing、
   收起永远被压。修复:块尾即文档末尾时 editing 触及右界收一位
   (光标恰在块尾边界物理处于收起 replace 区间右界外、源码可
   见,不算编辑抑制);插入发生在边界外、新字符可见,无隐藏
   输入窗口。有尾换行/块后有内容时语义零变化。

- 单测:005 三例(无尾换行收起/有尾换行对照/收起态键入安全,
  含贴闭围栏行尾打字破坏围栏语法卡正确退场的语义澄清)
- 浏览器:calloutPaint 卡行左右线+header 边线 computed 断言;
  codeCardChrome 阅读卡壳 border 断言;行内代码断言撤净
- 全量单测 10218 例 / compile / 契约八项 / 双浏览器套件全绿

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R7 亲审复审

Head 685cce1419a98911901bbff304d90606c00955ef;base/merge-base 3d70cb36ca6c29cabcd718eaaaf7e5dd5718ecb5。相对374cf6ef为1提交5文件,原五线程及作者004/005回复已读,发布前仍同head/open。

Spec

  • vsidianPR678-004 fixed(泄漏源整体撤除):行内code边线及变量撤回,需求对象按作者本轮澄清改为代码卡壳。已沿原线程明确这次撤除与此前限定重置的差别。
  • vsidianPR678-005 部分修复/仍开放:原EOF空光标现在可折叠;但右界统一减1也缩短非空选区相交面,选中末尾闭围栏最后一个反引号仍保持收起,源码选区被隐藏。缺口转移至liveCodeCard.ts555–557,原线程已列触发/影响/建议;不笼统标fixed、不另建重复ID。
  • 001–003原修复未变。新卡壳边线有Live行级/header与Reading容器computed断言;固定灰色不能证明任意主题/容器背景的视觉对比度,人工观感边界保留。

Standards

未另建独立Standards问题。旧inline边线测试撤回与功能撤除一致;不能把撤回后的结果写成旧inline功能验收完成。EOF真实键盘专用fixture仍未加入,作者明确只在StateField覆盖,不冒充本方浏览器执行。

本方验证

完整固定Git树、Node24.22.1:原liveCodeCard 115pass;额外生产StateField/围栏表/迁移/装饰组合2探针中原005转绿、末字符非空选区失败,合计 116pass/1fail,首败保留非flaky。tsc --noEmit、两mjs语法、diff检查通过。未重跑全量/真实Chromium/VSCode/Windows/物理输入,未改产品;作者10218/双浏览器通过仅作者证据。
旧374cf6ef CI41261048680已核验13/13job成功(含browser124715368687),该head仍包含005旧缺口,CI绿不注销缺陷。当前685cce14 CI41262071376仍运行,继续只读观察,不重跑。本轮COMMENT不是APPROVE,不resolve。

验收反馈(截图标注)与复审「部分修复」一并处理:

1. 边线连续性 + 分隔线可视(验收标注「不是连续线段」「分解线
   依然不可视」):header 顶/左/右 border 与底部分隔线统一迁
   inset box-shadow——与卡行边线同机制同色,消除 border 与
   shadow 拼接的接角 1px 错位(连续感来源);分隔线原
   editorGroup-border 主题 token 在用户主题不可视(探针 fallback
   0.35 透明灰实证同族问题),一并换 --vsidian-code-card-border
   同源色。codeCardPaintCssContract 契约同步(变更理由:验收
   反馈点名,非顺手放宽)。

2. PR678-005 五轮(复审边界转移):四轮把 fence.to 统一收窄
   误伤了非空选区——折叠后选中最后闭围栏字符(EOF Shift+Left
   形态)仍被收起遮挡。重写为块级触及判定 blockEditingTouches:
   唯一放行点是「空选区且 head === fence.to === docLength」
   (物理在收起 replace 区间右界外);空选区其余位置维持闭区间、
   非空选区维持真实开区间相交(正反向/多光标语义与共享谓词
   一致)。selectionTouchesRange 共享谓词不再被本路径消费。

- 单测:005 五轮例(末字符正向/反向选区展开、多光标、EOF 空光标
  收起不回归);契约断言更新
- 浏览器:calloutPaint header 四段 shadow 同源断言 + 分隔线不再
  走 border;codeCardChrome 阅读卡壳 border 断言保持
- 全量单测 10219 例 / compile / 契约八项 / 双浏览器套件全绿
tree.json 经 file-tree merge 两阶段合并(自动合并 11 项,零待决),
render + check --strict 通过。#680 变更(blockquoteTablePaint/
contextMenu 测试修正 + 文件树登记)与本分支改动零文件重叠。

@ONEGAYI ONEGAYI left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R8 亲审复审(含main同步)

最终head 042abcd8ca6bdee3a49fd101b22ed79de8866be6;base/merge-base已前移至 a2598a0e1547a24902ebb446dc11a83114b265fd(#680)。先审d6808da4五文件修复,再核对main合并;同步没有改变src生产树。原五线程与作者005回复均已读,发布前同head/open,无并发新增overview。

Spec

vsidianPR678-005 fixed(EOF折叠及末字符非空选区转移范围)。已沿原线程回复4434050880:只有EOF空光标获豁免,正/反向非空选区与实际启用的多光标均按真实相交展开。001–004此前修复/撤除范围保持,无新增证实独立缺陷。
卡头与卡行边线统一inset shadow,分隔线改同源色;旧border-bottom断言随明示视觉方案迁移,不把computed属性存在扩大为接角/任意主题实机观感通过。

Standards

未发现新增独立问题。main带入的四个文档/测试文件逐blob与已审#680合并树一致;tree.json深比较只新增3项登记、更新3项测试说明,严格检查通过。生产src相对d6808da4无差异,未把main同步误当新的产品修复。

本方验证与边界

  • d6808da:原liveCodeCard/codeCardPaintCssContract 141pass,额外4项原生产StateField组合探针全过,共145pass。正向末字符、反向Shift+Left形态、allowMultipleSelections=true且确认2个ranges、EOF空光标逐项对照;原R6/R7失败保留。
  • 最终042abcd8:上述两文件加contextMenu/contextMenuDom/tableCellInput共5文件 301pass;file-tree strict与diff检查通过。d6808da4 tsc及mjs语法通过;main仅测试/文档增量,未冒称最终head重新跑compile或全量。
  • 未改产品,临时探针已移除。没有真实Chromium/VSCode/Windows/物理键盘或完整视觉验收;作者10219/双浏览器成功不计本方执行。
  • 上轮685cce14 CI41262071376已13/13成功,不注销当时005转移缺陷;当前042abcd8 CI41262784250运行中,继续只读至终态,不重跑。
    本轮仅一个COMMENT总览与005原线程回复,不APPROVE、不resolve。

## 问题

宿主验收截图标注「不是连续线段」:代码卡头部横带与首围栏行接缝处,
卡壳左右边线各向内凹出一道弧,观感上边框在此断成两段。

## 根因(探针实测,非推测)

沿卡壳左缘逐扫描线取边线外缘像素 x(dpr=2):

- 头部横带段:x 恒定 12(一条竖线)
- 接缝下方:x 17 → 8 连续内凹,跨 12 设备像素(6 CSS 像素)后回正

这份内凹来自 `.vsidian-code-card-edge-top` 自带的 `border-top-left-radius: 6px`。
该规则是 #79 卡片初版留下的——当时没有头部横带,首行自己承担顶边圆角;
#81 引入头部横带后,顶边圆角已改由头部 `border-radius: 6px 6px 0 0` 承担
(`styleContract` 的 `live-code-card-edge` 条目原文即写明「顶边圆角由头部
横带承担」),但首行这层圆角没撤。两层圆角叠加的结果,就是头部外圆角之后
紧接着一道内凹。

对照探针:把首行顶角圆角置 0 后,接缝下方左缘从 x 8 起全程恒定,右缘同理。

## 变更

- `src/webview/main.css`:`.vsidian-code-card-edge-top` 的 `border-top-left-radius`
  / `border-top-right-radius` 由 6px 改为 0,注释记录根因与唯一承担者
- `test/unit/codeCardPaintCssContract.test.ts`:原断言钉住「首行顶角 6px」,
  改钉「首行顶角 0 + 尾行底角 6px」
- `test/browser/calloutPaint.mjs`:新增像素层断言——截图沿卡壳左缘逐扫描线
  取边线外缘 x,中段(跳过首尾圆角过渡带)必须去重后单值,且不得出现边线
  缺行。这是用户真正看到的「连续/断裂」,CSS 层断言抓不住

## 验证

- `npm run compile` 通过
- `npm run test:unit`:444 文件 / 10219 用例全绿
- `npm run check:stylecontract`:八项零失败
- 浏览器套件 calloutPaint / codeCardChrome / codeCardClickOffset / quoteBarPaint 全绿
## 背景

对 bbf0f59(A87 六轮:首围栏行顶角改直角)执行 review-loops 三轮
审查修复循环。首轮子代理审查发现 4 项 P3(无 P0-P2),第二轮复核后
修复,第三轮复核确认全部关闭、无新问题。

## 审查发现与处置

- F1 像素断言只测左缘:右缘镜像补证(独立裁剪 + 独立全套断言)
- F2 暗像素阈值 180 有假绿路径(暗底下背景全列命中 → x=0 单值空转绿):
  断言升级为「单值 + 无缺行 + 落预期带」,阈值放宽至 190(容纳 1px 劈列
  的 ~50% 抗锯齿混色 ≈184,两侧底色 ≈230/240 仍不命中)
- F3 styleContract example 8px 与实现 6px 存量漂移:example 对齐 6px,
  purpose 补「首行顶角为直角」;三份生成产物随 compile 同步再生成
- F4 契约正则可前缀匹配 0.5px:值边界锚定到分号
- N1 落带按 dpr=1 硬编码(套件将来设 dpr=2 会全面假红,仓内有先例):
  带中心按位图宽自标定(左 bandWidth/2、右 -1,±2 劈列容差)
- N2 非对称暗底(卡内暗卡外亮)下「取暗像素」范式失效:属范式固有边界,
  换对比式检测与问题规模不相称,注释留档不修代码
- N3 循环内 const window 遮蔽惯用名:改名 midRows

## 验证

- 检测力实证:CSS 临时回 6px 时套件红——computed 断言先红;跳过其后
  由像素断言独立红(左缘 x 去重 [6,9,8,7],正是内凹台阶);dpr=2 探针
  同状态两侧中段 x 集合均非单值(左 [12,21,18,17,15,14,13]、
  右 [11,2,5,6,7,8,9,10])。还原后绿
- npm run compile 通过(产物再生成一致)
- vitest codeCardPaintCssContract + styleContract 43 用例绿;
  node --test checkStyleContract 绿;npm run check:stylecontract 八项零失败
- calloutPaint 浏览器套件绿;产物代码零改动(main.css 与上提交逐字节一致)
@ONEGAYI
ONEGAYI merged commit 48eadd6 into main Nov 1, 2026
13 checks passed
@ONEGAYI
ONEGAYI deleted the feat/callout-live-refinement branch November 1, 2026 02:58
ONEGAYI added a commit that referenced this pull request Nov 1, 2026
版本内容(Unreleased 段转正为 1.6.1 - 2026-11-01,顶部重建空
Unreleased 段):

- 改进:Live Callout 容器形态收口(#672/#673)、引用内代码块与公式
  完整渲染(#674/#675)、标题按类型着色(#671)、连续删除防护、
  行内代码细边线与代码卡壳边线连续化
- 修复:表格格内输入选区竞态(#667)、代码卡头部间距点击偏移
- 补账:v1.6.0 以来随 PR #678/#681 落地但未登记 Unreleased 的用户
  可见变更全部入册;验收轮观感修复按约定并入所属主题组

版本与产物:

- package.json version 1.6.1;样式指南随版本段重生成(版本戳)
- API 嗅探:CHANGELOG-API Unreleased 为空、API 事实源 v1.6.0..HEAD
  零 diff——无 API 版本动作,只发本体(API 停留 1.4.0)
- checkStyleContract 基线复验:8 项零失败(候选 v1.6.1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment