波波 2026-10-26 · 接 #617「C 端 1923 项裸值」
10-26 四批更新:路线 A 已执行;319 处失效已修;另修第四批自己引入的 188 处金色死值。裸值 1923 → 271。
1923 项裸值不是「没用令牌」造成的,是「C 端实际在用的色板与 v1 真源不同源」造成的。
| 路线 | 做法 | 后果 | 裁定 |
|---|---|---|---|
| A 归并 | 把实测色归到真源最近令牌 | 颜色变了(多数 Δ<15,肉眼几乎无感) | ✅ 已选并执行(义父要「极致简化、砍抽象层」——把 25 个色收敛成 8 个才是简化) |
| B 新增 | 照抄实测值,登记成真源新色阶 | 颜色零变化,但真源从 26 色膨胀到 50+ 色 | ❌ 不采纳。等于给每个裸值配一个令牌,是加抽象层 |
| 裸值存量 | 说明 | |
|---|---|---|
| 起始 | 1923 | |
| 第一批(等值替换) | 1623 | 零视觉变化 |
| 二批·档1 归并 | 1045 | 579 项,Δ≤13 |
| 三批·按色值全仓 | 316 | 798 项(等值 21 + Δ≤15 归并 55 + 照抄色阶 798 中的实色部分) |
| 四批·零新建令牌 + 三族 | 271 | 211 项,见第七节 |
| 剩余(长尾孤色) | 271 | 184 个唯一色,其中 134 个只出现 1 次,决议保留,见第七节 |
注:三批后的 316 与四批后的 271 是「颜色属性上的裸色值」口径;
全量 HEX/RGBA 字面量(含渐变端点、非颜色用途)为 492 → 358。
三个文件 profile-head / local-services / asset-grid(占全仓 79%):
为什么还要看语义:#F5F0E4 有 8 处用在 background:(深蓝底上的按钮底),
而等值令牌 --color-lake-text 语义是「湖蓝底上的文字色」。值相等但语义错配——
改文字色时会把按钮底一起改掉。这 8 处故意不换。
验收(反证过的,不是靠肉眼):
把替换后的 var() 解回色值,与备份逐项比对——584/558/441 项序列全等、零未定义令牌。
该脚本先经反证(故意写错令牌名 → 退出码 1 并点名)才拿来做验收。
按「归并代价」分三档。Δ = RGB 欧氏距离(<15 肉眼几乎无感,15–40 需看,>40 明显不同色)。
实际落盘 579 项(比表内 674 少 95,差额是属性语义闸门拦下的:
#faf7f0Δ17.9 超阈、#fdf1ef真源无同族色,均未动)。
验收:三文件序列等长、零未定义令牌、零 Δ>15(脚本先经反证:注入大 Δ 能被抓到)。
| 实测色 | 归并到 | Δ | 属性(全部匹配) |
|---|---|---|---|
#2b2b2b ×186 | --color-text-primary | 12.1 | 全 186 处 color |
#e5dfd5 ×139 | --color-border | 4.4 | 全 139 处 border |
#c4bdb0 ×70 | --color-text-disabled | 2.2 | 全 70 处 color |
#f0ebe0 ×49 | --color-fill | 9.3 | border-bottom 25 + background 24 |
#6b655c ×40 | --color-text-secondary | 4.2 | 全 40 处 color |
#b08a4f ×34 | --color-gold-deep | 9.5 | background 22 + color 12 |
#f3e8dc ×25 | --color-fill | 13.0 | 全 25 处 background |
#f9f5ef ×15 | --color-bg | 9.0 | 全 15 处 background |
#f3eae2 ×13 | --color-fill | 7.5 | 全 13 处 background |
#f5f0e4 ×8 | --color-fill | 2.0 | 全 8 处 background |
<details><summary>原始 Δ 表(归档)</summary>
| C 端实测色 | 次数 | 归并到 | 真源值 | Δ |
|---|---|---|---|---|
#2b2b2b | 186 | --color-ink-1 | #2B2620 | 12.1 |
#e5dfd5 | 139 | --color-border | #E8E2D6 | 4.4 |
#c4bdb0 | 70 | --color-ink-dis | #C4BBAF | 2.2 |
#ddd6c8 | 50 | --color-border-strong | #D8D0C0 | 11.2 |
#f0ebe0 | 49 | --color-fill | #F5F0E6 | 9.3 |
#6b655c | 40 | --color-ink-2 | #6B6259 | 4.2 |
#b08a4f | 34 | --color-gold-deep | #A8854E | 9.5 |
#f3e8dc | 25 | --color-fill | #F5F0E6 | 13.0 |
#faf7f0 | 25 | --color-paper | #F5F1E8 | 11.2 |
#fdf1ef | 20 | --color-paper | #F5F1E8 | 10.6 |
#f9f5ef | 15 | --color-paper | #F5F1E8 | 9.0 |
#f3eae2 | 13 | --color-fill | #F5F0E6 | 7.5 |
#f5f0e4 | 8 | --color-fill | #F5F0E6 | 2.0 |
</details>
| C 端实测色 | 次数 | 归并到 | 真源值 | Δ |
|---|---|---|---|---|
#2b2b2b | 186 | --color-ink-1 | #2B2620 | 12.1 |
#e5dfd5 | 139 | --color-border | #E8E2D6 | 4.4 |
#c4bdb0 | 70 | --color-ink-dis | #C4BBAF | 2.2 |
#ddd6c8 | 50 | --color-border-strong | #D8D0C0 | 11.2 |
#f0ebe0 | 49 | --color-fill | #F5F0E6 | 9.3 |
#6b655c | 40 | --color-ink-2 | #6B6259 | 4.2 |
#b08a4f | 34 | --color-gold-deep | #A8854E | 9.5 |
#f3e8dc | 25 | --color-fill | #F5F0E6 | 13.0 |
#faf7f0 | 25 | --color-paper | #F5F1E8 | 11.2 |
#fdf1ef | 20 | --color-paper | #F5F1E8 | 10.6 |
#f9f5ef | 15 | --color-paper | #F5F1E8 | 9.0 |
#f3eae2 | 13 | --color-fill | #F5F0E6 | 7.5 |
#f5f0e4 | 8 | --color-fill | #F5F0E6 | 2.0 |
| C 端实测色 | 次数 | 最近真源 | Δ | 疑点 |
|---|---|---|---|---|
#8a6248 | 51 | --color-ink-3 | 33.1 | 暖棕 vs 暖灰,色相不同 |
#1e2a44 | 49 | --color-lake-deep | 30.5 | 深藏蓝,真源湖蓝偏青 |
#9a6b3d | 25 | --color-gold-deep | 34.1 | 深棕金 |
#c9dce4 | 20 | --color-border | 34.5 | 冷调浅蓝底,真源无冷调浅底 |
#e8c4bd | 20 | --color-border-strong | 20.2 | 暖粉调 |
#b07a70 | 20 | --color-gold-deep | 36.6 | 陶土红棕 |
| C 端实测色 | 次数 | 说明 |
|---|---|---|
#a69e91 | 91 | 中性暖灰(次文/副文主力色),真源 ink 三级都不对得上 |
#c0564c | 65 | 陶土红(本地生活板块重音色) |
#8c867c | 50 | 中性暖灰(三级辅文) |
#6b4a34 | 25 | 深棕 |
#a04438 | 20 | 藏红偏棕 |
状态更新(10-26 二批,义父授权「你选择最优方案执行」后):
已补 styles/legacy-token-bridge.wxss(42 键全部 var() 到已接线令牌,不新造颜色),
check_v3_token_defs.py 已从「42 键 / 319 处」变为 零真缺陷。
本节保留为事故记录与根因存档。
清理裸值时发现:C 端有 42 个令牌键 / 319 处引用「引用了,但根本没定义,且没有降级值」。
var() 求值为空 ⇒ 该条 CSS 声明整条被丢弃:
padding: 0 var(--kl-space-xl) → 实际变成 padding: 0(左右留白没了)border: 1px solid var(--kl-border-tertiary) → 边框消失color: var(--ink) → 文字色失效(退回继承色)不报错、裸值门禁查不出、编译也过,只有肉眼看才发现。比 1923 项裸值严重得多。
| 令牌 | 处数 | 主要受害页面 | 猜测语义 |
|---|---|---|---|
--gold | 58 | agreement(协议页) | 金 |
--ink | 35 | agreement / feedback | 主文墨色 |
--muted | 32 | hotel-booking | 次文 |
--paper | 25 | agreement / feedback | 纸底 |
--c-cream | 24 | selection / sel-demand | 深底反白 |
--line | 20 | nav-bar / agreement / hotel-booking | 描边 |
--serif | 16 | orders | 标题衬线字体 |
--c-border-warm | 14 | sel-demand / sel-header | 暖描边 |
--c-ink-soft | 10 | sel-demand / sel-header | 副文 |
--cloud | 10 | redemption-code(凭证页) | 深底浅色 |
--white | 9 | feedback / hotel-booking | 白面 |
--kl-*(8 键) | 10 | item-detail(风物详情页) | A 端令牌族,C 端零定义 |
| 其余 30 键 | 56 | 分散 | 见脚本输出 |
styles/foundation-tokens.wxss 的接线注释里写着:
「已剔除 89 条 aliases… --line/--ink/--paper/--moss 共 35 处消费靠降级值…故一并剔除」。
带降级值的那批剔除后没事(取不到就走 fallback);
不带降级值的那批就整条失效了 —— 一次看起来零影响的操作,留下了静默缺陷。
补定义 = 让这些样式第一次生效 = 线上视觉会变,这是当初停下的理由。
义父授权后重新权衡:
var() 指向已接线令牌;将来做色板收口时,这一个文件就是唯一要删的,改回去零成本。
⚠️ 仍需真机确认:这些样式第一次生效,视觉会变。静态门禁只能证明「能取到值、语法没错」,
证明不了「好看」。C 端要传包才生效,请出包后重点看:协议页、风物详情页、凭证页。
已固化 scripts/check_v3_token_defs.py(只读体检,含反证):
补一个定义进去,计数立刻从 42键/319处 掉到 41键/261处 —— 证明它抓的是真缺陷,不是噪音。
它只报「无降级值且无定义」,不像 check-ui-tokens.py 把带 fallback 的也算进去(那种根本不会失效)。
这些是暖棕/陶土/冷调浅蓝,归并后色相会变,不是「几乎无感」级别,不敢不看就改。
--color-clay 陶土红、--color-warm-gray 暖灰?),还是认定 C 端专属、真源不收?
桥接层让 319 处样式第一次生效,视觉会变。静态门禁只能证明「能取到值、语法没错」,
证明不了好不好看。协议页(--gold/--ink/--paper)、
风物详情页(8 个 --kl-*)、凭证页(--cloud/--moss)。
tokens.wxss 尾部有 on-dark 覆写段(--color-ink-1 在深底被改成 #F5F1E8)。取色时只取首次出现(浅底主段)——第一版脚本取了最后出现,把浅底色配到了深墨色上,归类全错,已修。
没有这道闸门,#faf7f0(近白底)会被配到 --color-ink-1(主文深墨)——数值差不大但语义荒谬。
--space-N 与真源不同源(数值即值 vs px×2), 已由 tokens-alias-c-end.wxss 的 19 项撞名钉回处理,属独立事项。
剩余 316 项里 201 个唯一色有 134 个只出现 1 次。为孤色建令牌 = 把裸值搬进桥接层:
令牌数涨、裸值只是换了个地方存,不是收口。真正的收口是真源色板统一后一次性归并,
届时这 134 个孤色会自然落进已有色阶。
故第四批只做三类,其余保留裸值:
| 动作 | 项数 | 新增令牌 | 判据 |
|---|---|---|---|
| 等值 Δ=0 | 156 | 0 | 值完全相等 |
| Δ≤15 归并 | 33 | 0 | 肉眼无感 |
| 三个语义完整的族照抄 | 73 | 10 | 见 7.2 |
| 合计 | 211(落盘,36 个文件) | 10 | 479 → 268(residual_scan 口径,见 7.6) |
三个族的收益率 7:1,与三批的 47:1(17 令牌换 798 项)差一个数量级——这就是停止线。
剩下的低频孤立 rgba 变体(1 换 2~3)一律不建。
legacy-token-bridge.wxss 第八节)--lake-fog-{12,14,18,22,25,30,75}(7 键 / 45 处): RGB(245,240,228) 正是 --color-lake-text 的 RGB,按 alpha 分档。
真源 --invert-22 的 RGB 是 255,253,248(纯白偏暖),Δ25.9,不能混用——混了湖蓝底上的
「月白」会变「纸白」,冷调全失。
--alpha-03 / --alpha-06(2 键 / 19 处):foundation 只给 10/18/30/42/52/62/72/84 八档,C 端实测还有 .06 与 .025 两档超淡洗底,
往上并到 --alpha-10 会把极淡底压深一档。
--c-gold-bronze: #b0833a(1 键 / 9 处):Δ 到 --color-gold-deep 21.6 超阈,8 个文件稳定在用,是独立色阶不是噪声。
--c-slate-gray: #687477(1 键 / 8 处):Δ15.3 超阈 0.3。阈值是我定的,超 0.3 没有意义,但门禁按 >15 判红,就照抄建档一次清干净,不留边角。
#fff 112 处按属性分流:字色走 --color-text-invert(#FFFDF8,Δ2.2 暖白),
其余走 --color-surface(#FFFFFF,Δ0)。出包后看一眼深底上的白字——从纯白变暖白。
现象:第四批 apply 后验收脚本报「未定义 188」。
根因:批量替换脚本的 EXEMPT 只排除了 4 个真源文件,漏了 app.wxss。
app.wxss 既是令牌定义处(page{} 里的 --color-gold: #C9A96E)又是消费处,
于是定义行被当成裸值换成了 var(--color-gold) ⇒ 自引用死值,
连带 legacy-token-bridge 的 --gold / --c-gold-deep(它们 var() 到这两个键)一起失效。
| 失效键 | 引用处数 | 影响 |
|---|---|---|
--gold | 58 | 协议页金框/金线(重灾) |
--color-gold | 73 | 全站金色元素 |
--color-gold-deep | 55 | 全站深金元素 |
--c-gold-deep | 2 | selection 时间轴圆点 |
同类误伤还有 3 处定义行(已还原为原实色):
selection.wxss 的 --c-cream / --c-gold-deep、tenant-theme.wxss 的 --color-primary。
后两者是页面级/租户级有意差异化(注释明写「值与历史裸 hex 一致,统一时不漂移」),
不是漏网裸值;tenant-theme 更是「租户包生成时会覆盖」的文件,改成 var() 引用会改变租户行为。
修法:
app.wxss 定义行还原为 #C9A96E / #A8854E,与 foundation 188-189 行的 --gold-500 / --gold-600 逐字相同 ⇒ 与真源意图一致,非新造色。
EXEMPT 补 app.wxss,并加定义行保护(紧邻前一个 token 是 --xxx: 就不换)。已反证:对当前工作区 dry-run,selection.wxss 两行定义零改动。
教训:
只有专门的 var() 链成环检测能抓(本次 check_v3_token_defs.py 抓到了 4 个键,已反证有效)。
自己的脚本报了 188,顺着找到根因——算抓到了,但门禁本该在替换后立即跑。
--color-lake-text 是 3.6.0 基线遗留自引用」的注释归因存疑: git 证据显示第三批前后 app.wxss 的定义行都是实色 #F5F0E4。注释无害(解释了为何写实色),
但不是历史遗留,下次别再据这类注释下结论。
| 门禁 | 结果 |
|---|---|
令牌失效/循环 check_v3_token_defs.py | ✅ 零(自引用/循环/无定义三类全零) |
全仓一致性 bobo_verify_4.py | ✅ 80 文件 / 5057 字面量,零未定义、零 Δ>15、零 alpha 不一致 |
WXSS 语法 check_v3_wxss_syntax.js | ✅ 84/84 |
TS 语法 check_ts_syntax.sh | ✅ 125 文件零错 |
裸值门禁 check-ui-tokens.py miniprogram-v3 | 167 项 / 38 文件(存量基线已重拍,只卡新增) |
bobo_verify_4.py 比三批版多一道 alpha 一致性判据:三批的 Δ 只比 RGB 三通道,
会把rgba(43,38,32,.06)和实色#2B2620判成 Δ=0。已反证三批实际零 alpha 丢失,
但判据本身必须补——否则下次抓不到。
现象:check-ui-tokens.py miniprogram-v3 报 220 项,其中 legacy-token-bridge.wxss 29 项、
app.wxss 19 项——这些全是令牌定义值(--color-gold: #C9A96E 这种),
不是「绕过令牌的裸值消费」。EXEMPT_FILES 按文件名豁免覆盖不到
「既是定义处又是消费处」的 app.wxss。后果:C 端永远清不到零,#617 没有完成定义。
修法:scan() 里去注释后先过一遍 TOKEN_DEF(限定在声明位置:行首/分号/大括号之后,
避免误伤渐变与普通属性值),把定义行整段剔除。
| 端 | 改前 | 改后 |
|---|---|---|
| C 端 miniprogram-v3 | 220 / 40 文件 | 167 / 38 文件 |
| A 端 admin-console | 5278 / 87 文件 | 5001 / 87 文件 |
| B 端 miniprogram-staff | 0 | 0(不变) |
换了尺子必须重拍基线(脚本注释里本就写了这条):C 端基线 1923 → 167,
旧基线备份在 /tmp/baseline_bobo_bak.json(未入仓库,重拍即失效,无需保留)。
已反证:往 home.wxss 追加 .bobo-inject { color:#ABCDEF; background:rgba(1,2,3,.4) }
⇒ --baseline 模式报「新增裸值 2 类」,退出码 1。还原后退出码 0。
| 口径 | C 端当前值 | 出自由 |
|---|---|---|
| 裸值门禁(阻断项,已豁免遮罩/反白/降级值/定义行) | 167 | check-ui-tokens.py |
| 颜色属性上的裸色值 | 271 | /tmp/bobo_residual_scan.py(我自己的盘点尺,含定义行) |
| 全量 HEX/RGBA 字面量(含渐变端点、非颜色用途) | 358 | 裸匹配,不看属性 |
此前汇报里的「316」是第三批当时的门禁数,不是同一个时点,别再混用。