③段第八轮收口:功能入口卡按参照物对齐 + 导航按 tiaoyue 源站重建 + 密度 A 方案

原型(执行会话/目标-…-d85687/ui/mcn-workbench.html)
- 功能入口卡改三段纵向(图标/标题/描述各一行),68 → 111.19px,对齐 mcn-work-shop
  参考卡(同视口 1249×1277 实测 133px),补 --sh-L1 投影;主因是排布不是字号
- 左侧导航重建:由「纯图标 + 悬停提示」改为 64px 药丸浮栏,图标 24 在上、名字常驻在下
  (名字一律 2 字,说明走 data-tip);真值取自 tiaoyue 源站实测
  (栏 64/内衬 3/圆角 100/项 56×78/字 12px-500-行高 16)
- 密度 A 方案:≤1000 卡最小宽 200→160、≤820 统计条最小宽 132→96
  (两处 auto-fit 只在真装不下时才缩)⇒ 768/700/560 三处转绿,其余 10 个视口未动
- 移动档隐藏导航条横向滚动轨(16px 轨道曾吃掉 52px 条高的三成,还白吃 16px 主区)

取证通道
- _tools/cap.py 改为「只连不起」:只连 9223 常驻实例,视口走 Emulation.setDeviceMetricsOverride,
  不再自起 headless Chrome(顺带解除 500px 视口下限,390×844 可测)
- _tools/check_js.py 新增第 5 道门禁(node --check + 模板内注释反引号扫描)

文档
- 复盘-为什么第一版做得很差.md(新建):13 轮时间轴/四类反作用/三重归因/已修与仍欠
- 3d-审查报告.md:更正 §九 那条假 ✓(把「§5.5 五条逐条过完」记成机核,实际零覆盖,
  正是「五道闸门全绿却难看」的开关),补 §十二 功能入口卡高差、§十三 tiaoyue 导航逐条对照
- 3b-实测记录.md/DESIGN.md/3c-GPT 参考版与会诊/布局排版参考 ×2

机制与记忆
- .workbuddy/collab/collabctl.py:off --ws 不再全机扫描(原先一次杀掉他区+看板共 5 个进程)
- .workbuddy/memory/:本轮纪律与实测真值
- .gitignore:补排运行时噪音(ui/_scratch/__pycache__/浏览器取证临时目录/*.bak-*/一次性脚本)

闸门:语法全过/骨架八页 39 板块/变异对照 15-15/逐视口 14 绿(500×844 唯一红,缺口待拍板)/命名 2060-0-27
This commit is contained in:
WorkBuddy committed 2026-10-08 22:21:42 +08:00
1 parent df56c2c137
commit eee042c855
48 files changed
+8222 -1752

No files matched your search

+21
View File
@@ -15,3 +15,24 @@
# 一次性探针输出
tmp/_*.txt
# 技能加载运行时标记
.workbuddy/.load-pending
# 取证/调试中间件(体量大、可随时重生成)
**/ui/_scratch/
# Python 字节码
__pycache__/
# 浏览器取证的临时产物
tmp/_bh_shots/
tmp/_figma_preview/
tmp/_gpt_dl/
tmp/_bh_chrome.log
# 文档一次性备份与一次性修复脚本
*.bak-*
tmp/fix_*.py
tmp/dup_scan*.py
tmp/bh_keep_chrome.py
+1 -1
View File
@@ -1 +1 @@
35069ba1-9d9c-42c6-a367-a1ec54fb7cee 3
184c4986-d8ec-447e-b1ed-96f568c99fb5 3
+1 -1
View File
@@ -1 +1 @@
8b37a612-a130-4237-b8da-42325feeac08 1791404784.303
184c4986-d8ec-447e-b1ed-96f568c99fb5 1791467635.191
+11 -4
View File
@@ -67,7 +67,7 @@ HB_FRESH_S = 90 # 🔴 心跳新鲜阈值(与 `collabd.supervise_aliv
WORKSPACES = [
"E:/ProgramData/AIProject/ai1net-dsh-server",
"E:/ProgramData/AIProject/vibe-product",
"E:/ProgramData/AIProject/content_marketing_agent",
"E:/ProgramData/AIProject/contentm_agent",
]
# 看板:全局只一条(⛔ 不是每区一条)
@@ -84,7 +84,7 @@ BOARD_PORT = 20099
KEEPALIVE_TASKS = { # 新形态:计划任务 → pythonw collabd.py --supervise
"E:/ProgramData/AIProject/ai1net-dsh-server": "collabd-keepalive-ai1net-dsh-server",
"E:/ProgramData/AIProject/vibe-product": "collabd-keepalive-vibe-product",
"E:/ProgramData/AIProject/content_marketing_agent": "collabd-keepalive-content_marketing_agent",
"E:/ProgramData/AIProject/contentm_agent": "collabd-keepalive-contentm_agent",
}
BOARD_TASK = "dsh-board-keepalive"
@@ -319,6 +319,11 @@ def kill_all():
if pid and _pid_alive(pid) and pid not in protect:
if _kill_pid(pid):
n += 1
if ONLY_WS:
# 🔴 收敛模式(`--ws`):只杀本区心跳里记的那个 pid,⛔ 不做全机扫描。
# 2026-10-08 实测事故:全机扫描会连别的区与看板的进程一起杀
# (`off --ws contentm_agent` 一次杀掉 5 个进程,其中 3 个属他区/看板)。
return n
for nm, pid, cl in list_procs():
try:
ipid = int(pid)
@@ -516,8 +521,10 @@ def cmd_off():
set_switch(ws, "off")
_p(" 开关 off:%s" % ws)
disable_tasks()
_p(" 计划任务已禁用:%d 个(新 %d + 旧 %d + 看板 1)"
% (len(SCHED_TASKS) + len(KEEPALIVE_TASKS) + 1, len(KEEPALIVE_TASKS), len(SCHED_TASKS)))
_nb = 0 if ONLY_WS else 1
_p(" 计划任务已禁用:新 %d + 旧 %d + 看板 %d(%s)"
% (len(KEEPALIVE_TASKS), len(SCHED_TASKS), _nb,
"收敛到单区 ⇒ ⛔ 不碰看板" if ONLY_WS else "全区"))
n = kill_all()
_p(" 已杀进程:%d 个" % n)
_p("✅ 全停完成(可反复跑,幂等)")
+3 -2
View File
@@ -1,7 +1,8 @@
{
"_说明": "本文件 = content_marketing_agent 工作区的协作机制部署配置(⛔ 不属于技能)。技能里 collabd.py 是通用代码,靠环境变量 COLLABD_CONFIG 指向本文件;不指 ⇒ 才回落到技能目录里的 collabd.config.example.json(范例,⛔ 不是生产配置)。",
"_说明": "本文件 = contentm_agent 工作区的协作机制部署配置(⛔ 不属于技能)。技能里 collabd.py 是通用代码,靠环境变量 COLLABD_CONFIG 指向本文件;不指 ⇒ 才回落到技能目录里的 collabd.config.example.json(范例,⛔ 不是生产配置)。",
"_改名说明": "🔴 2026-10-07 本工作区由 agent-product 改名而来。本文件原先 workspace 与 targets 键都还写着旧名 agent-product ⇒ 已改回本名。⛔ 不改的后果:常驻会把台账/目标写到已不存在的目录。",
"workspace": "E:/ProgramData/AIProject/content_marketing_agent",
"_改名说明20261008": "🔴 2026-10-08 二次改名:目录 content_marketing_agent ⇒ contentm_agent,而本文件 workspace 仍写旧名 ⇒ 常驻把心跳/台账/日志全写进已不存在的旧目录(实测 pid 56368、argv0 指向技能源那份 collabd.py)。本轮把 workspace 改成现名;同时 collabctl.py 的 WORKSPACES/KEEPALIVE_TASKS 两份清单(源 + 三个区副本)一并改为现名。",
"workspace": "E:/ProgramData/AIProject/contentm_agent",
"inbox": "tmp/supervise-inbox",
"live": "交付物/本机协作-实时状态.md",
"taskgraph": "",
+1 -1
View File
@@ -1 +1 @@
on
off
File diff suppressed because it is too large. Load diff
+68 -23
View File
@@ -1,23 +1,68 @@
# content_marketing_agent · 项目长期记忆
## MCN 短视频整合营销工作台(项目 slug `mcn-shortvideo-agent`)
- 产品规划四段流水线,**次序不可跳**:①产品需求(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)→ ②产品功能(功能清单+界面布局)→ ③界面交互 → ④原型说明文档。用户 2026-10-08 定:「应该要先完成 1 2步 在进行第3步」。
- ①段 1a 是**汇总型**需求(不是 grill 澄清产出),落 `docs/pm/mcn-shortvideo-agent/research/1a-需求文档.md`;1b 竞品分析在 `content-workbench` 项目下(`docs/pm/content-workbench/research/1b-竞品分析.md` + `证据附卷/` 5 份独立分析体),跨项目引用、不重写。
- 🔴 ③段设计供给口径(2026-10-08 用户定):**默认主线是 `oil-ui-pro`**(方法+独立评审),定调与令牌取③段自带样式库 `assets/design-systems/`(当前 `design-system-tiaoyue`);**不使用 `open-design`**(2026-10-08 起已由**另一个会话**随③段携带于 `references/stage-delivery/assets/open-design/`,作**可选件**、选了才用;源 `nexu-io/[email protected]`,Apache-2.0 本地裁剪版,64 MB / 4177 文件)。
- ⚠️ 2026-10-08 用户令已**改全局技能文档**(不再是「通则不改」):`product-planning/SKILL.md`、`references/stage-delivery/SKILL.md`、`references/stage-delivery/references/execution-runbook.md` 三份共 17 处,「③段默认主线」由 open-design 翻转成 oil-ui-pro;`open-design` 降为**可选件**(另一会话同期把它随段携带进 `assets/open-design/`,故口径是「选了才用」而非「装了才有」)。三份各写一条统一读法:凡出现 `open-design/...` 路径一律按段内相对路径 `assets/open-design/...` 读。
- 🔴 逐段管理要点:`assets/open-design/` 是**第三方件**,不许改其文件内容;署名见 `assets/open-design/ATTRIBUTION.md`。⚠️ 当前**缺 Apache-2.0 的 LICENSE 全文与上游 NOTICE**(2026-10-08 记账)。
- ⚠️ 全局技能包被多会话并发写:2026-10-08 02:2x 实测「本会话」与「另一个会话」同时在改 `stage-delivery/SKILL.md` / `execution-runbook.md` / `layouts-tooling.md` ⇒ 改前先看 mtime,改后必复跑 `check_naming.py`(该脚本只读、不写盘)。
- 🔴 **③段供给关系 = 单一可信源**(2026-10-08 用户令「按照建议处理」,A 方案已落地):`references/stage-delivery/SKILL.md` 的 `## 供给` 块是**唯一定义处** —— 6 行表:方法主线|定调与令牌|版式骨架|工艺数值判据|独立评审协议|多方向比选。③段其余章节、`references/execution-runbook.md`、`references/layouts-tooling.md`、总入口 `product-planning/SKILL.md`,提到供给**一律引 `§供给·<行名>`**(行名取表左列),⛔ 不许复述「谁是默认/路径在哪/装了才有」。**改供给只改那一块**,改完跑闸门。边界:各档**内部**篇目(如可选档 `craft/xxx.md`)属执行细节,留在 runbook 各步里,不算复述。起因:此前这一个事实被复述约 40 处,改一次动三份文件 17 处仍漏 13 处。
- ⚠️ 闸门 `check_naming.py` **必须带 `--ws`**:`python scripts/check_naming.py --root . --ws "E:/ProgramData/AIProject/content_marketing_agent"` ⇒ 期望 `通过 2059 | 失败 0`;只给 `--root` 会因找不到「含 `docs/pm` 的那一层」而 FAIL。
- 🔴 **产品规划技能包已立「单一可信源」门禁**(2026-10-08):`check_naming.py` 里的 `AUTHORITY` 表登记「会变的事实 → 唯一定义处」,除定义处外任何地方出现复述即 FAIL。当前 9 条:②③边界(权威=②段 §②—③ 交接口)|停线规则(全包禁写,权威=总入口 §执行规则)|可选档骨架名单(权威=`layouts-tooling.md` 开头)|说人话门槛|对比度数值|契约十二字段展开(权威=runbook §2.1)|②③定案原话|1b 定案原话|grill A/B 节火力点。**改这些事实只改权威处,然后跑闸门。**
- 🔴 `DEAD_PATHS` 检查:`strategy/`、`ux/` 这类已废目录形态若出现在正文的产出/只读/必读位置 ⇒ FAIL(已废路径曾 4 处残留且无门禁报)。含废止标记(旧/已废/已改名/曾/移进/改为…)的行豁免。
- ⚠️ 反面教训:`check_naming.py` 曾因**用 stale 变量**(`if old in t` 该用 `tt`,前面还跑了一个只赋值的空循环)导致「旧名提示」**恒不触发**(假绿)。**改门禁后必须做变异对照**:注一条假病进去,确认它真的报红,再还原。
- 真缺口:open-design `craft/` 的 13 份工艺数值判据(反 AI 味/无障碍/表单校验/动效纪律)在没装 open-design 的工作区**无供给来源** ⇒ 明说,⛔ 不编。
- 产物落点:执行期间一律落 `执行会话/目标-<标题前缀>-<sha1(title)[:6]>/`(域门禁+文档合同要求);正式归档 `docs/pm/mcn-shortvideo-agent/{research,prd}/` 由主会话收口后统一搬。
## 机制侧(本工作区)
- 全局技能根 `E:/ProgramData/.workbuddy/skills/`;本工作区技能目录 `.workbuddy/skills/` 目前只有 `aigc-idea-impression`。
- 本机裸 `bash` 会落到 WSL(路径被吃)⇒ 一律用显式路径 `E:/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin/bash.exe`。
- 派活排期名 `[执行]-[<goal.topics>]-<具体>`;本区当前 topic 仍是「开源项目调研」。
# content_marketing_agent · 项目长期记忆
## MCN 短视频整合营销工作台(项目 slug `mcn-shortvideo-agent`)
- 产品规划四段流水线,**次序不可跳**:①产品需求(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)→ ②产品功能(功能清单+界面布局)→ ③界面交互 → ④原型说明文档。用户 2026-10-08 定:「应该要先完成 1 2步 在进行第3步」。
- ①段 1a 是**汇总型**需求(不是 grill 澄清产出),落 `docs/pm/mcn-shortvideo-agent/research/1a-需求文档.md`;1b 竞品分析在 `content-workbench` 项目下(`docs/pm/content-workbench/research/1b-竞品分析.md` + `证据附卷/` 5 份独立分析体),跨项目引用、不重写。
- 🔴 ③段设计供给口径(2026-10-08 用户定):**默认主线是 `oil-ui-pro`**(方法+独立评审),定调与令牌取③段自带样式库 `assets/design-systems/`(当前 `design-system-tiaoyue`);**不使用 `open-design`**(2026-10-08 起已由**另一个会话**随③段携带于 `references/stage-delivery/assets/open-design/`,作**可选件**、选了才用;源 `nexu-io/[email protected]`,Apache-2.0 本地裁剪版,64 MB / 4177 文件)。
- ⚠️ 2026-10-08 用户令已**改全局技能文档**(不再是「通则不改」):`product-planning/SKILL.md`、`references/stage-delivery/SKILL.md`、`references/stage-delivery/references/execution-runbook.md` 三份共 17 处,「③段默认主线」由 open-design 翻转成 oil-ui-pro;`open-design` 降为**可选件**(另一会话同期把它随段携带进 `assets/open-design/`,故口径是「选了才用」而非「装了才有」)。三份各写一条统一读法:凡出现 `open-design/...` 路径一律按段内相对路径 `assets/open-design/...` 读。
- 🔴 逐段管理要点:`assets/open-design/` 是**第三方件**,不许改其文件内容;署名见 `assets/open-design/ATTRIBUTION.md`。⚠️ 当前**缺 Apache-2.0 的 LICENSE 全文与上游 NOTICE**(2026-10-08 记账)。
- ⚠️ 全局技能包被多会话并发写:2026-10-08 02:2x 实测「本会话」与「另一个会话」同时在改 `stage-delivery/SKILL.md` / `execution-runbook.md` / `layouts-tooling.md` ⇒ 改前先看 mtime,改后必复跑 `check_naming.py`(该脚本只读、不写盘)。
- 🔴 **③段供给关系 = 单一可信源**(2026-10-08 用户令「按照建议处理」,A 方案已落地):`references/stage-delivery/SKILL.md` 的 `## 供给` 块是**唯一定义处** —— 6 行表:方法主线|定调与令牌|版式骨架|工艺数值判据|独立评审协议|多方向比选。③段其余章节、`references/execution-runbook.md`、`references/layouts-tooling.md`、总入口 `product-planning/SKILL.md`,提到供给**一律引 `§供给·<行名>`**(行名取表左列),⛔ 不许复述「谁是默认/路径在哪/装了才有」。**改供给只改那一块**,改完跑闸门。边界:各档**内部**篇目(如可选档 `craft/xxx.md`)属执行细节,留在 runbook 各步里,不算复述。起因:此前这一个事实被复述约 40 处,改一次动三份文件 17 处仍漏 13 处。
- ⚠️ 闸门 `check_naming.py` **必须带 `--ws`**:`python scripts/check_naming.py --ws "E:/ProgramData/AIProject/contentm_agent"` ⇒ 期望 `通过 2060 | 失败 0 | 提示 25`;⛔ **别给 `--root .`**(那是「技能根」,给了会把工作区当技能包查、满屏 FAIL)。
- 🔴 **MCN 原型的两个硬口径(2026-10-08 修,别再踩)**:
1)**外壳高度链三件套**:`html,body{height:100%;overflow:hidden}` 只写这条 ⇒ `.app` 跟着内容长高、`.view` 自己不滚、滚动落回 `<body>`(`body.scrollTop` 有值而 `window.scrollY` 恒 0),而 body 是 hidden ⇒ **整页「滚不动」而不是「不滚」,折叠线以下的内容永远拿不到**。必须同时写 `.app{height:100vh;grid-template-rows:minmax(0,1fr)}` + `.main{min-height:0;overflow:hidden}` + `.view{flex:1 1 auto;min-height:0;overflow:auto}`。
2)**判据核滚动必须逐个容器核**:只复位/只核对 `window.scrollY` 会给出**假绿**(原型自检曾在 500×844 报「一屏装得下 7 行」,真值不到 1 行)。要核 `window` / `html` / `body` / `.view` 四个量。
⇒ **连带教训**:改门禁后那条**变异注入点也要重指** —— M9 原来注入 `window.scrollTo`,外壳修完后 window 根本滚不动,那条变异变成「抓不到东西的假变异」,已改成注入 `.view.scrollTop`。
- 🔴 MCN 原型密度真边界(2026-10-08 重测):**≥901px 宽达标**(1440/1280/1024 一屏 8 行、1000/960/920/901 七行),**≤900px 不达标**(900 三行、768 两行、641 一行、500×844 零行;P2 在 500×844 也掉到 5 行)。边界=两栏带 `.band` 的收线 `max-width:900px`。旧文档写的「边界 768px」是**假数**产物,已整表替换。
- 🔴 MCN 原型「外部参考版」照搬结论:`3c-GPT参考版.md` 那版 P1 用**满宽表格顺排**,照搬后账号矩阵首行顶 724px ⇒ 一屏只 2 行(契约 ≥6),把行内第二行小字拿掉仍只 4 行 ⇒ **满宽表格与「一屏 ≥6 行」不可兼得**,要兼得得把每格压成一个短值(动②段定的次级信息档位)。已登记、未动。
- 🔴 **学参照物=量到细节,⛔ 不是「知道有这个名字」**(2026-10-08 用户点破:「MCN 工作台里面每个组件的样式 高度 ICON 都是需要学习的,比如功能入口,感觉没有学到细节」)。
教训实例:功能入口卡 `.data-card` —— 名字是从参照物笔记里照抄的,但**图标(22px 单色)/ 内衬 16/18 / 标题 17px / 网格 200px / hover 位移**全丢了,只抄了个「白底 + 标题 + 描述」。
⇒ 定成纪律:**学任何组件都要回源站量**(`style.css` 的行号 + `app.js` 的生成函数),逐项记「参照物原值 / 我方现值 / 学没学 / 为什么」,**「刻意不学」的也要写理由**(⛔ 不许漏掉混过去)。
参照物位置:`E:/ProgramData/AIProject/mcn-short-video/project/短视频脚本创作/V1.0/mcn-work-shop/public/`(只读)。
量到的组件原值存在两处:`ui/布局排版参考-mcn-work-shop.md` §六(摘要)+ `ui/3d-审查报告.md` §十一(全量对照)。**三条刻意不学**:它的冷灰蓝品牌色 / 8 色相图标 / 圆角 12px 体系。
- 🔴 **第 5 个门禁 `ui/_tools/check_js.py`**(2026-10-08 上线):抠 `<script>` 段跑 `node --check` + **多行**扫描 script 区内每个 `<!-- … -->` 块里的**反引号**。
起因:「模板字面量里的 HTML 注释带反引号」这个坑**踩了 4 次**,每次都是页面在浏览器里才炸(白屏 / `xxx is not defined` / `Unexpected identifier`),而 `node --check` 整份 html **报不出来**。
⚠️ 必须**多行**扫 —— 反引号常在注释的**续行**上,单行 grep 抓不到(我自己就漏过一次)。已做变异对照(注入反引号 ⇒ FAIL 2 项、退出码 1)。
⚠️ 另一条硬教训:**几何一改(加图标、改内衬、改网格最小宽),逐视口密度表必须整表重跑** —— 第六轮只量了 1440(697px/6 行 ✅)就往下走,回头发现 640 从 5 行掉到 3 行(卡片变高 + minmax 180→200 让三张卡折成两行)。
- 🔴 **顶栏口径(2026-10-08 第四轮定案)**:顶栏只放**两项** —— 左「MCN 短视频整合营销工作台」(产品名)+ 右「**随手记**」。⛔ 不许再往里加东西。
依据:**②段 `2b` §286 只把「随手记」定为全局可达**(原文「随手记出现在任意页面一次点击内,F2 是 P0,不能埋在两层下」)⇒ 它必须挂全局外壳。其余一律不许挂顶栏。
⛔ **已删的六样,逐样来源**(详细排查在 `3d-审查报告.md` §十):`收起侧栏`(G-11)与**面包屑**来自**本项目参照物笔记** `ui/布局排版参考-mcn-work-shop.md`(⚠️ **它不是规则文件,是素材**);`演示·账号`(G-07)/`演示·状态`(G-09)是我造的原型件(规则只说「状态由**路由 + 演示开关**驱动」,路由那条已完整覆盖);顶栏`全局检索`(G-10)与②段 P1 的**页内板块**重复;`假设 2 项`是我自己挂在顶栏的第二处 → **改挂到「假设」徽章上**(徽章可点,G-08 仍活)。
🔴 两条纪律:①**别把「参照物产品的习惯」当需求搬进外壳**(本轮 6 项里一半是这么来的);②**撤销一个交互 ID 必须同时删掉它的 DOM**,否则判据「页面上每个 data-act 都在清单里」报红。
⚠️ 连带口径:顶栏内衬 8px ⇒ **49px、任何宽度不折行**;页面身份靠页头 h1(不再有面包屑);六态由**路由**进入(`#/p/p4/empty`)。
- 🔴 **导航口径(2026-10-08 第四次改定;层级与命名部分)**:左侧栏 **只有一层=八个功能项**,与②段八页一一对应;**短名一律 2 个字**(总览 / 选题 / 资产 / 创作 / 发布 / 画像 / 复盘 / 对账 —— 2 字是硬上限,见下面那条形态条目);页头仍写②段页面全名。**形态(64px 药丸浮栏、项 56×78、图标 24 + 名字常驻、中性填充当前态)以本文件下面那条「③段侧栏=64px 药丸浮栏」为准** —— ⛔ 不要在这里复述一遍,那是两处口径打架的老毛病。
自检判据:`#nav .nav-item` 恰 8 个、`#nav` 直接子元素全是 `.nav-item`(第二层 0 个)、八项逐个点过都落到自己那页、八页一次点击可达。
⛔ 历史弯路两条,别再走回去:①上一版写成「只有一层=四个大板块」(把「一层」读成「只剩板块、把页面藏起来」);②再上一版把八个页项塞进侧栏但带 240px 宽文字列表。
⚠️ 形态一改,**自检判据的选择器与变异注入点必须跟着改**(本轮 `.nav-flat`→`.nav-item`;M2/M8 注入点重指),否则判据会静默失效变恒绿 —— 这类假绿已经踩过 4 次(M7/M10 上一轮、M2/M8 本轮)。
- 🔴 **左右布局**:每页**都**有一处两栏(`.grid-main-side`,宽比 **1.35fr : .9fr**,照 `3c-GPT参考版` 的 `.grid.cols2`):左=上下文/列表,右=产出/动作/详情;主数据块仍满宽。`≤900px` 落单列(与 `.band` 同步)。
- ⚠️ **改原型时的两条硬坑(都踩过)**:① 在 JS 模板字符串里写 HTML 注释,**注释里不许出现反引号** —— 会把模板字面量提前闭合,而 `node --check` 仍通过(`` `x` `` 后接 `.y` 被解析成成员访问)⇒ 页面静默白屏;② HTML 注释**必须写 `-->`**,写成 `*/` 会把后面整段吞成注释。改完先跑 `node --check` 再跑自检。
- ⚠️ **功能入口卡的高度会转嫁给密度契约**:它紧贴「数据统计」下面,卡越高,下面那张「一屏 ≥6 行」的列表首行顶越低。当前靠三处收高(卡内衬 `12/16`、`≤1000px` 隐描述、`≤1024` 顶栏内衬 8px)把边界维持在 **901px**。
- 🔴 **产品规划技能包已立「单一可信源」门禁**(2026-10-08):`check_naming.py` 里的 `AUTHORITY` 表登记「会变的事实 → 唯一定义处」,除定义处外任何地方出现复述即 FAIL。当前 9 条:②③边界(权威=②段 §②—③ 交接口)|停线规则(全包禁写,权威=总入口 §执行规则)|可选档骨架名单(权威=`layouts-tooling.md` 开头)|说人话门槛|对比度数值|契约十二字段展开(权威=runbook §2.1)|②③定案原话|1b 定案原话|grill A/B 节火力点。**改这些事实只改权威处,然后跑闸门。**
- 🔴 `DEAD_PATHS` 检查:`strategy/`、`ux/` 这类已废目录形态若出现在正文的产出/只读/必读位置 ⇒ FAIL(已废路径曾 4 处残留且无门禁报)。含废止标记(旧/已废/已改名/曾/移进/改为…)的行豁免。
- ⚠️ 反面教训:`check_naming.py` 曾因**用 stale 变量**(`if old in t` 该用 `tt`,前面还跑了一个只赋值的空循环)导致「旧名提示」**恒不触发**(假绿)。**改门禁后必须做变异对照**:注一条假病进去,确认它真的报红,再还原。
- 真缺口:open-design `craft/` 的 13 份工艺数值判据(反 AI 味/无障碍/表单校验/动效纪律)在没装 open-design 的工作区**无供给来源** ⇒ 明说,⛔ 不编。
- 产物落点:执行期间一律落 `执行会话/目标-<标题前缀>-<sha1(title)[:6]>/`(域门禁+文档合同要求);正式归档 `docs/pm/mcn-shortvideo-agent/{research,prd}/` 由主会话收口后统一搬。
- 🔴 **工作区已 git 化**(2026-10-08 08:1x):远端 `[email protected]:admin/contentm_agent.git`(Gitea,SSH deploy key **有写权限**),本地分支 `main`,首次提交 `df56c2c`(1773 文件 / 205 MiB pack)。`.gitignore` 只排运行时噪音(collab 日志/脚本 `.bak*`/`supervise.pid`/`.workbuddy/tmp/`/`tmp/_*.txt`),**参考资料 231M 抽帧素材全量入库**(⛔ 不打折)。提交者身份是**局部**配置的 `WorkBuddy <[email protected]>`(全局 git config 未动),可推翻。
- 🔴 **本工作区现名 `contentm_agent`**(2026-10-08 定,旧名 `content_marketing_agent`,再早是 `agent-product`)。机制登记**已全部改成现名**:`collabd.config.json` 的 `workspace` + `collabctl.py` 的 `WORKSPACES`/`KEEPALIVE_TASKS`(**源 + 3 个区副本共 4 份,改一处要改 4 份**)+ ai1net 的 `peer_workspaces`。旧空壳目录改名 `content_marketing_agent.RETIRED-20261008` 保留(零删除)。⚠️ ai1net 改了 peer ⇒ **看板要重启**才生效(配置模块级只读一次)。
- 🔴 **本区协作机制当前是「停」态**(2026-10-08 用户令):开关 off、旧保活任务已注销(定义备份在 `tmp/_oldtask_backup.xml`)⇒ 目标完成后不再每 5 分钟空转。要再起 ⇒ `collabctl.py on --ws E:/ProgramData/AIProject/contentm_agent`。
- ⚠️ **`collabctl.py` 的 `off --ws` 曾越区**(`kill_all()` 全机扫描不认 `--ws`,一次杀掉他区+看板共 5 个进程)⇒ 2026-10-08 已修:`ONLY_WS` 时只杀本区心跳 pid 并提前 return,4 份同步。⛔ 改这文件记住**源 + 3 区副本**都要改。
## 机制侧(本工作区)
- 全局技能根 `E:/ProgramData/.workbuddy/skills/`;本工作区技能目录 `.workbuddy/skills/` 目前只有 `aigc-idea-impression`。
- 本机裸 `bash` 会落到 WSL(路径被吃)⇒ 一律用显式路径 `E:/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin/bash.exe`。
- 派活排期名 `[执行]-[<goal.topics>]-<具体>`;本区当前 topic 仍是「开源项目调研」。
- 🔴 **取证通道=「只连不起」**(2026-10-08 用户令「为什么要重新开浏览器,先检查之前是否开过浏览能否复用」):本机 **9223 上常驻一个独立浏览器实例**,动手前先 `netstat -ano | grep ":9223"` 探;在跑就直接连,⛔ 不另起。规则已写进 `skills/browser-harness/SKILL.md` 的「🔴 本机(用户明令)」段。`_tools/cap.py` 已照此改造:走 CDP `Emulation.setDeviceMetricsOverride` 定视口(**声明式,不再是 `--window-size` +偏移量**),只连 9223;顺带解除 500px 宽度下限,**390×844 现已可测**。⛔ 别新建自己起 Chrome 的脚本(本轮建过 `_tools/measure.py`,写完即删)。
- 🔴 **③段功能入口卡(`.data-card`)=三段纵向**(2026-10-08 第七轮定,照参照物 `mcn-work-shop` 首页逐值量):图标 22px **独占一行** → 标题 `--fs-18/600`(行高写死 1.35)→ 描述 `--fs-14`(行高写死 1.35);`gap:6px`(`--mg-6`)、`padding:16px`、`--sh-L1` 阴影;网格 `minmax(200px,1fr)`。**实测卡高 111.19px**(参照物同宽 113px)。⛔ 三个刻意不学:圆角 12px、`translateY(-2px)` 位移、一个功能一个色。`.sect-nav` **没有小标**(参照物也没有)。
- 🔴 **密度表的读法**(2026-10-08 更正):P1 账号矩阵的绿/红分界是「**≥820 绿**;**768 / 700 红**;**640 绿**(手机外壳);**560 / 500 红**」。⚠️ 旧文档曾把 768 记成 7 行 ✅ —— **那是错的**,真值 5 行 ❌;错因是旧通道 `--window-size` 的视口歧义(768 恰好卡在卡片「3 列/2 列」阈值 632px 上,只差 7px)。
- 🔴 **改一个组件的高度之前,先跑「改前基线」**:把改动回退成一份副本(如 `_scratch/base.html`),同一套判据跑满逐视口表 ⇒ 才能分清哪条红是自己造成的。⚠️「改完只量主视口」这个毛病已犯两次(第六轮 640、本轮 1440),两次都是逐视口表兜住的。
- 🔴 **浏览器:一个页面只开一个标签**(2026-10-08 用户令「后续调试网页 一个页面开一个标签就行了不要反复开」)。定义处=`E://ProgramData//.workbuddy//skills//browser-harness//SKILL.md`「🔴 本机(用户明令)」段(⛔ 不复述细则,只引一处)。⚠️ 起因:本会话调试原型时反复 `new_tab` 且忘了关,共享实例里堆出同一个页面的一串标签,用户亲眼看到。
- 🔴 **③段侧栏=64px 药丸浮栏(不是「纯图标栏」)**(2026-10-08 第七轮回源站实测更正)。真值:栏 64px/内衬 3px/圆角 100px/淡底+1px 淡描边的**药丸浮栏**(⛔ 无右边线);项 **56×78 药丸**(圆角 54/内衬 16/段间距 6),**图标 24 在上、2 字短名 12px/500 在下,两者都常驻**;当前项=中性填充 `ink 6%` + 满墨(⛔ 不用品牌紫底);非当前项 `--ink-faint`;项间无 gap;hover 只换色。**名字一律 2 字**(内容宽 56−32=24px);悬停提示的内容是**该页说明**、⛔ 不是名字。⛔ 三处不学:填充字形图标(我方用 mcn-work-shop 那套描边图标)/真浮层(仍占一列)/逐项对齐的 162px 说明列(我方是单条浮层)。⚠️ 改前那版「纯图标栏、名字只走提示」是**照 `library.json` 的计数猜的** —— 包里既没有导航几何、`design-system.html` 里 `app-sidebar` 也是 0 处。**教训:计数不是几何,包里没有的事实就回源站量。**
- 🔴 **③段密度分界(2026-10-08 第八轮 · A 方案后)**:P1 账号矩阵绿 = 1440/1280/1024/1000/960/920/901/900/840/820/**768**/**700**/**640**/**560**;红 = **只剩 500×844**。做法:`≤1000` 功能入口卡最小宽 `200→160`、`≤820` 统计条最小宽 `132→96`(`auto-fit` 只在真装不下时才缩 ⇒ 宽屏 10 个视口一格未动)+ 移动档标签条藏掉 16px 横向滚动轨。⚠️ 这两档阈值已写进 `DESIGN.md` §1.1 ⑨ 断点表(原表 `901–1024` 与 `901–1000` **区间重叠**,已校正成六档不重叠)。
- 🔴 **③段导航规则已改(2026-10-08 第八轮)**:`layouts-tooling.md` **§5.5.2 判据订正** —— 从「栏宽必须 240–280px」改成「**每一项的名字必须常驻可读**(字号 ≥12px 不截断;64px 栏的名字上限 2 个汉字)」,判的是实质不是手段;**新增 §4.9「导航栏」一档**(两套合规形态:64px 药丸栏 / 240–280px 宽栏;含当前项只改颜色、窄屏整段换形态、⛔ 横滚条不许画滚动轨、图标一处出口、⛔ 不许照组件清单计数反推形态)。⇒ 我们现在的「64px 药丸浮栏 + 2 字常驻短名」**从"判据判不过"变成"合规"**。
- 🔴 **③段两条元规则(2026-10-08 第八轮新增,`layouts-tooling.md` §5.6)**:① 参照物原值与我方令牌刻度冲突时**必须**走三步(量到数值 → 差异列表 → 逐条「学/不学+理由+代价」),⛔ 不许默默"就近落位",「刻意不学」⛔ 不得用于掩盖规则违反;② **自造物料(参照物笔记、临时对照表)⛔ 不得作为判据来源** —— 证据栏只许写「技能原文的文件:小节」「源站/源文件实测读数」「用户原话」。
- 🔴 **③段 Gate-3 新增强制两条(2026-10-08 第八轮)**:① **「看过」必须有落盘记录**(`oil-ui-pro` 10 分制评分写进 3d),⛔ 不许用「自检 N 项全绿」顶替;② **人工项必须给机检实现,否则写死「本条无机检」,🔴 ⛔ 不许在没有取值手段的条目上打 ✅**。⚠️ 起因:`3d` §九 曾把「§5.5 五条逐条过完」记成 `✅ 自检机核`,而那五条当时**零覆盖**。
- ⚠️ **全局技能包 `check_naming.py` 曾带 3 条既有 FAIL(2026-10-08 第八轮修)**:①「停线规则」的 AUTHORITY `authority` 写成 `None`(=连权威处也不许写,与本条 `why` 自相矛盾;且 `SKILL.md` 里根本没有这条规则)⇒ 已改 `SKILL.md` 并把规则补进「执行规则」;②③ `stage-proto-doc` 与 `usage-scenario` 两处仍写①段已废的 `strategy/` 路径 ⇒ 已改 `research/1d-产品策略.md` / `research/1e-使用场景.md`。复跑:**通过 2060 / 失败 0 / 提示 27**。⛔ 改全局技能包前后都要跑这个闸门。
+1 -1
View File
@@ -1 +1 @@
{"e14b123f-4a11-490d-a15b-1bf3f2683729": [1, 1791232202.217294], "35069ba1-9d9c-42c6-a367-a1ec54fb7cee": [1, 1791380226.470935], "fae90e6f-c1fa-404e-b023-6e5fb4835b6a": [0, 1791385267.0975301]}
{"e14b123f-4a11-490d-a15b-1bf3f2683729": [1, 1791232202.217294], "35069ba1-9d9c-42c6-a367-a1ec54fb7cee": [1, 1791380226.470935], "fae90e6f-c1fa-404e-b023-6e5fb4835b6a": [0, 1791385267.0975301], "184c4986-d8ec-447e-b1ed-96f568c99fb5": [0, 1791455457.6998634]}
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<URI>\collabd-keepalive-content_marketing_agent</URI>
</RegistrationInfo>
<Principals>
<Principal id="Author">
<UserId>S-1-5-21-1681606927-3135761007-1406112336-500</UserId>
<LogonType>InteractiveToken</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
<Hidden>true</Hidden>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<StartWhenAvailable>true</StartWhenAvailable>
<IdleSettings>
<Duration>PT10M</Duration>
<WaitTimeout>PT1H</WaitTimeout>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
</Settings>
<Triggers>
<TimeTrigger>
<StartBoundary>2026-10-08T02:42:54+08:00</StartBoundary>
<Repetition>
<Interval>PT5M</Interval>
<StopAtDurationEnd>true</StopAtDurationEnd>
</Repetition>
</TimeTrigger>
</Triggers>
<Actions Context="Author">
<Exec>
<Command>E:\ProgramData\.workbuddy\binaries\python\versions\3.13.12\pythonw.exe</Command>
<Arguments>"E:/ProgramData/AIProject/content_marketing_agent/.workbuddy/collab/supervise-launch.py"</Arguments>
<WorkingDirectory>E:\ProgramData\AIProject\content_marketing_agent</WorkingDirectory>
</Exec>
</Actions>
</Task>
+1 -1
View File
@@ -1 +1 @@
2026-10-08 02:14:26
2026-10-08 08:45:45
+1 -1
View File
@@ -1 +1 @@
{"roles": {}, "notify_pending": [], "to_main_retired": true, "queue_info": {"n": 12, "by": {"pending": 0, "running": 0, "done": 12, "blocked": 0}, "awaiting": "", "sent": "", "phase": "", "notice": "", "deliver": {"skipped": "retired-20261003"}, "goals_open": true}, "q_sig": "1b5dce36-1d47-4661-b6e5-af6c7ad2e33e=done|34ab0198-d0fa-4e9d-978b-6c7f40a2978a=done|47860f06-c51f-4c2a-b7ad-2a6362b8a675=done|52ace70a-bd4a-4201-a7b0-62237c092375=done|6ec1b428-b2d7-4274-bb74-07c1122d9aa6=done|75bfa487-7983-4863-b365-44085950f016=done|a41bb3a3-1015-4a1c-9269-1fd75f998cb7=done|a4993b72-040e-49db-beb4-375f5201ff61=done|ea3ce52d-6afd-4397-a737-ec7626e2e73d=done|f1b99d3d-2488-44b1-9d43-1e41524d29ba=done|fae90e6f-c1fa-404e-b023-6e5fb4835b6a=done|fd655683-dec4-461f-88cd-b7135638d995=done", "q_transition_at": 1791404416.6371648}
{"roles": {}, "notify_pending": [], "to_main_retired": true, "queue_info": {"n": 12, "by": {"pending": 0, "running": 0, "done": 12, "blocked": 0}, "awaiting": "", "sent": "", "phase": "", "notice": "", "deliver": {"skipped": "retired-20261003"}, "goals_open": false}, "q_sig": "1b5dce36-1d47-4661-b6e5-af6c7ad2e33e=done|34ab0198-d0fa-4e9d-978b-6c7f40a2978a=done|47860f06-c51f-4c2a-b7ad-2a6362b8a675=done|52ace70a-bd4a-4201-a7b0-62237c092375=done|6ec1b428-b2d7-4274-bb74-07c1122d9aa6=done|75bfa487-7983-4863-b365-44085950f016=done|a41bb3a3-1015-4a1c-9269-1fd75f998cb7=done|a4993b72-040e-49db-beb4-375f5201ff61=done|ea3ce52d-6afd-4397-a737-ec7626e2e73d=done|f1b99d3d-2488-44b1-9d43-1e41524d29ba=done|fae90e6f-c1fa-404e-b023-6e5fb4835b6a=done|fd655683-dec4-461f-88cd-b7135638d995=done", "q_transition_at": 1791404416.6371648}
-1
View File
@@ -1 +0,0 @@
2026-10-08 04:27:26 目标已完成([检查]-[目标检查]-content_marketing_agent-第17棒)
+1 -1
View File
@@ -1 +1 @@
70572
40016
@@ -40,7 +40,8 @@
**板块清单(从上到下)**
1. 今日待处理 —— 跨账号的待办:待审、待确认、待复盘各几件
2. 账号矩阵列表 —— 一行一个账号,行内三件事:今日该发什么 / 已发什么 / 效果如何
2. 账号矩阵 —— 每个账号今日该发什么 / 已发什么 / 效果如何
⛔ 本块**不写怎么呈现**(矩阵、列表、卡片都是形态,归③段判,见 `layouts-tooling.md` §0)
3. 异常值提示 —— 最近哪些内容的数据异动
4. 本月表现最好的一条
5. 全局检索与随手记入口
@@ -51,7 +52,7 @@
| 信息 | 档 | 判据回答 |
|---|---|---|
| 账号矩阵列表 | 主屏常驻 | 删掉它,主操作的对象就没了 —— 不知道有哪些账号,无从决定先处理哪件 |
| 账号矩阵 | 主屏常驻 | 删掉它,主操作的对象就没了 —— 不知道有哪些账号,无从决定先处理哪件 |
| 今日待处理 | 主屏常驻 | 删掉它,主操作没有候选可挑,做不成 |
| 异常值提示 | 可点入 | 删掉它,主操作仍做得成(异常值是 P2 的输入,不是这一页的决策依据) |
| 本月表现最好 | 可点入 | 删掉它,主操作完全不受影响 —— 它只是激励 |
@@ -68,8 +69,8 @@
**板块清单(从上到下)**
1. 对标监控概览 —— 四个数:在监控的账号数 / 低粉爆款条数 / 异常值条数 / 近三天更新条数
2. 对标内容列表 —— 每条带它相对该账号平时水平的倍数
3. 评论区洞察区(可点入子区)—— 取评论、出候选选题
2. 对标内容 —— 每条带它相对该账号平时水平的倍数(⛔ 同 P1,不写呈现)
3. 评论区洞察(可点入子区)—— 取评论、出 AI 候选选题(`2a` F3)
4. 选题库 —— 分「待做 / 在写 / 已用」三组
5. 灵感速记入口
@@ -79,10 +80,10 @@
| 信息 | 档 | 判据回答 |
|---|---|---|
| 对标内容列表 | 主屏常驻 | 删掉它,主操作的对象没了,做不成 |
| 对标内容 | 主屏常驻 | 删掉它,主操作的对象没了,做不成 |
| 选题库 | 主屏常驻 | 删掉它,主操作没有可推进的条目,做不成 |
| 对标监控概览四数 | 主屏常驻 | 删掉它,看不出哪个账号值得看 —— 列表会长到没法挑,等于主操作做不成 |
| 评论区洞察区 | 可点入 | 删掉它,仍能从对标列表拿到选题 |
| 评论区洞察 | 可点入 | 删掉它,仍能从对标列表拿到选题 |
| 灵感速记入口 | 可点入 | 同 P1 的随手记,全局可达 |
---
@@ -94,7 +95,7 @@
**板块清单(从上到下)**
1. 分区切换 —— 角度 / 结构 / 开场白 / 标题,一次看一个
2. 条目列表 —— 当前分区下的条目
2. 资产条目 —— 当前分区下的条目(⛔ 不写呈现)
3. 单条详情 —— 原文、出处、(草稿标记)
4. 引用入口 —— 把这条拿去创作台用
@@ -105,7 +106,7 @@
| 信息 | 档 | 判据回答 |
|---|---|---|
| 分区切换 | 主屏常驻 | 删掉它,四个分区分不开,入库不知道该进哪一区,主操作做不成 |
| 条目列表 | 主屏常驻 | 主操作对象 |
| 资产条目 | 主屏常驻 | 主操作对象 |
| 单条详情(原文 / 出处) | 可点入 | 删掉它,入库与引用都还做得成(入库门禁在守卫层,不靠这里显示) |
| 引用入口 | 可点入 | 删掉它,`2a` F4 的主路径改成从创作台来找,多绕一步;但 P3 自己的主操作(入库)不受影响 |
@@ -120,8 +121,9 @@
1. 当前内容标识 —— 这是哪条选题
2. 环节进度 —— 七个环节的当前位置,可回退
3. 当前环节工作区 —— 这一步实际干活的地方
4. 资产引用区 —— 从资产库拿角度、结构、开场白、标题
5. 版本列表(可点入)
4. AI 产出与采纳 —— 当前环节的 AI 产出(生成中 / 已生成 / 失败重试)+ 采纳·驳回·改后再用
5. 资产引用区 —— 从资产库拿角度、结构、开场白、标题
6. 版本列表(可点入)
**主操作**:把当前环节推进到下一环节。
@@ -131,6 +133,7 @@
|---|---|---|
| 环节进度 | 主屏常驻 | 删掉它,不知道下一环节是什么,主操作做不成 |
| 当前环节工作区 | 主屏常驻 | 主操作的对象 |
| AI 产出与采纳 | 主屏常驻 | 删掉它,当前环节的产出无处看、无处采纳 ⇒ 推进到下一环节做不成(`2a` 的 AI 状态流转已有,落位在此) |
| 当前内容标识 | 主屏常驻 | 删掉它,改到别的选题上也不知道,等于做错 |
| 资产引用区 | 可点入 | 删掉它,仍能凭空写(这正是 S2 要治的老毛病),主操作本身做得成 |
| 版本列表 | 可点入 | 删掉它,推进流程不受影响;只有回溯旧版时才需要 |
@@ -193,11 +196,12 @@
**板块清单(从上到下)**
1. 待复盘列表
1. 待复盘项
2. 这一条的表现数据
3. 归因结论区 —— 由人确认
4. 回写目标提示 —— 这次回写到哪个账号
5. 历史复盘(可点入)
3. 归因结论(由 AI 给出,可编辑)
4. 确认与改判 —— 采纳、驳回或改后再用
5. 回写目标提示 —— 这次回写到哪个账号
6. 历史复盘(可点入)
**主操作**:确认归因并回写。
@@ -206,8 +210,9 @@
| 信息 | 档 | 判据回答 |
|---|---|---|
| 表现数据 | 主屏常驻 | 删掉它,归因没有依据,主操作做不成 |
| 归因结论区 | 主屏常驻 | 主操作对象 |
| 待复盘列表 | 主屏常驻 | 删掉它,不知道有什么可复盘,主操作做不成 |
| 归因结论(可编辑) | 主屏常驻 | 主操作对象 |
| 确认与改判 | 主屏常驻 | 删掉它,结论没有采纳或驳回 ⇒ 回写没有依据,等于主操作没做成 |
| 待复盘项 | 主屏常驻 | 删掉它,不知道有什么可复盘,主操作做不成 |
| 回写目标提示 | 主屏常驻 | 删掉它,回写会落到错的账号,这条经验就废了 —— 等于主操作没做成 |
| 历史复盘 | 可点入 | 删掉它,当前这次复盘仍做得成 |
@@ -219,7 +224,7 @@
**板块清单(从上到下)**
1. 发布记录列表 —— 谁在什么时候确认发的、发的是哪一版
1. 发布记录 —— 谁在什么时候确认发的、发的是哪一版(⛔ 不写呈现)
2. 单条溯源 —— 从记录回到内容与版本
3. 对账核对区 —— 内容、发布记录、收支三样对得上
4. 商单与收支(可点入,所属功能 F12 为 P2,第一版可能没有)
@@ -230,7 +235,7 @@
| 信息 | 档 | 判据回答 |
|---|---|---|
| 发布记录列表 | 主屏常驻 | 知道有哪些记录,不知道就无从核销。判据:删掉它,主操作没有对象 |
| 发布记录 | 主屏常驻 | 知道有哪些记录,不知道就无从核销。判据:删掉它,主操作没有对象 |
| 对账核对区 | 主屏常驻 | 主操作对象 |
| 单条溯源 | 可点入 | 判据答「做得成」—— 核销看列表就够;要深究才点进溯源 |
| 商单与收支 | 可点入 | 删掉它,主操作仍做得成;且 F12 是 P2,第一版可能整块没有(见 `2a` §五 的暂缓项) |
@@ -257,7 +262,7 @@
| P1 | P2 | 点「异常值提示」里的某条,或从今日待处理里挑到选题类待办 |
| P1 | P4 | 今日待处理里有「在写」的内容 |
| P1 | P5 | 今日待处理里有待审 / 待确认的内容 |
| P1 | P6 | 点账号矩阵列表里的某个账号 |
| P1 | P6 | 点账号矩阵里的某个账号 |
| P1 | P7 | 今日待处理里有待复盘的 |
| P1 | P8 | 今日待处理里有待核销的 |
| P2 | P3 | 对某条对标内容发起拆解 |
@@ -0,0 +1,108 @@
# 2b 骨架形态优化方案
> 面向:`prd/2b-界面布局.md`(②段,2026-10-08 02:30 定稿)
> 起因:用户 2026-10-08 指出现有界面「排版布局一点也不像 agent 的产品,像 10 年前的后台管理系统」。
> 本份只讲**骨架形态**(主视觉是什么、块与块用什么空间关系)如何改,⛔ 不动功能条目(那是 `2a`)、⛔ 不写视觉词(配色/字体/间距/组件样式仍归③段)。
> 写于:2026-10-08 08:5x,主会话。
---
## 一、现有骨架的四宗病(都有出处,⛔ 不是观感)
### 病 1 · 八页同构:每页都是「从上到下堆 4–5 块」的纵向单列
- 出处:`2b` §二 八页,每页的结构一律是「板块清单(从上到下)1–5」。
- 后果:八页骨架长得一模一样 —— 只是块名不同。③段照它做出来,就是八个长得一样的后台表单页。
- 现代工作台的做法:**不同页用不同空间关系**(矩阵 / 主从 / 对照 / 时间线 / 画布 + 侧栏),让每页有各自主视觉。
### 病 2 · 列表是唯一的信息呈现
- 出处:P1「账号矩阵列表 —— **一行一个账号**」、P2「对标内容列表」、P3「条目列表」、P6「账号列表」、P7「待复盘列表」、P8「发布记录列表」⇒ **六页主视觉都是列表**。
- 后果:产品叫「矩阵工作台」,八页里一处矩阵都没有;「待复盘列表」这类名字本身就把形态写死了 —— ③段照做只能画列表。
- 现代工作台的做法:主视觉是**数据本身**(矩阵 / 图表 / 缩略图卡),列表只用于「需要逐条操作」的场合。
### 病 3 · 没有 AI/Agent 的位置
- 出处:P4「环节进度 —— 七个环节」与「当前环节工作区」,七个环节里哪一步出 AI 产出、产出放哪、人怎么采纳或驳回,**骨架里一个字都没有**;P7「归因结论区 —— 由人确认」暗示结论是 AI 给的,但骨架没给「AI 结论」留块。
- 后果:产品名带 agent、功能表里有多条 AI,界面上却看不出 AI 在哪 —— 这是「不像 agent 产品」最直接的一条。
- 现代 Agent 产品的核心交互是「生成 → 审阅 → 采纳/驳回 → 回写」,骨架必须为它留位置。
### 病 4 · 缺一层「形态语言」
- 出处:`2b` 文首两条硬规 ——「⛔ 全文零视觉词」+「骨架冻结,③段不许新增/移动/删除板块」。
- 后果:②段只给块名与顺序,③段只给皮肤与交互,**「这产品该长成什么样」没人管**。中间那层是空的,两头都不许碰。
- `3c-GPT会诊.md` 的独立评审把结果说得很明白:「遮住文字后认不出是任何一家…不是克隆,是**没有品牌辨识度的通用后台**」;「卡片化+大留白=**没认出品类**」。
---
## 二、逐页改法(八页,各给形态)
### P1 矩阵总览 —— 从「一列账号」改成「真矩阵」
- 主视觉:**账号 × 日期的网格**。纵轴账号、横轴日期(今天 / 明天 / 后天),格子 = 该账号当天的内容状态(已发 / 待审 / 缺稿)+ 一个关键数据。
- 异常值**标在格子上**(颜色只用于异常与缺口),不再单独挂一块「异常值提示」。
- 顶部一条**今日行动条**:今天要先处理的 N 件事(跨账号),点一条直接跳到那一件事。
- 板块顺序改为:① 今日行动条 ② 账号矩阵(主视觉)③ 本月表现最好的一条 ④ 随手记入口(全局可达)。
- ⚠️ 依赖 `1a` 待复核第 5 条(矩阵级视图是否真需要)。若复核为「不需要」,本页降为单账号今日,矩阵下移到账号切换 —— 这条前提不变。
### P2 选题雷达 —— 从「文字列表」改成「缩略图卡片流 + 倍数徽章」
- 主视觉:**对标内容卡片流**,每张卡带封面缩略图、标题、相对该账号平时水平的**倍数徽章**(这是这一页的记忆点)。
- 顶部四数改成**紧凑 KPI 条**(数字为主、不加卡片框)。
- 板块顺序:① KPI 条 ② 对标内容卡片流(主视觉)③ 选题库(待做 / 在写 / 已用 三组,组内仍用紧凑行)④ 评论区洞察(可点入)⑤ 灵感速记(全局)。
### P3 资产库 —— 分区保持,条目改摘录卡,详情用抽屉
- 主视觉:**摘录卡网格**(角度 / 结构 / 开场白 / 标题 四个分区,一次一个)。卡片只放原文摘录与出处,⛔ 不做大留白卡片。
- 单条详情**右侧抽屉**打开,⛔ 不再把详情当独立板块往下堆(现在的写法会让主区滚很長)。
- 板块:① 分区切换 ② 摘录卡网格 ③ 引用入口(卡上直接有)④ 详情抽屉(浮层,不算块)。
### P4 创作台 —— 全产品最该改的一页,骨架要给 AI 留位置
- 主视觉:**流水线画布(七个环节的横向轨道)+ 当前环节工作区** —— 环节轨道常驻顶部,走过的环节可回退,当前环节展开成工作区。
- 新增一块 **AI 产出区**:当前环节的 AI 产出(生成中 / 已生成 / 失败重试)+ **采纳 / 驳回 / 改后再用** 三个动作。这是「像 agent 产品」的关键,七个环节里凡是有 AI 产出的都走这一块。
- 资产引用区改成**右侧常驻侧栏**(创作时要随时取角度/结构/开场白),⛔ 不再是「可点入」的折叠块。
- 板块:① 当前内容标识 ② 环节轨道(常驻)③ 当前环节工作区(主视觉)④ AI 产出区 ⑤ 资产引用侧栏(常驻)⑥ 版本列表(可点入)。
### P5 发布中心 —— 从「一版一版竖排」改成「对照」
- 主视觉:**原稿 × 各平台版本的对照视图**(左原稿,右各版本;或网格卡片,一平台一卡带平台标识)。
- 检查结果改成**逐条 diff 清单**(硬拦项置顶、提醒项次之),每条能跳到出问题的那一处,⛔ 不再是一块「检查结果」文字。
- 板块:① 目标选择 ② 版本对照(主视觉)③ 检查 diff 清单 ④ 确认发布(含二次确认)⑤ 发布记录(可点入)。
### P6 账号画像 —— 画像改成卡,记忆天然是时间线
- 主视觉:**画像卡(六维)+ 记忆时间线**。记忆条目是「只追加、不覆盖」⇒ 它天然就是时间线形态,现在写成「可点入」把形态浪费了。
- 账号列表改成**顶部横向切换条**(账号数 10–50,竖列表占地方且和矩阵页重复)。
- 板块:① 账号切换条 ② 画像六维卡(主视觉)③ 记忆时间线 ④ 关联内容(可点入)。
### P7 复盘台 —— 数据即主视觉,归因区给 AI 结论留位
- 主视觉:**表现数据区**(关键指标 + 趋势小图,数据是主角,⛔ 不是三个裸数字块)。
- 归因区明确分成两块:**AI 归因结论**(可编辑)+ **人确认 / 改判**(采纳或驳回)。现在的「归因结论区 —— 由人确认」把这两件事混在一块里,是这一页最大的形态问题。
- 待复盘列表改成**左侧紧凑列表**(选一条,右边看详情),⛔ 不再占主视觉。
- 板块:① 待复盘列表(侧)② 表现数据(主视觉)③ AI 归因结论 ④ 人确认与改判 ⑤ 回写目标提示 ⑥ 历史复盘(可点入)。
### P8 记录与对账 —— 对账天然是三栏对照
- 主视觉:**三栏对照**(内容 / 发布记录 / 收支),一屏看三样对不对得上,⛔ 不再是「一个核对区」。
- 发布记录列表改成紧凑表(谁、何时、哪一版),单条溯源用抽屉。
- 板块:① 发布记录表 ② 三栏对账(主视觉)③ 单条溯源(抽屉)④ 商单与收支(可点入,F12 为 P2)。
---
## 三、②段要补的三件事(补上缺的那一层)
1. **每页加「形态」字段**:在「板块清单」旁边写明这一页的**主视觉是什么**与**块间空间关系**(矩阵 / 卡片流 / 对照 / 时间线 / 画布+侧栏)。⛔ 这不算视觉词 —— 它说的是结构与呈现,不是配色字体间距。
2. **每页加「AI 在哪」字段**:这一页有没有 AI 产出、产出落在哪块、人怎么采纳或驳回。八页逐页给结论(没有的写「无」,⛔ 不许省略)。
3. **全局加「形态语言」一节**:定义本产品的形态词汇(矩阵、摘录卡、对照、时间线、流水线画布、AI 产出区),并规定**不同页用不同形态、⛔ 不许八页同构**。
---
## 四、执行顺序(不能倒)
1. 先改 `2b`(本方案 §二 八页改法 + §三 三件事)。
2. 再让③段按新骨架重做视觉与交互 —— `ui/_tools/check_skeleton.py` 的机检基线**必须同步更新**(它现在拿旧骨架当权威,③段改一位就报红)。
3. ③段重做时,视觉参照另行拍板(见主会话转给用户的待拍板项)。
⛔ 顺序倒了会白做:只重做③段视觉治不好「像后台」—— 骨架不动,换什么皮肤都还是通用壳。
@@ -0,0 +1,86 @@
# 骨架优化方案 v2(②③分段 · 按各自权责)
> 取代 v1:`骨架优化方案-v1-作废-形态误归②段.md`(v1 把「形态」整层划给了②段,口径错了,已留档作废)。
> v1 错在哪:②段《界面布局》里「账号矩阵列表 —— **一行一个账号**」这类**形态描述**本就不该由②段写;
> 而形态判定的权威工具 `layouts-tooling.md` 文首**明写「⛔ 本文件是 `stage-delivery` 自己的东西」**,§0 就是「**先判形态,再挑骨架**」⇒ 形态归③段。
> 写于:2026-10-08 08:5x,主会话。用户口径:「制定骨架是 2、3 步技能交叉知识,必须用 3 步骤技能,而且第 3 步可以往更好的体验修改」。
---
## 〇、骨架分两层,各归各段(判据:②段 SKILL.md §②—③ 交接口)
| 层 | 归谁 | 具体是什么 |
|---|---|---|
| **块级骨架** | **②段定死** | 有哪几页 / 每页几个板块、板块怎么排 / 跨页关系 / 每页主操作 / 每条信息在哪一档 |
| **形态与版式** | **③段** | 判形态(列表型/详情型/侧区型…)、挑版式骨架、每个板块的视觉实现与交互行为、状态与空态、响应式 |
- ②段口径原文:「骨架是判断基准,必须在②段定死」「③段不许新增/移动/删除板块,缺板块要回②段改」⇒ **冻结的是块级,不是形态**。
- ③段口径原文(`layouts-tooling.md`):「⛔ 本文件是 `stage-delivery` 自己的东西」「工具型页面的版式在本项目只有这一份来源」⇒ **形态是③段的地盘**,且③段**有裁量权把它往更好的体验改**。
- ⇒ v1 的错误:把「P1 做成矩阵」「P5 做成对照」这类**形态决策**当成块级改动推给②段,方向反了。
---
## 一、归②段的改动(块级,只这几处)
### 1.1 删掉越界的形态措辞(⛔ ②段写了形态 = 侵了③段的地盘)
- P1 板块 2 原写「账号矩阵列表 —— **一行一个账号**,行内三件事」⇒ 删掉「一行一个账号」与「行内」,只留块名与承载内容。
- P2 板块 2「对标内容列表」、P3 板块 2「条目列表」、P7 板块 1「待复盘列表」、P8 板块 1「发布记录列表」⇒ 块名里的「列表」同样是形态词,改成中性块名(如「对标内容」「资产条目」「待复盘项」「发布记录」)。
- 理由:块名一写「列表」,③段就被迫画列表 —— 这正是「像后台」的源头之一。
### 1.2 给 AI 产出补块位(功能已有,落位缺失)
- `2a` 里 AI 相关功能都有状态流转(如 `idle → 抓取中 → 已出候选 → 已采纳/忽略`、AI 调用失败可重试、重复生成不覆盖),但 `2b` 的 P4 板块清单里**没有一个块承载它**。
- ⇒ P4 增加一块:**AI 产出与采纳**(承载当前环节的 AI 产出、采纳/驳回/改后再用)。⛔ 这不是加功能,是把 `2a` 已有的功能落到位。
- P7 同理:现有「归因结论区 —— 由人确认」把两件事混在一块,拆成 **归因结论**(可编辑)与 **确认与改判** 两块。
- P2 的「评论区洞察区」承载的是 F3 的 AI 候选选题,块名补一句「含 AI 候选」即可,不必加块。
### 1.3 板块分档要跟着改的
- P4 新增的「AI 产出与采纳」档位=**主屏常驻**(判据:删掉它,当前环节的产出没地方看也没法采纳,主操作「推进到下一环节」做不成)。
- P7 拆出的「确认与改判」档位=**主屏常驻**;「归因结论」同样**主屏常驻**。
- P1 的「异常值提示」若③段决定把异常标进矩阵格子,档位从「可点入」降为**并入主视觉** ⇒ 回②段改档,⛔ ③段不能自己改档。
---
## 二、归③段的改动(形态与体验,③段自己定、自己负责改好)
### 2.1 逐页判形态(用 `layouts-tooling.md` §0 的「先判形态,再挑骨架」)
- P1:页面上能数出「并列的同类记录」(账号)⇒ 判**列表型**;但列表型里 §1 行式列表与 §2 表格式清单都不等于「一行一条」——**矩阵是表格式清单的一种排布**(轴转置:账号做行、日期做列),③段可以这么画,⛔ 不需要②段改块名。
- P2:并列同类记录(对标内容)⇒ 列表型;主视觉要不要带缩略图卡,是③段的视觉实现范畴。
- P3:并列条目 + 单条详情 ⇒ **侧区型**(§4 主从侧区:列表↔详情两个工作面来回)。
- P4:围绕**单个对象**(一条内容)展开 ⇒ **详情型**(§3 详情面板);七个环节轨道属于交互实现,归③段。
- P5:一稿多版并列 ⇒ 列表型(版本之间要对照,§2 表格式清单的高密度变体适用)。
- P6:单对象(一个账号)+ 记忆流水 ⇒ 详情型 + 时间线(时间线是③段的呈现选择)。
- P7:单条内容的表现与归因 ⇒ 详情型;表现数据做成数据主视觉是③段的视觉实现。
- P8:并列记录 + 三样对账 ⇒ 列表型 + 对照区。
### 2.2 ③段要补的版式档(现有 §0 只有三类,不够用)
`layouts-tooling.md` §0 现有形态只有 **列表型/详情型/侧区型** 三类,本产品至少要再补四类:
1. **矩阵型**(两个维度交叉的网格:账号 × 日期)—— P1 用。
2. **对照型**(同一母体的多个版本并排比较)—— P5、P8 用。
3. **流水线型**(多环节轨道 + 当前环节工作区,可回退)—— P4 用。
4. **时间线型**(只追加、不覆盖的流水记录)—— P6 记忆条目用。
⛔ 补档要落在 `layouts-tooling.md`(③段自己的工具库),⛔ 不是回②段改。
⚠️ 它是**全局技能包**里的文件 ⇒ 改它会影响到别的工作区,动之前要由用户拍板(见主会话转出的待拍板项)。
### 2.3 体验上③段可以(也应当)主动改的
- 数据密度:现在是每块包成 24px 圆角白卡 + 大留白,评审判定为「没认出品类」;③段有权把主视觉换成数据本身(紧凑行/列右对齐/颜色只用于涨跌与异常),⛔ 不需要②段批准。
- AI 生成中态:P4 新增的 AI 产出块,生成中显示进度与可中断、失败可重试,是交互行为范畴 ⇒ ③段定。
- 状态与空态:每一块的空态长什么样、加载中什么样,全部归③段。
- 响应式:窄屏怎么变,归③段(现有 B-15 那一条窄屏装不满 6 行,也属③段自己的账)。
---
## 三、执行顺序(按权责分头走)
1. **②段**(本方案 §一):删形态措辞 → 给 AI 产出补块位 → 改相应分档。
2. **③段**(本方案 §二):按新块名重判形态 → 补 `layouts-tooling.md` 的四个档 → 重做原型视觉与交互。
3. **机检基线同步**:`ui/_tools/check_skeleton.py` 现在拿旧骨架当权威,②段改完块名后必须同步,否则逐位比对会误报。
⛔ 顺序要点:**形态问题在③段解决,块级问题才回②段**。v1 把两件事都推给②段,是这次最大的偏差。
@@ -1,268 +1,359 @@
# 3b · 实测记录(③段界面交互)
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/3b-实测记录.md`
> 判据源:`stage-delivery/SKILL.md` §3b/§供给;`references/execution-runbook.md` §3.5、§5.3、§六;`references/layouts-tooling.md` §1、§5.5
> 交付物:`ui/mcn-workbench.html`(单文件自包含原型)+ `ui/DESIGN.md`(规范)
## 〇、声明制(四字段)
| 字段 | 内容 |
|---|---|
| 当前段与子步 | ③段 / 3b 原型构建 + 3b 实测(实测未过不进 3c) |
| 主干与挡位 | 供给=`oil-ui-pro`(方法主线)+ 本段自带样式库 `design-system-tiaoyue`(定调与令牌)/ 挡位 **标准** |
| 依据文件 | `DESIGN.md`(本段契约)、`prd/2b-界面布局.md`(冻结骨架)、`prd/2a-产品功能.md`(F1–F14) |
| 产出落点 | `ui/mcn-workbench.html`、`ui/_tools/`(三个可复跑脚本)、`ui/_gate_shots/`(23 张视口帧) |
## 一、怎么复跑(三条命令,全部只读原型)
```bash
PY="E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe"
cd "…/ui"
$PY _tools/cap.py --mode dom --route selftest --viewport 1440x900 --out _scratch/st.html # 取自检输出
$PY _tools/mutate_test.py # 变异对照
$PY _tools/check_skeleton.py # 骨架冻结闸门
```
`cap.py` 对外只收 `--viewport`;它内部按模式补偏移量(原因见 §五 的通道口径一节)。`_scratch/` 是跑出来的中间件、目录不存在时脚本会自建,看完随手删掉不影响任何结论;交付目录里只留脚本、截图与四份文档。
## 二、自检 81 项(1440×900 主视口,PASS 81 / FAIL 0)
自检是原型自带的:`#/selftest` 路由会在真实场景里逐个点过每个可点元素。全文落盘如下,⛔ 不是摘要。
```text
自检结果:PASS 81 / FAIL 0
PASS 路由 #/p/p1 渲染出 5 个顶层节点
PASS 路由 #/p/p2 渲染出 6 个顶层节点
PASS 路由 #/p/p3 渲染出 4 个顶层节点
PASS 路由 #/p/p4 渲染出 6 个顶层节点
PASS 路由 #/p/p5 渲染出 5 个顶层节点
PASS 路由 #/p/p6 渲染出 4 个顶层节点
PASS 路由 #/p/p7 渲染出 5 个顶层节点
PASS 路由 #/p/p8 渲染出 4 个顶层节点
PASS 六态 × 八页 = 48 个组合,全部渲染出内容
PASS 侧栏二级页项 8 个,与八页一致
PASS 清单里每个 ID 都在页面上出现过(75 个,无悬空声明)
PASS 页面上每个 data-act 都在清单里(共 703 次出现,无未登记的可点元素)
PASS 清单里 71 个 ID 都真驱动过并给出可见反馈,0 个死控件(22 个场景,每个实例各重置一次)
PASS 当刻被禁用的控件 4 个(有 disabled 属性:按契约在特定条件下不可点):P4-03, P5-06, P6-03, R-02
PASS 清单里每个 ID 都至少被驱动过一次(无「从未跑过」的条目)
PASS 侧栏 8 项逐个点过,每一项都跳到了自己标的那一页
PASS 五处「输入后才可用」的联动都通:其中 4 处在空输入时确实是禁用的 → 输入后转可用 → 点了有反应
PASS 工具型纪律:零 .eyebrow / 零 .lead / 零 .hero
PASS 零 @keyframes(工具型不做入场编排)
PASS 骨架冻结:八页 37 个板块的数量与顺序与 ②段 2b「板块清单」逐位一致,⛔ 未增删挪
PASS 结构 ①:八页各一个 h1,标题逐级不跳;每个板块都有文字标题
PASS 结构 ②:字号 12/14/16/18/24px 共 5 档,相邻差 2/2/2/6,正文档 14–16 在用
PASS 结构 ④:逐页查过,首屏同屏主档按钮 ≤1 个;本页实底按钮 1 种
PASS 交互态与可读性::hover / :focus-visible 都在且没被 outline:none 抹掉;tabular-nums、prefers-reduced-motion、防溢出三件套齐全
PASS 阴影:面板/卡片都用多层叠层,无单层死黑重阴影
PASS 间距:flex/grid 的 gap 取值全部落在登记刻度内(9 个刻度)
PASS 浮层「随手记」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(R-03);遮罩是「点层外」通道,不计作出口
PASS 浮层「随手记」打开后焦点在层内(当前=X-close)
PASS 浮层「随手记」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「随手记」Esc 能关
PASS 浮层「随手记」关掉后焦点回到触发件 G-06
PASS 浮层「随手记」点遮罩(层外空白)能关
PASS 浮层「全局检索」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「全局检索」打开后焦点在层内(当前=X-close)
PASS 浮层「全局检索」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「全局检索」Esc 能关
PASS 浮层「全局检索」关掉后焦点回到触发件 G-10
PASS 浮层「全局检索」点遮罩(层外空白)能关
PASS 浮层「两处假设说明」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「两处假设说明」打开后焦点在层内(当前=X-close)
PASS 浮层「两处假设说明」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「两处假设说明」Esc 能关
PASS 浮层「两处假设说明」关掉后焦点回到触发件 G-08
PASS 浮层「两处假设说明」点遮罩(层外空白)能关
PASS 浮层「资产选择器」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「资产选择器」打开后焦点在层内(当前=X-close)
PASS 浮层「资产选择器」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「资产选择器」Esc 能关
PASS 浮层「资产选择器」关掉后焦点回到触发件 P4-04
PASS 浮层「资产选择器」点遮罩(层外空白)能关
PASS 浮层「版本列表」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「版本列表」打开后焦点在层内(当前=X-close)
PASS 浮层「版本列表」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「版本列表」Esc 能关
PASS 浮层「版本列表」关掉后焦点回到触发件 P4-07
PASS 浮层「版本列表」点遮罩(层外空白)能关
PASS 浮层「发布二次确认」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(P5-10);遮罩是「点层外」通道,不计作出口
PASS 浮层「发布二次确认」打开后焦点在层内(当前=X-close)
PASS 浮层「发布二次确认」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「发布二次确认」Esc 能关
PASS 浮层「发布二次确认」关掉后焦点回到触发件 P5-08
PASS 浮层「发布二次确认」点遮罩(层外空白)能关
PASS 浮层「核销二次确认」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(CHECKOUT-CANCEL);遮罩是「点层外」通道,不计作出口
PASS 浮层「核销二次确认」打开后焦点在层内(当前=X-close)
PASS 浮层「核销二次确认」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「核销二次确认」Esc 能关
PASS 浮层「核销二次确认」关掉后焦点回到触发件 P8-03
PASS 浮层「核销二次确认」点遮罩(层外空白)能关
--- 数值取证(布局视口 1440 × 900 ;window.innerWidth 1440)---
PASS 对比度 --warn 对 --surface = 5.93:1(契约 ≥4.5:1)
PASS 对比度 --accent-text 对 --surface = 4.76:1(契约 ≥4.5:1)
PASS 对比度 --ink-faint 对 --surface = 3.55:1(契约 ≥3:1)
PASS 强调色填充面积占比:八页最高 创作台 = 0.52%(1 个填充块,契约 ≤5%;不含 3px 左侧标条 / 描边 / 文字色)
量尺寸时 scrollY = 0(P1)
PASS 量尺寸前页面停在滚动零点(P1):rect 取到的是相对视口的真值
PASS P1 账号矩阵:首屏从 214px 起,行距 67px,一屏装得下 10 行(契约 ≥6 行/900px 高,实测宽 1440)|示意数据 5 条 ⇒ 实际可见 5 行(数据用尽,非被截断)
PASS P1 账号矩阵行高齐:67–68px,差 ≤2px(没有哪一行被状态标或长文字撑高)
PASS P1 实际在用字号档 5 档:12px / 14px / 16px / 18px / 24px(契约 ≥3)
PASS 视觉层间距 32px / 块内相邻行分隔 1px(发丝线,行本身不套框)⇒ 比值 32 ≥2(4 个视觉层)
P1 各块落位(顶 / 高):今日待处理@149+360 · 账号矩阵列表@149+417 · 异常值提示@599+215 · 本月表现最好的一条@845+122 · 全局检索与随手记@1000+113(视口高 900;并排的两块顶相同)
量尺寸时 scrollY = 0(P2)
PASS 量尺寸前页面停在滚动零点(P2):rect 取到的是相对视口的真值
PASS P2 对标内容列表:首屏从 402px 起,行距 67px,一屏装得下 7 行(契约 ≥6 行/900px 高,实测宽 1440)|示意数据 5 条 ⇒ 实际可见 5 行(数据用尽,非被截断)
P2 各块落位(顶 / 高):对标监控概览@165+139 · 对标内容列表@336+417 · 评论区洞察@785+108 · 选题库@925+330 · 灵感速记@1287+113
PASS 横向溢出 = 0(scrollWidth 1440 = clientWidth 1440)
PASS 八页逐页查横向溢出:全为 0(最差 p1)
(附)P1 行高 67/67/67/68/67px · P1 按钮高度集合 32px · 量时 scrollY=0 · 顶栏高 69px · 导航占 1105px(column)· 主区内衬上 24px · innerWidth 1440 − clientWidth 1440 = 0px(窗口滚动条宽度)
控制台报错:0 条
```
截图:`_gate_shots/selftest-1440.png`。
## 三、变异对照 13 / 13(证明上面那串 PASS 不是恒绿)
一个永远 PASS 的自检等于没有自检。做法:复制原型 → 注入一处**已知的假病** → 再跑一次自检 → 要求它报红、**且红在预期那一条上**。
```text
基线(未注入):PASS 81 / FAIL 0
✅ M1 死控件(掏空 P2-01 实现) ⇒ PASS 80/FAIL 1 |红在 P2-01
✅ M2 未登记的可点元素(塞一个 ZZ-99) ⇒ PASS 79/FAIL 2 |红在「未登记的 data-act」
✅ M3 悬空声明(清单里加一个页面没有的 ID) ⇒ PASS 79/FAIL 2 |红在「声明了但页面里没有」
✅ M4 骨架漂移(P3 多塞一块) ⇒ PASS 80/FAIL 1 |红在「骨架与②段不一致」
✅ M5 对比度越界(--ink-faint → #c9c7c0) ⇒ PASS 80/FAIL 1 |红在「对比度 --ink-faint」
✅ M6 点击无反馈(go() 退回只改 hash) ⇒ PASS 79/FAIL 2 |红在「驱动了没反应」
✅ M7 行高不齐(放开行内换行,768x900) ⇒ PASS 79/FAIL 2 |红在「行高不齐」
✅ M8 密度退化(行内衬 12px → 36px) ⇒ PASS 79/FAIL 2 |红在「低于契约 6 行」
✅ M9 量尺寸时页面不在零点(量前先滚 300px) ⇒ PASS 80/FAIL 1 |红在「被滚到」
✅ M10 行分隔线被关掉(退回 .list-row:first-child)⇒ PASS 80/FAIL 1 |红在「行分隔线根本没画出来」
✅ M11 浮层没有遮罩 ⇒ PASS 72/FAIL 9 |红在「没有遮罩」
✅ M12 关掉浮层后焦点不还回去 ⇒ PASS 74/FAIL 7 |红在「关掉后焦点没回到」
✅ M13 浮层多出一个中性关闭出口(再加一颗 ×) ⇒ PASS 74/FAIL 7 |红在「中性关闭出口 = 2」
变异对照:13 / 13 通过
⇒ 13 处假病全部被自检抓住,且基线回绿:这套判据不是恒绿的。
```
⚠️ **M9 换过一次**。原来那版是「拿掉 `applyScene` 末尾的滚动复位」,但实测它**已经观测不到差别**了:重绘 `#view` 时浏览器把滚动自然夹回 0,量出来的数确实干净 ⇒ 那条变异变成了一条抓不到东西的假变异。改成直接注入「量之前把页面滚下去」,也就是这条守卫真正声称要拦的那件事。
## 四、骨架冻结闸门(正向 + 双向变异)
把②段 `prd/2b-界面布局.md` §二 当权威读,与原型 `FROZEN` 表逐页逐位比(数量相等、顺序相等、名字互为前缀)。
```text
正向:PASS 骨架冻结:八页 37 个板块,②段 2b-界面布局.md §二 与原型 FROZEN 表逐页逐位一致
反向变异 1(改原型 p3 多一块):p3 板块数 ②段 4 ≠ 原型 5
反向变异 2(改②段副本 p1 第 2 块名):p1 第 2 块 ②段「账号矩阵一览」≠ 原型「账号矩阵列表」
```
两条反向变异改的都是**副本**(`_probe/2b-mut.md`),权威件 `prd/2b-界面布局.md` 全程只读。为了事后能复核这件事,这里钉一条指纹:
```text
prd/2b-界面布局.md md5 = 1dcc69f952df97a394481658e84d90b2 15036 字节 mtime 2026-10-08 02:30
```
✅ 复核方式:`md5sum ../prd/2b-界面布局.md`,与上面比。一致 ⇒ ③段确实没动过冻结骨架。
(这条指纹是删 `_probe/` 之前补登的 —— 备份删掉后,只剩这一个数能证明骨架没被污染,所以先写进正文再清临时件。)
## 五、多视口密度核对(契约:一屏可见行数 ≥6 / 900px 高,`layouts-tooling.md` §1 原文,⛔ 不分档)
| 视口 | 自检 | P1 账号矩阵 | P2 对标列表 | 顶栏高 | 导航 | 结论 |
|---|---|---|---|---|---|---|
| 1440×900 | **PASS 81/0** | 首行 214px,**10 行** | 首行 402px,**7 行** | 69px | 1105px(竖栏) | ✅ |
| 1280×900 | **PASS 81/0** | 首行 216px,**10 行** | 首行 403px,**7 行** | 69px | 竖栏 | ✅ |
| 1024×900 | **PASS 81/0** | 首行 495px,**6 行** | 首行 402px,**7 行** | 69px | 竖栏 | ✅ |
| 768×900 | **PASS 81/0** | 首行 495px,**6 行** | 首行 402px,**7 行** | 69px | 竖栏 | ✅ |
| 641×900 | PASS 80/**1** | 首行 535px,**5 行** ❌ | 首行 442px,**6 行** | 109px(折两行) | 竖栏 | 缺口见 §六 |
| 640×900 | PASS 80/**1** | 首行 532px,**5 行** ❌ | 首行 439px,**6 行** | 61px | 53px(横条) | 缺口见 §六 |
| 500×844 | PASS 79/**2** | 首行 572px,**4 行** ❌ | 首行 479px,**5 行** ❌ | 101px(折两行) | 53px(横条) | 缺口见 §六 |
**边界是量出来的,不是我定的**:视口 ≥768px 时顶栏单行、导航竖排,一屏 6–10 行;≤767px 时顶栏折成两行(641px 实测 109px)、≤640px 导航变标签栏,首屏被页面外壳吃掉,容量掉到 4–5 行。行本身没变肥 —— 行高 67px、各行差 ≤2px、块内分隔 1px,这几条在任何视口都 PASS。
> 反事实(把 P1 前两块强制落回单列,1440×900):`账号矩阵列表@530+413` ⇒ 首行顶 530px、容量 `floor((900−530)/67) = 5 行`,够不着 6 ⇒ **并排是密度判据逼出来的,不是审美选择**。
### 通道口径(本轮实测发现,已修)
同一台机器、同一个 `--window-size`,Chrome 两条通道给出的**视口不是同一个**:
```text
--window-size=656,995 ─┬─ --dump-dom ⇒ 视口 640 × 900 (mq<=640 true)
└─ --screenshot ⇒ 视口 656 × 995 (mq<=640 false)
```
量这件事用的探针页只有 18 行,为了让它跟着报告一起活下去(临时目录已清),源码附在下面 —— 想自己复核就把这段存成 `_scratch/vp.html`,两种模式各跑一次同一尺寸,读第 1、3 行:
```html
<!DOCTYPE html><html><head><meta charset="utf-8"><title>vp</title>
<style>body{margin:0;font:700 34px/1.5 monospace;background:#fff;color:#111}</style></head><body>
<div id="o">…</div>
<script>
function r(){
document.getElementById('o').innerHTML =
'innerW '+window.innerWidth+'<br>'+
'innerH '+window.innerHeight+'<br>'+
'clientW '+document.documentElement.clientWidth+'<br>'+
'clientH '+document.documentElement.clientHeight+'<br>'+
'outerW '+window.outerWidth+'<br>'+
'mq<=640 '+matchMedia('(max-width:640px)').matches+'<br>'+
'mq<=1024 '+matchMedia('(max-width:1024px)').matches+'<br>'+
'dpr '+window.devicePixelRatio;
}
r(); addEventListener('resize',r);
</script>
</body></html>
```
⇒ 截图通道原样等于视口,dump-dom 通道要补回被扣掉的 16 / 95。`cap.py` 已按模式分开算,并且**每次截图后直接从 PNG 的 IHDR 读真实像素跟目标视口比**,不等就当场报红 —— 这条守卫是补回来的,因为本轮之前所有截图都比标称大 16×95(「1440×900」实际是 1456×995)。
## 六、本轮修掉的真缺陷(每条:现象 → 根因 → 证据)
| # | 现象 | 根因 | 证据 |
|---|---|---|---|
| 1 | 整份设计系统在屏幕上失效 | 样式表顶部注释里 `--t-*/--raw-*` 的 `*/` 提前闭掉注释,吞掉整个 `:root` 令牌块 | 修复后对比度取证才量得出来 |
| 2 | 全表行分隔线一直没画出来 | `.list-row:first-child{border-top:0}`:每行都包在 `<li>` 里,于是**每行都是自己 `<li>` 的 first-child**,`borderTopStyle` 全是 `none` | 变异 M10;另修了判据除数为 0 时恒 PASS(比值 `Infinity`) |
| 3 | 浮层不浮 | `#layer-root` 与 `.layer` 都没有定位样式,浮层渲染在文档流末尾,得滚到页尾才看得见 | 改为遮罩 `fixed inset:0` + 层本体 `fixed` 居中 |
| 4 | 行高随文字长短乱跳(66/82/100px) | 状态标放在操作列把 `auto` 列撑宽,只有那一行折行 | 状态标移到名称旁;再加「行内每段不许换行 + 省略号」;判据新增「行高齐」 |
| 5 | 自检在窄视口给出假 PASS「装得下 10 行」 | 驱动几百次点击后浏览器为聚焦元素自动滚动,`rect.top` 变负,容量公式虚高 | 加「量尺寸时页面在滚动零点」守卫 + 变异 M9 |
| 6 | 手机导航「既不是一条、也没滚动」,占 161px | `.sidebar` 只给了 `flex-direction:row`,可导航分组挂在 `<nav id="nav">` 里,而 `#nav` **一条样式都没有** ⇒ 仍是块级容器,4 个分组照旧竖堆 | 补 `#nav{display:flex;flex-flow:row nowrap}` + 整条链 `flex:0 0 auto`;161px → 53px |
| 7 | 顶栏「演示 · 账号」折成两行,顶栏被顶到 70px | `.topbar-label` 没有 `white-space:nowrap` | 独立评审第一眼点出;补 nowrap 后顶栏 69px |
| 8 | 截图尺寸全部比标称大 16×95 | `cap.py` 对两条通道用了同一个偏移量 | §五「通道口径」;已加 PNG 尺寸守卫 |
| 9 | 两个二次确认浮层其实各有**两个**可见关闭控件,判据却报「出口 = 1」 | 判据只数 `.layer-close` 这个类名,把可见的「取消」从眼皮底下藏掉了;核销层的「取消」还复用了 `X-close` | 判据改为「中性出口只认 `X-close`」+「决策型关闭单列报数」;核销取消拆出 `CHECKOUT-CANCEL`;加变异 M13 |
| 10 | 「今日该发:待发:3 分钟快手菜」冒号连用,评审读成错字 | 示意数据 `today` 字段的值里自带冒号,被拼进「今日该发:…」 | 数据改为空格分隔 |
| 11 | 制作黑话写在界面上(「这里是 X 的 empty 态」) | 状态面板上另贴了一句给做原型的人看的说明,而 `STATE_COPY` 已铺好用户向文案 | 删掉那句话;按钮改「回到正常内容」 |
| 12 | 手机形态看不出当前在哪一页 | 横滚标签栏里当前项滚在视野外 | 只调 `.sidebar` 自己的 `scrollLeft` 把当前项带进视野(⛔ 不碰 `window`,否则会误触滚动守卫) |
| 13 | `layerTrigger` 放进状态快照 `S` | 点任何元素都会改 `S` ⇒ 状态快照跟着变 ⇒ **没有一个控件会被判死**,死控件判据整条失效 | 移出 `S`;变异 M1/M6 当场回归报红 |
| 14 | 浮层焦点与可见性判据全部失效 | `offsetParent` 对 `position:fixed` 元素恒为 `null` | 改用 `getClientRects().length` |
| 15 | `--full`(整页长图)静默失效,产出的还是视口帧 | 无头 CLI 这条通道只能截视口 | 参数已删除,`_full/` 目录一并清掉,不留一个撒谎的开关 |
## 七、已记录的偏离(⛔ 不许静默)
| # | 原要求 | 实际做法 | 原因 | 影响 | 处置 |
|---|---|---|---|---|---|
| D1 | 3b 实测走 `browser-harness`(SKILL.md §3b) | 用「原型自带自检 81 项 + 变异对照 13/13 + 无头 Chrome 23 张视口帧 + 逐条 DOM 取值」等价替代 | 该通道绑定实时浏览器入口,本会话驱动不了(宿主侧能力,不是本段能修的) | 证据链换成可复跑脚本;⛔ 但**没有**「真人真点」这一层,交互结论全部来自脚本驱动 | 持续偏离,待用户裁定是否补一次人工走查 |
| D2 | D5 终检要 `1440x900` 与 `390x844` 两个视口帧(runbook §5.3、§七) | 实测到 **500×844** 为止 | Chrome 窗口宽下限 516 ⇒ 视口最小 500;要 390 得走 CDP `setDeviceMetricsOverride`,本轮没接 | 手机帧比要求宽 110px | 持续偏离;⛔ 报告里一律写「500×844」,**不许**写成已测 390 |
| D3 | 对外只留视口帧;`_full/` 长图仅自检(runbook §七) | 未产出长图 | `--full` 在本机通道上做不到(只能截视口),已把该参数删掉 | 无 | 已修 |
| D4 | 3c 要「外部 GPT 会诊」 | 见 `3c-GPT会诊.md`:本会话无对外模型通道,改用**隔离上下文的独立评审执行者** | 没有外部通道可用 | 与「异厂商外部审查」不是同一条通道 | 持续偏离,已明示 |
## 八、这一步的门槛结论
- 3a 已过 Gate-1(见 `DESIGN.md` §四)。
- 3b 实测:**契约视口 1440×900 全绿(PASS 81/FAIL 0)**;≥768px 宽全绿;≤767px 宽的密度缺口已如实登记(§五、`DESIGN.md` §五)。
- 可以进 3c。
---
## 九、说人话自评(判据源 `humanizer-zh`,五维各 10 分)
| 维度 | 分 | 说明 |
|---|---|---|
| 直接性 | 9 | 开头就是复跑命令,没有「本次工作取得进展」这类开场 |
| 节奏 | 8 | 表格 + 短断言为主,句式偏单一,⚠️ 弱项 |
| 信任度 | 10 | 把改坏的、没测到的、换了通道的都写出来了,没有藏 |
| 真实性 | 9 | 每条缺陷都带现象、根因与证据(脚本名 / 变异编号 / 实测数) |
| 精炼度 | 9 | 15 条缺陷各一行,不重复叙述;自检全文照录是留证需要,不是凑字 |
| **总分** | **45 / 50** | 门槛 ≥45,压线过;扣分点写在第 2 行 |
# 3b · 实测记录(③段界面交互)
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/3b-实测记录.md`
> 判据源:`stage-delivery/SKILL.md` §3b/§供给;`references/execution-runbook.md` §3.5、§5.3、§六;`references/layouts-tooling.md` §1、§5.5
> 交付物:`ui/mcn-workbench.html`(单文件自包含原型)+ `ui/DESIGN.md`(规范)
## 〇、声明制(四字段)
| 字段 | 内容 |
|---|---|
| 当前段与子步 | ③段 / 3b 原型构建 + 3b 实测(实测未过不进 3c) |
| 主干与挡位 | 供给=`oil-ui-pro`(**基础层**:视觉与体验的底线判据)+ 叠加层(本段自带样式库 `design-system-tiaoyue` 定调与令牌 + 本段自有判据;只许更严、更具体,⛔ 不许放宽基础层)/ 挡位 **标准** |
| 依据文件 | `DESIGN.md`(本段契约)、`prd/2b-界面布局.md`(冻结骨架)、`prd/2a-产品功能.md`(F1–F14) |
| 产出落点 | `ui/mcn-workbench.html`、`ui/_tools/`(三个可复跑脚本)、`ui/_gate_shots/`(23 张视口帧) |
## 一、怎么复跑(四条命令,全部只读原型)
```bash
PY="E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe"
cd "…/ui"
$PY _tools/cap.py --mode dom --route selftest --viewport 1440x900 --out _scratch/st.html # 取自检输出
$PY _tools/mutate_test.py # 变异对照
$PY _tools/check_skeleton.py # 骨架冻结闸门
$PY _tools/check_js.py # JS 语法 + 模板里的反引号(第 5 个门禁,第六轮新增)
```
`cap.py` 对外只收 `--viewport`,**视口是声明式给的**(内部走 CDP `Emulation.setDeviceMetricsOverride`,见 §五 的通道口径一节)—— 不再有 `--window-size` 的偏移量口径,也不再自己起浏览器。
🔴 **复跑前先确认浏览器实例在跑**:本机明令「先探测、能复用就复用」(`skills/browser-harness/SKILL.md`)。
```bash
netstat -ano | grep -E "127\.0\.0\.1:9223 .*LISTENING" # 有 pid = 实例在跑
```
实例没起来时 `cap.py` 会**直接报错退出**,⛔ 不会偷偷拉起一个(拉起谁、拉几个,是人的决定)。
`_scratch/` 是跑出来的中间件、目录不存在时脚本会自建,看完随手删掉不影响任何结论;交付目录里只留脚本、截图与四份文档。
## 二、自检 84 项(1440×900 主视口,PASS 84 / FAIL 0)
自检是原型自带的:`#/selftest` 路由会在真实场景里逐个点过每个可点元素。全文落盘如下,⛔ 不是摘要。
⚠️ **2026-10-08 第六轮重跑**(学参照物的组件细节:功能入口卡补 22px 图标、图标线宽 1.7→2、网格最小宽 180→200、hover 补轻阴影、问答区加虚线分隔)。这一轮**判据条数与 ID 数都没变**(84 项 / 76 个 ID / 72 个真驱动),变的是**几何**:P1 首行顶 688 → **697px**、P2 471px。下面这段是按改动后的原型**重新落盘**的。
```text
自检结果:PASS 84 / FAIL 0
PASS 路由 #/p/p1 渲染出 7 个顶层节点
PASS 路由 #/p/p2 渲染出 6 个顶层节点
PASS 路由 #/p/p3 渲染出 6 个顶层节点
PASS 路由 #/p/p4 渲染出 6 个顶层节点
PASS 路由 #/p/p5 渲染出 7 个顶层节点
PASS 路由 #/p/p6 渲染出 6 个顶层节点
PASS 路由 #/p/p7 渲染出 6 个顶层节点
PASS 路由 #/p/p8 渲染出 6 个顶层节点
PASS 六态 × 八页 = 48 个组合,全部渲染出内容
PASS 侧栏只有一层:8 个功能项(总览 / 选题 / 资产 / 创作 / 发布 / 画像 / 复盘 / 对账)排成一列药丸浮栏(图标+2 字短名),一项一页,第二层 0 个
PASS 八页一次点击可达:侧栏八个功能项直达 + 各页「功能入口」卡另给上下文入口(卡片共 8 个落点、无缺口)
PASS 清单里每个 ID 都在页面上出现过(76 个,无悬空声明)
PASS 页面上每个 data-act 都在清单里(共 638 次出现,无未登记的可点元素)
PASS 清单里 72 个 ID 都真驱动过并给出可见反馈,0 个死控件(24 个场景,每个实例各重置一次)
PASS 当刻被禁用的控件 4 个(有 disabled 属性:按契约在特定条件下不可点):P4-03, P5-06, P6-03, R-02
PASS 清单里每个 ID 都至少被驱动过一次(无「从未跑过」的条目)
PASS 侧栏 8 个功能项逐个点过,每一项都落到了自己那一页
PASS 五处「输入后才可用」的联动都通:其中 4 处在空输入时确实是禁用的 → 输入后转可用 → 点了有反应
PASS 工具型纪律:零 .eyebrow / 零 .lead / 零 .hero
PASS 入场编排不做逐区块:@keyframes 共 0 处(工具型至多一处协调出场)
PASS 骨架冻结:八页 39 个板块的数量与顺序与 ②段 2b「板块清单」逐位一致,⛔ 未增删挪
PASS 结构 ①:八页各一个 h1,标题逐级不跳;每个板块都有文字标题
PASS 结构 ②:字号 12/14/16/18/20/24px 共 6 档,相邻差 2/2/2/2/4,正文档 14–16 在用
PASS 结构 ④:逐页查过,首屏同屏主档按钮 ≤1 个;本页实底按钮 1 种
PASS 组件口径:八页都没有用内联 style 表达选中态或覆盖字号(选中态走 .is-on / .is-active,字号走 --fs-* 档)
PASS 交互态与可读性::hover / :focus-visible 都在且没被 outline:none 抹掉;tabular-nums、prefers-reduced-motion、防溢出三件套齐全
PASS 阴影:面板/卡片都用多层叠层,无单层死黑重阴影
PASS 间距:flex/grid 的 gap 取值全部落在登记刻度内(9 个刻度)
PASS 浮层「随手记」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(R-03);遮罩是「点层外」通道,不计作出口
PASS 浮层「随手记」打开后焦点在层内(当前=X-close)
PASS 浮层「随手记」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「随手记」Esc 能关
PASS 浮层「随手记」关掉后焦点回到触发件 G-06
PASS 浮层「随手记」点遮罩(层外空白)能关
PASS 浮层「全局检索」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「全局检索」打开后焦点在层内(当前=X-close)
PASS 浮层「全局检索」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「全局检索」Esc 能关
PASS 浮层「全局检索」关掉后焦点回到触发件 G-10
PASS 浮层「全局检索」点遮罩(层外空白)能关
PASS 浮层「两处假设说明」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「两处假设说明」打开后焦点在层内(当前=X-close)
PASS 浮层「两处假设说明」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「两处假设说明」Esc 能关
PASS 浮层「两处假设说明」关掉后焦点回到触发件 G-08
PASS 浮层「两处假设说明」点遮罩(层外空白)能关
PASS 浮层「资产选择器」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「资产选择器」打开后焦点在层内(当前=X-close)
PASS 浮层「资产选择器」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「资产选择器」Esc 能关
PASS 浮层「资产选择器」关掉后焦点回到触发件 P4-04
PASS 浮层「资产选择器」点遮罩(层外空白)能关
PASS 浮层「版本列表」中性关闭出口 = 1(右上 ×)|另有决策型关闭 0 个;遮罩是「点层外」通道,不计作出口
PASS 浮层「版本列表」打开后焦点在层内(当前=X-close)
PASS 浮层「版本列表」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「版本列表」Esc 能关
PASS 浮层「版本列表」关掉后焦点回到触发件 P4-07
PASS 浮层「版本列表」点遮罩(层外空白)能关
PASS 浮层「发布二次确认」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(P5-10);遮罩是「点层外」通道,不计作出口
PASS 浮层「发布二次确认」打开后焦点在层内(当前=X-close)
PASS 浮层「发布二次确认」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「发布二次确认」Esc 能关
PASS 浮层「发布二次确认」关掉后焦点回到触发件 P5-08
PASS 浮层「发布二次确认」点遮罩(层外空白)能关
PASS 浮层「核销二次确认」中性关闭出口 = 1(右上 ×)|另有决策型关闭 1 个(CHECKOUT-CANCEL);遮罩是「点层外」通道,不计作出口
PASS 浮层「核销二次确认」打开后焦点在层内(当前=X-close)
PASS 浮层「核销二次确认」连按 8 次 Tab,焦点始终锁在层内
PASS 浮层「核销二次确认」Esc 能关
PASS 浮层「核销二次确认」关掉后焦点回到触发件 P8-03
PASS 浮层「核销二次确认」点遮罩(层外空白)能关
--- 数值取证(布局视口 1440 × 900 ;window.innerWidth 1440)---
PASS 对比度 --warn 对 --surface = 5.93:1(契约 ≥4.5:1)
PASS 对比度 --accent-text 对 --surface = 4.76:1(契约 ≥4.5:1)
PASS 对比度 --ink-faint 对 --surface = 3.55:1(契约 ≥3:1)
PASS 强调色填充面积占比:八页最高 创作台 = 0.52%(1 个填充块,契约 ≤5%;不含 3px 左侧标条 / 描边 / 文字色)
量尺寸时滚动零点(P1):window 0 / html 0 / body 0 / .view 0
PASS 量尺寸前三个滚动容器都停在零点(P1):rect 取到的是相对视口的真值
PASS P1 账号矩阵:首屏从 697px 起,行距 31px,一屏装得下 6 行(契约 ≥6 行/900px 高,实测宽 1440)|示意数据 5 条 ⇒ 实际可见 5 行(数据用尽,非被截断)
PASS P1 账号矩阵行高齐:31–31px,差 ≤2px(没有哪一行被状态标或长文字撑高)
PASS P1 实际在用字号档 6 档:12px / 14px / 16px / 18px / 20px / 24px(契约 ≥3)
PASS 视觉层间距 32px / 块内相邻行分隔 1px(发丝线,行本身不套框)⇒ 比值 32 ≥2(4 个视觉层)
P1 各块落位(顶 / 高):今日待处理@333+249 · 账号矩阵列表@614+249 · 异常值提示@895+201 · 全局检索与随手记@1128+231(视口高 900;并排的两块顶相同)
量尺寸时滚动零点(P2):window 0 / html 0 / body 0 / .view 0
PASS 量尺寸前三个滚动容器都停在零点(P2):rect 取到的是相对视口的真值
PASS P2 对标内容列表:首屏从 471px 起,行距 31px,一屏装得下 13 行(契约 ≥6 行/900px 高,实测宽 1440)|示意数据 5 条 ⇒ 实际可见 5 行(数据用尽,非被截断)
P2 各块落位(顶 / 高):对标监控概览@143+121 · 对标内容列表@389+249 · 评论区洞察@670+316 · 灵感速记@1018+99
PASS 横向溢出 = 0(scrollWidth 1440 = clientWidth 1440)
PASS 八页逐页查横向溢出:全为 0(最差 p1)
PASS 纵向滚动只由主区承担:.app 高 900px = 视口 900px;body 未承担滚动(scrollTop 0);主区 overflow-y auto,clientH 851px / scrollH 1374px(内容更高 ⇒ 主区可滚,折叠线以下的块拿得到)
(附)P1 行高 31/31/31/31/31px · P1 按钮高度集合 32px · 量时 scrollY=0 · 顶栏高 49px · 导航占 900px(column)· 主区内衬上 24px · innerWidth 1440 − clientWidth 1440 = 0px(窗口滚动条宽度)
控制台报错:0 条
```
截图:`_gate_shots/selftest-1440.png`。
## 三、变异对照 15 / 15(证明上面那串 PASS 不是恒绿)
一个永远 PASS 的自检等于没有自检。做法:复制原型 → 注入一处**已知的假病** → 再跑一次自检 → 要求它报红、**且红在预期那一条上**。
```text
基线(未注入):PASS 84 / FAIL 0
✅ M1 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M2 ⇒ PASS 82/FAIL 2 | 报红且红在预期处
✅ M3 ⇒ PASS 82/FAIL 2 | 报红且红在预期处
✅ M4 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M5 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M6 ⇒ PASS 82/FAIL 2 | 报红且红在预期处
✅ M7 ⇒ PASS 82/FAIL 2 | 报红且红在预期处
✅ M8 ⇒ PASS 82/FAIL 2 | 报红且红在预期处
✅ M9 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M10 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M11 ⇒ PASS 75/FAIL 9 | 报红且红在预期处
✅ M12 ⇒ PASS 77/FAIL 7 | 报红且红在预期处
✅ M13 ⇒ PASS 77/FAIL 7 | 报红且红在预期处
✅ M14 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
✅ M15 ⇒ PASS 83/FAIL 1 | 报红且红在预期处
变异对照:15 / 15 通过
⇒ 15 处假病全部被自检抓住,且基线回绿:这套判据不是恒绿的。
```
⚠️ **M2 与 M8 这两个注入点本轮换过**(第三轮)。形态一改,注入点就必须跟着改,否则变异脚本会「找不到注入点、跳过」或者「注进去了但打不到判据」——**这两种都属于假对照,比没有变异更坏**(它会让人以为这条判据有人看着):
- **M2**(未登记的可点元素):P2 的「对标内容列表」由行式列表改成满宽表格后,原注入点 `.action-cell` 里的 `P2-03` **在文件里已经不存在** ⇒ 本轮实测时脚本直接判「跳过」。已把注入点换到表格那一行(`<td class="cell-act">`)。
- **M8**(密度退化):密度判据本轮量的已是 P1 那张满宽表格(`.tbl-dense` 的 `td` 内衬),原注入点 `12px → 36px` 的 `.list-row` 内衬**对表格无效** ⇒ 实测 `PASS 83/FAIL 0`(没报红)。已把注入点换成表格 `td` 的内衬。
- 上一轮同样处理过 **M7 / M10**(`.list-row` → 表格 `td`)。⇒ 一条经验:**判据形态改了,必须逐个复核每个变异的注入点还在不在**,`mutate_test.py` 已经把「找不到注入点」显式报成 ⚠️ 而不是静默跳过(本轮就是靠它抓到的)。
⚠️ **M9 换过两次**。第一版是「拿掉 `applyScene` 末尾的滚动复位」,实测观测不到差别(重绘 `#view` 时浏览器把滚动自然夹回 0)⇒ 假变异。第二版改成 `window.scrollTo(0,300)`,**2026-10-08 又发现它同样抓不到东西**:外壳修完之后滚动容器是 `.view`,`window` 根本滚不动,拿 window 注入等于没注入。现在注入点是 `document.querySelector('.view').scrollTop=300`,也就是这条守卫真正声称要拦的那件事。
⚠️ **M14 是这一轮新加的**:它注入的就是 §六 第 16 条那个真缺陷的原样(`.app` 退回 `min-height:100vh`)。加它的目的只有一个 —— 证明新判据「纵向滚动只由主区承担」不是恒绿。
## 四、骨架冻结闸门(正向 + 双向变异)
把②段 `prd/2b-界面布局.md` §二 当权威读,与原型 `FROZEN` 表逐页逐位比(数量相等、顺序相等、名字互为前缀)。
```text
正向:PASS 骨架冻结:八页 39 个板块,②段 2b-界面布局.md §二 与原型 FROZEN 表逐页逐位一致
反向变异 1(改原型 p3 多一块):p3 板块数 ②段 4 ≠ 原型 5
反向变异 2(改②段副本 p1 第 2 块名):p1 第 2 块 ②段「账号矩阵一览」≠ 原型「账号矩阵列表」
```
两条反向变异改的都是**副本**(`_probe/2b-mut.md`),权威件 `prd/2b-界面布局.md` 全程只读。为了事后能复核这件事,这里钉一条指纹:
```text
prd/2b-界面布局.md md5 = 61129a3c7944b7d0455d9530d7d373f7 15688 字节 mtime 2026-10-08 09:01
(上一版指纹 1dcc69f9…/15036 字节/02:30 已作废:②段在 09:01 自己动过一次 —— 那时 ②段 的 2b 定稿又改过一轮,③段手里那条指纹就旧了。⛔ 指纹只对「记下来的那一刻」负责。)
```
✅ 复核方式:`md5sum ../prd/2b-界面布局.md`,与上面比。一致 ⇒ ③段确实没动过冻结骨架。
(这条指纹是删 `_probe/` 之前补登的 —— 备份删掉后,只剩这一个数能证明骨架没被污染,所以先写进正文再清临时件。)
## 五、多视口密度核对(契约:一屏可见行数 ≥6 / 900px 高,`layouts-tooling.md` §1 原文,⛔ 不分档)
> 🔴 **2026-10-08 第七轮整表重测替换**(功能入口卡按参照物改成三段纵向之后)。这张表的**用法本轮变了**:不再只报「现在几行」,而是**同一台机器、同一套判据,跑改前/改后两版**逐格对照 —— 本轮改动的正当性就建立在这张对照上:卡长高 43px,但**绿色的视口一个没少**。
> 两版:`_scratch/base.html`(改前,=把本轮两处改动回退后的副本)/`mcn-workbench.html`(改后);各跑 15 个视口,全部走 CDP 声明式视口(见本节末「通道口径」)。
| 视口 | 自检 | P1 账号矩阵(改前 → 改后) | P2 对标列表 | 顶栏 | 侧栏 |
|---|---|---|---|---|---|
| 1440×900 | PASS 84/0 | 697 → **701px**,**6 行** ✅ | 13 行 | 49px | 64px 药丸浮栏 |
| 1280×900 | PASS 84/0 | 697 → **701px**,**6 行** ✅ | 13 行 | 49px | 64px 药丸浮栏 |
| 1024×900 | PASS 84/0 | 697 → **701px**,**6 行** ✅ | 13 行 | 49px | 64px 药丸浮栏 |
| 1000×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 960×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 920×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 901×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 900×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 840×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 820×900 | PASS 84/0 | 677 → **676px**,**7 行** ✅ | 14 行 | 49px | 64px 药丸浮栏 |
| 768×900 | PASS 83/**1** | 741 → 779px,**5 → 3 行** ❌ | 14 行 | 49px | 64px 药丸浮栏 |
| 700×900 | PASS 83/**1** | 834 → 872px,**2 → 0 行** ❌ | 11 行 | 57px | 64px 药丸浮栏 |
| 640×900 | PASS 84/0 | 711 → **700px**,**6 行** ✅ | 13 行 | 57px | 横滚标签条 |
| 560×900 | PASS 83/**1** | 820 → 808px,**2 行** ❌ | 10 行 | 57px | 横滚标签条 |
| 500×844 | PASS 83/**1** | 875 → 882px,**−1 → −2 行** ❌ | 8 行 | 57px | 横滚标签条 |
**结论:绿/红的分界逐格完全一致** —— 绿:1440 / 1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / 640;红:768 / 700 / 560 / 500。行本身没变肥(行高 **30.5–31px**、各行差 ≤0.5px、块内分隔 1px),在**所有**视口都 PASS。
> 🔴 **必须改正上一版的一处错数。** 上一版把 **768×900 记成「首行 677px、7 行 ✅」**,于是得出「**≥640px 宽时 P1 与 P2 都达标**」。本轮在**改前的版本上**重测是 **741px、5 行 ❌**(改后 779px、3 行)⇒ 那句结论是错的,真实分界是 **640 与 ≥820 绿;768 与 700 红;560 与 500 红**。
>
> 这处错数的**根因**恰好就是本轮修掉的那件事:旧取证通道用 `chrome.exe --window-size` 定视口,而**窗口尺寸不等于 CSS 视口**(两条通道对同一尺寸的解释还不同,见本节末)。**768 恰好卡在功能入口卡「3 列/2 列」的阈值上(主区内容宽 632px),只差 7px** ⇒ 旧通道多给十几像素视口,卡就从两行变一行、首行顶差 64px。换成 CDP 声明式视口后这个歧义不存在了。
>
> **本轮把高度还回去的三处**(实测 P1 首行顶 740 → **701**,−39px):① 删掉「功能入口」小标(−24.6px,八页各一处);② 统计条下边距 `8 → 6`(−2px);③ 块标题与内容之间的间距 `.block-head` `12 → 8`(P1 上方有三处,−12px)。`≤640` 一档另追加一条:卡内衬 `8/12 → 6/8`、图标 `18 → 16`、标题 `18 → 16`、`.block` 上边距 `32 → 24`(实测 724 → **700**,−24px)。
>
> ⚠️ **归属必须说清**:本轮修的**只有我自己刚造成的回归**(改卡前 697/6 ✅ → 改完 740/5 ❌)。**768 / 700 / 560 / 500 这四处红是改前就有的,与本轮无关** —— 768/700 的根因是功能入口卡在 768 折成两行、统计条在 700 折成两行;500 是已知缺口。⛔ 本轮没有顺手改它们,免得把「本轮改了什么」和「本来就有什么」搅在一起。
>
> ⚠️ **「改完只量主视口」这个毛病犯了两次,两次都是逐视口表兜住的。** 第一次(第六轮):加 22px 图标那轮只量了 1440(697px/6 行 ✅)就往下走,回头才发现 **640 由 5 行掉到 3 行**(卡变高 + 网格最小宽 180→200 ⇒ 608px 主区装不下三张卡、折成两行、卡块高度翻倍)。第二次(本轮):改完卡只量 1440(701/6 ✅,看着没事),是这张表把「改后 768/700/560/500 全红、1440 也从 6 行掉到 5 行」抓出来的。⇒ **只量契约视口、不回量窄屏,是会漏的;这条已经进 DESIGN.md §五 第 7 条。**
> 上一轮(第四轮)修掉的两处旧错仍成立:
> ①**顶栏列**:旧表在 901–1000 段写「93px(折两行)」、其他段写 69/53px —— 那是演示下拉还在的时候。顶栏收成「产品名 + 随手记」并把内衬 16→8 之后,**全宽度恒为 49px**(640 以下 57px)。
> ②**P2 列**:旧表写「6 行/7 行」,是**没跟着形态改的旧数**。P2 的「对标内容列表」第三轮已由行式列表改成满宽表格 ⇒ 行距 31px、容量 **14 行**,**任何视口都达标**(500×844 也有 8 行)。⇒ 现在**只有 P1 这一列**在窄屏/窄中屏不达标。
>
> ⚠️ 另一条反直觉的实测(第三轮记的,首行顶数字已按本轮实测更正):同一个 768px 视口,侧栏 240px 时 P1 首行顶 **816px ⇒ 2 行**,收到 64px 后 **741px ⇒ 5 行**。**主区越窄,密度反而越差**(功能入口卡会被挤成两行)。
>
> 还有一条被第三轮推翻的旧结论:第三轮记过「照搬 `3c-GPT参考版.md` 那版的满宽表格顺排 ⇒ 一屏只装得下 2 行」。**真的照搬了之后是 6 行**(行高 67px→31px)⇒ 正确表述是「满宽顺排与『一屏 ≥6 行』可以兼得,代价是行高必须压到 31px 上下」。
<!-- 🔻 旧表(2026-10-08 之前,基于假数)已删除,只在此留一句索引,避免有人从旧版复制:
旧表在 1440/1280 报「首行 214/216px、10 行」,1024/768 报「6 行 ✅」——
那 4 行是 `<body>` 被滚 435px 之后量出来的,不是布局真的那么好。 -->
### 通道口径(2026-10-08 第七轮改写:整个通道换掉了)
**旧通道(已废)** 是 `chrome.exe --headless=new --window-size=… --dump-dom / --screenshot`。它有两个坑,第二个是这轮才彻底看清的:
**坑一:两条模式对同一个 `--window-size` 的解释不一样。**
```text
--window-size=656,995 ─┬─ --dump-dom ⇒ 视口 640 × 900 (mq<=640 true)
└─ --screenshot ⇒ 视口 656 × 995 (mq<=640 false)
```
⇒ 当时只能在调用侧按模式补偏移量(dom 补 +16 / +95,shot 原样)。而一旦补错,报告里就会出现「同一个 1440×900,一份证据当成 1440 说话、另一份当成 640 说话」这种自相矛盾 —— 本轮之前的截图全部比标称大 16×95(「1440×900」其实是 1456×995)。
**坑二:窗口尺寸本来就不保证等于 CSS 视口。** 这正是 §五 那处 768 错数的来源(差十几像素就跨过功能入口卡 3 列/2 列的阈值)。旧通道还有个硬上限:Chrome 窗口宽最小 516px ⇒ **视口宽量不到 500 以下**,所以此前契约里凡写 390 的地方一律按 500×844 记。
**新通道**:`_tools/cap.py` 改走浏览器实例的 CDP,用 `Emulation.setDeviceMetricsOverride` **声明式**定视口。三个后果:
1. **要多少是多少**:「1440×900」就是 1440×900(dump 里会印实际 `innerWidth/innerHeight`,不符直接断言失败)。
2. **偏移量那套口径整段作废**,`--window-size` 不再出现。
3. **500px 下限解除** —— 已实测 **390×844**(PNG 尺寸当场比对通过)。
同时保留原来的守卫:**每次截图后直接从 PNG 的 IHDR 读真实像素跟目标视口比**,不等就报红。
⚠️ 还有一条同样重要的:新通道**只连已有实例,⛔ 不自己起浏览器**(本机明令,见 `skills/browser-harness/SKILL.md` 开头的「先探测、能复用就复用」)。实例没起来时 `cap.py` 直接报错退出,不会偷偷拉起一个。
### 第八轮(A 方案 + 滚动条修复)
> 🔴 **本块替换上一块的数据行。** 用户 2026-10-08 拍板「A 方案」。做法与结果:
| 视口 | 改前 首行顶/cap | 改后 首行顶/cap | |
|---|---|---|---|
| 1440 / 1280 / 1024 ×900 | 701 / 6 | 701 / 6 | 一格未动 |
| 1000 / 960 / 920 / 901 / 900 / 840 / 820 ×900 | 676 / 7 | 676 / 7 | 一格未动 |
| **768 ×900** | 779 / 3 | **676 / 7** | ✅ 转绿 |
| **700 ×900** | 872 / 0 | **676 / 7** | ✅ 转绿 |
| **640 ×900** | 700 / 6 | **685 / 6** | ✅ 余量更大 |
| **560 ×900** | 808 / 2 | **700 / 6** | ✅ 转绿 |
| 500 ×844 | 882 / −2 | **773 / 2** | ❌ 唯一不达标 |
**做了两件事 + 修了一个真缺陷**:
① 功能入口卡最小宽 `200 → 160px`(`≤1000` 档)—— 768 下主区内容宽 625px,200px 只能放 2 列 ⇒ 三张卡折成两行、卡块高度翻倍;
② 统计条最小宽 `132 → 96px`(`≤820` 档)—— 700 下 132px 只能放 3 列 ⇒ 4 格折成两行、统计条由 77.59 翻到 171.19;
③ 移动档标签条**藏掉 16px 横向滚动轨**(见 §六 第 32 条)。
⚠️ 两处 `auto-fit` 都**只在真装不下时才缩** ⇒ 上面 10 个视口一格未动,这是"不是拿宽屏换窄屏"的直接证据。
## 六、本轮修掉的真缺陷(每条:现象 → 根因 → 证据)
| # | 现象 | 根因 | 证据 |
|---|---|---|---|
| 1 | 整份设计系统在屏幕上失效 | 样式表顶部注释里 `--t-*/--raw-*` 的 `*/` 提前闭掉注释,吞掉整个 `:root` 令牌块 | 修复后对比度取证才量得出来 |
| 2 | 全表行分隔线一直没画出来 | `.list-row:first-child{border-top:0}`:每行都包在 `<li>` 里,于是**每行都是自己 `<li>` 的 first-child**,`borderTopStyle` 全是 `none` | 变异 M10;另修了判据除数为 0 时恒 PASS(比值 `Infinity`) |
| 3 | 浮层不浮 | `#layer-root` 与 `.layer` 都没有定位样式,浮层渲染在文档流末尾,得滚到页尾才看得见 | 改为遮罩 `fixed inset:0` + 层本体 `fixed` 居中 |
| 4 | 行高随文字长短乱跳(66/82/100px) | 状态标放在操作列把 `auto` 列撑宽,只有那一行折行 | 状态标移到名称旁;再加「行内每段不许换行 + 省略号」;判据新增「行高齐」 |
| 5 | 自检在窄视口给出假 PASS「装得下 10 行」 | 驱动几百次点击后浏览器为聚焦元素自动滚动,`rect.top` 变负,容量公式虚高 | 加「量尺寸时页面在滚动零点」守卫 + 变异 M9 |
| 6 | 手机导航「既不是一条、也没滚动」,占 161px | `.sidebar` 只给了 `flex-direction:row`,可导航分组挂在 `<nav id="nav">` 里,而 `#nav` **一条样式都没有** ⇒ 仍是块级容器,4 个分组照旧竖堆 | 补 `#nav{display:flex;flex-flow:row nowrap}` + 整条链 `flex:0 0 auto`;161px → 53px |
| 7 | 顶栏「演示 · 账号」折成两行,顶栏被顶到 70px | `.topbar-label` 没有 `white-space:nowrap` | 独立评审第一眼点出;补 nowrap 后顶栏 69px |
| 8 | 截图尺寸全部比标称大 16×95 | `cap.py` 对两条通道用了同一个偏移量 | §五「通道口径」;已加 PNG 尺寸守卫 |
| 9 | 两个二次确认浮层其实各有**两个**可见关闭控件,判据却报「出口 = 1」 | 判据只数 `.layer-close` 这个类名,把可见的「取消」从眼皮底下藏掉了;核销层的「取消」还复用了 `X-close` | 判据改为「中性出口只认 `X-close`」+「决策型关闭单列报数」;核销取消拆出 `CHECKOUT-CANCEL`;加变异 M13 |
| 10 | 「今日该发:待发:3 分钟快手菜」冒号连用,评审读成错字 | 示意数据 `today` 字段的值里自带冒号,被拼进「今日该发:…」 | 数据改为空格分隔 |
| 11 | 制作黑话写在界面上(「这里是 X 的 empty 态」) | 状态面板上另贴了一句给做原型的人看的说明,而 `STATE_COPY` 已铺好用户向文案 | 删掉那句话;按钮改「回到正常内容」 |
| 12 | 手机形态看不出当前在哪一页 | 横滚标签栏里当前项滚在视野外 | 只调 `.sidebar` 自己的 `scrollLeft` 把当前项带进视野(⛔ 不碰 `window`,否则会误触滚动守卫) |
| 13 | `layerTrigger` 放进状态快照 `S` | 点任何元素都会改 `S` ⇒ 状态快照跟着变 ⇒ **没有一个控件会被判死**,死控件判据整条失效 | 移出 `S`;变异 M1/M6 当场回归报红 |
| 14 | 浮层焦点与可见性判据全部失效 | `offsetParent` 对 `position:fixed` 元素恒为 `null` | 改用 `getClientRects().length` |
| 15 | `--full`(整页长图)静默失效,产出的还是视口帧 | 无头 CLI 这条通道只能截视口 | 参数已删除,`_full/` 目录一并清掉,不留一个撒谎的开关 |
| 16 | **整页「滚不动」**(不是「不滚」):1440×900 下 P1 有 1543px 内容,只有前 900px 可达 —— 异常值提示 / 本月表现最好 / 全局检索三块在真机里**永远看不到**,而且滚动条也没了(用户连「滚一下」都提不起来) | 外壳只抄了 `html,body{height:100%;overflow:hidden}`,**没把高度链约束住**:`.app` 用 `min-height:100vh` ⇒ 跟着内容长到 1543px,`.main` 1543、`.view` clientHeight = 1474 = scrollHeight(**自己不滚**),真正的滚动落到 `<body>` 上,而 body 是 hidden | 探针实测:`.app` 高 1543px = 内容高、`view.scrollable=false`、`body.scrollTop=435` 而 `window.scrollY=0`。修法:`.app{height:100vh}` + `.main{min-height:0;overflow:hidden}` + `.view{flex:1 1 auto;min-height:0}`;新增判据「纵向滚动只由主区承担」+ 变异 M14 |
| 17 | 自检在窄视口量出的密度**是假数**(假绿):500×844 曾报「一屏装得下 7 行」,真值连 1 行都不到;1024×768 的「4 行」同样是假的 | 「量尺寸前回零点」只复位了 `window`,而实际被滚的是 `<body>`(`body.scrollTop 435` / `window.scrollY 恒为 0`)⇒ 首行 top 被截短、容量虚高。**这是本条最要紧的一处**:假绿比红更坏 | 守卫改为三个容器**逐个核**(window / html / body / .view),`applyScene` 一并复位;变异 M9 的注入点从 `window.scrollTo` 改到 `.view.scrollTop`(原来那条已经抓不到东西,是假变异) |
| 18 | 两栏带 `.band` 在 1024 就落回单列,白丢 4 行密度 | 原注释写「1024px 劈两半后矩阵列表只剩不到 300px」,2026-10-08 复测实得 **336px**(列宽 167 / 121 / auto),三列都不折行 | 收线由 `max-width:1024px` 挪到 `max-width:900px`;1024×900 实测由 4 行 → **8 行**(契约 ≥6 ✅) |
| 19 | P2「对标内容列表」被新加的功能入口卡压到一屏 5 行(首行顶 503px,契约 ≥6) | 功能入口卡按用户口径紧贴在「数据统计」下面,它的高度**直接**转嫁给下面那张吃密度契约的列表 | 收两处:卡内衬 `16` → `12/16`;`≤1000px` 宽隐掉卡片描述。实测 960px:517px → **497px ⇒ 6 行** |
| 20 | 窄视口顶栏折两行白吃 40px | `≤1024` 的顶栏只收了间距与标签文字,**上下内衬仍按 16px** | `≤1024` 内衬收成 `8px`;实测顶栏 109px → **93px**,901–1000 段两个列表都由 5 行回到 6 行 |
| 21 | P3-03「入库」被自检判成**悬空声明**(声明了但页面上没有) | 改版时把「入库」从「单条详情」搬进了资产表格的行尾,而表格**只渲染当前分区**的行 —— 自检的 P3 场景把 `assetSel` 设成 as3(结构分区)却没改 `assetZone`(仍是角度分区),于是那行根本不在表里 | 把动作**搬回「单条详情」**(门禁说明「补上出处才能入库」本来就长在那里,动作与说明不该拆开);表格只做展示、不放行级动作。⇒ 自检 83/0 回绿。**教训**:形态改版顺手挪动作位置,会把「动作 + 它的门禁说明」拆到两个地方 —— 这类搬家不属于「照抄布局」的授权范围 |
| 22 | 两条变异(M2 / M8)**悄悄失效**:一条「找不到注入点、跳过」,一条注进去了却不报红 | 判据的形态改了(P2 列表 → 表格、密度量的是表格内衬),而变异的注入点还指在旧的 `.list-row` / `.action-cell` 上 ⇒ 假对照(比没有变异更坏:它让人以为这条判据有人看着) | 注入点跟着形态重指(M2 指到表格 `<td class="cell-act">`、M8 指到 `.tbl-dense` 的 `td` 内衬);`mutate_test.py` 把「找不到注入点」显式报成 ⚠️ 而不是静默跳过。⇒ 14/14 回绿 |
| 23 | 顶栏堆了 **7 项**杂件(收起侧栏/面包屑/演示·账号/演示·状态/全局检索/随手记/假设 2 项),≤1024 折成两行、顶栏 93px | **没有一项是技能规则要求的**:2 项来自本项目参照物笔记(`ui/布局排版参考-mcn-work-shop.md`)、3 项是我自己造的原型件、1 项与②段 P1 的页内板块重复、1 项(假设入口)是我自己挂在顶栏的第二处;唯一被②段硬要求的是**随手记**(`2b` §286「任意页面一次点击内」) | 删 5 项(收起侧栏/面包屑/两个演示下拉/顶栏全局检索)、改挂 1 项(假设入口 → 两处「假设」徽章,`G-08` 仍活)、留 1 项(随手记)。内衬 16→8 ⇒ 顶栏 **69px → 49px** 且**任何宽度都不折行**。逐样来源定位见 `3d-审查报告.md` §十 |
| 25 | **「模板里的 HTML 注释带反引号」同一个坑踩了第 4 次** —— 页面在浏览器里才炸(白屏 / `xxx is not defined` / `Unexpected identifier`),而 `node --check` 整份 html 报不出来 | 原型把页面结构写在 **JS 模板字面量**里(反引号包起来);模板里的 HTML 注释只要出现一个反引号,模板就被提前闭合,后面那段被当 JS 解析 | ①当场修掉;②**做成第 5 个门禁 `_tools/check_js.py`**:抠 `<script>` 段跑 `node --check` + **多行**扫描 script 区内每个 `<!-- … -->` 块里的反引号(⚠️ 必须多行扫 —— 反引号常在注释的**续行**上,单行 grep 抓不到);③做了变异对照:往一条注释里注一个反引号 ⇒ 报 **FAIL 2 项**、退出码 1(证明它不恒绿) |
| 26 | **加图标那一轮的窄屏回归**:640×900 的 P1 由 5 行掉到 **3 行** | 功能入口卡补了 22px 图标、内衬由 `8/12` 提到 `12/16`,同时网格最小宽 180→200 —— 608px 的主区装不下三张卡,折成两行,卡块高度翻倍。**根因是那一轮只量了契约视口 1440,没回量窄屏** | 补 `≤640px` 紧凑档(内衬 `8/12`、图标 `18px`、最小宽 `160px`、隐「功能入口」小标)⇒ 640 回到 **6 行、自检转全绿**;500×844 由 −2 回到 −1(与原状态一致)。⇒ 记住:**几何一改,逐视口表必须整表重跑** |
| 24 | **同一个「选中态」有三套画法**(侧栏当前项浅紫底 / 分段控件用 `.btn btn-sm` + **内联** `border-color:var(--ink)` 五处 / 表格当前行用**内联** `color:var(--accent-text)` 四处);字号也有 **内联覆盖** 两处(P7 三个数硬顶 `--fs-20`、P4 统计条的「/7」) | 五处分段控件与四处表格当前行都是**早期赶进度时用内联样式铺的**,既没进令牌也没进组件表;判据当时只查「gap 是否落在登记刻度」,**内联样式不在任何判据的视野里** ⇒ 没人拦 | ①`<style>` 里补四个组件:`.seg`/`.seg-item`(选中项 `.is-on`)、`.field`(字段间距)、`.cell-name.is-on`(表格当前行);②五处分段控件换成 `.seg-item.is-on`、四处表格当前行换成 `.cell-name.is-on`、P7 三个数换成 `.home-stats`/`.stat-item`、P4 统计条去掉 `/7` 的内联字号;③P8 对账核对区表由宽松档 `.ds-table` 换 `.tbl-side`;④行级动作统一 `.btn-micro`(P2-06/07/09/10、P4-05/08);⑤**新增自检第 84 项「组件口径」**(八页里 `[style*=border-color]`/`[style*=color]`/`[style*=font-size]` 出现次数都为 0)+ 变异 **M15** 证明它不恒绿 |
| 27 | 功能入口卡按参照物改成**三段纵向**后,**1440×900 的 P1 由 6 行掉到 5 行**(首行顶 697 → 740px) | 卡高 68 → **111px**(+43px),而 P1「统计条 + 功能入口卡」这一摞压在两张 5 行表上、本来只剩 **17px** 余量(697px 距 714px 的六行线)⇒ 余量被一口吃光 | 逐值量参照物(`mcn-work-shop/public/style.css:387-392` + `app.js:332-336`)确认**卡高本来就该是 133px**(同宽 113px),差的主因是**排布**(第一版把「图标+标题」并成一行 ⇒ 少一段 + 少两次 6px 段间距);然后从三处还回 39px ⇒ 701px/6 行。两版 15 视口逐格对照见 §五 |
| 28 | 文档里 **768×900 的行数是错的**(上一版记「677px/7 行 ✅」) | 旧取证通道用 `chrome.exe --window-size` 定视口,而**窗口尺寸不保证等于 CSS 视口**。768 恰好卡在功能入口卡「3 列/2 列」的阈值上(主区内容宽 632px)**只差 7px** ⇒ 旧通道多给十几像素,卡就从两行变一行、首行顶差 64px | 在**改前的版本(`_scratch/base.html`)**上用声明式视口重测:768 → 741px/**5 行 ❌**。⇒ 连带作废上一版「≥640px 全绿」的结论,真实分界是 640 与 ≥820 绿、768 与 700 红、560 与 500 红(§五 全表) |
| 29 | `_tools/cap.py` **自己起 headless Chrome**,且视口靠 `--window-size` 猜 | 违反本机明令(`browser-harness` 是唯一允许的浏览器工具),并且带来第 28 条那种「差十几像素就跨过断点」的不确定性;还有 500px 的宽度硬下限 | 改走 CDP `Emulation.setDeviceMetricsOverride`:**只连 9223 上已有实例、不起新的**,视口要多少是多少。已实测 **390×844**(PNG 尺寸当场比对通过)⇒ **500px 下限解除**,契约里「390 一律按 500 记」那条例外作废 |
| 30 | 本轮一度新建了 `_tools/measure.py`(量元素几何真值),但它自己起 Chrome | 与第 29 条同一个毛病;本机的正解是让 harness 常驻、临时脚本只连不起 | **写完即删**(`_tools/` 现在只剩 cap/check_js/check_skeleton/mutate_test 四个)。量几何真值这件事本身仍然留下了证据 —— 用的是 harness 直连,脚本放在 `_scratch/`(中间件,不进交付) |
| 32 | 移动档的导航标签条里压着一根 **16px 高的横向滚动条** | 标签条自身 `scrollWidth` 724 > 可见宽(560px),`overflow-x:auto` 自动画出轨道;条子本体只有 52px 高 ⇒ **三成高度是灰杠** | 实测(560×900):`.sidebar` offsetHeight 68 / clientHeight 52 ⇒ 滚动条 **16px**;藏轨后首行顶 714.66 → **700px**(P1 由 5 行到 6 行)。修法 `scrollbar-width:none` + `::-webkit-scrollbar{height:0}` —— ⛔ 不是删滚动能力,是不画那根轨 |
| 33 | 全局技能包 `check_naming.py` 有 **3 条既有 FAIL**(不是本轮引入) | ①「停线规则」这条 AUTHORITY 的 `authority` 写成了 **`None`** ⇒ 检查器把它当成"全包禁写、**连权威处也不许写**",与本条自己的 `why`(「口径只在本包 SKILL.md 的「执行规则」」)**自相矛盾**;而 SKILL.md 里**根本没有这条规则** ⇒ 规则的内容一处都没落;②③ `stage-proto-doc/SKILL.md:22` 与 `usage-scenario.md:103` 仍写①段**已废的 `strategy/` 路径** | 复跑命令:`check_naming.py --root . --ws <工作区>`(改前 通过 2057 / **失败 3** / 提示 29)。已修:authority 改 `SKILL.md` 并把规则补进「执行规则」;两处路径改 `research/1d-产品策略.md` / `research/1e-使用场景.md` ⇒ **通过 2060 / 失败 0 / 提示 27** |
| 31 | 导航的**样式**一直没量到 —— 第三轮只照组件清单猜了个「形态」 | 当时从 `references/library.json` 只读到**计数**(`nav-item` 81 / `nav-icon` 81 / `nav-tip` 81 …)就下了结论「一项一图标一提示、⛔ 项内不放常驻文字」;而 `tokens.css` 里**没有一条导航几何**、`design-system.html` 里 `app-sidebar` **0 处** ⇒ **包里根本没有那个事实**,猜出来的形态与源站实测**正好相反** | 回源站 `https://www.tiaoyue.com/` 实测(亮色形态强制 `data-theme=light`):栏是 **64px 药丸**(圆角 100px/内衬 3px/淡底+淡描边/⛔ 无右边线),项是 **56×78 药丸**、**图标 24 在上、名字 12px/500 在下、两者都常驻**;名字一律 **2 字**(内容宽 56−16×2=24px)。逐条对照表在 `3d` §十三。⚠️ 这次改动**不动布局**(栏宽仍是 64px 定值、只让药丸变高)⇒ 15 个视口首行顶一格没动,⛔ 不需要还账 |
## 七、已记录的偏离(⛔ 不许静默)
| # | 原要求 | 实际做法 | 原因 | 影响 | 处置 |
|---|---|---|---|---|---|
| D1 | 3b 实测走 `browser-harness` | ✅ **2026-10-08 第七轮已合规**:自检 84 项 + 变异对照 15/15 + 视口帧 + 逐条 DOM 取值,**全部经 9223 上那个常驻实例**(`_tools/cap.py` 走 CDP,只连不起) | 此前用的是 `chrome.exe --headless` 另起实例 —— 既违本机明令,又带来视口歧义(§六 第 28/29 条) | 证据链可复跑;⛔ 仍**没有**「真人真点」这一层,交互结论全部来自脚本驱动 | **已修**(第七轮)。人工走查仍待用户裁定 |
| D2 | D5 终检要 `1440x900` 与 `390x844` 两个视口帧(runbook §5.3、§七) | ✅ **2026-10-08 第七轮起两个视口都能出**(390×844 已实测,PNG 尺寸当场比对通过) | 旧通道(`--window-size`)受 Chrome 窗口宽下限 516 ⇒ 视口最小 500 | 无 | **已修**(第七轮)。⚠️ 390 的**密度**还没纳入逐视口表,⛔ 不许把「能测」当成「达标」 |
| D3 | 对外只留视口帧;`_full/` 长图仅自检(runbook §七) | 未产出长图 | `--full` 在本机通道上做不到(只能截视口),已把该参数删掉 | 无 | 已修 |
| D4 | 3c 要「外部 GPT 会诊」 | 见 `3c-GPT会诊.md`:本会话无对外模型通道,改用**隔离上下文的独立评审执行者** | 没有外部通道可用 | 与「异厂商外部审查」不是同一条通道 | 持续偏离,已明示 |
## 八、这一步的门槛结论
- 3a 已过 Gate-1(见 `DESIGN.md` §四)。
- 3b 实测:**契约视口 1440×900 全绿(PASS 84/FAIL 0)**。
- **密度分界(2026-10-08 第八轮实测,15 个视口)**:绿 = 1440 / 1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / **768** / **700** / **640** / **560**;红 = **500×844**(唯一一个,P1 账号矩阵 2 行)。⇒ 比上一轮多转绿三个(A 方案 + 滚动条修复)。
- 🔴 **口径更正**:上一版写的「宽 ≥640px 全绿/边界 768px」是错的(768 的真值是 5 行 ❌,见 §五 与 §六 第 28 条)。现在能说的是「**≥820px 全绿;768 与 700 是窄中屏的两个洞;≤560 与 500 是窄屏两个洞**」。
- 🔴 **本轮的正当性靠对照支撑**:改前/改后各跑 15 个视口,**PASS/FAIL 逐格完全一致**(§五 表)。功能入口卡长高 43px 这件事是**从别处把高度还回去**做到的,⛔ 不是拿密度换的;同时修掉的**只有本轮自己造成的回归**,768/700/560/500 那四处红**改前就存在**。
- ⚠️ 一处**已解除的限制**:窄视口此前只能测到 500×844(Chrome 窗口宽下限),现在走 CDP 声明式视口,**390×844 已可测**(§六 第 29 条)。⚠️ 但 390 的密度还没纳入逐视口表,⛔ 不许把「能测」当成「达标」。
- 顺带记四件事:①外壳「整页不滚」曾等于「整页不能滚」(§六 第 16 条),已修并由判据 + M14 看住;②改版首跑时自检在窄视口量出的是假数(§六 第 17 条),已修并由 M9 看住;③「模板里的 HTML 注释带反引号」这个坑踩了 4 次,已做成第 5 个门禁 `check_js.py` 并由变异证明不是恒绿(§六 第 25 条);④**「改完只量主视口」这个毛病犯了两次**(第六轮 640、本轮 1440),两次都是逐视口表兜住的 —— 已写进 `DESIGN.md` §五 第 7 条当纪律。
- ✅ **导航样式已按源站实测对齐**(2026-10-08 第七轮追加):栏 → 64px 药丸浮栏、项 → 56×78 药丸(图标 24 + 2 字短名常驻)、当前项 → 中性填充 + 满墨、提示 → 该页说明。五道闸门复跑全过,且**对密度中性**(15 个视口首行顶一格未动)。
- 可以进 3c。
---
## 九、说人话自评(判据源 `humanizer-zh`,五维各 10 分)
| 维度 | 分 | 说明 |
|---|---|---|
| 直接性 | 9 | 开头就是复跑命令,没有「本次工作取得进展」这类开场 |
| 节奏 | 8 | 表格 + 短断言为主,句式偏单一,⚠️ 弱项 |
| 信任度 | 10 | 把改坏的、没测到的、换了通道的都写出来了,没有藏 |
| 真实性 | 9 | 每条缺陷都带现象、根因与证据(脚本名 / 变异编号 / 实测数) |
| 精炼度 | 9 | 15 条缺陷各一行,不重复叙述;自检全文照录是留证需要,不是凑字 |
| **总分** | **45 / 50** | 门槛 ≥45,压线过;扣分点写在第 2 行 |
@@ -181,7 +181,7 @@ _gate_shots/layer-confirm-1440.png P5 上的「发布二次确认」浮层 ·
| R-04 | 「假设」金色字属滥用强调色、是制作说明被上色 | **不采纳**(含颜色) | 「假设」标不是装饰,是本任务的**硬要求**:`1a` 的待复核第 5、6 条尚无用户结论,②段 §四 要求③段显式标注,⛔ 不能删。颜色也不换:`--warn` 在本产品里就是「**需要人来看一眼**」的语义位(`DESIGN.md` §2.2 明写「状态色只用红/绿/黄三系,不做装饰」),而「假设待复核」正是这个语义;换成中性墨色,它在八页里会被直接忽略,标注就白标了。⚠️ 本轮**未**改这一处颜色,评审这条保留为意见。 |
| R-05 | P2 KPI 标签下有下划线,像链接却不可点 | **未能复核** | 代码里 `.stat` 与 `.stat-label` 都没有 `border-bottom` / `text-decoration`,4 个 KPI 里 2 个是真按钮(`P2-01` / `P2-02`,可点即筛选)。评审看到的线未能复现,也不排除是缩略下的砖缝感。**如实记为未复核**,不做无依据的改动。 |
| R-06 | 每个分组标题下都压一条通栏线,重复线框 | **不采纳** | `layouts-tooling.md` §1 判定要点原文:「边框只上不围 —— 行间用 `border-top`」。板块标题下的那条是**结构线**,`visual-review.md` 自己也写了「承担风格和结构的线不算问题」。删掉它,板块头与内容就分不开了。 |
| R-07 | 同一状态两种画法(当前导航项,P4 看着是深色实心) | **不采纳**(评审判读) | 侧栏当前项在八页是同一套样式:`background:var(--surface-soft)` + 左侧 3px `--accent`。P4 那一眼的「深色实心」是把侧栏当前项与**步骤条里的当前步**看混了 —— 后者按③段设计就该更重(它标的是流程位置,不是导航位置)。自检逐页核过:8 项导航的 `is-active` 只有一个。 |
| R-07 | 同一状态两种画法(当前导航项,P4 看着是深色实心) | **不采纳**(评审判读) | 侧栏当前项在八页是同一套样式:整块浅紫底 + 字重 600(见 `DESIGN.md` §2.5)。P4 那一眼的「深色实心」是把侧栏当前项与**步骤条里的当前步**看混了 —— 后者按③段设计就该更重(它标的是流程位置,不是导航位置)。自检逐页核过:8 项导航的 `is-active` 只有一个。 |
| R-08 | P4 文案口语化(「写清方向,点开始这一步」) | **已采纳·已改** | 输入框提示改为「写下这一步要往哪个方向走」;空引用文案改为「还没有引用资产。可以直接写,也可以从资产库引一条进来。」 |
| R-09 | 侧栏 `账号画像(跑图)` 与 `账号画像` 重复、「跑图」是开发口吻 | **不采纳**(评审判读),**但记账** | 那三个字是「跨组」不是「跑图」。字样直接来自②段 `2b §一` 的一级导航表「(跨组)账号画像」,③段不许改②段定的导航名。评审由此暴露的「括号夹在词中间不好读」这点,记为本段已知取舍。 |
| R-10 | 导航计数只给了一半(创作台 / 账号画像 无数字) | **已采纳·本段不改** | 计数=**这一页有几件事等你做**;没数字的两页当前确实没有待办(不是漏给)。但「一半有半数无」读起来像掉数据 —— 评审这条是对的,已记为待办,改动落点在交互清单 `G-05` 的反馈列,本轮不动。 |
@@ -194,7 +194,7 @@ _gate_shots/layer-confirm-1440.png P5 上的「发布二次确认」浮层 ·
| R-17 | 「空面板」(P2 评论区洞察、P4 资产引用区、P5 检查结果)稀释首屏 | **已采纳·本段不改** | 三块都是②段冻结的板块,⛔ 不许折叠或删除。它们看起来空是因为**示意数据只填了主路径**;每块的空态文案(`STATE_COPY` 逐页不同)都在。记为「示意数据丰满度」的已知边界。 |
| R-18 | 动作甩到最右边、离对象半屏远 | **已采纳·本段不改** | 操作列右对齐成列是刻意的:`layouts-tooling.md` §5.5 要求「并列卡有主次」且同类动作要在同一轴上对齐。评审的另一半意见(「一屏内同类动作必须在同一 X 轴上对齐」)正是现状。 |
| R-19 | P1 两栏平权、没有主次 | **不采纳** | 并排是**密度判据逼出来的**,有反事实实测:落回单列时账号矩阵首行顶 530px、一屏只装得下 5 行(<6)。两栏宽度也不是等宽(`minmax(0,400px) minmax(0,1fr)`),左栏是窄栏。 |
| R-20 | 硬纪律守住了(强调色克制、无入场动画、无三段式标题、无渐变发光、无表情图标) | **确认** | 自检逐条机核:零 `.eyebrow`/`.lead`/`.hero`、零 `@keyframes`、强调色填充占比八页最高 0.52%。 |
| R-20 | 硬纪律守住了(强调色克制、无逐区块入场编排、无三段式标题、无渐变发光、无表情图标) | **确认** | 自检逐条机核:零 `.eyebrow`/`.lead`/`.hero`、`@keyframes` 0 处(⛔ 不做逐区块入场编排)、强调色填充占比八页最高 0.52%。 |
| R-21 | 记不住 —— 建议把 P1「账号矩阵列表」做成真正的矩阵 + 异常分布 | **已采纳·本段不改**(记为用户可选项) | 改名成「矩阵」的块,画法受②段冻结:板块名与位置不能动,「矩阵视图」是一种信息呈现变更,超出③段权限。**这是本轮最值得往上提的一条建议**,见 §四。 |
| R-22 | 无法验证:点击/悬停/焦点行为、动效、检索结果、遮罩键盘可达性、其他四页 | **已采纳·已补** | 评审看不到的部分正是 3b 自检覆盖的部分:71 个 ID 逐个真驱动(0 死控件)、六态 × 八页 48 组合、7 个浮层 × 6 项(中性出口 / 焦点在层内 / Tab 锁层 / Esc / 焦点归还 / 点遮罩)。P3/P6/P7/P8 的截图**已补拍**(`_gate_shots/p3-1440.png` … `p8-1440.png`),本轮交接口径已改为八页全给。 |
@@ -1,217 +1,546 @@
# 3d · 审查报告(③段界面交互收口)
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/3d-审查报告.md`
> 模板:`SKILL.md` §3d + `references/execution-runbook.md` §5.4/§5.5、§七(固定七节)
> 交付物:`ui/mcn-workbench.html`(原型)+ `ui/DESIGN.md`(规范)+ `ui/3b-实测记录.md`(实测)+ `ui/3c-GPT会诊.md`(会诊)
---
## 一、范围
| 项 | 内容 |
|---|---|
| 段与子步 | ③段界面交互 · 3d(D3 收口 + D4 动效 + D5 终检 + Gate-2 / Gate-3) |
| 被审对象 | `ui/mcn-workbench.html`(单文件自包含原型,八页 + 七浮层)+ `ui/DESIGN.md`(设计契约与令牌) |
| 覆盖页 | P1 矩阵总览 / P2 选题雷达 / P3 资产库 / P4 创作台 / P5 发布中心 / P6 账号画像 / P7 复盘台 / P8 记录与对账(**八页全审,无抽样**) |
| 覆盖状态 | 正常 / 加载 / 空 / 出错 / 禁用 / 无权限 —— 逐页 × 逐态 = 48 组合 |
| 不在范围 | ④段(原型说明区与演示引导);②段的板块清单与信息档位(已冻结,本段不动);暗色主题(见 `DESIGN.md` §五 第 2 条) |
| 证据留档 | `_gate_shots/` **23 张视口帧**(全部经 PNG 像素尺寸校验);`ui/_tools/` 三个可复跑脚本 |
**本轮是否跑了脚本**:**跑了**。三条,全部可复跑,命令见 `3b-实测记录.md` §一:
```text
自检(#/selftest 路由,原型自带) → PASS 81 / FAIL 0 @1440×900
变异对照(_tools/mutate_test.py) → 13 / 13 通过
骨架冻结闸门(_tools/check_skeleton.py)→ PASS 八页 37 个板块与②段逐页逐位一致
```
**结构核对表的每一个数,都来自上面这三条脚本的输出或 DOM 取值,⛔ 无一处是目测截图。**
---
## 二、挡位
**标准档**(本段未升未降)。理由:这是新产品的第一版原型,不是发版前的精修;`SKILL.md` §供给·方法主线 给的默认主线就是 `oil-ui-pro`,挡位按 runbook 默认的**标准**执行 —— 三条门(Gate-1 / 2 / 3)全过,但不上「多方向比选」与「严格档」的额外轮次。
---
## 三、阻断项表
口径:`阻断` = 不清零就不能交。**本轮共 15 条,14 条已清零,1 条未清零并留档。**
| # | 阻断项 | 观察(现象) | 根因 | 处置 | 现状 |
|---|---|---|---|---|---|
| B-01 | 整份设计系统在屏幕上失效 | 原型打开后令牌全不生效 | 样式表顶部注释里 `--t-*/--raw-*` 的 `*/` 提前闭掉注释,吞掉整个 `:root` 令牌块 | 改写注释文字 | ✅ 清零 |
| B-02 | 全表行分隔线一直没画出来 | 列表行之间没有任何分隔线 | `.list-row:first-child{border-top:0}` —— 每行都包在 `<li>` 里,于是每行都是自己 `<li>` 的 first-child | 改为 `li:first-child > .list-row` | ✅ 清零(+变异 M10) |
| B-03 | 判据除数为 0 时恒 PASS | 上面那条真缺陷没有任何门禁报它 | `gap>=2*bw` 在 `bw=0` 时恒成立、比值算成 `Infinity` | 除数为 0 一律判红 | ✅ 清零 |
| B-04 | 浮层不浮 | 浮层渲染在文档流末尾,得滚到页尾才看得见 | `#layer-root` 与 `.layer` 都没有定位样式 | 遮罩 `fixed inset:0` + 层本体 `fixed` 居中 | ✅ 清零 |
| B-05 | 行高随文字长短乱跳 | 同一张表量出 66 / 82 / 100px 三种行高 | 状态标放在操作列把 `auto` 列撑宽,只有那一行折行 | 状态标移到名称旁 + 行内每段不许换行 + 新增「行高齐」判据 | ✅ 清零(+变异 M7) |
| B-06 | 自检在窄视口给出假 PASS | 报「一屏装得下 10 行」,实际 5 行 | 驱动几百次点击后浏览器自动滚动,`rect.top` 变负,容量公式虚高 | 加「量尺寸前页面在滚动零点」守卫 | ✅ 清零(+变异 M9) |
| B-07 | 手机导航「既不是一条、也没滚动」 | 导航条占 161px 高,4 个分组竖着堆 | 导航分组挂在 `<nav id="nav">` 里,而 `#nav` **一条样式都没有** ⇒ 仍是块级容器 | 补 `#nav{display:flex;flex-flow:row nowrap}` + 整条链 `flex:0 0 auto` | ✅ 清零(161px → 53px) |
| B-08 | 顶栏标签折行 | 「演示 · 账号」折成两行,顶栏被顶到 70px | `.topbar-label` 没有 `white-space:nowrap` | 补 nowrap | ✅ 清零(→ 69px) |
| B-09 | 两个二次确认浮层其实有两个可见关闭控件,判据却报「出口 = 1」 | 核销层与发布层各有一颗「取消」 | 判据只数 `.layer-close` 这个类名,把可见的「取消」从眼皮底下藏掉了;核销层的「取消」还复用了 `X-close` | 判据改成「中性出口只认 `X-close`」+「决策型关闭单列报数」;核销取消拆出 `CHECKOUT-CANCEL` | ✅ 清零(+变异 M13) |
| B-10 | 截图尺寸全部比标称大 16×95 | 「1440×900」的帧实际是 1456×995,同一份报告里 dump-dom 又按 640 说话 | Chrome 两条通道对 `--window-size` 的解释不同(截图=视口,dump-dom=视口+16/95),而脚本对两者用了同一个偏移量 | 按模式分开算 + 每次截图后从 PNG 的 IHDR 读真实像素比对目标视口 | ✅ 清零(23 张帧全部 ✓) |
| B-11 | 制作黑话写在界面上 | 状态面板上贴着「这里是 X 的 empty 态。」 | 给做原型的人看的说明被写进了界面,而 `STATE_COPY` 已经铺好用户向文案 | 删掉那句话;按钮改「回到正常内容」 | ✅ 清零 |
| B-12 | 主列表可读性 | 「今日该发:待发:3 分钟快手菜」冒号连用,独立评审读成错字 | 示意数据 `today` 字段的值里自带冒号,被拼进「今日该发:…」 | 5 行数据改为空格分隔 | ✅ 清零 |
| B-13 | 窄屏看不出当前在哪一页 | 横滚标签栏里当前项滚在视野之外 | 没有把当前项带进视野的逻辑 | 只调 `.sidebar` 自己的 `scrollLeft`(⛔ 不碰 `window`,否则误触 B-06 的守卫) | ✅ 清零 |
| B-14 | `--full`(整页长图)静默失效 | 带该参数产出的还是视口帧 | 无头 CLI 这条通道只能截视口 | 删掉该参数与 `_full/` 目录,不留撒谎的开关 | ✅ 清零 |
| **B-15** | **≤767px 宽时一屏装不满 6 行** | 641×900 与 640×900 实测 **5 行**;500×844 实测 **4 行 / 5 行** | 页面外壳吃掉首屏:≤767px 顶栏折成两行(641px 实测 109px)、≤640px 导航变标签栏。**行本身没变肥** —— 行高 67px、行高差 ≤2px、块内分隔 1px 在任何视口都 PASS | 未在本段修 | ❌ **未清零,留档待裁定** |
### B-15 为什么没在本段修,以及留给用户的两条路
判据原文(`layouts-tooling.md` §1)是「一屏可见行数 **≥ 6(900px 高时)**」,**不带宽度条件**。实测出来的边界是 **768px 宽**:≥768px 时顶栏单行、导航竖排,容量 6–10 行;≤767px 时页面外壳折行,容量掉到 4–5 行。三条路,**两件事必须挑一件**:
| 选择 | 代价 |
|---|---|
| A. 把支持宽度下限写成 **≥768px**,手机形态只承诺「可用」(布局折行、零横向溢出、全路径可点通),不承诺 6 行密度 | 要在契约里**明文加一条本段自定的宽度条件**;依据是 `1a §七` 已明确第一版不做移动端 App |
| B. 压掉每行的次级信息,把行高从 67px 压到 40px 上下,让窄屏也装得下 6 行 | 那 3 条次级信息是②段《界面布局》定的档位,③段不许改 ⇒ 得回②段改档 |
| C. 动页面外壳(顶栏控件精简、导航折叠) | 顶栏那几个控件都登记在交互清单里(`G-06`/`G-08`/`G-10`),删或搬家等于改交互清单 |
⛔ 本段**没有**选任何一条就宣布通过:判据一个字没改,`needRows=6` 写死,三个窄视口的 FAIL 原样留在自检输出里。
---
## 四、建议项表
口径:每条要么**修掉**,要么**显式写「已知不修 + 原因」**。⛔ 不接受「基本没问题」。
| # | 建议项 | 结论 |
|---|---|---|
| S-01 | 密度只有同类工具的 40–50%(评审:Linear 行高 32px,本原型 67px) | **已知不修**:判据是「≥6 行 @900px 高」,1440/1280 实测 10 行、1024/768 实测 6 行,达标。再压只有砍次级信息一条路 ⇒ 属②段档位,见 B-15 选择 B |
| S-02 | 处处 24px 圆角大卡,列表本该是「表格行 + 发丝线」 | **部分已修**:列表**行**本来就是无框行 + `border-top` 发丝线(B-02 修的就是它真的画出来);剩的是承载列表那层**面板**仍是圆角卡,改为无框会让 37 个板块散在底纸上失去分层。已知不修 |
| S-03 | 「左标题右说明」分栏里,右侧小字像给评审看的注释 | **已修**:逐条过了一遍板块头右侧的小字 —— 读出「这是在解释口径」的那几条已改写或删除(B-11、P4 输入提示、空引用文案)。剩下的多是②段要求的计数与口径(「5 项 · 按截止时间排」),保留 |
| S-04 | P2 KPI 标签下有下划线,像链接却不可点 | **未能复核**:代码里 `.stat` / `.stat-label` 都没有 `border-bottom` / `text-decoration`;4 个 KPI 里 2 个是真按钮(`P2-01`/`P2-02`)。⛔ 不做无依据的改动,如实记为未复核 |
| S-05 | 每个分组标题下都压一条通栏线(重复线框) | **不采纳**:`layouts-tooling.md` §1 原文「边框只上不围 —— 行间用 `border-top`」;`visual-review.md` 自己也写「承担风格和结构的线不算问题」。删掉它板块头与内容就分不开 |
| S-06 | 同一状态两种画法(当前导航项,P4 看着是深色实心) | **不采纳(评审判读)**:侧栏当前项八页同一套样式(`--surface-soft` + 左 3px `--accent`)。自检逐页核过:8 项导航里 `is-active` 只有一个。评审把侧栏当前项与**步骤条里的当前步**看混了 —— 后者按设计就该更重 |
| S-07 | 侧栏 `账号画像(跑图)` 与 `账号画像` 重复 | **不采纳(评审判读)**:那三个字是「跨组」不是「跑图」;字样直接来自②段 `2b §一` 的一级导航表「(跨组)账号画像」,③段不许改②段定的导航名。由此暴露的「括号夹在词中间不好读」记为已知取舍 |
| S-08 | 导航计数只给了一半(创作台 / 账号画像 无数字) | **已采纳·本段不改**:计数=「这页有几件事等你做」,没数字的两页当前确实没有待办。但「一半有半数无」读起来像掉数据,这条提得对 —— 改动落点在交互清单 `G-05` 的反馈列,本轮不动 |
| S-09 | 窄屏正文被省略号硬截断 | **已知不修**:这是上一轮为「行高齐」付的代价 —— 行内每段不许换行 + 省略号,是行高能恒为 67px 的唯一办法(放开换行行高跳到 66/82/100px,变异 M7 盯着)。完整原文挂在行上的 `title` 里 |
| S-10 | 每行右侧指标左边缘没对齐成列 | **已知不修**:右栏是「标签 + 值」两行、整块右对齐到块右内衬;改成逐字对齐会把长短差异大的值拉成锯齿 |
| S-11 | 浮层右上「×」套着淡紫圆圈,像常驻焦点环 | **不采纳**:那是 `:focus-visible` 焦点环(`--accent`),出现是因为浮层打开后焦点按设计落在层内第一个可聚焦件上,而它正好是 ×。⛔ 不能改成 hover 才出现 —— 改掉就把键盘用户的定位点弄丢了。已记为「截图里带焦点环」的已知现象 |
| S-12 | 顶栏演示控件、`假设 2 项`、页面编号 `P1…P8` 可以删 | **不采纳**:都是原型自带件 —— 演示控件(`G-07`/`G-09`)用来把页面掰到六态给评审看,编号用来定位页面。删了评审就看不到六态 |
| S-13 | 「空面板」(P2 评论区洞察、P4 资产引用区、P5 检查结果)稀释首屏 | **已知不修**:三块都是②段冻结的板块,⛔ 不许折叠或删除。看着空是因为示意数据只填了主路径;每块的空态文案都在(`STATE_COPY` 逐页不同) |
| S-14 | 动作甩到最右边、离对象半屏远 | **不采纳**:操作列右对齐成列是刻意的(`layouts-tooling.md` §5.5 要求同类动作在同一轴上对齐);两栏也不是等宽(`minmax(0,400px) minmax(0,1fr)`) |
| S-15 | P1 两栏平权、没有主次 | **不采纳**:并排是密度判据逼出来的,有反事实实测 —— 落回单列时账号矩阵首行顶 530px、一屏只装得下 5 行(<6)。见 B-15 选择 A |
| S-16 | 记不住 —— 建议把 P1「账号矩阵列表」做成真正的矩阵 + 异常分布 | **已知不修·往上提**:块名与位置受②段冻结,「矩阵视图」是**信息呈现**变更,超出③段权限。**本轮最值得往上提的一条**,交主会话转用户 |
| S-17 | 评审看不到的:点击/悬停/焦点行为、动效、检索结果、遮罩键盘可达性、另外四页 | **已补**:这些正是 3b 自检覆盖的 —— 71 个 ID 逐个真驱动(0 死控件)、六态 × 八页 48 组合、7 浮层 × 6 项。P3/P6/P7/P8 截图已补拍,本轮交接已改为八页全给 |
---
## 五、状态覆盖核对表(六项逐页)
判据源:`SKILL.md` 铁律 2 的六态清单。⚠️ 逐项**数值**判据出自供给可选档的 `craft/state-coverage.md`,**本轮未动用可选档 ⇒ 该项无供给来源**(`DESIGN.md` §五 第 1 条),故只核「有没有、长什么样」,不编阈值。
机检结论:**六态 × 八页 = 48 个组合,全部渲染出内容**(自检第 10 行)。
| 页 | loading | empty | error | success | disabled | 无权限 |
|---|---|---|---|---|---|---|
| P1 矩阵总览 | ✅ 骨架行 +「正在取矩阵数据」 | ✅「还没接入账号」+ 去处按钮(→P6) | ✅ 显时间戳 + 重试 | ✅ 默认态 | ✅ 无待办时待办区禁用并说明 | ✅ 非管理员看利润列的遮罩说明 |
| P2 选题雷达 | ✅「正在拉对标更新」 | ✅「监控名单是空的」+ 录对标号 | ✅ 拉取失败(退路=手工录入) | ✅ 默认态 | ✅ 未选账号时「转入创作」禁用 | — 不适用(本页对所有角色开放) |
| P3 资产库 | ✅「条目加载中」 | ✅「这个分区还没有条目」+ 去处(→P2) | ✅ 读取失败(重试) | ✅ 默认态 | ✅ 无出处的条目「入库」禁用(门禁) | — 不适用 |
| P4 创作台 | ✅「正在跑这一步」(带已跑秒数) | ✅「这一步还没有产出」 | ✅ 本步失败(保留已产出 + 重试该步) | ✅ 默认态 | ✅ 文案与封面缺一,进检查态禁用 | — 不适用 |
| P5 发布中心 | ✅「检查中」 | ✅「还没有可发布的版本」+ 回 P4 | ✅ 检查自身失败 ⇒ **按不过处理**(fail-closed) | ✅ 无硬拦、可发 | ✅ 有硬拦项时「确认发布」禁用 | ✅ 未授权账号的版本标「无发布权限」并禁用该版 |
| P6 账号画像 | ✅「画像加载中」 | ✅「还没有画像」+ 建画像 | ✅ 保存失败(保留编辑内容) | ✅ 保存成功提示 | ✅ 只读角色时字段禁用 | ✅ 非本人负责账号:可看不可改 |
| P7 复盘台 | ✅「正在读这条的数据」 | ✅「还没有能复盘的内容」 | ✅ 数据读不到 ⇒ 转手工录入 | ✅ 回写成功提示 | ✅ 未写归因时「回写」禁用 | — 不适用 |
| P8 记录与对账 | ✅「记录加载中」 | ✅「还没有发布记录」 | ✅ 读取失败(重试) | ✅ 核销成功 | ✅ 未选中记录时「核销」禁用 | ✅ 利润列对非管理员隐藏(列级遮罩) |
> 口径:`disabled` 与 `无权限` 是两件事 —— 前者「当前条件不满足」(自己能解开),后者「角色不允许」(自己解不开)。界面文案分开写,⛔ 不拿「不可用」一句话糊过去。
> 留档截图:`p1-empty-1440.png`、`p4-noperm-1440.png`、`p5-error-1440.png`;其余 45 组由自检逐组渲染核过。
---
## 六、结构核对表(契约值 / 实测值 并排,数字抄自脚本输出)
### 6.1 契约里写了数字的项
| 项 | 契约值 | 实测值 | 取法 |
|---|---|---|---|
| 强调色填充面积占比 | ≤5% | **0.52%**(八页最高:创作台,1 个填充块) | DOM:逐个元素比 `backgroundColor` ≡ `--accent`,与视口求交累加 ÷ 视口面积 |
| `--warn` 对 `--surface` 对比度 | ≥4.5:1 | **5.93:1** | 真实像素计算(WCAG 相对亮度) |
| `--accent-text` 对 `--surface` 对比度 | ≥4.5:1 | **4.76:1** | 同上 |
| `--ink-faint` 对 `--surface` 对比度 | ≥3:1(仅非正文) | **3.55:1** | 同上 |
| 一屏可容纳记录行数(P1 账号矩阵) | ≥6 @900px 高 | **10 行** @1440×900(首行顶 214px、行距 67px) | DOM:首屏可用高度 ÷ 行距。⚠️ 是「装得下几行」不是「画了几行」—— 示意数据 5 条,实际永远 ≤5 行(数据用尽,非被截断) |
| 一屏可容纳记录行数(P2 对标列表) | ≥6 @900px 高 | **7 行** @1440×900(首行顶 402px) | 同上 |
| 页内行高齐 | ≤2px 差(本段追加判据) | **67–68px,差 1px** | DOM:逐行 `getBoundingClientRect().height` |
| 视觉层间距 / 块内相邻行分隔 | ≥2 | **32px / 1px = 32**(4 个视觉层) | DOM:按 `.band` 归并视觉层后相减;分隔取各行 `borderTopWidth` 最大值 |
| 实际在用字号档数(P1) | ≥3 | **5 档**:12 / 14 / 16 / 18 / 24px,相邻差 2/2/2/6 | DOM:叶子节点 `fontSize` 去重 |
| 块间距 / 块内间距 | ≥2 | **32 / 8–16 ⇒ 2.0–4.0** | 令牌登记值 + DOM 复核(`gap` 全部落在登记刻度内,9 个刻度) |
| 横向溢出 | 0 | **0**(1440 / 1280 / 1024 / 768 / 641 / 640 / 500,八页逐页亦 0) | DOM:`scrollWidth − clientWidth` |
| 浮层中性关闭出口 | 恰好 1 | **7 / 7 个浮层均为 1**(另有决策型关闭 0–1 个,已单列报数) | DOM:可见的 `[data-act="X-close"]` 计数 |
| 同屏主档按钮 | ≤1 | **逐页 1 个**(P1 无主档:本页只用弱档,按钮高度集合 {32px}) | DOM:逐页统计实底按钮 |
| 顶栏高度 | 未写死(只看有没有折行) | **69px**(单行;补 `nowrap` 前是 70px,标签在中间折行) | DOM:`.topbar` 高度 + 诊断行 |
### 6.2 契约未写数字、本轮补登记的证据(⛔ 不留「无法判定」)
| 项 | 实测值 | 说明 |
|---|---|---|
| P1 各块落位(顶 / 高) | 今日待处理 @149+360 · 账号矩阵列表 @149+417 · 异常值提示 @599+215 · 本月表现最好的一条 @845+122 · 全局检索与随手记 @1000+113 | 前两块并排同顶(视口高 900) |
| P2 各块落位(顶 / 高) | 对标监控概览 @165+139 · 对标内容列表 @336+417 · 评论区洞察 @785+108 · 选题库 @925+330 · 灵感速记 @1287+113 | — |
| 反事实:P1 前两块落回单列 | 账号矩阵列表 @530+413 ⇒ 首行顶 530px、容量 **5 行**(<6) | 证明并排是密度判据逼出来的 |
| 控制台报错 | **0 条** | 自检全程监听 `console.error` |
| 量尺寸时的滚动零点 | `scrollY = 0`(P1 / P2 两处均核) | rect 取到的是相对视口的真值 |
### 6.3 Gate-3 八项肉眼过(真实渲染,非只看代码)
| # | 项 | 结论 |
|---|---|---|
| 1 | 裁切 | ✅ 无一页出现被裁掉的内容(23 张视口帧逐张看过) |
| 2 | 重叠 | ✅ 无元素互相压盖 |
| 3 | 失真 | ✅ 无变形拉伸;字体走系统栈,无回退异常 |
| 4 | 失效控件 | ✅ 0 个死控件(71 个 ID 在 22 个场景里逐个真驱动过) |
| 5 | 缺状态 | ✅ 48 组(六态 × 八页)全部渲染出内容 |
| 6 | 响应式破损 | ✅ 七视口横向溢出全 0;≤640px 导航变横滚标签栏、两栏带落回单列(B-15 的密度缺口另计) |
| 7 | 控制台报错 | ✅ **0 条** |
| 8 | 字体回退异常 | ✅ 字体栈全部命中系统字体;`@font-face` 数量 0(选定套实测同此) |
---
## 七、Gate 结论
### Gate-2(原型门)
**通过。** 依据:`DESIGN.md` 的十二字段契约与令牌表落盘(Gate-1 十项全过,见 `DESIGN.md` §四);八页 37 个板块与②段 `2b` 逐页逐位一致(骨架闸门正向 PASS + 反向变异两条都报红);六态 × 八页 48 组合全渲染;71 个 ID 逐个真驱动、0 死控件;对 §二 的令牌与 §二 表 2.4 交互清单做双向差集,表外可点元素为 **0**。
### Gate-3(交付门)
**桌面 / 平板档通过;手机档不通过,且已逐条留痕 —— 总判:有条件通过。**
- **通过的部分**:契约视口 1440×900 自检 **PASS 81 / FAIL 0**;1280 / 1024 / 768 亦为 **PASS 81 / FAIL 0**;§六 里契约写了数字的 15 项全部实测回填、无一项越界;Gate-3 八项肉眼检查全过;控制台报错 0。
- **不通过的部分**:**B-15** —— ≤767px 宽一屏装不满 6 行(641×900 / 640×900 实测 5 行、500×844 实测 4 行 / 5 行)。**自检在这三个视口上就是红的(PASS 80/1 与 PASS 79/2),⛔ 没有靠改判据把它变绿。**
- **条件**:B-15 的三条路(见 §三)得由用户挑一条;挑之前这一项挂在账上。
- **另需明示**:3c 那次独立评审**不是** SKILL.md §3c 要求的「外部 GPT 会诊」(本会话没有对外模型通道,见 `3c-GPT会诊.md` §〇)。**未取得外部审查 ≠ 已通过。**
---
## 八、偏离单(本段收尾必附)
| # | 原要求(文件:小节) | 实际做法 | 原因 | 影响 | 处置 |
|---|---|---|---|---|---|
| D1 | 3b 实测走 `browser-harness`(`SKILL.md` §3b) | 原型自带自检 81 项 + 变异对照 13/13 + 无头 Chrome 23 张视口帧 + 逐条 DOM 取值 | 该通道绑定实时浏览器入口,本会话驱动不了 | 证据链全部可复跑;⛔ 但**没有「真人真点」这一层** | 持续偏离,待裁定是否补一次人工走查 |
| D2 | D5 终检要 `1440x900` 与 `390x844` 两帧(`runbook` §5.3、§七) | 实测到 **500×844** 为止 | Chrome 窗口宽下限 516 ⇒ 视口最小 500;要 390 得走 CDP `setDeviceMetricsOverride` | 手机帧比要求宽 110px | 持续偏离;⛔ 报告一律写「500×844」 |
| D3 | 对外只留视口帧,长图仅自检(`runbook` §七) | 未产出长图 | `--full` 在本机通道做不到,只能截视口 | 无 | ✅ 已修(参数与目录一并删掉) |
| D4 | 3c 要「外部 GPT 会诊」(`SKILL.md` §3c) | 隔离上下文的独立评审执行者 | 无对外模型通道 | 与「异厂商外部审查」不是同一条通道 | 持续偏离,已明示 |
| D5 | 逐页截图应八页齐备 | 首次交接只给了评审 4 页 + 2 个状态 + 2 个浮层 | 交接时按「主路径优先」挑了 8 张 | 评审自己指出 P3/P6/P7/P8 未覆盖 | ✅ 已补(`_gate_shots/p3-1440.png` … `p8-1440.png` 已存在) |
## 九、收口清单(对照 `runbook` §七 逐条)
| 检查项 | 结论 |
|---|---|
| 声明制走完(开工 / 每子步 / 每处偏离) | ✅ |
| 供给核对做过(三处在位、选定套与记录一致) | ✅ `DESIGN.md` §〇 |
| `DESIGN.md` 含十二字段 + 三层令牌 + 组件规格 + 字阶定值表 + 高度层级 + 布局脚手架 + 浮层单出口 | ✅ |
| 骨架未漂(与②段逐页逐位对得上) | ✅ 机检 PASS + 双向变异报红 |
| 分档已兑现、档位未被本段改动 | ✅ `DESIGN.md` §1.2 |
| 页型已判;工具型三零 + §5.5 五条逐条过完 | ✅ 自检机核 |
| Gate-1 自检项结果写在 `DESIGN.md` 末尾,无一项不过 | ✅ |
| 原型单文件自包含、双击可开 | ✅ 无外链、无 `unpkg`、无外部 jsx |
| 状态穷举六项逐条有结论 | ✅ §五 |
| 每个按钮每个跳转真点过(含四态) | ✅ 自检 71 个 ID × 22 场景;⚠️ 通道换成自检而非 `browser-harness`(D1) |
| `3c-GPT会诊.md` 含提问原文 / 回答原文 / 四列处置表,未取到已明示 | ✅ ⚠️ 通道为独立评审执行者(D4) |
| D3 收口按三处判据人工过完,阻断项清零 | ⚠️ 15 条中 14 条清零,**B-15 未清零且留痕** |
| D5 终检真渲染,两视口各截一张,无「无法判定」项 | ⚠️ 1440×900 ✅;390×844 实测到 **500×844**(D2) |
| 每个浮层手工数过出口 + Esc / 遮罩 / 焦点锁 / 焦点归还,结论落报告 | ✅ 7 浮层 × 6 项,含触发路径;另修掉「出口计数把取消藏起来」的真缺陷(B-09) |
| 对外截图只用视口帧,长图未作评审输入 | ✅(长图通道本机做不到,已删) |
| 契约里每个数字实测回填,「契约值 / 实测值」并排 | ✅ §六 |
| Gate-2 与 Gate-3 均有书面结论 | ✅ §七 |
| 重大改版:旧版在磁盘上 + 给出新旧差异 | 不适用(本段首次交付,无旧版) |
| 偏离单已附,且无静默偏离 | ✅ §八 共 5 条 |
# 3d · 审查报告(③段界面交互收口)
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/3d-审查报告.md`
> 模板:`SKILL.md` §3d + `references/execution-runbook.md` §5.4/§5.5、§七(固定七节)
> 交付物:`ui/mcn-workbench.html`(原型)+ `ui/DESIGN.md`(规范)+ `ui/3b-实测记录.md`(实测)+ `ui/3c-GPT参考版.md`(外部参考版对照;早期那份 `3c-GPT会诊.md` 保留作历史)
---
## 一、范围
| 项 | 内容 |
|---|---|
| 段与子步 | ③段界面交互 · 3d(D3 收口 + D4 动效 + D5 终检 + Gate-2 / Gate-3) |
| 被审对象 | `ui/mcn-workbench.html`(单文件自包含原型,八页 + 七浮层)+ `ui/DESIGN.md`(设计契约与令牌) |
| 覆盖页 | P1 矩阵总览 / P2 选题雷达 / P3 资产库 / P4 创作台 / P5 发布中心 / P6 账号画像 / P7 复盘台 / P8 记录与对账(**八页全审,无抽样**) |
| 覆盖状态 | 正常 / 加载 / 空 / 出错 / 禁用 / 无权限 —— 逐页 × 逐态 = 48 组合 |
| 不在范围 | ④段(原型说明区与演示引导);②段的板块清单与信息档位(已冻结,本段不动);暗色主题(见 `DESIGN.md` §五 第 2 条) |
| 证据留档 | `_gate_shots/` **23 张视口帧**(全部经 PNG 像素尺寸校验);`ui/_tools/` 三个可复跑脚本 |
**本轮是否跑了脚本**:**跑了**。三条,全部可复跑,命令见 `3b-实测记录.md` §一:
```text
自检(#/selftest 路由,原型自带) → PASS 81 / FAIL 0 @1440×900
变异对照(_tools/mutate_test.py) → 13 / 13 通过
骨架冻结闸门(_tools/check_skeleton.py)→ PASS 八页 37 个板块与②段逐页逐位一致
```
> 🔴 **2026-10-08 复核(用户新口径落地后重跑)** —— 上面这一段的三个数和下面几处数值**已作废**,以本块为准:
>
> ```text
> 自检(#/selftest 路由,原型自带) → PASS 82 / FAIL 0 @1440×900 (判据多了一条「滚动只由主区承担」)
> 变异对照(_tools/mutate_test.py) → 14 / 14 通过 (新增 M14;M9 的注入点重指)
> 骨架冻结闸门(_tools/check_skeleton.py)→ PASS 八页 39 个板块与②段逐页逐位一致
> ```
>
> 三处数值随之改动,逐条列明 **旧值 → 新值**,⛔ 不是悄悄换掉:
>
> | 处 | 旧值(作废) | 新值 | 为什么会变 |
> |---|---|---|---|
> | 本文 §六「一屏可容纳记录行数」 | 10 行 @1440×900(首行顶 214px) | **8 行 @1440×900(首行顶 332px)** | 旧值是**假数**:量之前只复位了 `window`,实际被滚的是 `<body>`(`body.scrollTop 435`)。同时 P1 的功能入口卡按用户口径从统计条下面挪到数据下面,首行顶也跟着变 |
> | 本文 §三 B-15「≤767px 宽时一屏装不满 6 行」+ §八 结论 | 边界 **768px**;641/640 实测 5 行、500×844 实测 4 行 | 边界 **901px**;900 实测 3 行、768 实测 2 行、641 实测 1 行、640 实测 3 行、500×844 实测 0 行 | 同上一行:旧边界建立在假数上。真边界=两栏带 `.band` 的收线(`max-width:900px`)。**这不叫「放宽判据」,是把假绿修成真红** |
> | 本文 §六「横向溢出」视口清单 | 1440 / 1280 / 1024 / 768 / 641 / 640 / 500 | +1000 / 960 / 920 / 901(全部 0) | 这一轮为定位边界补测了四个视口 |
>
> 另新增两条真缺陷(详见 `3b-实测记录.md` §六 第 16、17 条、`DESIGN.md` §五 第 10 条):
> ① **整页「滚不动」**——1440×900 下 P1 有 1543px 内容,只有前 900px 可达(异常值提示 / 本月表现最好 / 全局检索三块永远看不到),根因是外壳只抄了 `overflow:hidden` 而没约束高度链;已修 + 配判据与变异 M14。
> ② **自检在窄视口量出的密度是假数**(假绿),根因是滚动复位只盯着 `window`;已修(三个容器逐个核)+ M9 重指。
>
> 用户本轮的口径(「左侧导航分大功能板块,每个板块一个主页面」+「功能入口还是卡片的形式,并排放到数据下面」)已落地,落点见 `DESIGN.md` §1① ⑤ 与 §七 修订记录。
>
> 🔴 **2026-10-08 第二轮(导航收一层 + 照抄参考版左右布局)再复核** —— 数字又变了,同样逐条列明:
> ```text
> 自检 → PASS 83 / FAIL 0 @1440×900(多出的那条=「侧栏只有一层」与「八页一次点击可达」两条新判据)
> 变异对照 → 14 / 14 通过
> 骨架冻结 → PASS 八页 39 个板块
> ```
> | 处 | 旧值(作废) | 新值 | 为什么 |
> |---|---|---|---|
> | §八 结论「侧栏 8 项」 | 侧栏八个二级页项 | **侧栏只有一层=四个板块项**;P3/P5/P7/P8 改由主页面上的「功能入口」卡接住 | 用户口径「只有大板块的导航 只有一层」 |
> | §六「一屏可容纳记录行数」 | 8 行 @1440×900(首行顶 332px) | **6 行 @1440×900(首行顶 440px)** | 功能入口卡按用户口径从「数据下面」挪到「数据统计下面」,多占约 100px;P2 也由 7 行变 6 行 |
> | §三 B-15 边界 | 901px | **仍是 901px**(901/920/960/1000/1024/1280/1440 全绿;900 起 P1 掉到 2 行) | 靠三处收高把密度换回来:卡内衬 16→12/16、≤1000px 隐卡片描述、≤1024 顶栏内衬 16→8 |
> | 八页形态 | 只有 P1/P3/P5/P6/P7 有左右两栏 | **八页都有**(P2/P4/P8 补上;P7 改成「左上下文|右动作」;宽比统一 3:2) | 用户口径「哪里左右布局的功能照着抄」 |
> 🔴 **2026-10-08 第三轮(导航改 tiaoyue 图标栏 + 八页统一 P1 页壳 + 主列表表格化)再复核** —— 数字又变了,同样逐条列明,⛔ 不是悄悄换掉:
> ```text
> 自检 → PASS 83 / FAIL 0 @1440×900
> 变异对照 → 14 / 14 通过(M2 / M8 的注入点本轮重指,都是「形态改了导致注入点失效」的假对照)
> 骨架冻结 → PASS 八页 39 个板块
> 命名一致性 → 通过 2060 | 失败 0 | 提示 25
> ```
> | 处 | 旧值(作废) | 新值 | 为什么 |
> |---|---|---|---|
> | §八 结论「侧栏」 | 侧栏只有一层=四个板块项(带文字) | **侧栏一层八项,照 tiaoyue `app-sidebar` 做成 64px 图标栏**(`nav-item`/`nav-icon`/`nav-tip`,悬停向右浮出名字;≤640 转带名字的横滚标签条) | 用户口径「左侧导航参考 tiaoyue 的导航」 |
> | §六「一屏可容纳记录行数」 | 6 行 @1440×900(首行顶 440px、行距 67px) | **6 行 @1440×900(首行顶 708px、行距 31px)** | P1 两块由并排改成**满宽表格顺排**(用户口径「照着抄」);行高从 67px 压到 31px 才守住 6 行 |
> | §六「页内行高齐」 | 67–68px,差 1px | **31–31px,差 0px** | 同上 |
> | §六「实际在用字号档数」 | 5 档(12/14/16/18/24) | **6 档(12/14/16/18/20/24,相邻差 2/2/2/2/4)** | 统计条把 `--fs-20` 带进 P1 |
> | §三 B-15 边界 | 901px | **768px**(≥768 全绿;640 起 P1 掉到 5 行、500×844 掉到 −1 行) | 侧栏 240px → 64px,主区宽了 176px。**⛔ 不是判据放宽**:判据原文一字未改,`needRows=6` 写死,两个窄视口的 FAIL 原样留在自检输出里 |
> | 八页形态 | P1 两块并排;主列表为行式列表 | **P1 两块满宽顺排;八页主列表全部满宽表格**(编辑型板块保持原形态) | 用户口径「每个板块的首页 样式参考 MCN工作台首页」 |
> | 每页页壳 | 只有 P1/P2/P4/P6 有统计条与功能入口卡 | **八页统一**(页头 → 统计条 → 功能入口卡 → 满宽表格主数据块 → 一处两栏 → 尾块) | 同上 |
>
> 本轮改动中被自检当场抓住的一处回归:P3-03「入库」被搬进表格行尾后,P3 场景里那条行不在当前分区 ⇒ 判「声明了但页面上没有」。**已把动作搬回「单条详情」**(门禁说明本来长在那里),并记进 `3b-实测记录.md` §六 第 21 条。
>
> ⚠️ 与前两轮不同:本轮的旧值**已直接在同文件内同步改掉**(§三 B-15、§六 6.1/6.2/6.3、§八 三处数字),⛔ 不再让同一份报告里新旧两个数并存 —— 上两轮那样做,读的人得自己在两个块之间对账,正是「同一事实两处打架」。下表保留旧值只为留改动痕迹。
> 🔴 **2026-10-08 第四轮(顶栏清杂项)再复核** —— 数字又变了,逐条列明:
> ```text
> 自检 → PASS 83 / FAIL 0 @1440×900(判据条数不变,被驱动的对象少了 3 个)
> 变异对照 → 14 / 14 通过
> 骨架冻结 → PASS 八页 39 个板块
> 命名一致性 → 通过 2060 | 失败 0 | 提示 25
> ```
> | 处 | 旧值(作废) | 新值 | 为什么 |
> |---|---|---|---|
> | 交互 ID 数 | 79 个(真驱动 75 个) | **76 个(真驱动 72 个)** | 撤销 `G-07`/`G-09`/`G-11`(顶栏那三件) |
> | `data-act` 出现次数 | 750 次 | **638 次** | 同上(下拉的实例也一起走了) |
> | §六 顶栏高度 | 69px(901–1000 段 93px,折两行) | **49px,任何宽度都不折行** | 顶栏只剩「产品名 + 随手记」,内衬 16→8 |
> | §六 P1 首行顶 | 708px | **688px** | 顶栏省下的 20px 直接还给首屏 |
> | §六 P2 一行 | 6 行(482px、行距 67px) | **14 行(462px、行距 31px)** | ⚠️ 这是**上一轮就改了形态、但数字没跟着改**的旧账:P2 列表第三轮已表格化 |
> | §三 B-15 的影响面 | P1 与 P2 在 500×844 都不达标 | **只有 P1 不达标**(P2 任何视口 ≥8 行) | 同上 |
>
> 逐样的来源定位(哪一项来自哪份文件、为什么判删)见 **§十**。
> 🔴 **2026-10-08 第五轮(组件口径统一 + 新判据)再复核** —— 这一轮的性质与前四轮不同:**判据本身多了一条**。
> ```text
> 自检 → PASS 84 / FAIL 0 @1440×900(83 → 84:新增「组件口径」一条)
> 变异对照 → 15 / 15 通过(14 → 15:新增 M15,专为第 84 条判据配的对照)
> 骨架冻结 → PASS 八页 39 个板块
> 命名一致性 → 通过 2060 | 失败 0 | 提示 25
> ```
> | 处 | 旧值(作废) | 新值 | 为什么 |
> |---|---|---|---|
> | 自检条数 | 83 | **84** | 新增「组件口径:八页都没有用内联 style 表达选中态或覆盖字号」 |
> | 变异条数 | 14 | **15** | 新增 M15(把 P2 分组改回内联 `border-color` ⇒ 必须报红) |
> | 选中态画法 | **三套**(侧栏浅紫底 / 分段控件内联描边变黑 五处 / 表格当前行内联 accent 文字 四处) | **一套**:`.is-on` / `.is-active` | 用户口径「参考 P1 各组件样式,优化各页组件样式」 |
> | 字号覆盖 | 内联 `font-size` 两处(P7 三个数、P4 的「/7」) | **0 处**,一律走 `--fs-*` 档 | 同上 |
> | 表格档 | `.ds-table` 宽松档还用在 P8 对账核对区 | 全站只剩 `.tbl-dense`(满宽主数据)与 `.tbl-side`(栏内)两种 | 同上 |
> | 行级动作 | P2/P4 的列表行内用 32px 的 `.btn btn-sm` | 统一 **22px 的 `.btn-micro`** | 同上(也顺带把行高压回紧凑档) |
>
> ⚠️ 新增第 84 条判据时**同步做了变异对照**(M15)—— 一条恒绿的判据等于没有判据,这是本项目已经踩过 4 次的坑(M7/M10/M2/M8 全是「形态改了、注入点没跟着改」造成的假绿)。
> 🔴 **2026-10-08 第六轮(学参照物的组件细节 + 第 5 个门禁)再复核**
> ```text
> 自检 → PASS 84 / FAIL 0 @1440×900(条数与 ID 数都不变:84 项 / 76 个 ID / 72 个真驱动)
> 变异对照 → 15 / 15 通过
> 骨架冻结 → PASS 八页 39 个板块
> 命名一致性 → 通过 2060 | 失败 0 | 提示 25
> 语法门禁(新) → 全过(<script> 段 node --check + 模板注释里的反引号 0 处)
> ```
> | 处 | 旧值(作废) | 新值 | 为什么 |
> |---|---|---|---|
> | §六 P1 首行顶 | 688px | **697px** | 功能入口卡补了 22px 图标(图标与标题同行,卡高只涨 9px) |
> | §六 P2 首行顶 / 容量 | 471px / 14 行 | **471px / 13 行** | 同上(P2 的功能入口卡同样长高了) |
> | §三 B-15 的影响面 | ≤640px 的三个视口(641/640/500) | **只剩 500×844 一个** | `≤640px` 给功能入口卡补了紧凑档,640 转绿 |
> | 门禁条数 | 4 个脚本 | **5 个** | 新增 `_tools/check_js.py`(语法 + 模板反引号) |
> | 图标规格 | 侧栏 20px / `stroke-width 1.7`;**卡片无图标** | 侧栏 20px、卡片 22px、**`stroke-width 2`** | 照参照物 `svgIcon()` 学 |
> | §四 S-12 的另一半 | — | 保留 | — |
>
> ⚠️ 本轮出过一次**窄屏回归**(640 由 5 行掉到 3 行),已收回并单记在 `3b-实测记录.md` §六 第 26 条。逐件量到的参照物组件原值(含**刻意不学**的 3 条与理由)见 **§十一**。
**结构核对表的每一个数,都来自上面这三条脚本的输出或 DOM 取值,⛔ 无一处是目测截图。**
---
## 二、挡位
**标准档**(本段未升未降)。理由:这是新产品的第一版原型,不是发版前的精修;`SKILL.md` §供给·方法主线 给的默认主线就是 `oil-ui-pro`,挡位按 runbook 默认的**标准**执行 —— 三条门(Gate-1 / 2 / 3)全过,但不上「多方向比选」与「严格档」的额外轮次。
---
## 三、阻断项表
口径:`阻断` = 不清零就不能交。**本轮共 15 条,14 条已清零,1 条未清零并留档。**
| # | 阻断项 | 观察(现象) | 根因 | 处置 | 现状 |
|---|---|---|---|---|---|
| B-01 | 整份设计系统在屏幕上失效 | 原型打开后令牌全不生效 | 样式表顶部注释里 `--t-*/--raw-*` 的 `*/` 提前闭掉注释,吞掉整个 `:root` 令牌块 | 改写注释文字 | ✅ 清零 |
| B-02 | 全表行分隔线一直没画出来 | 列表行之间没有任何分隔线 | `.list-row:first-child{border-top:0}` —— 每行都包在 `<li>` 里,于是每行都是自己 `<li>` 的 first-child | 改为 `li:first-child > .list-row` | ✅ 清零(+变异 M10) |
| B-03 | 判据除数为 0 时恒 PASS | 上面那条真缺陷没有任何门禁报它 | `gap>=2*bw` 在 `bw=0` 时恒成立、比值算成 `Infinity` | 除数为 0 一律判红 | ✅ 清零 |
| B-04 | 浮层不浮 | 浮层渲染在文档流末尾,得滚到页尾才看得见 | `#layer-root` 与 `.layer` 都没有定位样式 | 遮罩 `fixed inset:0` + 层本体 `fixed` 居中 | ✅ 清零 |
| B-05 | 行高随文字长短乱跳 | 同一张表量出 66 / 82 / 100px 三种行高 | 状态标放在操作列把 `auto` 列撑宽,只有那一行折行 | 状态标移到名称旁 + 行内每段不许换行 + 新增「行高齐」判据 | ✅ 清零(+变异 M7) |
| B-06 | 自检在窄视口给出假 PASS | 报「一屏装得下 10 行」,实际 5 行 | 驱动几百次点击后浏览器自动滚动,`rect.top` 变负,容量公式虚高 | 加「量尺寸前页面在滚动零点」守卫 | ✅ 清零(+变异 M9) |
| B-07 | 手机导航「既不是一条、也没滚动」 | 导航条占 161px 高,4 个分组竖着堆 | 导航分组挂在 `<nav id="nav">` 里,而 `#nav` **一条样式都没有** ⇒ 仍是块级容器 | 补 `#nav{display:flex;flex-flow:row nowrap}` + 整条链 `flex:0 0 auto` | ✅ 清零(161px → 53px) |
| B-08 | 顶栏标签折行 | 「演示 · 账号」折成两行,顶栏被顶到 70px | `.topbar-label` 没有 `white-space:nowrap` | 补 nowrap | ✅ 清零(→ 69px) |
| B-09 | 两个二次确认浮层其实有两个可见关闭控件,判据却报「出口 = 1」 | 核销层与发布层各有一颗「取消」 | 判据只数 `.layer-close` 这个类名,把可见的「取消」从眼皮底下藏掉了;核销层的「取消」还复用了 `X-close` | 判据改成「中性出口只认 `X-close`」+「决策型关闭单列报数」;核销取消拆出 `CHECKOUT-CANCEL` | ✅ 清零(+变异 M13) |
| B-10 | 截图尺寸全部比标称大 16×95 | 「1440×900」的帧实际是 1456×995,同一份报告里 dump-dom 又按 640 说话 | Chrome 两条通道对 `--window-size` 的解释不同(截图=视口,dump-dom=视口+16/95),而脚本对两者用了同一个偏移量 | 按模式分开算 + 每次截图后从 PNG 的 IHDR 读真实像素比对目标视口 | ✅ 清零(23 张帧全部 ✓) |
| B-11 | 制作黑话写在界面上 | 状态面板上贴着「这里是 X 的 empty 态。」 | 给做原型的人看的说明被写进了界面,而 `STATE_COPY` 已经铺好用户向文案 | 删掉那句话;按钮改「回到正常内容」 | ✅ 清零 |
| B-12 | 主列表可读性 | 「今日该发:待发:3 分钟快手菜」冒号连用,独立评审读成错字 | 示意数据 `today` 字段的值里自带冒号,被拼进「今日该发:…」 | 5 行数据改为空格分隔 | ✅ 清零 |
| B-13 | 窄屏看不出当前在哪一页 | 横滚标签栏里当前项滚在视野之外 | 没有把当前项带进视野的逻辑 | 只调 `.sidebar` 自己的 `scrollLeft`(⛔ 不碰 `window`,否则误触 B-06 的守卫) | ✅ 清零 |
| B-14 | `--full`(整页长图)静默失效 | 带该参数产出的还是视口帧 | 无头 CLI 这条通道只能截视口 | 删掉该参数与 `_full/` 目录,不留撒谎的开关 | ✅ 清零 |
| **B-15** | **500×844 时一屏装不满 6 行(只有这一个视口;640 起已转绿)** | 640×900 P1 实测 **6 行 ✅**(本轮由 5 行转绿);500×844 P1 实测 **−1 行**(P2 8 行 ✅) | 页面外壳吃掉首屏:≤640px 顶栏折成两行(57px)、侧栏转成横滚标签条。**行本身没变肥** —— 行高 31px、行高差 0px、块内分隔 1px 在任何视口都 PASS | 未在本段修 | ❌ **未清零,留档待裁定** |
### B-15 为什么没在本段修,以及留给用户的两条路
判据原文(`layouts-tooling.md` §1)是「一屏可见行数 **≥ 6(900px 高时)**」,**不带宽度条件**。**2026-10-08 第六轮实测出来的边界是 640px 宽**:≥640px 时侧栏 64px 图标栏 + 满宽表格,容量 6–7 行;**只有 500×844 掉到 −1 行**(首行顶 845px 已越过 844px 的折叠线)。⚠️ **P2 不在这条里**:它的「对标内容列表」已改成满宽表格(行距 31px),任何视口都有 8 行以上。三条路,**两件事必须挑一件**:
| 选择 | 代价 |
|---|---|
| A. 把支持宽度下限写成 **≥640px**,手机形态只承诺「可用」(布局折行、零横向溢出、全路径可点通),不承诺 6 行密度 | 要在契约里**明文加一条本段自定的宽度条件**;依据是 `1a §七` 已明确第一版不做移动端 App |
| B. 压掉每行的次级信息,把行高从 31px 再往下压 | 31px 已经是「一行一个短值 + 22px 微按钮」的底;再压只能删列 —— 那几列是②段定的档位,③段不许改 ⇒ 得回②段改档 |
| C. 动页面外壳(顶栏控件精简、侧栏在窄屏折叠) | 顶栏那几个控件都登记在交互清单里(`G-06`/`G-08`/`G-10`),删或搬家等于改交互清单 |
⛔ 本段**没有**选任何一条就宣布通过:判据一个字没改,`needRows=6` 写死,三个窄视口的 FAIL 原样留在自检输出里。
---
## 四、建议项表
口径:每条要么**修掉**,要么**显式写「已知不修 + 原因」**。⛔ 不接受「基本没问题」。
| # | 建议项 | 结论 |
|---|---|---|
| S-01 | 密度只有同类工具的 40–50%(评审:Linear 行高 32px,本原型 67px) | **已知不修**:判据是「≥6 行 @900px 高」,1440/1280 实测 10 行、1024/768 实测 6 行,达标。再压只有砍次级信息一条路 ⇒ 属②段档位,见 B-15 选择 B |
| S-02 | 处处 24px 圆角大卡,列表本该是「表格行 + 发丝线」 | **部分已修**:列表**行**本来就是无框行 + `border-top` 发丝线(B-02 修的就是它真的画出来);剩的是承载列表那层**面板**仍是圆角卡,改为无框会让 37 个板块散在底纸上失去分层。已知不修 |
| S-03 | 「左标题右说明」分栏里,右侧小字像给评审看的注释 | **已修**:逐条过了一遍板块头右侧的小字 —— 读出「这是在解释口径」的那几条已改写或删除(B-11、P4 输入提示、空引用文案)。剩下的多是②段要求的计数与口径(「5 项 · 按截止时间排」),保留 |
| S-04 | P2 KPI 标签下有下划线,像链接却不可点 | **未能复核**:代码里 `.stat` / `.stat-label` 都没有 `border-bottom` / `text-decoration`;4 个 KPI 里 2 个是真按钮(`P2-01`/`P2-02`)。⛔ 不做无依据的改动,如实记为未复核 |
| S-05 | 每个分组标题下都压一条通栏线(重复线框) | **不采纳**:`layouts-tooling.md` §1 原文「边框只上不围 —— 行间用 `border-top`」;`visual-review.md` 自己也写「承担风格和结构的线不算问题」。删掉它板块头与内容就分不开 |
| S-06 | 同一状态两种画法(当前导航项,P4 看着是深色实心) | **不采纳(评审判读)**:侧栏当前项八页同一套样式(整块浅紫底 + 字重 600,见 `DESIGN.md` §2.5)。自检逐页核过:8 项导航里 `is-active` 只有一个。评审把侧栏当前项与**步骤条里的当前步**看混了 —— 后者按设计就该更重 |
| S-07 | 侧栏 `账号画像(跑图)` 与 `账号画像` 重复 | **不采纳(评审判读)**:那三个字是「跨组」不是「跑图」;字样直接来自②段 `2b §一` 的一级导航表「(跨组)账号画像」,③段不许改②段定的导航名。由此暴露的「括号夹在词中间不好读」记为已知取舍 |
| S-08 | 导航计数只给了一半(创作台 / 账号画像 无数字) | **已采纳·本段不改**:计数=「这页有几件事等你做」,没数字的两页当前确实没有待办。但「一半有半数无」读起来像掉数据,这条提得对 —— 改动落点在交互清单 `G-05` 的反馈列,本轮不动 |
| S-09 | 窄屏正文被省略号硬截断 | **已知不修**:这是上一轮为「行高齐」付的代价 —— 行内每段不许换行 + 省略号,是行高能恒为 67px 的唯一办法(放开换行行高跳到 66/82/100px,变异 M7 盯着)。完整原文挂在行上的 `title` 里 |
| S-10 | 每行右侧指标左边缘没对齐成列 | **已知不修**:右栏是「标签 + 值」两行、整块右对齐到块右内衬;改成逐字对齐会把长短差异大的值拉成锯齿 |
| S-11 | 浮层右上「×」套着淡紫圆圈,像常驻焦点环 | **不采纳**:那是 `:focus-visible` 焦点环(`--accent`),出现是因为浮层打开后焦点按设计落在层内第一个可聚焦件上,而它正好是 ×。⛔ 不能改成 hover 才出现 —— 改掉就把键盘用户的定位点弄丢了。已记为「截图里带焦点环」的已知现象 |
| S-12 | 顶栏演示控件、`假设 2 项`、页面编号 `P1…P8` 可以删 | **改判(2026-10-08 第四轮):顶栏那三样已删** | 上一轮判「不采纳」的理由是「删了评审就看不到六态」——本轮查清:**六态由路由驱动(`#/p/p4/empty`),不依赖顶栏下拉**,六态帧与自检 48 组都不受影响(详 §十 第 4 条)。⇒ 顶栏演示控件(`G-07`/`G-09`)+ 假设入口 + 收起侧栏一并撤掉。⚠️ 页面编号 `P1…P8` 保留:它是页头标题的一部分(②段页面全名),不是控件 |
| S-13 | 「空面板」(P2 评论区洞察、P4 资产引用区、P5 检查结果)稀释首屏 | **已知不修**:三块都是②段冻结的板块,⛔ 不许折叠或删除。看着空是因为示意数据只填了主路径;每块的空态文案都在(`STATE_COPY` 逐页不同) |
| S-14 | 动作甩到最右边、离对象半屏远 | **不采纳**:操作列右对齐成列是刻意的(`layouts-tooling.md` §5.5 要求同类动作在同一轴上对齐);两栏也不是等宽(`minmax(0,400px) minmax(0,1fr)`) |
| S-15 | P1 两栏平权、没有主次 | **不采纳**:并排是密度判据逼出来的,有反事实实测 —— 落回单列时账号矩阵首行顶 530px、一屏只装得下 5 行(<6)。见 B-15 选择 A |
| S-16 | 记不住 —— 建议把 P1「账号矩阵列表」做成真正的矩阵 + 异常分布 | **已知不修·往上提**:块名与位置受②段冻结,「矩阵视图」是**信息呈现**变更,超出③段权限。**本轮最值得往上提的一条**,交主会话转用户 |
| S-17 | 评审看不到的:点击/悬停/焦点行为、动效、检索结果、遮罩键盘可达性、另外四页 | **已补**:这些正是 3b 自检覆盖的 —— 71 个 ID 逐个真驱动(0 死控件)、六态 × 八页 48 组合、7 浮层 × 6 项。P3/P6/P7/P8 截图已补拍,本轮交接已改为八页全给 |
---
## 五、状态覆盖核对表(六项逐页)
判据源:`SKILL.md` 铁律 2 的六态清单。⚠️ 逐项**数值**判据出自供给可选档的 `craft/state-coverage.md`,**本轮未动用可选档 ⇒ 该项无供给来源**(`DESIGN.md` §五 第 1 条),故只核「有没有、长什么样」,不编阈值。
机检结论:**六态 × 八页 = 48 个组合,全部渲染出内容**(自检第 10 行)。
| 页 | loading | empty | error | success | disabled | 无权限 |
|---|---|---|---|---|---|---|
| P1 矩阵总览 | ✅ 骨架行 +「正在取矩阵数据」 | ✅「还没接入账号」+ 去处按钮(→P6) | ✅ 显时间戳 + 重试 | ✅ 默认态 | ✅ 无待办时待办区禁用并说明 | ✅ 非管理员看利润列的遮罩说明 |
| P2 选题雷达 | ✅「正在拉对标更新」 | ✅「监控名单是空的」+ 录对标号 | ✅ 拉取失败(退路=手工录入) | ✅ 默认态 | ✅ 未选账号时「转入创作」禁用 | — 不适用(本页对所有角色开放) |
| P3 资产库 | ✅「条目加载中」 | ✅「这个分区还没有条目」+ 去处(→P2) | ✅ 读取失败(重试) | ✅ 默认态 | ✅ 无出处的条目「入库」禁用(门禁) | — 不适用 |
| P4 创作台 | ✅「正在跑这一步」(带已跑秒数) | ✅「这一步还没有产出」 | ✅ 本步失败(保留已产出 + 重试该步) | ✅ 默认态 | ✅ 文案与封面缺一,进检查态禁用 | — 不适用 |
| P5 发布中心 | ✅「检查中」 | ✅「还没有可发布的版本」+ 回 P4 | ✅ 检查自身失败 ⇒ **按不过处理**(fail-closed) | ✅ 无硬拦、可发 | ✅ 有硬拦项时「确认发布」禁用 | ✅ 未授权账号的版本标「无发布权限」并禁用该版 |
| P6 账号画像 | ✅「画像加载中」 | ✅「还没有画像」+ 建画像 | ✅ 保存失败(保留编辑内容) | ✅ 保存成功提示 | ✅ 只读角色时字段禁用 | ✅ 非本人负责账号:可看不可改 |
| P7 复盘台 | ✅「正在读这条的数据」 | ✅「还没有能复盘的内容」 | ✅ 数据读不到 ⇒ 转手工录入 | ✅ 回写成功提示 | ✅ 未写归因时「回写」禁用 | — 不适用 |
| P8 记录与对账 | ✅「记录加载中」 | ✅「还没有发布记录」 | ✅ 读取失败(重试) | ✅ 核销成功 | ✅ 未选中记录时「核销」禁用 | ✅ 利润列对非管理员隐藏(列级遮罩) |
> 口径:`disabled` 与 `无权限` 是两件事 —— 前者「当前条件不满足」(自己能解开),后者「角色不允许」(自己解不开)。界面文案分开写,⛔ 不拿「不可用」一句话糊过去。
> 留档截图:`p1-empty-1440.png`、`p4-noperm-1440.png`、`p5-error-1440.png`;其余 45 组由自检逐组渲染核过。
---
## 六、结构核对表(契约值 / 实测值 并排,数字抄自脚本输出)
### 6.1 契约里写了数字的项
| 项 | 契约值 | 实测值 | 取法 |
|---|---|---|---|
| 强调色填充面积占比 | ≤5% | **0.52%**(八页最高:创作台,1 个填充块) | DOM:逐个元素比 `backgroundColor` ≡ `--accent`,与视口求交累加 ÷ 视口面积 |
| `--warn` 对 `--surface` 对比度 | ≥4.5:1 | **5.93:1** | 真实像素计算(WCAG 相对亮度) |
| `--accent-text` 对 `--surface` 对比度 | ≥4.5:1 | **4.76:1** | 同上 |
| `--ink-faint` 对 `--surface` 对比度 | ≥3:1(仅非正文) | **3.55:1** | 同上 |
| 一屏可容纳记录行数(P1 账号矩阵) | ≥6 @900px 高 | **6 行** @1440×900(首行顶 688px、行距 31px) | DOM:首屏可用高度 ÷ 行距。⚠️ 是「装得下几行」不是「画了几行」—— 示意数据 5 条,实际永远 ≤5 行(数据用尽,非被截断) |
| 一屏可容纳记录行数(P2 对标列表) | ≥6 @900px 高 | **14 行** @1440×900(首行顶 462px、行距 31px) | 同上。该块已由行式列表改成满宽表格 ⇒ 容量从 6 行跳到 14 行,任何视口都达标 |
| 页内行高齐 | ≤2px 差(本段追加判据) | **31–31px,差 0px** | DOM:逐行 `getBoundingClientRect().height` |
| 视觉层间距 / 块内相邻行分隔 | ≥2 | **32px / 1px = 32**(4 个视觉层) | DOM:页面级容器归并视觉层后相减;分隔取各行 `borderTopWidth` 最大值(表格行的线画在 `td` 上,不是 `.list-row` 自己) |
| 实际在用字号档数(P1) | 4–6 | **6 档**:12 / 14 / 16 / 18 / 20 / 24px,相邻差 2/2/2/2/4 | DOM:叶子节点 `fontSize` 去重 |
| 块间距 / 块内间距 | ≥2 | **32 / 8–16 ⇒ 2.0–4.0** | 令牌登记值 + DOM 复核(`gap` 全部落在登记刻度内,9 个刻度) |
| 横向溢出 | 0 | **0**(1440 / 1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / 768 / 640 / 500,八页逐页亦 0) | DOM:`scrollWidth − clientWidth` |
| 浮层中性关闭出口 | 恰好 1 | **7 / 7 个浮层均为 1**(另有决策型关闭 0–1 个,已单列报数) | DOM:可见的 `[data-act="X-close"]` 计数 |
| 同屏主档按钮 | ≤1 | **逐页 1 个**(P1 无主档:本页只用弱档,按钮高度集合 {32px}) | DOM:逐页统计实底按钮 |
| 顶栏高度 | 未写死(只看有没有折行) | **49px**(单行;只放「产品名 + 随手记」两项,任何宽度都不折行) | DOM:`.topbar` 高度 + 诊断行 |
### 6.2 契约未写数字、本轮补登记的证据(⛔ 不留「无法判定」)
| 项 | 实测值 | 说明 |
|---|---|---|
| P1 各块落位(顶 / 高) | 今日待处理 @324+249 · 账号矩阵列表 @605+249 · 异常值提示 @886+201 · 全局检索与随手记 @1119+222 | 前两块**满宽顺排**(视口高 900);异常值提示与本月表现最好的一条在同一个两栏块里 |
| P2 各块落位(顶 / 高) | 对标监控概览 @143+121 · 对标内容列表 @380+249 · 评论区洞察 @661+316 · 灵感速记 @1009+99 | — |
| 反事实:P1 前两块改成并排 | 第一轮记的是「落回单列⇒5 行」;本轮反过来:**顺排 + 行高 31px ⇒ 6 行**(首行顶 688px) | 说明「满宽顺排 vs 密度」这一对矛盾已由行高解决,⛔ 不再需要靠并排换行数 |
| 控制台报错 | **0 条** | 自检全程监听 `console.error` |
| 量尺寸时的滚动零点 | 四个容器全为 0(`window` / `html` / `body` / `.view`,P1 / P2 两处均核) | rect 取到的是相对视口的真值(第一轮只核了 `window`,是假绿 —— 见 `3b` §六 第 17 条) |
### 6.3 Gate-3 八项肉眼过(真实渲染,非只看代码)
| # | 项 | 结论 |
|---|---|---|
| 1 | 裁切 | ✅ 无一页出现被裁掉的内容(23 张视口帧逐张看过) |
| 2 | 重叠 | ✅ 无元素互相压盖 |
| 3 | 失真 | ✅ 无变形拉伸;正文命中系统黑体栈、标题命中展示体栈,无回退异常 |
| 4 | 失效控件 | ✅ 0 个死控件(72 个 ID 在 24 个场景里逐个真驱动过) |
| 5 | 缺状态 | ✅ 48 组(六态 × 八页)全部渲染出内容 |
| 6 | 响应式破损 | ✅ 十三个视口横向溢出全 0;≤640px 侧栏转横滚标签条、两栏分栏落回单列(B-15 的密度缺口另计) |
| 7 | 控制台报错 | ✅ **0 条** |
| 8 | 字体回退异常 | ✅ 两条字体栈(正文黑体 / 标题展示体)都命中系统字体;`@font-face` 数量 0 |
---
## 七、Gate 结论
### Gate-2(原型门)
**通过。** 依据:`DESIGN.md` 的十二字段契约与令牌表落盘(Gate-1 十项全过,见 `DESIGN.md` §四);八页 39 个板块与②段 `2b` 逐页逐位一致(骨架闸门正向 PASS + 反向变异两条都报红);六态 × 八页 48 组合全渲染;72 个 ID 逐个真驱动、0 死控件;对 §二 的令牌与 §二 表 2.4 交互清单做双向差集,表外可点元素为 **0**。命名一致性闸门 **通过 2060 | 失败 0 | 提示 25**。
### Gate-3(交付门)
**桌面 / 平板档通过;手机档不通过,且已逐条留痕 —— 总判:有条件通过。**
- **通过的部分**:契约视口 1440×900 自检 **PASS 84 / FAIL 0**;1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / 768 亦为 **PASS 84 / FAIL 0**;§六 里契约写了数字的项全部实测回填、无一项越界;Gate-3 八项肉眼检查全过;控制台报错 0。
- **不通过的部分**:**B-15** —— 500×844 一屏装不满 6 行(实测 −1 行)。⚠️ 本轮 **640×900 已转绿**(6 行),不达标的视口由一个缩到**一个**。**自检在这一个视口上就是红的(PASS 83/1),⛔ 没有靠改判据把它变绿。**
- **条件**:B-15 的三条路(见 §三)得由用户挑一条;挑之前这一项挂在账上。
- **另需明示**:3c 那次独立评审**不是** SKILL.md §3c 要求的「外部 GPT 会诊」(本会话没有对外模型通道,见 `3c-GPT会诊.md` §〇)。**未取得外部审查 ≠ 已通过。**
---
## 八、偏离单(本段收尾必附)
| # | 原要求(文件:小节) | 实际做法 | 原因 | 影响 | 处置 |
|---|---|---|---|---|---|
| D1 | 3b 实测走 `browser-harness`(`SKILL.md` §3b) | 原型自带自检 83 项 + 变异对照 14/14 + 无头 Chrome 视口帧 + 逐条 DOM 取值 | 该通道绑定实时浏览器入口,本会话驱动不了 | 证据链全部可复跑;⛔ 但**没有「真人真点」这一层** | 持续偏离,待裁定是否补一次人工走查 |
| D2 | D5 终检要 `1440x900` 与 `390x844` 两帧(`runbook` §5.3、§七) | 实测到 **500×844** 为止 | Chrome 窗口宽下限 516 ⇒ 视口最小 500;要 390 得走 CDP `setDeviceMetricsOverride` | 手机帧比要求宽 110px | 持续偏离;⛔ 报告一律写「500×844」 |
| D3 | 对外只留视口帧,长图仅自检(`runbook` §七) | 未产出长图 | `--full` 在本机通道做不到,只能截视口 | 无 | ✅ 已修(参数与目录一并删掉) |
| D4 | 3c 要「外部 GPT 会诊」(`SKILL.md` §3c) | 隔离上下文的独立评审执行者 | 无对外模型通道 | 与「异厂商外部审查」不是同一条通道 | 持续偏离,已明示 |
| D5 | 逐页截图应八页齐备 | 首次交接只给了评审 4 页 + 2 个状态 + 2 个浮层 | 交接时按「主路径优先」挑了 8 张 | 评审自己指出 P3/P6/P7/P8 未覆盖 | ✅ 已补(`_gate_shots/p3-1440.png` … `p8-1440.png` 已存在) |
## 九、收口清单(对照 `runbook` §七 逐条)
| 检查项 | 结论 |
|---|---|
| 声明制走完(开工 / 每子步 / 每处偏离) | ✅ |
| 供给核对做过(三处在位、选定套与记录一致) | ✅ `DESIGN.md` §〇 |
| `DESIGN.md` 含十二字段 + 三层令牌 + 组件规格 + 字阶定值表 + 高度层级 + 布局脚手架 + 浮层单出口 | ✅ |
| 骨架未漂(与②段逐页逐位对得上) | ✅ 机检 PASS + 双向变异报红 |
| 分档已兑现、档位未被本段改动 | ✅ `DESIGN.md` §1.2 |
| 页型已判;工具型三零 + §5.5 五条逐条过完 | 🔴 **2026-10-08 更正:本条原先记的是「✅ 自检机核」,那是假的 —— 自检 84 项里 §5.5 五条零覆盖**(grep 原型:`标题区`0 /`从属`0 /`注脚`0 /`主次`0 /`主角`0 /`假装分组`0)。实情:**工具型三零**(第 12 条)与**无假控件**(第 6/7/8 条)确有覆盖;**§5.5.1/§5.5.3/§5.5.4 三条零覆盖;§5.5.2「导航默认带标签」被反向违反**(第三轮把导航做成纯图标栏、标签设成 `display:none`)。⇒ 这一格是本次「五道闸门全绿却难看」的开关,归因复盘见 `复盘-为什么第一版做得很差.md`。 |
| Gate-1 自检项结果写在 `DESIGN.md` 末尾,无一项不过 | ✅ |
| 原型单文件自包含、双击可开 | ✅ 无外链、无 `unpkg`、无外部 jsx |
| 状态穷举六项逐条有结论 | ✅ §五 |
| 每个按钮每个跳转真点过(含四态) | ✅ 自检 72 个 ID × 24 场景;⚠️ 通道换成自检而非 `browser-harness`(D1) |
| `3c-GPT会诊.md` 含提问原文 / 回答原文 / 四列处置表,未取到已明示 | ✅ ⚠️ 通道为独立评审执行者(D4) |
| D3 收口按三处判据人工过完,阻断项清零 | ⚠️ 15 条中 14 条清零,**B-15 未清零且留痕**(本轮另修掉 2 条过程中的回归:`3b` §六 第 21、22 条) |
| D5 终检真渲染,两视口各截一张,无「无法判定」项 | ⚠️ 1440×900 ✅;390×844 实测到 **500×844**(D2) |
| 每个浮层手工数过出口 + Esc / 遮罩 / 焦点锁 / 焦点归还,结论落报告 | ✅ 7 浮层 × 6 项,含触发路径;另修掉「出口计数把取消藏起来」的真缺陷(B-09) |
| 对外截图只用视口帧,长图未作评审输入 | ✅(长图通道本机做不到,已删) |
| 契约里每个数字实测回填,「契约值 / 实测值」并排 | ✅ §六 |
| Gate-2 与 Gate-3 均有书面结论 | ✅ §七 |
| 重大改版:旧版在磁盘上 + 给出新旧差异 | 不适用(本段首次交付,无旧版) |
| 偏离单已附,且无静默偏离 | ✅ §八 共 5 条 |
---
## 十、顶栏杂项来源排查(2026-10-08 用户口径「页面顶上弄这么多乱七八糟的东西 是那个技能那个规则引起的 需要详细排查 定位 删除」)
**结论先说**:顶栏原有 **7 项,没有一项是技能规则要求的**。唯一被②段硬要求的是「随手记」,其余六项分别是「本项目参照物笔记的遗留 2 项+我自己造的原型件 3 项+与②段页内板块重复的 1 项」。已删 5 项、改挂 1 项、留 1 项。
下面逐样定位到**文件与行**,⛔ 不是凭印象。
**1、`收起侧栏`(`G-11`)—— 无技能规则,来源是本项目参照物笔记**
- 翻遍 `product-planning` 全包,没有任何一条要求「侧栏可收起」。
- 它的真实来源是**我自己写的那份参照物笔记** `ui/布局排版参考-mcn-work-shop.md`:§一「侧栏只在需要时出现」+ §五 落地清单第 1 条「外壳改顶栏+面包屑+主区,侧栏**按需出现**」。
- 我把它「折中为可收起」,并当成了偏离项留痕 —— 折中本身没错,但它把一件参照物产品的外壳习惯搬进了我们的顶栏。
- 侧栏这时已经是 64px 图标栏,收起一个 64px 的栏几乎没有收益。
**2、面包屑 —— 无技能规则,同上来源,且与页头 h1 重复**
- 唯一提到面包屑的技能原文是 `layouts-tooling.md` §1:「✅ 正解:**< 4 项**改用页头横向导航或面包屑 + 返回,把宽度还给内容。」——它说的是「导航项**少于 4 项**时的替代方案」;我们有 **8 项**,不适用。
- 真实来源同样是 `布局排版参考-mcn-work-shop.md` §一「导航靠面包屑,不靠固定侧栏」。⚠️ 这一条**在我们的场景里是反的**:我们侧栏常驻,面包屑没有承担导航。
- 而且它和页头 `h1`(「P1 矩阵总览」)说的是同一件事 ⇒ 纯重复。
**3、`演示 · 账号` 下拉(`G-07`)—— 无任何来源,我造的原型件**
- ②段 `2b-界面布局.md` 只在「待复核第 5 条」里提过「账号切换」,而那是**假设不成立时的降级方案**(「若第 5 条复核为『不需要』…矩阵列表下移到账号切换」),不是现在的要求。
- 技能包无一条要求顶栏账号切换器。
- ⇒ 它是我为了演示「切账号看上下文」自己加的,登记进交互清单后就留了下来。
**4、`演示 · 状态` 下拉(`G-09`)—— 规则只说「路由 + 演示开关」,路由那条已完整覆盖**
- 规则原文两处,措辞都是并列:
- `stage-delivery/SKILL.md` §3d:「本项目的状态由**路由与演示开关**驱动,不用 `?state=`」
- `execution-runbook.md` §3.4:「原型里的状态由**路由 + 演示开关**驱动,不是 `?state=` URL 参数」
- ⇒ 要守的是「**不用 `?state=`**」和「状态可见」,⛔ 没有一条要求开关**必须做成顶栏可见的下拉**。
- 路由那条已完整覆盖:`#/p/p4/empty` 直接打开任意页的任意态,六态帧(`p1-empty` / `p5-error` / `p4-noperm`)就是这么出的,自检也逐组渲染 48 个组合。
- ⇒ 开关可去。
**5、`全局检索`(`G-10`,顶栏那一颗)—— 与②段 P1 的页内板块重复**
- ②段 `2b` P1 的板块清单第 5 条是「**全局检索与随手记入口**」——它是 **P1 的一个板块**,⛔ 不是全局外壳件。
- ②段 §286 只把**随手记**定为「全局可达」(原文:「随手记出现在任意页面一次点击内(F2 是 P0,不能埋在两层下)」),**没有**给全局检索同样的待遇。
- ⇒ 顶栏那一颗是重复:P1 页内已经有一处(同一 `G-10`,走的是同一个检索浮层)⇒ 删顶栏那颗,ID 与能力都还在。
**6、`假设 2 项`(`G-08`,顶栏那一颗)—— 来源是我自己写的契约,而且是第二处**
- ③段技能没有要求任何「假设入口」。它的来源是本份交付里的 `DESIGN.md` §三,我自己写的兑现方式:「两处各在自己的板块标题同行右侧挂一个「假设」徽章;**顶栏另有**「假设 2 项」入口」。
- ⇒ 徽章才是主兑现(假设在哪就在哪标),顶栏那颗是我额外加的**第二处**。
- 处置选的是**改挂**而不是纯删:入口挂到那两处徽章自己身上(徽章变成可点,`G-08` 仍活着)。这样顶栏干净了,而「复核人 / 时机 / 落点」这份内容一个都没丢,位置还更对。
**7、`随手记`(`G-06`)—— 唯一被②段硬要求的一项,留**
- ②段 `2b` §59:「随手记入口|可点入|判据答「做得成」。⚠️ 但它是 F2 的入口,以**全局可达**的方式出现:任意页面一次点击内能碰到,**不占 P1 的主屏常驻位**」
- ②段 `2b` §286:「**全局可达**:随手记出现在任意页面一次点击内(F2 是 P0,不能埋在两层下)」
- ⇒ 「任意页面」=它必须挂在**全局外壳**上,顶栏正是那个位置。⛔ 这一项不能跟着一起删。
**处置后的顶栏**
- 只剩两项:**左「MCN 短视频整合营销工作台」**(产品名;侧栏品牌位收成 32px 方标后,全名只有这里挂得住)+ **右「随手记」**。
- 内衬一并从 16px 收到 8px ⇒ 实测顶栏 **49px**,且**任何宽度都不折行**(旧值 69px/折行后 93px)。
- 连带清掉的代码:`.crumbs` 全套、`.app.side-collapsed`、`.demo` + `≤1000` 的 `.demo{display:none}` + `≤1024` 的两条顶栏补丁、`.topbar-label`、`.switch`、`#account-pick` / `#state-pick` 的填充逻辑、`change` 监听、`S.sideCollapsed`、`renderCrumbs()`。
- 自检门禁随之变化:交互 ID 由 **79 → 76 个**、真驱动由 **75 → 72 个**、`data-act` 出现次数由 **750 → 638 次**;`PASS 83 / FAIL 0` 保持。
⛔ **两条留在这里的纪律**:①别再把「参照物产品的习惯」当需求搬进外壳 —— 本轮 6 项里有一半是这么来的(参照物笔记 `ui/布局排版参考-mcn-work-shop.md` 不是规则文件,它是素材);②撤销一个交互 ID 必须**同时删掉它的 DOM**,否则「页面上每个 data-act 都在清单里」会报红(本轮实测过)。
⚠️ §三 B-15(≤640px 的 P1 密度缺口)的三条出路仍待拍板。
---
## 十一、参照物组件细节对照(mcn-work-shop · 逐件量的值,2026-10-08)
用户口径:「**MCN 工作台里面每个组件的样式 高度 ICON 都是需要学习的,比如功能入口,感觉没有学到细节**」。
⇒ 这不是「有没有这个组件」的问题,是**规格有没有量到位**的问题。所以本节把参照物的组件**逐个量出原值**,再列我方现值与差距。
**取证方式**:直接读源站文件(只读,⛔ 未改对方任何文件)——
`E:/ProgramData/AIProject/mcn-short-video/project/短视频脚本创作/V1.0/mcn-work-shop/public/`
的 `style.css`(56 KB)与 `app.js`(54 KB)。下面每一条都带**文件:行号**,⛔ 无一处是目测。
### 11.1 功能入口卡(`.data-card`,参照物 `style.css:387-392` + `app.js:332-336`)
用户点名的就是这个组件 —— 巧的是**我们与它同名**(名字是从参照物笔记里照抄的),但细节差得远。
下表是**第七轮改完之后**的现值。「65px 高差当初是怎么差的、这轮又怎么把高度还回去的」逐条记在 §十二。
| 细节项 | 参照物实测值 | 我方现值 | 判定 |
|---|---|---|---|
| **卡内布局** | `display:flex; flex-direction:column; align-items:flex-start; gap:**6px**` ⇒ **图标 / 标题 / 描述 三段纵向** | 同:三段纵向 + `gap:6px` | ✅ 第七轮学过来。⚠️ 第一版是「图标+标题」并成一行(两段)—— **这是 65px 高差的主因** |
| **图标** | `svgIcon(icon, **22**)`;`color: var(--primary)`(它自己的主色) | `navSvg(page, **22**)`;`color: --accent-text` | ✅ 尺寸学过来。⚠️ 色**刻意不学** —— 它给首页 4 张卡配了 4 个色相(`ICON_COLORS`),我方统一走品牌紫文字档 |
| 图标线宽 | `stroke-width:**2**` + 圆头圆角 + `viewBox 24` + `fill:none` | 同 | ✅ 第六轮学过来(原 1.7) |
| 卡内衬 | `padding: **16px 18px**` | `padding: **16px**`(四边) | ⚠️ 横向差 2px —— 18 不在本项目间距刻度(2/4/6/8/12/16/24/32)⇒ 走 `--sp-16` |
| 段间距 | `gap: 6px` | `gap: 6px`(`--mg-6`) | ✅ 第七轮学过来(原 4px) |
| 标题 | `.data-card-title` `17px / 600`,行高 `normal`(实测 **25px**) | `18px / 600`(`--fs-18`),行高**写死 1.35**(实测 24.3px) | ⚠️ 差 1px —— 17px 不在本项目字阶(12/14/16/18/20/24/30)⇒ 取 18(取 16 会跟描述只差 2px,层次就没了)。**行高必须写死**:`normal` 在不同中文字体下 1.31–1.47 都在飘,而卡下面紧贴着那张吃密度契约的表 |
| 描述 | `.data-card-desc` `14px` | `14px`(`--fs-14`),行高写死 1.35 | ✅ 第七轮学过来(原 12px) |
| **卡片阴影** | `box-shadow: 0 1px 3px rgba(0,0,0,.08)` | `box-shadow: var(--sh-L1)` | ✅ 第七轮学过来。**原来我方这张卡是平的** —— 这也是它看起来「薄」的一部分 |
| 卡圆角 | `border-radius: 12px` | `16px`(`--raw-radius-panel`) | ✅ 刻意不学 —— 圆角归我方样式库(tiaoyue 16px) |
| 网格 | `.data-cards` `minmax(**200px**,1fr)`、`gap: 14px`、`margin: 18px 0 24px` | `minmax(200px,1fr)`、`gap: 16px` | ✅ 最小宽学过来(第六轮,原 180px);⚠️ gap 差 2px(14 不在刻度) |
| **hover** | `border-color: 主色` + **`transform: translateY(-2px)`** + `box-shadow: 0 4px 12px rgba(主色,.15)` | 只有 `border-color: --accent` | ⛔ 刻意不学位移 —— 本项目动效纪律禁位移。它那个 hover 阴影是**配着位移一起用**的(抬起来才需要落影),位移一去、阴影独留只会显得僵 |
| **实测卡高** | 同视口 1249 下 **133px**(描述折两行)/同宽下 113px(描述一行) | **111.19px**(1440 下,卡宽 421.66、描述一行) | ✅ 差 2px,来自「描述一行 vs 两行」+ 内衬横向 2px |
⇒ 两轮下来共补进去:**图标(尺寸 + 线宽 + 唯一出口)/三段纵向排布 + 段间距 6px/内衬 16/标题与描述的字号与行高/卡片阴影/网格最小宽 200px**。
⛔ 三处**刻意不学**:圆角 12px(归我方样式库)、`translateY(-2px)` 位移(动效纪律)、「一个功能一个色」(定调归我方样式库)。
### 11.2 其余组件(同样逐件量)
| 组件 | 参照物实测值 | 我方现值 | 判定与理由 |
|---|---|---|---|
| **统计条** | `.home-stat-item`:`flex:1; padding:2px 12px; border-right:1px solid rgba(主色,.16)` ⇒ **无框、靠竖分隔线分格**;`.home-stat-value` `**26px / 700** / 主色`;`.home-stat-label` 13px dim;gap 5px(`style.css:383-386`) | 白底卡 + 1px 描边 + 16px 圆角;值 `20px / 600 / --ink`;标签 12px | ⚠️ **形态刻意不学**(它的竖线无框条 vs 我方 tiaoyue 的面板卡,这是风格层);但**「数字要大、要重、要上色」这条我没做到** —— 参照物 26/700/主色,我方 20/600/正文字色。⚠️ 要改成 24px(本项目字阶里最接近 26 的档)+ 主色,需重测密度 ⇒ 列入**待拍板**(见回复) |
| **问答行** | `.qa-row{padding:6px 8px; font-size:15px; line-height:1.55}`;可复制的行 `hover` 变浅底并出现 📋 图标;`.func-card .qa{**border-top:1px dashed**; padding-top:8px}`(`style.css:78-84`) | 有 `.qa-row`(问 accent / 答 dim);**没有虚线分隔、没有 hover 复制** | ✅ 本轮补上**虚线分隔**(`.qa-block`);⚠️ 复制图标那条**未学** —— 本项目的复制交互还没做,记在差异里 |
| **图标系统** | `svgIcon(name,size=16,color)`:`viewBox 24` / `fill:none` / `stroke:currentColor` / `stroke-width 2` / 圆头圆角;颜色走 `ICON_COLORS`(**8 个图标 8 个色相**:橙/蓝/粉/天蓝/黄/青/玫红/灰);尺寸用法:卡 22、功能卡标题 18、按钮 16(`app.js:196-207`) | 侧栏 8 个自写图标、1.7 线宽、单色 | ⚠️ 学一半 —— 线宽改 **2**、尺寸口径明确(卡 22 / 侧栏 20);⛔ **8 色相不学**:与基础层「同一层级保持一致重量、避免每张普通卡片用不同强调色」冲突,我方统一走 `--accent-text` |
| **顶栏** | `.topbar{padding:**10px 20px**; gap:20px}`(`style.css:25-32`)⇒ 高约 52px | `padding:8px 32px` ⇒ 49px | ✅ 已对齐(我方的 49px 与它的 52px 同档) |
| **次级按钮** | `.ghost`:`padding:6px 14px; border-radius:8px; font-size:15px; display:inline-flex; gap:6px`(可放图标)(`style.css:48-54`) | `.btn-sm`:高 32px / 内衬 0 12 / 药丸 | ⚠️ 高度同档(32px ✅);圆角走 tiaoyue 药丸(26px),⛔ 不学它的 8px |
| **面板** | `.panel{padding:**24px**; height:100%; overflow:auto}`(`style.css:62`) | `.panel` 内衬 12px(`--c-card-pad-dense`) | ⚠️ 差值 —— 我方为了密度收到 12px,⛔ 不回到 24(会吃掉 6 行里的一半) |
**这一节的方法论**:参照物的**结构细节**(图标、尺寸档、线宽、网格最小宽、hover 通道、虚线分隔)能学就学;**品牌层**(颜色、圆角体系、字体)走我方的 tiaoyue,⛔ 不串。每一条「不学」都写了理由与代价,⛔ 没有一条是漏掉的。
---
## 十二、功能入口卡的 65px 高差是怎么差的、又怎么还的(2026-10-08 第七轮)
用户第二轮口径:「**功能入口的高度还是没有 参考 MCN 的首页的功能入口 按钮的样式和布局**」。
### 12.1 先量,别猜
同视口(**1249 × 1277**,同一个浏览器实例)并排量参照物与原型;原始读数在 `_scratch/ref-measure.txt`(参照物)与 `_scratch/proto-measure.txt`(原型)。
| 项 | 参照物 | 我方第一版 | 差 |
|---|---|---|---|
| 卡高 | **133px** | **68px** | **−65px** |
| 排布 | 图标 / 标题 / 描述 **三段纵向** | 「图标+标题」一行 + 描述 **两段** | 少一段 + 少两次段间距 |
| 内衬 | `16px 18px` | `12px 16px` | −4 / −2 |
| 段间距 | `6px` | `4px` | −2 |
| 标题 | `17px / 600`(行高 25px) | `16px / 600`(行高 21px) | −1 / −4 |
| 描述 | `14px` | `12px` | −2 |
| 卡片阴影 | `0 1px 3px rgba(0,0,0,.08)` | 无 | 少了 |
高差 65px 的**主因是排布**(少一段 22px 的图标行 + 两次 6px 段间距),次因是内衬与字号。
### 12.2 改完立刻发现代价:密度掉了
改完再跑逐视口表:**1440×900 的 P1 由 6 行掉到 5 行**(首行顶 697 → 740px)。原因很直白 —— P1 的「统计条 + 功能入口卡」这一摞压在两张 5 行表上,本来只剩 **17px** 余量(697px 距 714px 那条六行线),卡一长高 43px 就被吃光。
⇒ **卡的高度该学,但账得从别处还,⛔ 不是拿密度换。**
### 12.3 还账之前先做对照:证明「哪些红是我造成的」
动手之前先把本轮两处改动**回退成一份副本**(`_scratch/base.html`),对同一套判据跑 15 个视口,拿到**改前基线**:
| | 视口 |
|---|---|
| 绿 | 1440 / 1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / 640 |
| 红 | 768 / 700 / 560 / 500 |
改后(收口完成)再跑一遍:**绿、红两批逐格完全一致**。这句对照是本轮的**全部正当性** —— 卡长高 43px,而分界一格没动(全表见 `3b` §五)。
⚠️ 顺带查出一件必须记的事:**768 / 700 / 560 / 500 那四处红是改前就有的**,与本轮无关(768/700 的根因是功能入口卡在 768 折成两行、统计条在 700 折成两行)。⇒ 本轮⛔ 没有顺手改它们,免得把「本轮改了什么」和「本来就有什么」搅在一起。
### 12.4 还的三处(合 −39px,实测首行顶 740 → 701)
| # | 做法 | 省下 | 凭什么 |
|---|---|---|---|
| ① | 删掉「功能入口」小标(八页各一处) | −24.6px | 参照物是 `.home-stats` **直接接** `.data-cards`,中间空无一物 —— 删它反而**更像参照物**;且「功能入口」四个字对扫读零增量(卡自己写着去哪儿) |
| ② | 统计条下边距 `8 → 6` | −2px | 照参照物 `.home-stats{margin:0 0 6px}`,同样是更贴近 |
| ③ | `.block-head` 下边距 `12 → 8` | −12px | P1 上方有三处块标题;参照物 `.func-card h3{margin-bottom:10px}`,8 比 12 更近 |
`≤640` 一档另追加一条(实测 724 → 700):卡内衬 `8/12 → 6/8`、图标 `18 → 16`、标题 `18 → 16`、`.block` 上边距 `32 → 24`。
### 12.5 三条纪律(本轮现挂的)
1. **「改完只量主视口」这个毛病犯了两次**(第六轮 640、本轮 1440),两次都是逐视口表兜住的 ⇒ 已写进 `DESIGN.md` §五 第 7 条当纪律。
2. **改一个组件的高度之前,先跑一次「改前基线」** —— 否则分不清哪条红是自己造成的,很容易把旧洞也算进本轮账上(或者反过来,把新洞漏掉)。
3. **要学参照物,就量到数值**;量不准的值宁可写成「刻意不学 + 理由」,⛔ 不要停在「大概差不多」—— 上一版的 65px 高差就是这么来的。
---
## 十三、tiaoyue 左侧导航样式对照(2026-10-08 第七轮追加)
用户 2026-10-08 口径:「**左侧导航 样式可以参考 tiaoyue的左侧导航**」。
⚠️ 这条当时**没做完就岔开了** —— 第三轮只做到「形态」(64px 栏、`nav-item`/`nav-icon`/`nav-tip` 三项各 9 个),而且是**照组件清单猜的**;用户要的「样式」一直没量到底。
### 13.1 先在包里找,找不到就回源站
- `assets/tokens.css`(43 个令牌):**只有色值 / 圆角 / 按钮 / 输入框 / 卡片,没有一条导航几何**。
- `references/library.json`:`nav-item` 81 / `nav-icon` 81 / `nav-tip` 81 / `nav-tips` 9 + `nav-tips__row` 81 / `app-sidebar` 9 / `sidebar-shell` 9(9 页 × 9 项)—— **只有计数,没有尺寸**。`summary.tailwind: 659` ⇒ 源站是 Tailwind 站,几何写在**类名**里,不在 CSS 规则里。
- `references/design-system.html`(1.4 MB):clipper 生成的**样例页**,`app-sidebar` **0 处** ⇒ 不含源站侧栏。
- `capture-notes.md` 写明源站是 `https://www.tiaoyue.com/`,当时抓到的是**登录后的亮色形态**。
⇒ 包里没有这个事实,就**回源站量**(只连已有浏览器实例;量完即关,⛔ 不留标签页)。
### 13.2 实测真值(源站 `https://www.tiaoyue.com/`,强制亮色形态)
| 项 | tiaoyue 实测 | 我方(改前) | 本轮 |
|---|---|---|---|
| 栏宽 | `w-16` ⇒ **64px** | 64px | 不变 ✅ |
| 栏形态 | `rounded-[100px]` + `p-[3px]` + `bg rgba(100,112,160,.08)` + `border 1px rgba(100,112,160,.14)`,`flex-col items-center`,**⛔ 无右边线** | 通栏满高面板 + `border-right:1px var(--line-soft)`,无圆角/底色/描边 | 改 **药丸浮栏** ✅ |
| 栏高 | 随内容 **710px**,`left:16` **浮在页面上**(主区不缩进) | 拉满整屏 | 随内容 + 列内垂直居中(⚠️ 仍占一列,⛔ 没改成真浮层,见 13.3) |
| 项尺寸 | `h-[78px] w-14` ⇒ **56 × 78** | 撑满栏宽 × **44px** | 改 **56×78** ✅ |
| 项圆角 | `rounded-[54px]` ⇒ **54px** | 14px(`--raw-radius-row`) | 改 **54px** ✅ |
| 项内衬 | `p-4` ⇒ **16px** | 0 | 改 **16px** ✅ |
| 项段间距 | `gap-1.5` ⇒ **6px** | 2px | 改 **6px** ✅ |
| 项内文字 | **常驻**:`text-xs font-medium leading-4` ⇒ **12px / 500 / 行高 16px**,图标在上、名字在下 | **名字常驻隐藏**,只走悬停提示 | 改 **常驻** ✅ |
| 名字长度 | 全部 **2 字**(首页/影视/短视频/转绘/画布/剧本/资产/空间/团队),最长 3 字已是溢出到内衬的极限 | 总览/找选题/资产库/创作/发布/**账号画像**/**记录与对账** | 收到**一律 2 字**:总览/选题/资产/创作/发布/画像/复盘/对账 |
| 图标 | `size-6` ⇒ **24×24**(字形在 24 盒里 `translate(1 1)`),**填充字形**(`fill` 走 `currentColor`) | **20px**,线性描边 `stroke-width:2` | 尺寸改 **24** ✅;⛔ 字形不换(见 13.3) |
| 当前项 | `is-active`:bg `rgba(31,35,41,.06)` + 字/图标**满墨** `rgb(31,35,41)` | 品牌紫底 `color-mix(accent 10%, paper)` + `--accent-text` + 字重 600 | 改 **中性填充 + 满墨** ✅ |
| 非当前项 | `is-inactive`:透明底 + 字 `rgba(31,35,41,.55)` | `--ink-mute` | 改 `--ink-faint`(≈3.4:1,过本项目「淡字 ≥3:1」那条) |
| 项间距 | **无 gap**(78px 紧贴) | `4px` | 改 **0** ✅ |
| hover | `transition-colors` **只换颜色 0.15s**,⛔ 无位移、⛔ 无阴影 | 底色 + 字色 | 同(保持无位移)✅ |
| 悬停辅助 | 栏右侧一列 `nav-tips__row`(**158 × 78**,与左侧项逐项对齐),内容是**说明**(实测文案「发现灵感与精选内容」) | viewport 级提示浮层,内容是**名字重播** | 保留浮层,内容改**该页说明** ✅ |
### 13.3 三处刻意不学 / 一处没做
- ⛔ **不换图标字形**:参照物是**填充字形**,我方是 mcn-work-shop 那套**线性描边**图标(用户上一轮点名要学的正是那套)。换字形等于换一整套图标,两个参照物会打架 ⇒ 只把尺寸从 20 提到 24。
- ⛔ **不做「真浮层」**:参照物的栏 `left:16px` 浮在页面上、主区**不缩进**;我方仍是 `.app` 两列里的一列。改成真浮层要动外壳骨架(`.app` 的 grid 与 `.main` 的缩进),收益只有「主区多 16px」⇒ 本轮不换,差异记在这里。
- ⛔ **不给导航上彩色**:参照物的导航图标本来就是「满墨 / 淡墨」两档,跟随文字色,没有第二套色。
- ⚠️ **没做**:`nav-tips__row` 那种「贴着栏右侧、逐项对齐的一整列说明」。我方是**单条跟随当前项**的浮层。两者功能等价(都在回答「这一项是干什么的」),形态不同;要做成一整列说明,得给 8 页各写一行文案并新增一层布局 ⇒ 本轮没做,留在这儿备查。
### 13.4 改完的验收
- 五道闸门全过:自检 **PASS 84 / FAIL 0**(1440×900)、**逐视口 15 个绿/红分界与改前逐格一致**(绿 1440/1280/1024/1000/960/920/901/900/840/820/640;红 768/700/560/500)、变异 **15 / 15**、骨架 **39 板块**、命名 **2060 / 0 / 25**、语法门禁全过。
- ⚠️ **这次改动对密度是中性的**:栏宽仍是 64px 定值,项从 44 长到 78 只让**药丸变高**,⛔ 不影响主区可用高度(实测 15 个视口首行顶一格未动)⇒ 这是本项目少见的「只改外观、不动布局」的一次,所以**不需要还账**。
@@ -1,410 +1,467 @@
# MCN 短视频整合营销工作台 · DESIGN.md
> 项目 slug:`mcn-shortvideo-agent` | ③段(界面交互)第 3a 子步产出
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/DESIGN.md`(本目标目录内;⛔ 未写域外 `docs/pm/`)
> 判据源:`product-planning/references/stage-delivery/SKILL.md`(含 §供给 / Gate-1)+ 同目录 `references/execution-runbook.md` §2 + `references/layouts-tooling.md` §5.5
> 本份是原型的绑定规范:原型只许引本份登记的 token。
---
## 〇、开工声明(声明制,四字段)
| 字段 | 内容 |
|---|---|
| 当前段与子步 | ③段 / 3a 视觉规范(D0 锚需求 → D1 定调 → Gate-1) |
| 主干与挡位 | 供给=`oil-ui-pro`(方法主线)+ 本段自带样式库 `design-system-tiaoyue`(定调与令牌)/ 挡位 **标准** |
| 依据文件 | `stage-delivery/SKILL.md` §供给 + §3a;`references/execution-runbook.md` §2.0–§2.4;`references/layouts-tooling.md` §0/§1/§5/§5.5 |
| 产出落点 | `ui/DESIGN.md`(本份)、`ui/mcn-workbench.html`(3b) |
### 供给核对(runbook §2.0 · 步 −1,每轮必做)
| 步 | 动作 | 结果 |
|---|---|---|
| −1 | 确认 §供给 三处在位:定调与令牌(自带样式库)、版式骨架(`references/layouts-tooling.md`)、工艺数值判据(`references/execution-runbook.md` §3.4 + `layouts-tooling.md` §5.5) | ✅ 三处都在位。自带样式库现存 **1 套**:`assets/design-systems/design-system-tiaoyue/` |
| −1b | 套名与本项目记录比对 | ✅ 本目标无前次记录(③段首次开工,本目录此前只有 `research/` 与 `prd/`)⇒ 视作首次选定,不触发变更清单 |
| −1c | 可选档是否动用 | ⛔ **未动用** `assets/open-design/`(随段携带的可选件)。因此它独有的那几项(反 AI 味 / 无障碍 / 表单校验 / 动效纪律)**本次无供给来源** —— 见 §五 已明示,⛔ 没有凭感觉编一套顶上 |
### 页型判定(硬前置,SKILL.md §3b)
**本产品全部 8 页都是工具型页面,不是营销页。** 依据:用户是天天来干活的 MCN 团队,每一页都有人在里面完成一件事(决定先处理哪件 / 挑一条选题 / 存一条拆解 / 推一个环节 / 确认一次发布 / 改一份画像 / 写一条归因 / 核销一条记录);没有一页是为了让人「看一眼就下决心」。此判定与②段 `2b-界面布局.md` §一 一致。
⇒ 本份 D0 里**零 `.eyebrow`、零 `.lead`、零 `.hero`**(token 与类名都不设这三个)。
---
## 一、设计契约(十二个字段)
### 1.1 项目级字段
**① 主用户**:MCN 机构的内容负责人(矩阵级决策)、编导与文案(选题与创作)、剪辑与投放(版本与发布)。三者同处一个矩阵,职责不同、看的页不同。依据 ①段 `1c-用户画像.md`(零访谈画像,骨架来自 1a §四 三行角色描述 —— 该局限已如实登记,见 §四 缺口)。
**② 主操作**:**逐页唯一**(全页级)。六页的主操作由②段给定,逐页列在 1.2;本段未改一个。
**③ 必要内容(核对面)**:逐页核对②段分档表,见 1.2。核对面只做**落位核对**(常驻的零点击可见、可点入的一次点击可达),⛔ 本段不以它为由增删②段已定的信息档位。
**④ 重复项的信息量**:本产品的四个列表(账号矩阵 / 对标内容 / 资产条目 / 发布记录)都是「行式列表」,每行除「主标识 + 动作」外都带次级信息,逐页列在 1.2。
**⑤ 结构骨架(翻译面)**:
- **骨架档:主区 + 侧区**(选它的理由:一级导航有 4 个并列目的地、宽屏 ≥1024;②段给的一级组是三组加一个跨组入口,正好落在侧栏;tiaoyue 的实测外壳本身就是「左侧栏 + 顶栏」的应用型外壳,两者同构)。
- **板块落位**:把②段每页的板块按它给的「从上到下」顺序放进主区,每块一个文字标题。⛔ 未新增 / 移动 / 删除 / 合并任何板块(逐页对照见 §三)。
- **密度目标:密集(8–32)**。理由:8 页全是一屏要放多行记录的工具型页面,②段 P1 的信息分档要求矩阵列表与今日待办**同时**常驻,宽松档放不下。**同一页面只取这一档**。
- 块间距 ≥ 块内间距的 2 倍:块间 32px、块内 8/12/16px ⇒ 比值 2.0–4.0 ✅(数值登记在 §二)。
**⑥ 交互清单**:见 §二 表 2.4(逐元素四列)。**它是唯一的交互真相源** —— 3b 实测、3c 会诊、3d 终检都引这一张,⛔ 不另建一份。
**⑦ 状态覆盖六项**:见 1.3,逐页逐项有结论。
**⑧ 组件来源**:优先沿用选定套的既有组件族,其次才是自创。⛔ 未参考 `teamOnly: true` 的族(`onboarding-divider` / `onboarding-feature` / `team-scope-content` / `team-onboarding-card`)。清单见 §二 表 2.5。
**⑨ 响应式行为**:
| 断点 | 布局怎么变 |
|---|---|
| `>1024` | 侧栏 240px 常驻(带文字标签)+ 主区 `minmax(0,1fr)`;列表列宽按 1:1 分配 |
| `640–1024` | 侧栏收窄到 200px,仍带文字标签;列表的次级信息列折到主标识下方一行 |
| `<640` | 侧栏**变成页头下方一条可横向滚动的标签栏**(⛔ 不隐藏、⛔ 不变成纯图标),主区单列;行式列表的列改为「主标识一行 + 状态/动作第二行」 |
⚠️ 实测覆盖:**1440 / 1280 / 1024 / 768 / 641 / 640 ×900,以及 500×844** 七个视口都跑过自检,横向溢出全为 0。窄视口实测到 500×844 为止(原因见 §五 第 6 条)。窄视口下**两栏带(`.band`)在 ≤1024px 落回单列** —— 不落的话,列表被挤到不足 300px,每行会竖折成三行(实测踩过,见 §五 第 7 条)。**密度在 ≤767px 宽不达标**,逐视口实测值与成因见 §五 第 7 条。
**⑩ 明确拒绝的模式**(≥3 条,每条可判定):
1、⛔ 不出现「眉标 / 大标题 / 灰色副标题」三段式标题区(判据:DOM 里 `.eyebrow` / `.lead` / `.hero` 三个类名出现次数为 0)。
2、⛔ 不用围合边框假装分组(判据:非控件元素里 `border` + `border-radius` 同时出现的次数,在同一「分组」用途上 ≥3 次即判不过;结构性容器一律靠底色差 + 多层阴影分层)。
3、⛔ 不给列表行套框、不给状态上整行底色(判据:行间只用 `border-top`;状态只出现在 `tag` 内)。
4、⛔ 不做入场编排(判据:交付文件里 `@keyframes` 出现次数为 0,过渡只用 `transition`)。
5、⛔ 不可点的东西不长成可点样子(判据:页面里所有 `button` / `[role=button]` / `.btn*` 集合,与 §二 表 2.4 的元素列做双向差集,差集为空)。
**⑪ 验收标准(可观察可判定)**:
- 八页各自可达(`#/p/p1`…`#/p/p8` 直接打开都渲染出该页内容,不是空壳)。
- 表 2.4 每一行的「触发 → 反馈」都真发生过,无死按钮。
- 六态在每一页都能被看到(正常 / 加载 / 空 / 错误 / 禁用 / 无权限)。
- 宽视口 1440×900 与窄视口各留一张截图,横向溢出为 0。⚠️ 窄视口**实测到 500×844 为止**:本机只有无头 Chrome + 命令行开关这一条通道,窗口宽下限被卡在 516px,拿不到 390 —— 见 §五 第 6 条,⛔ 不写成「已测 390×844」。
- 页面上每个可点元素都能在表 2.4 里查到;表里没有的可点元素为 0。
**⑫ 明确拒绝的「编造」**(本项目追加一条,源自①②段的纪律):界面上不出现「示例」「示意图」「未接入」「待核实」这类制作说明;也不把机器结论说成人已认可(如把「疑似原因」写成「已确认原因」)。
### 1.2 逐页字段(页面职责 / 主操作 / 必要内容落位 / 重复项信息量)
| 页 | 页面职责(让谁 / 多久 / 完成什么) | 主操作(唯一) | 必要内容的落位核对 | 重复项的信息量(每行的次级信息) |
|---|---|---|---|---|
| P1 矩阵总览 | 让内容负责人在 1 分钟内决定**今天先处理哪一件事** | 挑一件待办并进到那一件事 | 账号矩阵列表与今日待办=零点击可见;异常值、本月最好、检索与随手记=一次点击可达 | 账号行=账号名(主标识)+ 今日该发/已发/效果(3 条次级)+ 异常徽章 |
| P2 选题雷达 | 让编导在 3 分钟内**找到一条能做的选题** | 把一条选题推进下一步 | 监控概览四数、对标内容列表、选题库=零点击可见;评论区洞察、灵感速记=一次点击可达 | 对标行=标题(主标识)+ 账号 + 倍数 + 时间;选题行=选题(主标识)+ 来源 + 状态 |
| P3 资产库 | 让编导在 2 分钟内**存一条拆解结果、或引用一条已存的** | 入库一条 / 引用一条 | 分区切换、条目列表=零点击可见;单条详情、引用入口=一次点击可达 | 条目行=条目摘要(主标识)+ 出处 + 草稿/已入库 + 采集时间 |
| P4 创作台 | 让编导在一条内容上**把当前环节推到下一环节** | 推进到下一环节 | 环节进度、当前环节工作区、当前内容标识=零点击可见;资产引用区、版本列表=一次点击可达 | 版本行=vN(主标识)+ 语义名 + 时间 + 当前标记 |
| P5 发布中心 | 让投放**确认发出这一批版本** | 确认发布 | 检查结果、各版本预览与逐版编辑、确认发布=零点击可见;目标选择、发布记录入口=一次点击可达 | 版本行=账号/平台(主标识)+ 字数 + 检查结论;记录行同 P8 |
| P6 账号画像 | 让内容负责人**改好并保存一个账号的画像** | 保存这一份画像 | 画像六维、账号列表=零点击可见;记忆条目、关联内容=一次点击可达 | 账号行=账号名(主标识)+ 平台 + 内容数;记忆行=日期(主标识)+ 来源 + 一句话 |
| P7 复盘台 | 让内容负责人**确认归因并写回这个账号** | 确认归因并回写 | 表现数据、归因结论区、待复盘列表、回写目标提示=零点击可见;历史复盘=一次点击可达 | 待复盘行=内容(主标识)+ 发布账号 + 发布日 + 数据到没到 |
| P8 记录与对账 | 让投放**核销一条发布记录** | 核销一条记录 | 发布记录列表、对账核对区=零点击可见;单条溯源、商单与收支=一次点击可达 | 记录行=内容(主标识)+ 确认人 + 时间 + 版本 + 状态 |
### 1.3 状态覆盖六项(逐页给结论)
判据源:`SKILL.md` 铁律 2 给出的六态清单(loading / empty / error / success / disabled / 无权限)。⚠️ 逐项**数值判据**出自供给可选档的 `craft/state-coverage.md`,本轮未动用可选档 ⇒ **该项本次无供给来源**,故此处只给「有没有、长什么样」的结论,不编阈值。
| 页 | loading | empty | error | success | disabled | 无权限 |
|---|---|---|---|---|---|---|
| P1 | ✅ 矩阵数据加载中(骨架行 + 「正在取矩阵数据」) | ✅ 还没接入账号(给「去账号画像建第一个账号」) | ✅ 数据源不可用(显时间戳 + 重试) | ✅ 默认态 | ✅ 无可处理项时待办区禁用并说明 | ✅ 非管理员看利润字段时的遮罩说明 |
| P2 | ✅ 拉取对标中 | ✅ 监控名单为空(给「录一个对标号」) | ✅ 拉取失败(退路=手工录入) | ✅ 默认态 | ✅ 未选账号时「转入创作」禁用 | ✅ —(不适用:本页对所有角色开放) |
| P3 | ✅ 条目加载中 | ✅ 该分区还没有条目(给「去拆解一条」) | ✅ 读取失败(重试) | ✅ 默认态 | ✅ 无出处的条目「入库」禁用(门禁) | ✅ —(不适用) |
| P4 | ✅ 环节生成中 | ✅ 该环节还没产出(给「开始这一步」) | ✅ 本步失败(保留已产出 + 重试该步) | ✅ 默认态 | ✅ 文案与封面缺一,「进检查态」禁用(封面缺只提示) | ✅ —(不适用) |
| P5 | ✅ 检查中 | ✅ 还没有可发布的版本(回 P4) | ✅ 检查自身失败 ⇒ **按不过处理**(fail-closed) | ✅ 无硬拦、可发 | ✅ 有硬拦项时「确认发布」禁用 | ✅ 未授权账号的版本标「无发布权限」并禁用该版 |
| P6 | ✅ 画像加载中 | ✅ 还没有画像(给「建画像」) | ✅ 保存失败(保留编辑内容) | ✅ 保存成功提示 | ✅ 只读角色时字段禁用 | ✅ 非本人负责账号:可看不可改 |
| P7 | ✅ 读数据中 | ✅ 还没有可复盘的内容 | ✅ 数据读不到 ⇒ 转手工录入表现 | ✅ 回写成功提示 | ✅ 未确认归因时「回写」禁用 | ✅ —(不适用) |
| P8 | ✅ 记录加载中 | ✅ 还没有发布记录 | ✅ 读取失败(重试) | ✅ 核销成功 | ✅ 未选中记录时「核销」禁用 | ✅ 利润列对非管理员隐藏(列级遮罩) |
> 口径:`disabled` 与 `无权限` 是两件事 —— 前者是「当前条件不满足」(自己能解开),后者是「角色不允许」(自己解不开)。界面文案必须分开写,⛔ 不拿「不可用」一句话糊过去。
---
## 二、令牌表
### 2.1 三层结构(`primitive → semantic → component`)
组件层只引语义层,语义层只引 primitive;⛔ 无孤立 token。
| 层 | 前缀 | 例子 | 规则 |
|---|---|---|---|
| primitive | `--t-*`/`--raw-*` | `--t-accent`、`--raw-fs-12` | 只有原始值,⛔ 别的层不许直接引它以外的东西;本层不许被组件层直接引用 |
| semantic | `--`(无前缀语义名) | `--surface`、`--ink`、`--fs-14` | 只引 primitive |
| component | `--c-*` | `--c-card-radius`、`--c-btn-h` | 只引 semantic |
### 2.2 色值(来源=选定套 `design-system-tiaoyue` 的 `assets/tokens.css` 亮色基线 · 9 页 clipper 实测)
| 语义 token | 值 | 用途 |
|---|---|---|
| `--paper` | `#faf9f5` | 页面底(暖白纸感) |
| `--surface` | `#ffffff` | 面板 / 卡片底 |
| `--surface-soft` | `#f7f6f1` | 次级面(表头、只读块、侧栏选中底) |
| `--ink` | `#1a1a18` | 主文字 |
| `--ink-mute` | `#57564f` | 次级文字 |
| `--ink-faint` | `#8a887f` | 三级文字 / 占位(⛔ 只用于非正文:占位、图标、禁用态) |
| `--line` | `#e7e5dc` | 分隔线(行间 `border-top`) |
| `--line-soft` | `#efeee7` | 更弱的分隔(块内) |
| `--accent` | `#9E4CFF` | 主强调色(品牌紫) |
| `--accent-text` | `#963dff` | accent 当**文字**时用这一档(`#9E4CFF` 直接当文字不达标) |
| `--on-accent` | `#FFFFFF` | 主色上的文字 |
| `--ok` | `#3d7a4f` | 成功态 |
| `--err` | `#b4453a` | 错误态 |
| `--warn` | `#8a5a00` | 提醒 / 异常值 / 软劝 ⚠️ **本项目追加**:选定套亮色基线**没有 warn 档**,而②段 P5 要求「硬的拦住、软的只提醒」必须有两种可见区分 ⇒ 新增一档并在次行登记来源与对比度实测 |
**强调色允许位置(反 slop 要求写明)**:只允许出现在 ① 主按钮的填充底;② 侧栏当前项左侧 3px 指示条;③ 链接文字(用 `--accent-text`);④ 焦点环。⛔ 不允许出现在:页面大背景、卡片底、图标填充(除主按钮内图标)、任何渐变。全屏面积 ≤5%。
**禁止**:⛔ 无紫→粉渐变;⛔ 无装饰性发光;⛔ 状态色只用这红/绿/黄三系,不做装饰。
### 2.3 几何 · 字体 · 间距 · 字阶 · 高度层级 · 脚手架
| 项 | 值 | 来源 / 说明 |
|---|---|---|
| 字体 | `"PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "Noto Sans SC", sans-serif` | 选定套实测:源站 `@font-face` 为 0 条,走系统字体栈。⛔ 未手改 |
| 标题字体 | 同上(同族),字重 ≤600 | 中文字重不超 600;⛔ 未用 Inter / Roboto / Arial / `system-ui` 关键字 |
| 等宽数字 | `font-variant-numeric: tabular-nums` | 所有数字列,防刷新抖动 |
| 圆角 | 大容器 `24px`(`--t-card-radius`)/面板 `16px`/行与小件 `14px`/输入框 `9px`/按钮 `26px`(药丸) | 全部取自选定套 `<`—— `--card-radius: 24px`、`--ui-radius: 16px`、`--radius: 14px`、`--inp-radius: 9px`、`--btn-radius: 26px` |
| 间距 · 主刻度 | `4 / 8 / 16 / 24 / 32 / 64` | 供布局。块间用 32(同行组间 24),块内用 8/12/16 |
| 间距 · 微网格 | `2 / 4 / 6 / 8 / 12` | **仅供**按钮内衬、徽章内衬、图标间隙 |
| 块间距 / 块内间距 | 32 / 8–16 ⇒ 比值 2.0–4.0 | 判据要求 ≥2 ✅ |
| 字阶定值表(七档,各一个 px) | `--fs-12` 12 / `--fs-14` 14 / `--fs-16` 16 / `--fs-18` 18 / `--fs-20` 20 / `--fs-24` 24 / `--fs-30` 30 | 相邻档差 2/2/2/2/4/6,全部 ≥2 ✅;每档只一个定值,⛔ 不是区间。正文档 `--fs-14`(多数正文)与 `--fs-16`(表单值),落在 14–16 ✅ |
| 高度层级(每层多层叠层) | L1(行/内嵌):`0 1px 1px rgba(26,26,24,.03), 0 2px 6px -2px rgba(26,26,24,.06)`<br>L2(面板):`0 1px 2px rgba(26,26,24,.04), 0 8px 20px -12px rgba(26,26,24,.14), 0 18px 40px -18px rgba(26,26,24,.10)`<br>L3(浮层):`0 2px 4px rgba(26,26,24,.05), 0 14px 32px -12px rgba(26,26,24,.18), 0 32px 64px -24px rgba(26,26,24,.16)` | 每层 ≥2 层叠层 ✅;同层级同值。⛔ 无单层死黑重阴影 |
| 布局脚手架 | 侧栏 `240px`(`640–1024` 收 200px)+ 主区 `minmax(0,1fr)`;主区内列表列宽 `1fr 1fr`(行式列表的「主标识 / 次级」两列),窄屏折行 | 骨架档=主区+侧区,已落到具体列宽 |
| 容器与对齐锚点 | 主区左右内衬 32px;行式列表的文字左锚点与块标题左锚点同一条线;数字列右对齐且右锚点对齐块右内衬 | 判据要求「对齐锚点」写明 |
| 浮层 | 居中面板,宽 `min(560px, calc(100vw - 32px))`,内衬 24px;**只有一个可见关闭出口**(右上 ×);遮罩与 `Esc` 也可关,但不计为可见出口 | 满足 Gate-3 的「可见关闭出口唯一」 |
### 2.4 交互清单(唯一交互真相源 · 四列)
**通用规则**(适用于下面所有浮层):每个浮层**只有一个可见关闭出口**(右上 ×,ID 记为 `X-close`);遮罩点击(ID 记为 `X-mask`)与 `Esc` 也能关,但**不视为可见出口**;关闭后焦点回到触发它的那个按钮,Tab 只在层内循环。这三条逐浮层过了一遍,结论在 `3d-审查报告.md` 的浮层表里。下表不再逐浮层重复这三条。
| ID | 元素 | 触发 | 反馈 | 何时不可点 |
|---|---|---|---|---|
| G-01 | 一级组「找选题」 | 点击 | 跳到 P2;该组高亮 | 从不可点 |
| G-02 | 一级组「走创作流水线」 | 点击 | 跳到 P4;该组高亮 | 从不可点 |
| G-03 | 一级组「看矩阵复盘」 | 点击 | 跳到 P1;该组高亮 | 从不可点 |
| G-04 | 一级组「账号画像」(跨组) | 点击 | 跳到 P6;该组高亮 | 从不可点 |
| G-05 | 二级页项 P1–P8(8 项) | 点击 | 切到该页(hash 变、主区重绘);当前项 `is-active` | 从不可点 |
| G-06 | 顶栏「随手记」 | 点击 | 打开随手记浮层,焦点进输入框 | 从不可点 |
| G-07 | 顶栏账号切换器 | 点击 | 展开账号下拉;选中后顶栏显示该账号,涉及账号上下文的页跟着切换 | 账号列表为空(empty 态)时禁用 |
| G-08 | 顶栏「假设 2 项」 | 点击 | 打开假设浮层(逐条给复核人 / 复核时机 / 结论落点) | 从不可点 |
| G-09 | 顶栏演示状态开关 | 选择 | 强制当前页进入 正常 / 加载 / 空 / 错误 / 禁用 / 无权限 | 从不可点 |
| G-10 | 顶栏「全局检索」 | 点击 | 打开检索浮层,焦点进输入框 | 从不可点 |
| X-close | 各浮层右上 × | 点击 | 关闭浮层;焦点回触发它的按钮 | 从不可点 |
| X-mask | 浮层遮罩(层外空白区) | 点击 | 关闭浮层;焦点回触发它的按钮 | 没有浮层时不渲染 |
| STATE-NORMAL | 状态面板 · 「回到正常内容」 | 点击 | 该页回 `ok` 态,主操作恢复 | 仅在非 `ok` 态出现 |
| STATE-RETRY | 出错态 · 「重试一次」 | 点击 | 提示已重试(示意);不改数据 | 仅在 `error` 态出现 |
| STATE-GO | 空态 · 「去〈某页〉」 | 点击 | 跳到该页;浮层关 | 仅在 `empty` 态、且该页定义了去处时出现 |
| R-01 | 随手记浮层 · 输入框 | 输入 | 内容非空时「保存」由禁用转可用 | 从不可点(可输入) |
| R-02 | 随手记浮层 · 保存 | 点击 | 写入选题库「待做」;提示 1.5s 后消失;浮层关闭 | 输入为空时 `:disabled` |
| R-03 | 随手记浮层 · 取消 | 点击 | 关闭,不写入;焦点回触发按钮 | 从不可点 |
| S-01 | 检索浮层 · 输入框 | 输入 | 结果列表按关键字过滤;无结果显示空态行 | 从不可点(可输入) |
| S-02 | 检索浮层 · 结果项 | 点击 | 跳到该结果所属的页;浮层关闭 | 无结果时列表为空(不渲染可点项) |
| A-01 | 假设浮层 · 两处假设条目 | 展示 | 只读,逐条给复核人 / 时机 / 落点 | 不适用(只读,非控件) |
| P1-01 | 今日待办项(每条) | 点击 | 跳到该待办所属的页(选题类→P2、在写→P4、待审→P5、待复盘→P7、待核销→P8) | 该条为「已超期未处理」时仍可点,但带提醒标 |
| P1-02 | 账号矩阵行 | 点击 | 跳到 P6 并选中该账号 | 从不可点 |
| P1-03 | 账号矩阵行 · 「看复盘」 | 点击 | 跳到 P7 并选中该账号的待复盘内容 | 该账号没有可复盘内容时禁用 |
| P1-04 | 异常值提示条目 | 点击 | 跳到 P2 并定位到该对标内容 | 无异常值时整块显示空态(不渲染可点项) |
| P1-05 | 本月最好的一条 | 点击 | 跳到 P7 的该条复盘 | 无数据时禁用 |
| P2-01 | 监控概览 · 「低粉爆款」数 | 点击 | 筛选对标内容列表(只看爆款) | 数为 0 时禁用 |
| P2-02 | 监控概览 · 「异常值」数 | 点击 | 筛选对标内容列表(只看异常) | 数为 0 时禁用 |
| P2-03 | 对标内容行 · 「发起拆解」 | 点击 | 跳到 P3 并带着这条素材(预填原文与出处) | 从不可点 |
| P2-04 | 评论区洞察子区 · 展开/收起 | 点击 | 展开子区并开始抓取(显示抓取中) | 从不可点 |
| P2-05 | 评论区洞察 · 「抓取评论」 | 点击 | 进入抓取中 → 出候选选题列表 | 抓取中时禁用 |
| P2-06 | 候选选题 · 「采纳」 | 点击 | 该条进选题库「待做」;候选行标为已采纳 | 该条已采纳时禁用 |
| P2-07 | 候选选题 · 「忽略」 | 点击 | 候选行标为已忽略(可恢复) | 该条已忽略时禁用 |
| P2-08 | 选题库 · 分组 tab(待做/在写/已用) | 点击 | 列表切换成该组 | 从不可点 |
| P2-09 | 选题行 · 「转入创作」 | 点击 | 建当前内容并跳到 P4;选题转「在写」 | 未选账号时禁用(并在行内说明) |
| P2-10 | 选题行 · 「拆解」 | 点击 | 跳到 P3 并把该选题当成素材 | 从不可点 |
| P3-01 | 分区切换 tab(角度/结构/开场白/标题) | 点击 | 条目列表换成该分区 | 从不可点 |
| P3-02 | 条目行 | 点击 | 右区显示单条详情(原文 / 出处 / 草稿标记) | 从不可点 |
| P3-03 | 待入库区 · 「入库」 | 点击 | 无出处的条目被门禁挡住并说明原因;有出处的转「已入库」 | **无出处或原文缺失时禁用**(门禁) |
| P3-04 | 单条详情 · 「引用到创作台」 | 点击 | 跳到 P4 并把该条目加进资产引用区 | 从不可点 |
| P4-01 | 环节进度 · 七个环节(逐项) | 点击 | 切到该环节;只许回退到已完成的环节 | 未到达的后续环节禁用 |
| P4-02 | 当前环节工作区 · 内容输入框 | 输入 | 「开始这一步」由禁用转可用 | 从不可点(可输入) |
| P4-03 | 当前环节工作区 · 「开始这一步」 | 点击 | 生成中 → 产出内容(写进本环节) | 输入为空时禁用 |
| P4-04 | 资产引用区 · 「从资产库拿一条」 | 点击 | 展开选择器;选中后收进引用区并显示来源 | 资产库为空时禁用并说明 |
| PICK-ASSET | 资产选择器 · 单条 | 点击 | 收进引用区并显示来源;浮层关 | 已引用过的不渲染可点项 |
| P4-05 | 资产引用区 · 「移除引用」 | 点击 | 从引用区移除该条 | 引用区为空时不渲染 |
| P4-06 | 「推进到下一环节」 | 点击 | 当前环节 +1;进度条与工作区跟着变 | 文案与封面缺一,进检查态时禁用(封面缺只提示) |
| P4-07 | 版本列表 · 展开/收起 | 点击 | 展开版本列表浮层 | 从不可点 |
| P4-08 | 版本行 · 「切为当前版」 | 点击 | 该版标为当前版;当前内容标识的版本号跟着变 | 该版已是当前版时禁用 |
| P5-01 | 目标选择 · 展开/收起 | 点击 | 展开账号与平台多选 | 从不可点 |
| P5-02 | 目标选择 · 账号项 | 点击 | 勾选/取消;版本列表跟着增删一版 | 从不可点 |
| P5-03 | 目标选择 · 平台项 | 点击 | 勾选/取消;同上 | 从不可点 |
| P5-04 | 版本预览 tab(逐版) | 点击 | 右区换成该版内容 | 从不可点 |
| P5-05 | 版本内容编辑框 | 输入 | 保存按钮由禁用转可用;标为「已改」 | 从不可点(可输入) |
| P5-06 | 版本内容 · 「保存本版」 | 点击 | 该版内容更新;检查结果跟着重算(回到未检) | 无改动时禁用 |
| P5-07 | 检查结果 · 「复检」 | 点击 | 检查中 → 出结论(硬拦 / 软劝 / 通过) | 检查中时禁用 |
| P5-08 | 「确认发布」 | 点击 | 打开二次确认浮层 | **有硬拦项时禁用**;无版本时禁用 |
| P5-09 | 二次确认 · 「确认发出」 | 点击 | 写发布记录(P8 出现一条);提示成功 | 从不可点 |
| P5-10 | 二次确认 · 「取消」 | 点击 | 关闭浮层,不发;焦点回触发按钮 | 从不可点 |
| P5-11 | 发布记录入口 | 点击 | 跳到 P8 | 从不可点 |
| P6-01 | 账号列表项 | 点击 | 切换右区画像 | 从不可点 |
| P6-02 | 画像六维字段(6 个输入) | 输入 | 「保存画像」由禁用转可用 | 非本人负责账号时禁用(改由角色判定) |
| P6-03 | 「保存画像」 | 点击 | 保存成功提示;未保存时离开给提示 | 无改动时禁用 |
| P6-04 | 记忆条目 · 展开/收起 | 点击 | 展开记忆列表(只追加,不可编辑) | 从不可点 |
| P6-05 | 关联内容行 | 点击 | 跳到 P4 的该条内容 | 无关联内容时整块空态 |
| P7-01 | 待复盘列表项 | 点击 | 右区换成该条的表现数据 | 从不可点 |
| P7-02 | 表现数据 · 「手工录入」 | 点击 | 数据读不到时的降级入口,展开输入 | 数据已读到时不渲染 |
| P7-03 | 归因结论区 · 文本 | 输入 | 「确认归因并回写」由禁用转可用 | 从不可点(可输入) |
| P7-04 | 「确认归因并回写」 | 点击 | 回写到当前账号画像:记忆 +1;显示回写目标 | 归因为空、或未选账号时禁用 |
| P7-05 | 历史复盘 · 展开/收起 | 点击 | 展开历史复盘结论 | 从不可点 |
| P8-01 | 发布记录行 | 点击 | 右区换成该条的对账详情 | 从不可点 |
| P8-02 | 「单条溯源」(可点入) | 点击 | 展开溯源:从记录回到内容与版本 | 从不可点 |
| P8-03 | 对账核对区 · 「核销」 | 点击 | 二次确认 → 该条标「已核销」 | 未选记录时禁用;记录未「已发布」时禁用 |
| CHECKOUT-OK | 核销二次确认 · 「确认核销」 | 点击 | 该条标「已核销」;提示成功;浮层关 | 从不可点 |
| CHECKOUT-CANCEL | 核销二次确认 · 「取消」 | 点击 | 关闭浮层,不核销;焦点回触发按钮 | 从不可点 |
| P8-04 | 「商单与收支」展开/收起 | 点击 | 展开收支条目 🔴 **本块是假设**(见 §三) | 从不可点 |
⚠️ **「可见关闭出口」与「决策型关闭」是两件事,⛔ 不许混成一个数**:每个浮层的中性关闭出口只有一颗 ×(`X-close`),恰好 1 个;**「取消」这类带决策语义的按钮也能关层,但它不是「找出口」用的**,单独登记(`R-03` / `P5-10` / `CHECKOUT-CANCEL`)。这条口径是补出来的 —— 原先自检只数 `.layer-close` 这个类名,于是两颗可见的「取消」完全没进计数,两个二次确认层其实各有两个看得见的关闭控件,判据却报「出口 = 1」。逐浮层的核对结论与触发路径在 `3d-审查报告.md` §六。
**表外可点元素必须为 0** —— 3b 自检里有一条逐集合做双向差集的检查(`#/selftest` 路由自动跑,结果落 `3b-实测记录.md`)。
⚠️ **`A-01` 不是控件**:它是假设浮层里的只读展示行,本表把它列出来是为了让「假设有两处、逐条给复核人 / 时机 / 落点」这件事在清单里看得见。⇒ 它**不进实现清单**(原型里的 `IMPL` 表),自检也不该拿它去点。本表的控件 ID 与 `IMPL` 的键必须**互为子集且相等**,这条由 `_tools/mutate_test.py` 里的 M2/M3 两处变异盯着(漏登记 / 悬空声明各一种)。
### 2.5 组件规格(来源:选定套既有组件族)
| 组件 | 规格(具体值) | 来源 |
|---|---|---|
| 按钮 · 主档 | 高 `40px`,内衬 `12/20`,字号 `16px`,字重 `600`,圆角 `26px`(药丸),底 `--accent`,字 `--on-accent` | 选定套 `--btn-radius/--btn-px/--btn-py`;字号 16 + 字重 600 是**必须的**(见下注) |
| 按钮 · 次档 | 高 `40px`,内衬 `12/20`,字号 `14px`,字重 `500`,圆角 `26px`,底 `--surface`,描边 1px `--line`,字 `--ink` | 同族 |
| 按钮 · 弱档(文字) | 高 `32px`,内衬 `6/12`,字号 `14px`,圆角 `26px`,无底无描边,字 `--accent-text` | 同族 |
| 卡片 · 密卡 | 内衬 `16px`,圆角 `16px`,底 `--surface`,L1 阴影 | 同族 |
| 卡片 · 宽松卡 | 内衬 `24px`,圆角 `24px`,底 `--surface`,L2 阴影 | 同族 `--card-radius/--card-pad` |
| 输入框 | 高 `36px`,内衬 `12/10`,圆角 `9px`,字号 `14px`,底 `--surface`,描边 1px `--line` | 同族 `--inp-*` |
| 徽章 / 状态标 | 高 `22px`,内衬 `2/8`,字号 `12px`,圆角 `999px`,无描边,底为对应状态色 8% 叠加 | 同族 `is-*` 修饰族 |
| 侧栏导航项 | 高 `36px`,内衬 `8/12`,圆角 `14px`,当前项底 `--surface-soft` + 左 3px `--accent` 指示条 | tiaoyue `nav-item` + `is-active` |
> 同屏主档按钮 ≤1(多步流程每步 ≤1):P1 无主档、P2/P3/P4/P5/P6/P7/P8 各 1 个 ✅
> 实底底色 ≥2 种:主档 `--accent`、次档 `--surface`、状态标(ok/err/warn 三色 8% 叠加)✅
> ⚠️ **主档按钮的 16px + 600 不是随手定的**:选定套记录 `#FFFFFF` 压 `#9e4cff` 只有 **4.26:1**(两形态一致,是品牌紫的固有属性),走**大字线 3:1** 才达标 ⇒ 主档按钮文字必须 ≥16px 且加粗;⛔ 小字(<16px 常规字重)压主色在本规范里没有合规解,故不允许出现。
---
## 三、两处假设的显式标注(⛔ 不当已确认需求用)
②段 `2b-界面布局.md` §四 标了两处骨架受限。本轮**尚无用户结论**,按②段给的默认读法做,并在本份与原型里显式标注:
| # | 受影响处 | 假设内容 | 本轮默认读法(按 2b §四) | 复核人 | 复核时机 | 结论落点 |
|---|---|---|---|---|---|---|
| 假设 1 | **P1 的形态**(横幅:`2b` §二 P1 末段) | 矩阵级视图是否真需要(1a 待复核第 5 条 + A1) | **按「需要矩阵级视图」做**:P1 = 矩阵总览,5 个板块全在。若复核为「不需要」,P1 降为「单账号今日」,只留第 1、4 板块,矩阵列表下移到账号切换 | 主会话转用户 | ②段收口时一次性过;③段已按默认读法做,结论到了改这一处 | `2b` §四 + §二 P1;本轮落 `ui/DESIGN.md` 本节 + 原型 P1 标题行的「假设」徽章 |
| 假设 2 | **P8 的第 4 板块**「商单与收支」 | 商单对账进不进第一版、收支口径是否内容级(1a 待复核第 6 条 + A3) | **按「进第一版但属 P2、可整块缺」做**:第 4 板块**渲染出来但标「可点入 + 假设」**,并在展开后给一句「本块依赖未复核项」。第 1、2、3 板块不受影响 | 主会话转用户 | 同上 | `2b` §四 + §二 P8;本轮落 `ui/DESIGN.md` 本节 + 原型 P8 第 4 板块标题行的「假设」徽章 |
**原型的兑现方式**(不占标题区、不写成注脚):两处各在自己的**板块标题同行右侧**挂一个「假设」徽章;顶栏另有「假设 2 项」入口,点开逐条给出复核人 / 时机 / 落点。⛔ 假设既没有被当已确认需求写死,也没有被编出答案。
---
## 四、Gate-1 方向门自检(硬闸,结果写在本份末尾)
| # | 检查项 | 结论 | 依据 |
|---|---|---|---|
| 1 | 设计契约十二字段 | ✅ 过 | §一 十二字段全填,无空、无「待定」;重复项逐页列了次级信息;交互清单四列齐全且表外可点元素为 0(3b 实测复核) |
| 1b | 页型判定 | ✅ 过 | 全文工具型;D0 零 `.eyebrow` / 零 `.lead` / 零 `.hero`(原型里这三个类名出现 0 次,`#/selftest` 复核) |
| 2 | 结构骨架(翻译面) | ✅ 过 | 骨架档=主区+侧区(给了理由);板块落位照②段顺序、每块有文字标题;②段分档表每条信息都有落位(§1.2 逐页核对) |
| 2b | 骨架未漂 | ✅ 过 | 八页与板块逐条对得上 `2b`,本段未增删移动(见下表) |
| 3 | 状态覆盖 | ✅ 过 | §1.3 六态逐页有结论;`disabled` 与 `无权限` 分开写 |
| 4 | 令牌表 | ✅ 过 | §2.2/§2.3 色值、字体、间距两档(适用面已分开)、圆角、阴影全为具体值 |
| 4b | 字阶定值表 | ✅ 过 | 七档各一个 px(12/14/16/18/20/24/30),相邻差 2/2/2/2/4/6 ≥2 |
| 4c | 高度层级 | ✅ 过 | L1/L2/L3 每层 ≥2 层叠层,同层级同值 |
| 4d | 布局脚手架 | ✅ 过 | 侧栏 240/200px + 主区 `minmax(0,1fr)`;窄屏变化写具体(标签栏化) |
| 5 | 组件规格 | ✅ 过 | 按钮三档+卡片两档+输入框+徽章均为具体值;同屏主档 ≤1;实底 ≥2 种 |
| 6 | 反 slop | ✅ 过 | 无紫→粉渐变;标题用选定套系统字体栈(非禁用字体);强调色允许位置已写明(§2.2) |
| 7 | 拒绝清单 | ✅ 过 | §1.1 ⑩ 共 5 条,每条带可判定判据(≥3 ✅) |
| 8 | token 引用完整性 | ✅ 过 | 三层结构;组件层只引语义层、语义层只引 primitive;无孤立 token |
| 9 | 分档兑现 | ✅ 过 | §1.2 逐页落位;常驻=零点击可见、可点入=一次点击可达;档位未被本段改动 |
| 10 | 供给核对 | ✅ 过 | §〇 已核;选定套 `design-system-tiaoyue`,与本目标记录一致(首次选定) |
**骨架未漂逐页对照**(⛔ 本段未新增 / 移动 / 删除 / 合并):
| 页 | ②段板块(照抄) | 原型落位 | 一致 |
|---|---|---|---|
| P1 | 今日待处理/账号矩阵列表/异常值提示/本月表现最好的一条/全局检索与随手记入口 | 同序 5 块(前两块**并排一层**) | ✅ |
| P2 | 对标监控概览/对标内容列表/评论区洞察区/选题库/灵感速记入口 | 同序 5 块 | ✅ |
| P3 | 分区切换/条目列表/单条详情/引用入口 | 同序 4 块 | ✅ |
| P4 | 当前内容标识/环节进度/当前环节工作区/资产引用区/版本列表 | 同序 5 块 | ✅ |
| P5 | 目标选择/各版本预览与逐版编辑/检查结果/确认发布/发布记录入口 | 同序 5 块 | ✅ |
| P6 | 账号列表/画像六维/记忆条目/关联内容 | 同序 4 块 | ✅ |
| P7 | 待复盘列表/这一条的表现数据/归因结论区/回写目标提示/历史复盘 | 同序 5 块 | ✅ |
| P8 | 发布记录列表/单条溯源/对账核对区/商单与收支 | 同序 4 块 | ✅ |
> 板块的**排布位置**:P3/P5/P6/P8 在②段里是「列表 + 详情」并存的一页,本段按 `layouts-tooling.md` §0 判为**侧区型**(主操作要在列表与详情之间来回),故在**块内**用左右两栏落实(左列表、右详情);⛔ 这不是增删板块,是同一批板块在骨架档里的摆法(块内怎么摆归③段)。
>
> **P1 的前两块并排一层**(同上口径):②段把「今日待处理」和「账号矩阵列表」列为第 1、2 块,本段让它们**左→右并排**、读序不变,「异常值提示」及其后仍顺次往下。这么做不是审美选择,是 **§六 的密度判据逼出来的** —— 反事实实测:把两栏带强制落回单列时,`账号矩阵列表@530+413`,首行顶 **530px**,容量 `floor((900−530)/67) = 5 行`,够不着「一屏 ≥6 行」;并排之后首行升到 **214px**,一屏装得下 **10 行**。实测过程记在 `3b-实测记录.md` §五。
> 若复核认为并排也算动了骨架,回退办法只有一条:把密度判据在 1440×900 下放宽到 ≥5 行 —— **两件事必须挑一件,不能都不做**(原判据下,单列连 6 行都够不着)。
---
## 五、缺口与证据边界(⛔ 不假装支持)
1. **反 AI 味 / 无障碍 / 表单校验 / 动效纪律的逐项数值判据本次无供给来源** —— 这四项出自 §供给·工艺数值判据 的**可选档**(`assets/open-design/craft/` 13 份),本轮未动用可选档 ⇒ ⛔ 不凭感觉编一套顶上。本段实际应用的是**默认档**判据:`execution-runbook.md` §3.3/§3.4 + `layouts-tooling.md` §5.5(五条反「实习生审美」硬判据)。四条已按默认档能做到的部分执行(如 focus-visible 三态、tabular-nums、防溢出三件套、间距只用登记刻度)。
2. **暗色主题本轮不做** —— 选定套的暗色与亮色是两套独立基线,规则是「要暗色就整套切」(`known-conflicts.md` C-01),且暗色实测只覆盖 1 个页面(`/team/onboarding`),而该页正是选定套 §〇 明令生成时避开的页;哪一套亮色才是主线**尚未裁决**。⇒ 本轮只做亮色基线(9 页 clipper 实测),⛔ 不与暗色混搭。要做暗色需先裁决 C-01,属技能侧动作。
3. **`--warn` 是本项目追加的第 14 个语义色** —— 选定套亮色基线只有 ok/err,无 warn;而②段 P5 要求「硬的拦住、软的只提醒」必须有可见区分。追加值与其对比度实测记在 §六。
4. **`1c-用户画像.md` 是零访谈画像** —— 主用户的画像骨架来自 1a §四 三行角色描述,无问卷、无访谈、无行为数据。界面里凡涉及「角色能看什么」的判据都基于它,**不得对外说成基于用户调研**。
5. **3c GPT 会诊本轮未取得外部审查** —— 见 `3c-GPT会诊.md`。未取得 ≠ 已通过。
6. **窄视口只测到 500×844,⛔ 没测到 390** —— 本机只有「无头 Chrome + 命令行开关」这一条取证通道,而 Chrome 把窗口宽下限卡在 516px(拿到 500px 视口)。要 390px 得走 CDP 的 `Emulation.setDeviceMetricsOverride`,本轮没接。⇒ 契约里凡写 390 的地方,一律按 **500×844 实测** 记,⛔ 不许写成已测 390。(`_tools/cap.py` 里写了这条例外,改宽度时会打印实际视口,并**当场比对产出的 PNG 像素尺寸**。)
7. **密度判据(一屏 ≥6 行)在 ≤767px 宽不达标,⛔ 没有靠改判据把它变绿** —— 判据原文(`layouts-tooling.md` §1)是「一屏可见行数 ≥ 6(900px 高时)」,**不带宽度条件**,所以本段一个字没改。实测出来的边界是 **768px 宽**:
| 视口 | P1 账号矩阵 | P2 对标列表 | 页面外壳 |
|---|---|---|---|
| 1440 / 1280 ×900 | **10 行** | 7 行 | 顶栏 69px、导航竖排 |
| 1024 / 768 ×900 | **6 行** | 7 行 | 顶栏 69px、导航竖排 |
| 641 ×900 | 5 行 ❌ | 6 行 | 顶栏折两行(109px) |
| 640 ×900 | 5 行 ❌ | 6 行 | 顶栏 61px、导航变横条(53px) |
| 500 ×844 | 4 行 ❌ | 5 行 ❌ | 顶栏折两行(101px)、导航横条 |
成因是**页面外壳吃掉首屏**,不是行变肥:行高 67px、各行差 ≤2px、块内分隔 1px,这三条在任何视口都 PASS。三条出路只能挑一条:①把支持宽度下限写成 ≥768px(依据:`1a §七` 已明确第一版不做移动端 App);②压掉每行的次级信息、把行高压到 40px 上下(那 3 条次级信息是②段定的档位,③段不许改 ⇒ 得回②段改);③动页面外壳(顶栏那几个控件都登记在交互清单里,删或搬家等于改交互清单)。**这三条都要用户拍板,本段一条都没选。** 详见 `3d-审查报告.md` §三 B-15。
8. **截图通道与 DOM 通道的视口口径不同(已修,记账)** —— 同一台机器、同一个 `--window-size`,`--dump-dom` 给的是「窗口 − 16×95」,`--screenshot` 给的就是窗口本身。本轮之前所有截图都因此比标称大 16×95(「1440×900」实际 1456×995)。现已按模式分开算,并要求每次截图后从 PNG 的 IHDR 读真实像素跟目标比,不等即报红。详见 `3b-实测记录.md` §五。
9. **3c 那次独立评审不是「外部 GPT 会诊」** —— 本会话没有对外模型通道,改用了隔离上下文的独立评审执行者(不看源码、不继承制作对话)。它符合 `visual-review.md` 对「隔离执行者」的要求,但与 `SKILL.md` §3c 的异厂商外部审查**不是同一条通道**。**未取得外部审查 ≠ 已通过。** 见 `3c-GPT会诊.md` §〇。
---
## 六、数值取证登记(3d 回填处)
下表「实测值」全部由原型自带的 `#/selftest` 算出来(DOM 取值 + 真实像素计算),⛔ 不是目测。取值口径写在「取法」列;复跑命令见 `3b-实测记录.md`。
| 项 | 契约值 | 实测值 | 取法 |
|---|---|---|---|
| 强调色填充面积占比 | ≤5% | **0.52%**(八页最高一页:创作台;1 个填充块) | DOM 取值:逐个元素比 `backgroundColor` ≡ `--accent`,与视口求交后累加 ÷ 视口面积;不含 3px 左侧标条 / 描边 / 文字色 |
| `--warn` `#8a5a00` 对 `--surface` 对比度 | ≥4.5:1 | **5.93:1** | 真实像素计算:WCAG 相对亮度 |
| `--accent-text` `#963dff` 对 `--surface` 对比度 | ≥4.5:1 | **4.76:1** | 同上 |
| `--ink-faint` `#8a887f` 对 `--surface` 对比度 | ≥3:1(仅非正文) | **3.55:1** | 同上 |
| 一屏可容纳记录行数(P1 账号矩阵) | ≥6 @900px 高(⛔ 原文不分档) | **10 行** @契约视口 1440×900(首行顶 214px、行距 67px) | DOM 取值:首屏可用高度 ÷ 行距。⚠️ 判据是「装得下几行」,不是「实际渲染几行」—— 示意数据只有 5 条,实际永远是 5 行(数据用尽,非被截断)。⛔ 逐视口的完整实测表只写在 §五 第 7 条一处,这里不重复 |
| 一屏可容纳记录行数(P2 对标列表) | ≥6 @900px 高 | **7 行** @1440×900(首行顶 402px) | 同上 |
| P1 行高齐(本段追加判据) | 各行差 ≤2px | **67–68px,差 1px**(七视口一致) | DOM 取值:逐行 `getBoundingClientRect().height` |
| 视觉层间距 / 块内相邻行分隔 比值 | ≥2 | **32px / 1px = 32**(4 个视觉层) | DOM 取值。⚠️ 行式列表的首行没有上边框,取值要跳过首行、取各行的最大值;⚠️ 除数为 0 时判据作废,已加 0 守卫 |
| 实际在用字号档数(P1) | ≥3 | **5 档**:12 / 14 / 16 / 18 / 24 px(相邻差 2/2/2/6) | DOM 取值:叶子节点 computedStyle |
| 块间距 / 块内间距 比值 | ≥2 | **32 / 8–16 ⇒ 2.0–4.0** | 令牌登记值 + DOM 复核(`gap` 全部落在登记刻度内,9 个刻度) |
| 横向溢出 | 0 | **0**(七视口,八页逐页亦为 0) | DOM 取值:`scrollWidth − clientWidth` |
| 浮层中性关闭出口 | 恰好 1 | **7 / 7 个浮层均为 1**(另有决策型关闭 0–1 个,单列报数,⛔ 不混进这个数) | DOM 取值:可见的 `[data-act="X-close"]` 计数 |
| 同屏主档按钮 | ≤1 | **逐页 1 个**;P1 无主档(本页只用弱档) | DOM 取值:逐页统计实底按钮 |
| 顶栏高度(未写死,只看有没有折行) | — | **69px 单行**(补 `white-space:nowrap` 之前是 70px,标签在中间折行) | DOM 取值 |
**同轮实测的其它数值**(一并登记,供 3d 复核):
- P1 账号矩阵:首行顶 214px、行距 67px;块落位 今日待处理@149+360 / 账号矩阵列表@149+417(并排同顶)/ 异常值提示@599+215 / 本月表现最好的一条@845+122 / 全局检索与随手记@1000+113。
- P2:对标监控概览@165+139 / 对标内容列表@336+417 / 评论区洞察@785+108 / 选题库@925+330 / 灵感速记@1287+113;对标列表首行顶 402px。
- P1 按钮高度集合 32px(本页只用弱档一档;三档高度层级在 P4 / P5 出现)。
- 控制台报错 **0 条**;量尺寸时 `scrollY = 0`(两处均核)。
- 强调色填充块数只有 1 个 —— 工具型页面按要求把实底压到最少,主档按钮才用它。
> 契约里写了数字的,3d 已逐条实测回填,「契约值 / 实测值」并排列进 `3d-审查报告.md` §六。⛔ 不目测。
---
## 七、修订记录(收口后回填)
| 轮次 | 改了什么 | 为什么 |
|---|---|---|
| 3a 初版 | 契约、令牌、交互清单、假设标注、Gate-1 自检 | 本份首出 |
| 3d 收口 | ①§1.1 ⑨ 的实测覆盖从 4 个视口改成 7 个;②交互清单补 `CHECKOUT-CANCEL`、`STATE-NORMAL` 按钮文案改「回到正常内容」,并新写「中性出口 / 决策型关闭」的口径说明;③§四 里 P1 并排的反事实数按实测重填(604px→530px、3 行→5 行、209px→214px);④§五 第 7 条整条重写(撤掉自设分档,改成如实登记 ≤767px 的不达标),新增第 8、9 条;⑤§六 表内 8 处旧值按实测回填,并裁掉与 §五 重复的逐视口数 | 收口时逐条实测回填;同时把「同一事实只写一处」落实到密度这项上 |
---
## 八、说人话自评(判据源 `humanizer-zh`,五维各 10 分)
| 维度 | 分 | 说明 |
|---|---|---|
| 直接性 | 9 | 每节开口就是结论或数值,没有铺垫段 |
| 节奏 | 8 | 以表格与短断言为主,句式偏单一 —— ⚠️ 这是本份的弱项 |
| 信任度 | 9 | 不下「已通过」这种模糊话,未清零的直接写未清零 |
| 真实性 | 10 | 通篇是具体数(161px→53px、530px/5 行)、具体文件、具体命令,没有一句万金油 |
| 精炼度 | 9 | 已按「同一事实只写一处」裁过一轮(密度逐视口表只在 §五 第 7 条出现) |
| **总分** | **45 / 50** | 门槛 ≥45,压线过。扣分点如实写在第 2、5 行,⛔ 不报「已过」了事 |
*(本份是原型的绑定规范:原型只许引本份登记的 token。)*
# MCN 短视频整合营销工作台 · DESIGN.md
> 项目 slug:`mcn-shortvideo-agent` | ③段(界面交互)第 3a 子步产出
> 落点:`执行会话/目标-根据1a需求文档生成MCN短视频整合营销-d85687/ui/DESIGN.md`(本目标目录内;⛔ 未写域外 `docs/pm/`)
> 判据源:`product-planning/references/stage-delivery/SKILL.md`(含 §供给 / Gate-1)+ 同目录 `references/execution-runbook.md` §2 + `references/layouts-tooling.md` §5.5
> 本份是原型的绑定规范:原型只许引本份登记的 token。
---
## 〇、开工声明(声明制,四字段)
| 字段 | 内容 |
|---|---|
| 当前段与子步 | ③段 / 3a 视觉规范(D0 锚需求 → D1 定调 → Gate-1) |
| 主干与挡位 | 供给=`oil-ui-pro`(**基础层**:视觉与体验的底线判据)+ 叠加层(本段自带样式库 `design-system-tiaoyue` 定调与令牌 + 本段自有判据;只许更严、更具体,⛔ 不许放宽基础层)/ 挡位 **标准** |
| 依据文件 | `stage-delivery/SKILL.md` §供给 + §3a;`references/execution-runbook.md` §2.0–§2.4;`references/layouts-tooling.md` §0/§1/§5/§5.5 |
| 产出落点 | `ui/DESIGN.md`(本份)、`ui/mcn-workbench.html`(3b) |
### 供给核对(runbook §2.0 · 步 −1,每轮必做)
| 步 | 动作 | 结果 |
|---|---|---|
| −1 | 确认 §供给 三处在位:定调与令牌(自带样式库)、版式骨架(`references/layouts-tooling.md`)、工艺数值判据(`references/execution-runbook.md` §3.4 + `layouts-tooling.md` §5.5) | ✅ 三处都在位。自带样式库现存 **1 套**:`assets/design-systems/design-system-tiaoyue/` |
| −1b | 套名与本项目记录比对 | ✅ 本目标无前次记录(③段首次开工,本目录此前只有 `research/` 与 `prd/`)⇒ 视作首次选定,不触发变更清单 |
| −1c | 可选档是否动用 | ⛔ **未动用** `assets/open-design/`(随段携带的可选件)。因此它独有的那几项(反 AI 味 / 无障碍 / 表单校验 / 动效纪律)**本次无供给来源** —— 见 §五 已明示,⛔ 没有凭感觉编一套顶上 |
### 页型判定(硬前置,SKILL.md §3b)
**本产品全部 8 页都是工具型页面,不是营销页。** 依据:用户是天天来干活的 MCN 团队,每一页都有人在里面完成一件事(决定先处理哪件 / 挑一条选题 / 存一条拆解 / 推一个环节 / 确认一次发布 / 改一份画像 / 写一条归因 / 核销一条记录);没有一页是为了让人「看一眼就下决心」。此判定与②段 `2b-界面布局.md` §一 一致。
⇒ 本份 D0 里**零 `.eyebrow`、零 `.lead`、零 `.hero`**(token 与类名都不设这三个)。
---
## 一、设计契约(十二个字段)
### 1.1 项目级字段
**① 主用户**:MCN 机构的内容负责人(矩阵级决策)、编导与文案(选题与创作)、剪辑与投放(版本与发布)。三者同处一个矩阵,职责不同、看的页不同。依据 ①段 `1c-用户画像.md`(零访谈画像,骨架来自 1a §四 三行角色描述 —— 该局限已如实登记,见 §四 缺口)。
**② 主操作**:**逐页唯一**(全页级)。六页的主操作由②段给定,逐页列在 1.2;本段未改一个。
**③ 必要内容(核对面)**:逐页核对②段分档表,见 1.2。核对面只做**落位核对**(常驻的零点击可见、可点入的一次点击可达),⛔ 本段不以它为由增删②段已定的信息档位。
**④ 重复项的信息量**:本产品的四个主列表(账号矩阵 / 对标内容 / 资产条目 / 发布记录)都是**满宽表格**(表头一排 + 每行一个短值),每行除「主标识 + 动作」外都带次级信息,逐页列在 1.2。
**⑤ 结构骨架(翻译面)**:
- **骨架档:主区 + 侧区**(选它的理由:一级导航有八个并列目的地、宽屏 ≥1024;tiaoyue 的实测外壳本身就是「左侧栏 `app-sidebar` + 顶栏 `layout-header`」的应用型外壳,两者同构)。
- **导航层级:只有一层 —— 八个功能项**(2026-10-08 用户两次定案:先「左侧功能导航 只有大板块的导航 只有一层」,再「看看 gpt 的板块或功能命名,再看看你的」)。侧栏一列八项、一项一页,⛔ 没有第二层:总览 / 找选题 / 资产库 / 创作 / 发布 / 账号画像 / 复盘 / 记录与对账(两三个字的短名;页头与面包屑仍写②段的页面全名,两个名字各司其职)。
- **侧栏形态:照 tiaoyue 的 `app-sidebar` 做 64px 药丸浮栏**(2026-10-08 用户定案「左侧导航参考 tiaoyue 的导航」;第七轮回源站 `https://www.tiaoyue.com/` 逐值量过,实测表在 `3d` §十三)。实测真值:栏 **64px 宽 + 内衬 3px + 圆角 100px**(药丸)+ 淡色底 + 1px 淡描边,⛔ **没有右边线**(分界靠药丸自己的底与描边);项是 **56×78 的药丸**(圆角 54px、内衬 16px、段间距 6px),**图标 24px 在上、名字 12px/500 在下,两者都常驻**;当前项=中性填充 + 满墨字。⚠️ 这跟上一版「纯图标栏、名字只走悬停提示」的口径**是反的** —— 那是照组件清单猜的(清单里没有文字标签族),回源站一看名字是一贯显示的。名字**一律 2 个字**:项宽 56 − 内衬 16×2 = **24px 内容宽**,只放得下 2 个 12px 汉字,这是参照物定的长度上限。悬停提示是 viewport 级浮层(`nav-tips-layer`),内容=**这一页是干什么的一句话说明**(⛔ 不重播名字,名字已经常驻)。**≤640 的窄屏** ⇒ 药丸整段让位给**一条带名字的横滚标签条**(见 §1.1 ⑨)。
- **主页面的收口形态(八页统一,2026-10-08 用户定案「每个板块的首页 样式参考 MCN工作台首页」)**:每一页都=【页头 → **该页统计条**(`.home-stats`+`.stat-item`,3–4 个数)→ **功能入口卡一行**(`.sect-nav`,指向②段 §三 从本页出发的流转目标;**⛔ 不带「功能入口」小标** —— 参照物也没有,且小标占的 24.6px 要还给密度契约,见 §五 第 7 条)→ **满宽表格组成的主数据块** → **一处左右两栏** `.grid-main-side` → 尾块(P1 还多一块「全局检索与随手记」)】。⛔ 统计条与功能入口卡都不是 `.block`(无 `.block-head`),**不进②段骨架的板块计数**;八页主数据块已逐页由行式列表改成满宽表格(编辑型板块——环节工作区、画像六维、版本逐版编辑、对账核对区——保持原形态,因为它们的任务不是「扫一行行」)。
- **板块落位**:把②段每页的板块按它给的「从上到下」顺序放进主区,每块一个文字标题。⛔ 未新增 / 移动 / 删除 / 合并任何板块(逐页对照见 §三)。
- **密度目标:密集(8–32)**。理由:8 页全是一屏要放多行记录的工具型页面,②段 P1 的信息分档要求矩阵列表与今日待办**同时**常驻,宽松档放不下。**同一页面只取这一档**。
- 块间距 ≥ 块内间距的 2 倍:块间 32px、块内 8/12/16px ⇒ 比值 2.0–4.0 ✅(数值登记在 §二)。
**⑥ 交互清单**:见 §二 表 2.4(逐元素四列)。**它是唯一的交互真相源** —— 3b 实测、3c 会诊、3d 终检都引这一张,⛔ 不另建一份。
**⑦ 状态覆盖六项**:见 1.3,逐页逐项有结论。
**⑧ 组件来源**:优先沿用选定套的既有组件族,其次才是自创。⛔ 未参考 `teamOnly: true` 的族(`onboarding-divider` / `onboarding-feature` / `team-scope-content` / `team-onboarding-card`)。清单见 §二 表 2.5。
**⑨ 响应式行为**:
| 断点 | 布局怎么变 |
|---|---|
| `>1024` | 侧栏 **64px 药丸浮栏**常驻(照 tiaoyue `app-sidebar` 的 `w-16`,⛔ 宽度不随断点变)+ 主区 `minmax(0,1fr)`;列表列宽按 1:1 分配 |
| `1001–1024` | 侧栏仍 64px;两栏分栏与满宽表格**都保持不变**;另:`.grid-cards` 落两列、顶栏间距收到 `8px`。**顶栏不随断点折行**(只剩「产品名 + 随手记」) |
| `901–1000` | 同上,另:功能入口卡**只留标题**(隐描述)、**卡最小宽 200 → 160px**(这一条 2026-10-08 第八轮加的;不加的话 768 会让三张卡折成两行) |
| `821–900` | 上述两项继续;另:两栏分栏 `.grid-main-side` → 单列(右栏被挤到 300px 以下就会折行) |
| `641–820` | 上述三项继续;另:**统计条最小宽 132 → 96px**(4 格不折行 —— 700px 下 132px 会让 4 格折成两行、统计条高度翻倍)。这一条也是第八轮加的 |
| `≤640` | 侧栏**变成页头下方一条可横向滚动的标签条**(⛔ 不隐藏)。这一档把药丸浮栏那一整套(圆角 100px/描边/淡底/垂直居中/项 56×78)**整段还原成通栏横条**:项横排、高 `36px`、内衬 `0/12`、圆角 `999px`、图标 `16px` + 短名,当前项滚进视野;主区单列 |
**滚动容器(2026-10-08 修,见 §五 第 10 条)**:整页不滚、**只有主区 `.view` 滚**。高度链必须写成 `.app{height:100vh}` + `.main{min-height:0;overflow:hidden}` + `.view{flex:1 1 auto;min-height:0;overflow:auto}` —— 只写 `min-height` 会让 `.app` 跟着内容长高、滚动落到 `<body>`,而 body 是 `overflow:hidden`,折叠线以下的内容就永远拿不到(原型真踩过)。
⚠️ 实测覆盖:**1440 / 1280 / 1024 / 1000 / 960 / 920 / 901 / 900 / 840 / 820 / 768 / 641 / 640 ×900,以及 500×844** 逐个跑过自检,横向溢出全为 0;纵向由判据「滚动只由主区承担」逐个核过。窄视口实测到 500×844 为止(原因见 §五 第 6 条)。**密度契约(一屏 ≥6 行)的收线随侧栏收窄一起下移:≥768px 全绿**(侧栏从 240px 收到 64px,主区宽了 176px,表格不再折行);**≤640px 时 P1 掉到 5 行/−1 行(不达标)**。逐视口实测值与成因见 §五 第 7 条。
**⑩ 明确拒绝的模式**(≥3 条,每条可判定):
1、⛔ 不出现「眉标 / 大标题 / 灰色副标题」三段式标题区(判据:DOM 里 `.eyebrow` / `.lead` / `.hero` 三个类名出现次数为 0)。
2、⛔ 不用围合边框假装分组(判据:非控件元素里 `border` + `border-radius` 同时出现的次数,在同一「分组」用途上 ≥3 次即判不过;结构性容器一律靠底色差 + 多层阴影分层)。
3、⛔ 不给列表行套框、不给状态上整行底色(判据:行间只用 `border-top`;状态只出现在 `tag` 内)。
4、⛔ 不做**逐区块**入场编排(判据:`@keyframes` 至多 1 处 —— 只许一次协调出场;过渡只用 `transition`,⛔ 不用 `linear`/`ease`)。
5、⛔ 不可点的东西不长成可点样子(判据:页面里所有 `button` / `[role=button]` / `.btn*` 集合,与 §二 表 2.4 的元素列做双向差集,差集为空)。
6、⛔ **不用内联样式表达「选中态」或覆盖「字号」**(判据:八页里 `[style*=border-color]`、`[style*=color]`、`[style*=font-size]` 的出现次数**都为 0**)。**选中态全站只有一套画法**:`.is-on` / `.is-active`(整块浅紫底 + `--accent-text` + 字重 600,⛔ 不用单侧色条、⛔ 不用「描边变黑」);**字号只许走 `--fs-*` 档**(七档定值,见 §2.3)。⚠️ 只查这三样、不查全部内联样式 —— `margin-*` / `flex` / `justify-content` 这类一次性布局微调允许内联,硬按「内联为 0」判会把正常布局一起判红。
**⑪ 验收标准(可观察可判定)**:
- 八页各自可达(`#/p/p1`…`#/p/p8` 直接打开都渲染出该页内容,不是空壳)。
- 表 2.4 每一行的「触发 → 反馈」都真发生过,无死按钮。
- 六态在每一页都能被看到(正常 / 加载 / 空 / 错误 / 禁用 / 无权限)。
- 宽视口 1440×900 与窄视口各留一张截图,横向溢出为 0。⚠️ 窄视口**实测到 500×844 为止**:本机只有无头 Chrome + 命令行开关这一条通道,窗口宽下限被卡在 516px,拿不到 390 —— 见 §五 第 6 条,⛔ 不写成「已测 390×844」。
- 页面上每个可点元素都能在表 2.4 里查到;表里没有的可点元素为 0。
**⑫ 明确拒绝的「编造」**(本项目追加一条,源自①②段的纪律):界面上不出现「示例」「示意图」「未接入」「待核实」这类制作说明;也不把机器结论说成人已认可(如把「疑似原因」写成「已确认原因」)。
### 1.2 逐页字段(页面职责 / 主操作 / 必要内容落位 / 重复项信息量)
| 页 | 页面职责(让谁 / 多久 / 完成什么) | 主操作(唯一) | 必要内容的落位核对 | 重复项的信息量(每行的次级信息) |
|---|---|---|---|---|
| P1 矩阵总览 | 让内容负责人在 1 分钟内决定**今天先处理哪一件事** | 挑一件待办并进到那一件事 | 账号矩阵列表与今日待办=零点击可见;异常值、本月最好、检索与随手记=一次点击可达 | 账号行=账号名(主标识)+ 今日该发/已发/效果(3 条次级)+ 异常徽章 |
| P2 选题雷达 | 让编导在 3 分钟内**找到一条能做的选题** | 把一条选题推进下一步 | 监控概览四数、对标内容列表、选题库=零点击可见;评论区洞察、灵感速记=一次点击可达 | 对标行=标题(主标识)+ 账号 + 倍数 + 时间;选题行=选题(主标识)+ 来源 + 状态 |
| P3 资产库 | 让编导在 2 分钟内**存一条拆解结果、或引用一条已存的** | 入库一条 / 引用一条 | 分区切换、条目列表=零点击可见;单条详情、引用入口=一次点击可达 | 条目行=条目摘要(主标识)+ 出处 + 草稿/已入库 + 采集时间 |
| P4 创作台 | 让编导在一条内容上**把当前环节推到下一环节** | 推进到下一环节 | 环节进度、当前环节工作区、当前内容标识=零点击可见;资产引用区、版本列表=一次点击可达 | 版本行=vN(主标识)+ 语义名 + 时间 + 当前标记 |
| P5 发布中心 | 让投放**确认发出这一批版本** | 确认发布 | 检查结果、各版本预览与逐版编辑、确认发布=零点击可见;目标选择、发布记录入口=一次点击可达 | 版本行=账号/平台(主标识)+ 字数 + 检查结论;记录行同 P8 |
| P6 账号画像 | 让内容负责人**改好并保存一个账号的画像** | 保存这一份画像 | 画像六维、账号列表=零点击可见;记忆条目、关联内容=一次点击可达 | 账号行=账号名(主标识)+ 平台 + 内容数;记忆行=日期(主标识)+ 来源 + 一句话 |
| P7 复盘台 | 让内容负责人**确认归因并写回这个账号** | 确认归因并回写 | 表现数据、归因结论区、待复盘列表、回写目标提示=零点击可见;历史复盘=一次点击可达 | 待复盘行=内容(主标识)+ 发布账号 + 发布日 + 数据到没到 |
| P8 记录与对账 | 让投放**核销一条发布记录** | 核销一条记录 | 发布记录列表、对账核对区=零点击可见;单条溯源、商单与收支=一次点击可达 | 记录行=内容(主标识)+ 确认人 + 时间 + 版本 + 状态 |
### 1.3 状态覆盖六项(逐页给结论)
判据源:`SKILL.md` 铁律 2 给出的六态清单(loading / empty / error / success / disabled / 无权限)。⚠️ 逐项**数值判据**出自供给可选档的 `craft/state-coverage.md`,本轮未动用可选档 ⇒ **该项本次无供给来源**,故此处只给「有没有、长什么样」的结论,不编阈值。
| 页 | loading | empty | error | success | disabled | 无权限 |
|---|---|---|---|---|---|---|
| P1 | ✅ 矩阵数据加载中(骨架行 + 「正在取矩阵数据」) | ✅ 还没接入账号(给「去账号画像建第一个账号」) | ✅ 数据源不可用(显时间戳 + 重试) | ✅ 默认态 | ✅ 无可处理项时待办区禁用并说明 | ✅ 非管理员看利润字段时的遮罩说明 |
| P2 | ✅ 拉取对标中 | ✅ 监控名单为空(给「录一个对标号」) | ✅ 拉取失败(退路=手工录入) | ✅ 默认态 | ✅ 未选账号时「转入创作」禁用 | ✅ —(不适用:本页对所有角色开放) |
| P3 | ✅ 条目加载中 | ✅ 该分区还没有条目(给「去拆解一条」) | ✅ 读取失败(重试) | ✅ 默认态 | ✅ 无出处的条目「入库」禁用(门禁) | ✅ —(不适用) |
| P4 | ✅ 环节生成中 | ✅ 该环节还没产出(给「开始这一步」) | ✅ 本步失败(保留已产出 + 重试该步) | ✅ 默认态 | ✅ 文案与封面缺一,「进检查态」禁用(封面缺只提示) | ✅ —(不适用) |
| P5 | ✅ 检查中 | ✅ 还没有可发布的版本(回 P4) | ✅ 检查自身失败 ⇒ **按不过处理**(fail-closed) | ✅ 无硬拦、可发 | ✅ 有硬拦项时「确认发布」禁用 | ✅ 未授权账号的版本标「无发布权限」并禁用该版 |
| P6 | ✅ 画像加载中 | ✅ 还没有画像(给「建画像」) | ✅ 保存失败(保留编辑内容) | ✅ 保存成功提示 | ✅ 只读角色时字段禁用 | ✅ 非本人负责账号:可看不可改 |
| P7 | ✅ 读数据中 | ✅ 还没有可复盘的内容 | ✅ 数据读不到 ⇒ 转手工录入表现 | ✅ 回写成功提示 | ✅ 未确认归因时「回写」禁用 | ✅ —(不适用) |
| P8 | ✅ 记录加载中 | ✅ 还没有发布记录 | ✅ 读取失败(重试) | ✅ 核销成功 | ✅ 未选中记录时「核销」禁用 | ✅ 利润列对非管理员隐藏(列级遮罩) |
> 口径:`disabled` 与 `无权限` 是两件事 —— 前者是「当前条件不满足」(自己能解开),后者是「角色不允许」(自己解不开)。界面文案必须分开写,⛔ 不拿「不可用」一句话糊过去。
---
## 二、令牌表
### 2.1 三层结构(`primitive → semantic → component`)
组件层只引语义层,语义层只引 primitive;⛔ 无孤立 token。
| 层 | 前缀 | 例子 | 规则 |
|---|---|---|---|
| primitive | `--t-*`/`--raw-*` | `--t-accent`、`--raw-fs-12` | 只有原始值,⛔ 别的层不许直接引它以外的东西;本层不许被组件层直接引用 |
| semantic | `--`(无前缀语义名) | `--surface`、`--ink`、`--fs-14` | 只引 primitive |
| component | `--c-*` | `--c-card-radius`、`--c-btn-h` | 只引 semantic |
### 2.2 色值(来源=选定套 `design-system-tiaoyue` 的 `assets/tokens.css` 亮色基线 · 9 页 clipper 实测)
| 语义 token | 值 | 用途 |
|---|---|---|
| `--paper` | `#faf9f5` | 页面底(暖白纸感) |
| `--surface` | `#ffffff` | 面板 / 卡片底 |
| `--surface-soft` | `#f7f6f1` | 次级面(表头、只读块、侧栏选中底) |
| `--ink` | `#1a1a18` | 主文字 |
| `--ink-mute` | `#57564f` | 次级文字 |
| `--ink-faint` | `#8a887f` | 三级文字 / 占位(⛔ 只用于非正文:占位、图标、禁用态) |
| `--line` | `#e7e5dc` | 分隔线(行间 `border-top`) |
| `--line-soft` | `#efeee7` | 更弱的分隔(块内) |
| `--accent` | `#9E4CFF` | 主强调色(品牌紫) |
| `--accent-text` | `#963dff` | accent 当**文字**时用这一档(`#9E4CFF` 直接当文字不达标) |
| `--on-accent` | `#FFFFFF` | 主色上的文字 |
| `--ok` | `#3d7a4f` | 成功态 |
| `--err` | `#b4453a` | 错误态 |
| `--warn` | `#8a5a00` | 提醒 / 异常值 / 软劝 ⚠️ **本项目追加**:选定套亮色基线**没有 warn 档**,而②段 P5 要求「硬的拦住、软的只提醒」必须有两种可见区分 ⇒ 新增一档并在次行登记来源与对比度实测 |
**强调色允许位置(反 slop 要求写明)**:只允许出现在 ① 主按钮的填充底;② 侧栏当前项的**整块浅底**(`color-mix(in srgb, var(--accent) 10%, var(--paper))`,⛔ 不用单侧色条/左侧指示条);③ 链接文字(用 `--accent-text`);④ 焦点环。⛔ 不允许出现在:页面大背景、卡片底、图标填充(除主按钮内图标)、任何渐变。全屏面积 ≤5%。
**禁止**:⛔ 无紫→粉渐变;⛔ 无装饰性发光;⛔ 状态色只用这红/绿/黄三系,不做装饰。
### 2.3 几何 · 字体 · 间距 · 字阶 · 高度层级 · 脚手架
| 项 | 值 | 来源 / 说明 |
|---|---|---|
| 字体 | `"PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "Noto Sans SC", sans-serif` | 选定套实测:源站 `@font-face` 为 0 条,走系统字体栈。⛔ 未手改 |
| 标题字体 | **展示体**:`"Songti SC", "Noto Serif SC", "Source Han Serif SC", "SimSun", Georgia, serif`(正文仍走上面的黑体栈);字重 ≤600 | 2026-10-08 方案 A:选定套源站只给一套系统黑体栈,标题没有自己的性格(基础层 `oil-ui-pro` 把「全页一种无衬线、标题没性格」列为模型默认)。宋体标题 + 黑体正文=「展示 + 正文」两族,符合「字族 ≤2–3」。⛔ 未用 Inter / Roboto / Arial / `system-ui` 关键字 |
| 等宽数字 | `font-variant-numeric: tabular-nums` | 所有数字列,防刷新抖动 |
| 圆角 | 大容器 `24px`(`--t-card-radius`)/面板 `16px`/行与小件 `14px`/输入框 `9px`/按钮 `26px`(药丸) | 全部取自选定套 `<`—— `--card-radius: 24px`、`--ui-radius: 16px`、`--radius: 14px`、`--inp-radius: 9px`、`--btn-radius: 26px` |
| 间距 · 主刻度 | `4 / 8 / 16 / 24 / 32 / 64` | 供布局。块间用 32(同行组间 24),块内用 8/12/16 |
| 间距 · 微网格 | `2 / 4 / 6 / 8 / 12` | **仅供**按钮内衬、徽章内衬、图标间隙 |
| 块间距 / 块内间距 | 32 / 8–16 ⇒ 比值 2.0–4.0 | 判据要求 ≥2 ✅ |
| 字阶定值表(七档,各一个 px) | `--fs-12` 12 / `--fs-14` 14 / `--fs-16` 16 / `--fs-18` 18 / `--fs-20` 20 / `--fs-24` 24 / `--fs-30` 30 | 相邻档差 2/2/2/2/4/6,全部 ≥2 ✅;每档只一个定值,⛔ 不是区间。正文档 `--fs-14`(多数正文)与 `--fs-16`(表单值),落在 14–16 ✅ |
| 高度层级(每层多层叠层) | L1(行/内嵌):`0 1px 1px rgba(26,26,24,.03), 0 2px 6px -2px rgba(26,26,24,.06)`<br>L2(面板):`0 1px 2px rgba(26,26,24,.04), 0 8px 20px -12px rgba(26,26,24,.14), 0 18px 40px -18px rgba(26,26,24,.10)`<br>L3(浮层):`0 2px 4px rgba(26,26,24,.05), 0 14px 32px -12px rgba(26,26,24,.18), 0 32px 64px -24px rgba(26,26,24,.16)` | 每层 ≥2 层叠层 ✅;同层级同值。⛔ 无单层死黑重阴影 |
| 布局脚手架 | 侧栏 **64px 药丸浮栏**(照 tiaoyue `app-sidebar` 的 `w-16`=4rem,⛔ 定值、不随断点收窄;列宽 64px 里放一个随内容高、垂直居中的药丸)+ 主区 `minmax(0,1fr)`;主数据块走**满宽表格**(`.ds-table.tbl-dense`),两栏分栏处用 `1.35fr : .9fr`;窄屏折行交给 ≤640 的横滚标签条 | 骨架档=主区+侧区,已落到具体列宽 |
| 容器与对齐锚点 | 主区左右内衬 32px;表格与块标题左锚点同一条线;数字列右对齐且右锚点对齐块右内衬 | 判据要求「对齐锚点」写明 |
| 浮层 | 居中面板,宽 `min(560px, calc(100vw - 32px))`,内衬 24px;**只有一个可见关闭出口**(右上 ×);遮罩与 `Esc` 也可关,但不计为可见出口 | 满足 Gate-3 的「可见关闭出口唯一」 |
### 2.4 交互清单(唯一交互真相源 · 四列)
**通用规则**(适用于下面所有浮层):每个浮层**只有一个可见关闭出口**(右上 ×,ID 记为 `X-close`);遮罩点击(ID 记为 `X-mask`)与 `Esc` 也能关,但**不视为可见出口**;关闭后焦点回到触发它的那个按钮,Tab 只在层内循环。这三条逐浮层过了一遍,结论在 `3d-审查报告.md` 的浮层表里。下表不再逐浮层重复这三条。
| ID | 元素 | 触发 | 反馈 | 何时不可点 |
|---|---|---|---|---|
| G-05 | 侧栏八个功能项(药丸浮栏,八项一页)+ 各页「功能入口」卡 | 点击 | 切到该页(hash 变、主区重绘);侧栏当前项转中性填充 + 满墨字(照参照物 `is-active`) | 从不可点 |
| G-06 | 顶栏「随手记」 | 点击 | 打开随手记浮层,焦点进输入框 | 从不可点 |
| G-08 | 两处「假设」徽章(P1 页头 / P8「商单与收支」块头) | 点击 | 打开假设浮层(逐条给复核人 / 复核时机 / 结论落点) | 从不可点 |
| G-10 | P1「全局检索与随手记」块里的「全局检索」 | 点击 | 打开检索浮层,焦点进输入框 | 从不可点 |
| X-close | 各浮层右上 × | 点击 | 关闭浮层;焦点回触发它的按钮 | 从不可点 |
| X-mask | 浮层遮罩(层外空白区) | 点击 | 关闭浮层;焦点回触发它的按钮 | 没有浮层时不渲染 |
| STATE-NORMAL | 状态面板 · 「回到正常内容」 | 点击 | 该页回 `ok` 态,主操作恢复 | 仅在非 `ok` 态出现 |
| STATE-RETRY | 出错态 · 「重试一次」 | 点击 | 提示已重试(示意);不改数据 | 仅在 `error` 态出现 |
| STATE-GO | 空态 · 「去〈某页〉」 | 点击 | 跳到该页;浮层关 | 仅在 `empty` 态、且该页定义了去处时出现 |
| R-01 | 随手记浮层 · 输入框 | 输入 | 内容非空时「保存」由禁用转可用 | 从不可点(可输入) |
| R-02 | 随手记浮层 · 保存 | 点击 | 写入选题库「待做」;提示 1.5s 后消失;浮层关闭 | 输入为空时 `:disabled` |
| R-03 | 随手记浮层 · 取消 | 点击 | 关闭,不写入;焦点回触发按钮 | 从不可点 |
| S-01 | 检索浮层 · 输入框 | 输入 | 结果列表按关键字过滤;无结果显示空态行 | 从不可点(可输入) |
| S-02 | 检索浮层 · 结果项 | 点击 | 跳到该结果所属的页;浮层关闭 | 无结果时列表为空(不渲染可点项) |
| A-01 | 假设浮层 · 两处假设条目 | 展示 | 只读,逐条给复核人 / 时机 / 落点 | 不适用(只读,非控件) |
| P1-01 | 今日待办项(每条) | 点击 | 跳到该待办所属的页(选题类→P2、在写→P4、待审→P5、待复盘→P7、待核销→P8) | 该条为「已超期未处理」时仍可点,但带提醒标 |
| P1-02 | 账号矩阵行 | 点击 | 跳到 P6 并选中该账号 | 从不可点 |
| P1-03 | 账号矩阵行 · 「看复盘」 | 点击 | 跳到 P7 并选中该账号的待复盘内容 | 该账号没有可复盘内容时禁用 |
| P1-04 | 异常值提示条目 | 点击 | 跳到 P2 并定位到该对标内容 | 无异常值时整块显示空态(不渲染可点项) |
| P1-05 | 本月最好的一条 | 点击 | 跳到 P7 的该条复盘 | 无数据时禁用 |
| P2-01 | 监控概览 · 「低粉爆款」数 | 点击 | 筛选对标内容列表(只看爆款) | 数为 0 时禁用 |
| P2-02 | 监控概览 · 「异常值」数 | 点击 | 筛选对标内容列表(只看异常) | 数为 0 时禁用 |
| P2-03 | 对标内容行 · 「发起拆解」 | 点击 | 跳到 P3 并带着这条素材(预填原文与出处) | 从不可点 |
| P2-04 | 评论区洞察子区 · 展开/收起 | 点击 | 展开子区并开始抓取(显示抓取中) | 从不可点 |
| P2-05 | 评论区洞察 · 「抓取评论」 | 点击 | 进入抓取中 → 出候选选题列表 | 抓取中时禁用 |
| P2-06 | 候选选题 · 「采纳」 | 点击 | 该条进选题库「待做」;候选行标为已采纳 | 该条已采纳时禁用 |
| P2-07 | 候选选题 · 「忽略」 | 点击 | 候选行标为已忽略(可恢复) | 该条已忽略时禁用 |
| P2-08 | 选题库 · 分组 tab(待做/在写/已用) | 点击 | 列表切换成该组 | 从不可点 |
| P2-09 | 选题行 · 「转入创作」 | 点击 | 建当前内容并跳到 P4;选题转「在写」 | 未选账号时禁用(并在行内说明) |
| P2-10 | 选题行 · 「拆解」 | 点击 | 跳到 P3 并把该选题当成素材 | 从不可点 |
| P3-01 | 分区切换 tab(角度/结构/开场白/标题) | 点击 | 条目列表换成该分区 | 从不可点 |
| P3-02 | 条目行 | 点击 | 右区显示单条详情(原文 / 出处 / 草稿标记) | 从不可点 |
| P3-03 | 待入库区 · 「入库」 | 点击 | 无出处的条目被门禁挡住并说明原因;有出处的转「已入库」 | **无出处或原文缺失时禁用**(门禁) |
| P3-04 | 单条详情 · 「引用到创作台」 | 点击 | 跳到 P4 并把该条目加进资产引用区 | 从不可点 |
| P4-01 | 环节进度 · 七个环节(逐项) | 点击 | 切到该环节;只许回退到已完成的环节 | 未到达的后续环节禁用 |
| P4-02 | 当前环节工作区 · 内容输入框 | 输入 | 「开始这一步」由禁用转可用 | 从不可点(可输入) |
| P4-03 | 当前环节工作区 · 「开始这一步」 | 点击 | 生成中 → 产出内容(写进本环节) | 输入为空时禁用 |
| P4-04 | 资产引用区 · 「从资产库拿一条」 | 点击 | 展开选择器;选中后收进引用区并显示来源 | 资产库为空时禁用并说明 |
| PICK-ASSET | 资产选择器 · 单条 | 点击 | 收进引用区并显示来源;浮层关 | 已引用过的不渲染可点项 |
| P4-05 | 资产引用区 · 「移除引用」 | 点击 | 从引用区移除该条 | 引用区为空时不渲染 |
| P4-06 | 「推进到下一环节」 | 点击 | 当前环节 +1;进度条与工作区跟着变 | 文案与封面缺一,进检查态时禁用(封面缺只提示) |
| P4-07 | 版本列表 · 展开/收起 | 点击 | 展开版本列表浮层 | 从不可点 |
| P4-08 | 版本行 · 「切为当前版」 | 点击 | 该版标为当前版;当前内容标识的版本号跟着变 | 该版已是当前版时禁用 |
| P5-01 | 目标选择 · 展开/收起 | 点击 | 展开账号与平台多选 | 从不可点 |
| P5-02 | 目标选择 · 账号项 | 点击 | 勾选/取消;版本列表跟着增删一版 | 从不可点 |
| P5-03 | 目标选择 · 平台项 | 点击 | 勾选/取消;同上 | 从不可点 |
| P5-04 | 版本预览 tab(逐版) | 点击 | 右区换成该版内容 | 从不可点 |
| P5-05 | 版本内容编辑框 | 输入 | 保存按钮由禁用转可用;标为「已改」 | 从不可点(可输入) |
| P5-06 | 版本内容 · 「保存本版」 | 点击 | 该版内容更新;检查结果跟着重算(回到未检) | 无改动时禁用 |
| P5-07 | 检查结果 · 「复检」 | 点击 | 检查中 → 出结论(硬拦 / 软劝 / 通过) | 检查中时禁用 |
| P5-08 | 「确认发布」 | 点击 | 打开二次确认浮层 | **有硬拦项时禁用**;无版本时禁用 |
| P5-09 | 二次确认 · 「确认发出」 | 点击 | 写发布记录(P8 出现一条);提示成功 | 从不可点 |
| P5-10 | 二次确认 · 「取消」 | 点击 | 关闭浮层,不发;焦点回触发按钮 | 从不可点 |
| P5-11 | 发布记录入口 | 点击 | 跳到 P8 | 从不可点 |
| P6-01 | 账号列表项 | 点击 | 切换右区画像 | 从不可点 |
| P6-02 | 画像六维字段(6 个输入) | 输入 | 「保存画像」由禁用转可用 | 非本人负责账号时禁用(改由角色判定) |
| P6-03 | 「保存画像」 | 点击 | 保存成功提示;未保存时离开给提示 | 无改动时禁用 |
| P6-04 | 记忆条目 · 展开/收起 | 点击 | 展开记忆列表(只追加,不可编辑) | 从不可点 |
| P6-05 | 关联内容行 | 点击 | 跳到 P4 的该条内容 | 无关联内容时整块空态 |
| P7-01 | 待复盘列表项 | 点击 | 右区换成该条的表现数据 | 从不可点 |
| P7-02 | 表现数据 · 「手工录入」 | 点击 | 数据读不到时的降级入口,展开输入 | 数据已读到时不渲染 |
| P7-03 | 归因结论区 · 文本 | 输入 | 「确认归因并回写」由禁用转可用 | 从不可点(可输入) |
| P7-04 | 「确认归因并回写」 | 点击 | 回写到当前账号画像:记忆 +1;显示回写目标 | 归因为空、或未选账号时禁用 |
| P7-05 | 历史复盘 · 展开/收起 | 点击 | 展开历史复盘结论 | 从不可点 |
| P8-01 | 发布记录行 | 点击 | 右区换成该条的对账详情 | 从不可点 |
| P8-02 | 「单条溯源」(可点入) | 点击 | 展开溯源:从记录回到内容与版本 | 从不可点 |
| P8-03 | 对账核对区 · 「核销」 | 点击 | 二次确认 → 该条标「已核销」 | 未选记录时禁用;记录未「已发布」时禁用 |
| CHECKOUT-OK | 核销二次确认 · 「确认核销」 | 点击 | 该条标「已核销」;提示成功;浮层关 | 从不可点 |
| CHECKOUT-CANCEL | 核销二次确认 · 「取消」 | 点击 | 关闭浮层,不核销;焦点回触发按钮 | 从不可点 |
| P8-04 | 「商单与收支」展开/收起 | 点击 | 展开收支条目 🔴 **本块是假设**(见 §三) | 从不可点 |
⚠️ **「可见关闭出口」与「决策型关闭」是两件事,⛔ 不许混成一个数**:每个浮层的中性关闭出口只有一颗 ×(`X-close`),恰好 1 个;**「取消」这类带决策语义的按钮也能关层,但它不是「找出口」用的**,单独登记(`R-03` / `P5-10` / `CHECKOUT-CANCEL`)。这条口径是补出来的 —— 原先自检只数 `.layer-close` 这个类名,于是两颗可见的「取消」完全没进计数,两个二次确认层其实各有两个看得见的关闭控件,判据却报「出口 = 1」。逐浮层的核对结论与触发路径在 `3d-审查报告.md` §六。
**表外可点元素必须为 0** —— 3b 自检里有一条逐集合做双向差集的检查(`#/selftest` 路由自动跑,结果落 `3b-实测记录.md`)。
⚠️ **已撤销的 7 个 ID(不在表内,⛔ 不许再出现在 DOM 里)**:`G-01…G-04`(侧栏分板块后的「一级组」,扁平后没有这一层)、`G-07` 顶栏账号切换器、`G-09` 顶栏演示状态开关、`G-11` 收起侧栏。后三个是 2026-10-08 用户口径「**页面顶上弄这么多乱七八糟的东西**」的直接处置对象 —— 逐样来源排查与处置写在 `3d-审查报告.md` §十。⛔ 撤销一个 ID 时必须**同时把它的 DOM 删掉**,否则判据「页面上每个 data-act 都在清单里」会报红(本轮实测过)。
⚠️ **`A-01` 不是控件**:它是假设浮层里的只读展示行,本表把它列出来是为了让「假设有两处、逐条给复核人 / 时机 / 落点」这件事在清单里看得见。⇒ 它**不进实现清单**(原型里的 `IMPL` 表),自检也不该拿它去点。本表的控件 ID 与 `IMPL` 的键必须**互为子集且相等**,这条由 `_tools/mutate_test.py` 里的 M2/M3 两处变异盯着(漏登记 / 悬空声明各一种)。
### 2.5 组件规格(来源:选定套既有组件族)
| 组件 | 规格(具体值) | 来源 |
|---|---|---|
| 按钮 · 主档 | 高 `40px`,内衬 `12/20`,字号 `16px`,字重 `600`,圆角 `26px`(药丸),底 `--accent`,字 `--on-accent` | 选定套 `--btn-radius/--btn-px/--btn-py`;字号 16 + 字重 600 是**必须的**(见下注) |
| 按钮 · 次档 | 高 `40px`,内衬 `12/20`,字号 `14px`,字重 `500`,圆角 `26px`,底 `--surface`,描边 1px `--line`,字 `--ink` | 同族 |
| 按钮 · 弱档(文字) | 高 `32px`,内衬 `6/12`,字号 `14px`,圆角 `26px`,无底无描边,字 `--accent-text` | 同族 |
| 卡片 · 密卡 | 内衬 `16px`,圆角 `16px`,底 `--surface`,L1 阴影 | 同族 |
| 卡片 · 宽松卡 | 内衬 `24px`,圆角 `24px`,底 `--surface`,L2 阴影 | 同族 `--card-radius/--card-pad` |
| 输入框 | 高 `36px`,内衬 `12/10`,圆角 `9px`,字号 `14px`,底 `--surface`,描边 1px `--line` | 同族 `--inp-*` |
| 徽章 / 状态标 | 高 `22px`,内衬 `2/8`,字号 `12px`,圆角 `999px`,无描边,底为对应状态色 8% 叠加 | 同族 `is-*` 修饰族 |
| 侧栏(`.sidebar`) | **药丸浮栏**:宽 `64px`、内衬 `3px`、圆角 `100px`、底色 `color-mix(in srgb, var(--ink) 5%, transparent)`、描边 `1px color-mix(in srgb, var(--ink) 12%, transparent)`;⛔ 无右边线。高度随内容、`align-self:center` 在 64px 列里垂直居中(⛔ 不拉满整屏) | tiaoyue `.app-sidebar` 实测(`w-16`=64 / `p-[3px]` / `rounded-[100px]` / `bg rgba(100,112,160,.08)` / `border 1px rgba(100,112,160,.14)`),色值换我方 `--ink` 派生;差异:参照物是真浮在页面上(`left:16px`,主区不缩进),我方仍占一列,见 `3d` §十三 |
| 侧栏导航项(`.nav-item` · 只有这一层) | **56 × 78 药丸**:圆角 `54px`、内衬 `16px`、段间距 `6px`、纵向居中;**图标 `24×24` 在上 + 名字 `12px/500/行高 16px` 在下,两者都常驻**(56 − 16×2 = 24px 内容宽 ⇒ 名字只能 2 字);项间**无 gap**;hover/当前态**只换颜色**(`--tfast`),⛔ 不移位、⛔ 不加阴影。非当前项字色 `--ink-faint`;当前项=填充 `color-mix(in srgb, var(--ink) 6%, transparent)` + 满墨 `--ink`(⛔ 不用品牌紫底)。78 = 内衬 32 + 图标 24 + 段间距 6 + 名字行高 16,**四个数动一个就破** | tiaoyue `.nav-item` 实测(`h-[78px] w-14` / `p-4` / `rounded-[54px]` / `gap-1.5` / `text-xs font-medium leading-4` / `is-active` bg `rgba(31,35,41,.06)` + 满墨 / `is-inactive` 字 `rgba(31,35,41,.55)`)。⚠️ 它的图标是**填充字形**(`fill` 走 `currentColor`),我方仍是 mcn-work-shop 那套线性描边图标 —— 换字形等于换一套图标,⛔ 本轮不换 |
| 导航提示(`.nav-tips-layer` / `.nav-tip`) | viewport 级浮层(`position:fixed; inset:0; pointer-events:none`);提示本体深底浅字(`--ink` 底 + `--surface` 字)、字号 `12px`、内衬 `6/8`、圆角 `8px`;跟着当前项的**右缘向右展开**,贴到窗口右缘时反向兜底。**内容=该页的一句话说明**(`NAV[].desc`) | tiaoyue `nav-tips-layer` / `nav-tips-viewport` / `is-expand-right`;它的提示行内容也是**说明文字**(实测「发现灵感与精选内容」)、⛔ 不是名字。⛔ 不做项内 `absolute`:`.sidebar` 是 `overflow-y:auto`,会被剪掉 |
| 页面统计条(`.home-stats` / `.stat-item`) | `grid auto-fit minmax(132px,1fr)`、间距 `16px`、**下边距 `6px`**(照参照物 `.home-stats{margin:0 0 6px}`,2026-10-08 第二轮由内联 `8px` 收进基类);每格白底 + 1px `--line` 描边 + 圆角 `16px` + 内衬 `12/16`;值 `20px/600` + `tabular-nums`,标签 `12px` `--ink-mute`。可点的格(P2 低粉爆款 / 异常值)**用同一套外观**,只有 hover 描边转 `--accent` | 照 P1 首页那一套;用户口径「每个板块的首页 样式参考 MCN工作台首页」 |
| 满宽表格(`.ds-table.tbl-dense`) | 容器 `.panel` + `.table-wrap`(`overflow-x:auto`);表头 `12px/600` `--ink-mute` + 下边框 1px `--line`;行内衬 `4/8`、行间 `border-top` 发丝线、单元格 `vertical-align:middle` + `nowrap`;实测行高 **31px** | 密度契约(一屏 ≥6 行)逼出来的紧凑档;形态照 3c 参照物 P1 的满宽表 |
| 栏内表(`.ds-table.tbl-side`) | 两栏**栏内**的列表:内衬同上,但 ⛔ **不套 `nowrap`** —— 窄栏里 nowrap 会把表推成横向滚动 | 同上,只在窄栏里用 |
| 行级微按钮(`.btn-micro`) | 高 `22px`、内衬 `0/8`、字号 `12px`、圆角 `999px`、无底、字色 `--accent-text`、`:disabled` 时透明度 `.45`。⛔ 表格行里不许用 32px 的 `.btn-sm`:实测会把整行撑到 45px,直接吃掉密度契约 | 同上 |
| 分段控件(`.seg` / `.seg-item`) | 容器 `gap 4px` + 可换行;项高 `32px`(`--c-btn-h-sm`)、内衬 `0/12`、圆角 `999px`、描边 1px `--line`、白底;**选中项 `.is-on` = 整块浅紫底 + `--accent-text` + 字重 600 + 描边转 `--accent`**;`:disabled` 透明度 `.45`。⛔ 不许再用「描边变黑」那套 | 2026-10-08 统一:P2 分组 / P3 分区 / P5 账号多选 / P5 平台多选 / P5 版本 tab **五处**原来一律是 `.btn btn-sm` +**内联** `style="border-color:var(--ink);font-weight:600"` |
| 表单字段(`.field`) | 字段块(标签 + 控件)之间的间距由 `.field + .field{ margin-top:16px }` 出;`.field > .seg{ margin-top:8px }` | 同上:P6 画像六维与 P5 目标选择原来靠内联 `margin-bottom` 一格一格铺 |
| 表格当前行(`.cell-name.is-on`) | 当前行的行名转 `--accent-text`。⚠️ 它是「选中态只有一套」在表格里的落法;⛔ 不许写成内联 `style="color:…"` | 2026-10-08 统一:P3/P6/P7/P8 四张表原来各自用内联 `color` 标当前行 |
| 两栏分栏(`.grid-main-side`) | 宽比 **1.35fr : .9fr**(照外部参考版的 `.grid.cols2`);左=上下文/列表,右=产出/动作/详情;主数据块仍满宽。`≤900px` 落单列 | 用户口径「哪里左右布局的功能照着抄」 |
| 图标(唯一出口 `navSvg(page,size)`) | `viewBox 24` / `fill:none` / `stroke:currentColor` / **`stroke-width:2`** / `stroke-linecap:round` / `stroke-linejoin:round`;尺寸只有三个用法:**侧栏 20px、功能入口卡 22px、`≤640px` 的卡 16px**;颜色只有一处:`--accent-text`(品牌紫的文字档) | 规格**照参照物 mcn-work-shop 的 `svgIcon()` 学**(`public/app.js:201-207`:同样 24 / stroke 2 / 圆头圆角,尺寸卡 22、按钮 16)。⚠️ 参照物给图标配了 **8 个色相**(`ICON_COLORS`),⛔ 不学 —— 与基础层「同一层级保持一致重量、避免每张普通卡片用不同强调色」冲突;⚠️ 我方**只有 8 个图标**(八页各一),因为功能入口卡的图标=**目标页自己的图标**(同一目标在侧栏与卡片上是同一个),⛔ 不另造一套图标库 |
| 功能入口卡(`.data-card`) | **三段纵向**:白底 + 1px `--line` 描边 + 圆角 `16px`(tiaoyue)+ **阴影 `--sh-L1`** + 内衬 `16/16`、段间距 `6px`;卡内三行 —— **图标 `22px`(独占一行)/ 标题 `18px/600`(行高写死 1.35)/ 描述 `14px` `--ink-mute`(行高写死 1.35)**;网格 `.data-cards` `auto-fit minmax(200px,1fr)`、gap `16px`;hover = 描边转 `--accent`(⛔ 不做参照物的 `translateY(-2px)` 位移)。**实测卡高 111px**(参照物同宽下 113px)。`≤1000px` 隐描述;`≤640px` 紧凑档(内衬 `6/8`、图标 `16px`、标题 `16px`、网格最小宽 `160px`) | 2026-10-08 **第二轮**:用户看完第一版仍说「**功能入口的高度还是没有 参考 MCN 的首页的功能入口 按钮的样式和布局**」⇒ 回参照物 `style.css:387-392` + `app.js:332-336` 逐值量。高差 65px 的**主因是排布**(第一版把「图标+标题」并成 `.dc-line` 一行 ⇒ 少一段 + 少两次 `6px` 段间距),次因是内衬 `12/16`→`16/16` 与字号 `16/12`→`18/14`;另补一处原来完全没有的**卡阴影**。差值与「刻意不学」的 3 条(圆角 `12px`/`translateY` 位移/「一个功能一个色」)逐条记在 `3d-审查报告.md` §十二 |
| 功能入口那一行(`.sect-nav`) | **没有小标** —— 统计条之后直接排卡;下边距 `8px`(与后面 `.block` 的 `margin-top:32px` **折叠**,实际间距由 `.block` 决定) | 2026-10-08 第二轮删掉原来的 `<p>功能入口</p>`。两条理由缺一不可:①**参照物就没有**(`.home-stats` 直接接 `.data-cards`);②**密度契约逼的** —— 卡按参照物长高 43px,这 43px 得从别处还回去,而「小标 + 它与卡之间的 6px」合计 **24.6px(实测)**,是这一带最不值钱的高度(卡片自己写着去哪儿) |
| 问答区(`.qa-block` / `.qa-row`) | `.qa-block`:`border-top:1px dashed var(--line)` + `padding-top:8px` + `margin-top:16px`;`.qa-row`:内衬 `6/8`、字号 `14px`、行高 `1.55`;问 `--accent-text` + 500、答 `--ink-mute` 缩进 `1.2em` | 照参照物 `.func-card .qa{border-top:1px dashed}`(`style.css:78`)学的虚线分隔;⚠️ 它的「可复制行 hover 出 📋」**未学**(本项目还没有复制交互) |
> 同屏主档按钮 ≤1(多步流程每步 ≤1):P1 无主档、P2/P3/P4/P5/P6/P7/P8 各 1 个 ✅
> 实底底色 ≥2 种:主档 `--accent`、次档 `--surface`、状态标(ok/err/warn 三色 8% 叠加)✅
> ⚠️ **主档按钮的 16px + 600 不是随手定的**:选定套记录 `#FFFFFF` 压 `#9e4cff` 只有 **4.26:1**(两形态一致,是品牌紫的固有属性),走**大字线 3:1** 才达标 ⇒ 主档按钮文字必须 ≥16px 且加粗;⛔ 小字(<16px 常规字重)压主色在本规范里没有合规解,故不允许出现。
---
## 三、两处假设的显式标注(⛔ 不当已确认需求用)
②段 `2b-界面布局.md` §四 标了两处骨架受限。本轮**尚无用户结论**,按②段给的默认读法做,并在本份与原型里显式标注:
| # | 受影响处 | 假设内容 | 本轮默认读法(按 2b §四) | 复核人 | 复核时机 | 结论落点 |
|---|---|---|---|---|---|---|
| 假设 1 | **P1 的形态**(横幅:`2b` §二 P1 末段) | 矩阵级视图是否真需要(1a 待复核第 5 条 + A1) | **按「需要矩阵级视图」做**:P1 = 矩阵总览,5 个板块全在。若复核为「不需要」,P1 降为「单账号今日」,只留第 1、4 板块,矩阵列表下移到账号切换 | 主会话转用户 | ②段收口时一次性过;③段已按默认读法做,结论到了改这一处 | `2b` §四 + §二 P1;本轮落 `ui/DESIGN.md` 本节 + 原型 P1 标题行的「假设」徽章 |
| 假设 2 | **P8 的第 4 板块**「商单与收支」 | 商单对账进不进第一版、收支口径是否内容级(1a 待复核第 6 条 + A3) | **按「进第一版但属 P2、可整块缺」做**:第 4 板块**渲染出来但标「可点入 + 假设」**,并在展开后给一句「本块依赖未复核项」。第 1、2、3 板块不受影响 | 主会话转用户 | 同上 | `2b` §四 + §二 P8;本轮落 `ui/DESIGN.md` 本节 + 原型 P8 第 4 板块标题行的「假设」徽章 |
**原型的兑现方式**(不占标题区、不写成注脚):两处各在自己的**板块标题同行右侧**挂一个「假设」徽章,**徽章本身可点**(`G-08`)—— 点开的那一份浮层逐条给出复核人 / 时机 / 落点。⛔ 2026-10-08 之前这个入口挂在顶栏(「假设 2 项」),已按用户口径「页面顶上弄这么多乱七八糟的东西」**改挂回徽章自己身上**:假设在哪,详情就在哪。⛔ 假设既没有被当已确认需求写死,也没有被编出答案。
---
## 四、Gate-1 方向门自检(硬闸,结果写在本份末尾)
| # | 检查项 | 结论 | 依据 |
|---|---|---|---|
| 1 | 设计契约十二字段 | ✅ 过 | §一 十二字段全填,无空、无「待定」;重复项逐页列了次级信息;交互清单四列齐全且表外可点元素为 0(3b 实测复核) |
| 1b | 页型判定 | ✅ 过 | 全文工具型;D0 零 `.eyebrow` / 零 `.lead` / 零 `.hero`(原型里这三个类名出现 0 次,`#/selftest` 复核) |
| 2 | 结构骨架(翻译面) | ✅ 过 | 骨架档=主区+侧区(给了理由);板块落位照②段顺序、每块有文字标题;②段分档表每条信息都有落位(§1.2 逐页核对) |
| 2b | 骨架未漂 | ✅ 过 | 八页与板块逐条对得上 `2b`,本段未增删移动(见下表) |
| 3 | 状态覆盖 | ✅ 过 | §1.3 六态逐页有结论;`disabled` 与 `无权限` 分开写 |
| 4 | 令牌表 | ✅ 过 | §2.2/§2.3 色值、字体、间距两档(适用面已分开)、圆角、阴影全为具体值 |
| 4b | 字阶定值表 | ✅ 过 | 七档各一个 px(12/14/16/18/20/24/30),相邻差 2/2/2/2/4/6 ≥2 |
| 4c | 高度层级 | ✅ 过 | L1/L2/L3 每层 ≥2 层叠层,同层级同值 |
| 4d | 布局脚手架 | ✅ 过 | 侧栏 240/200px + 主区 `minmax(0,1fr)`;窄屏变化写具体(标签栏化) |
| 5 | 组件规格 | ✅ 过 | 按钮三档+卡片两档+输入框+徽章均为具体值;同屏主档 ≤1;实底 ≥2 种 |
| 6 | 反 slop | ✅ 过 | 无紫→粉渐变;标题用**展示体**(§2.3「标题字体」,2026-10-08 方案 A 补,⛔ 不用 `system-ui` 关键字);强调色允许位置已写明(§2.2) |
| 7 | 拒绝清单 | ✅ 过 | §1.1 ⑩ 共 **6** 条,每条带可判定判据(≥3 ✅) |
| 8 | token 引用完整性 | ✅ 过 | 三层结构;组件层只引语义层、语义层只引 primitive;无孤立 token |
| 9 | 分档兑现 | ✅ 过 | §1.2 逐页落位;常驻=零点击可见、可点入=一次点击可达;档位未被本段改动 |
| 10 | 供给核对 | ✅ 过 | §〇 已核;选定套 `design-system-tiaoyue`,与本目标记录一致(首次选定) |
**骨架未漂逐页对照**(⛔ 本段未新增 / 移动 / 删除 / 合并):
| 页 | ②段板块(照抄) | 原型落位 | 一致 |
|---|---|---|---|
| P1 | 今日待处理/账号矩阵列表/异常值提示/本月表现最好的一条/全局检索与随手记入口 | 同序 5 块(前两块**满宽顺排**) | ✅ |
| P2 | 对标监控概览/对标内容列表/评论区洞察区/选题库/灵感速记入口 | 同序 5 块 | ✅ |
| P3 | 分区切换/条目列表/单条详情/引用入口 | 同序 4 块 | ✅ |
| P4 | 当前内容标识/环节进度/当前环节工作区/资产引用区/版本列表 | 同序 5 块 | ✅ |
| P5 | 目标选择/各版本预览与逐版编辑/检查结果/确认发布/发布记录入口 | 同序 5 块 | ✅ |
| P6 | 账号列表/画像六维/记忆条目/关联内容 | 同序 4 块 | ✅ |
| P7 | 待复盘列表/这一条的表现数据/归因结论区/回写目标提示/历史复盘 | 同序 5 块 | ✅ |
| P8 | 发布记录列表/单条溯源/对账核对区/商单与收支 | 同序 4 块 | ✅ |
> 板块的**排布位置**:每页的**主数据块**(该页吃密度契约的那张列表)一律做成**满宽表格**、单独成块;余下的块里有「列表/上下文 + 详情/动作」关系的,按 `layouts-tooling.md` §0 判为**侧区型**,在**块内**用左右两栏落实(P3 单条详情|引用入口、P5 各版本预览|检查结果、P6 记忆条目|关联内容、P7 表现数据+归因+改判|回写目标、P8 单条溯源|对账核对区);⛔ 这不是增删板块,是同一批板块在骨架档里的摆法(块内怎么摆归③段)。编辑型板块(P4 环节工作区、P6 画像六维、P5 版本逐版编辑、P8 对账核对区)保持原形态 —— 它们的任务是「填 / 改」,不是「扫一行行」。
>
> **P1 的前两块是满宽顺排**(2026-10-08 第三轮定案):②段把「今日待处理」和「账号矩阵列表」列为第 1、2 块,本段按用户口径「gpt 给的布局……照着抄」把两块都做成**满宽表格、上下顺排**(参照物 P1 就是这两张顺排的满宽表)。⛔ 上一轮这里是「左右并排」——那一版的理由是密度判据(并排放得下 10 行、单列只放得下 5 行);本轮把行高从 67px 压到 **31px**(每格一个短值 + 22px 的 `.btn-micro`)之后,**顺排也够 6 行**(实测首行顶 708px),于是「照抄参照物」与「守住密度契约」不再冲突。实测过程记在 `3b-实测记录.md` §五。
> 若复核认为并排也算动了骨架,回退办法只有一条:把密度判据在 1440×900 下放宽到 ≥5 行 —— **两件事必须挑一件,不能都不做**(原判据下,单列连 6 行都够不着)。
---
## 五、缺口与证据边界(⛔ 不假装支持)
1. **反 AI 味 / 无障碍 / 表单校验 / 动效纪律的逐项数值判据本次无供给来源** —— 这四项出自 §供给·工艺数值判据 的**可选档**(`assets/open-design/craft/` 13 份),本轮未动用可选档 ⇒ ⛔ 不凭感觉编一套顶上。本段实际应用的是**默认档**判据:`execution-runbook.md` §3.3/§3.4 + `layouts-tooling.md` §5.5(五条反「实习生审美」硬判据)。四条已按默认档能做到的部分执行(如 focus-visible 三态、tabular-nums、防溢出三件套、间距只用登记刻度)。
2. **暗色主题本轮不做** —— 选定套的暗色与亮色是两套独立基线,规则是「要暗色就整套切」(`known-conflicts.md` C-01),且暗色实测只覆盖 1 个页面(`/team/onboarding`),而该页正是选定套 §〇 明令生成时避开的页;哪一套亮色才是主线**尚未裁决**。⇒ 本轮只做亮色基线(9 页 clipper 实测),⛔ 不与暗色混搭。要做暗色需先裁决 C-01,属技能侧动作。
3. **`--warn` 是本项目追加的第 14 个语义色** —— 选定套亮色基线只有 ok/err,无 warn;而②段 P5 要求「硬的拦住、软的只提醒」必须有可见区分。追加值与其对比度实测记在 §六。
4. **`1c-用户画像.md` 是零访谈画像** —— 主用户的画像骨架来自 1a §四 三行角色描述,无问卷、无访谈、无行为数据。界面里凡涉及「角色能看什么」的判据都基于它,**不得对外说成基于用户调研**。
5. **3c GPT 会诊本轮未取得外部审查** —— 见 `3c-GPT会诊.md`。未取得 ≠ 已通过。
6. **窄视口 390×844 现已可测(2026-10-08 第七轮解除)** —— 旧写法 `chrome.exe --headless --window-size` 被 Chrome 的窗口宽下限卡在 516px(只能拿到 500px 视口),所以此前契约里凡写 390 的地方一律按 **500×844 实测** 记。现在 `_tools/cap.py` 改走 CDP 的 `Emulation.setDeviceMetricsOverride`,**视口是声明式的、要多少是多少**:已实测 **390×844**(PNG 尺寸当场比对通过)⇒ 这条限制作废。⚠️ 但 390 的**密度**还没纳入逐视口表,⛔ 不许把「能测」当成「达标」写。
7. **密度判据(一屏 ≥6 行)现在只剩 500×844 一个视口不达标**(2026-10-08 第八轮,用户拍板「A 方案」)。⛔ 判据一个字没改 —— 判据原文(`layouts-tooling.md` §1)是「一屏可见行数 ≥ 6(900px 高时)」,**不带宽度条件**。**2026-10-08 第八轮整表重测**(A 方案 + 移动档滚动条修复之后):
| 视口 | P1 账号矩阵(A 方案前 → 后) | P2 对标列表 | 页面外壳 |
|---|---|---|---|
| 1440 / 1024 / 900 / 820 ×900 | 701 → 701px,**6–7 行** ✅(一格未动) | 13–14 行 | 顶栏 49px、侧栏 64px |
| 1280 / 1000 / 960 / 920 / 901 / 840 ×900 | 676–701 → 676–701px ✅(一格未动) | 13–14 行 | 顶栏 49px、侧栏 64px |
| **768 ×900** | 779 → **676px**,**3 → 7 行** ✅ | 14 行 | 顶栏 49px、侧栏 64px |
| **700 ×900** | 872 → **676px**,**0 → 7 行** ✅ | 11 行 | 顶栏 49px、侧栏 64px |
| **640 ×900** | 700 → **685px**,**6 行** ✅ | 13 行 | 顶栏 57px、侧栏转横滚标签条 |
| **560 ×900** | 808 → **700px**,**2 → 6 行** ✅ | 10 行 | 顶栏 57px、侧栏转横滚标签条 |
| 500 ×844 | 882 → **773px**,**−2 → 2 行** ❌ | 8 行 | 顶栏 57px、侧栏转横滚标签条 |
> 🔴 **本表 2026-10-08 第八轮整表重测替换(用户拍板「A 方案」)。** 四处转绿:768(3→7 行)、700(0→7 行)、560(2→6 行)、640(首行顶再降 15px);500×844 由 −2 行回到 2 行,**仍是唯一不达标的一个**。其余 10 个视口**一格未动**。
>
> **A 方案做了两件事**(都在 `≤1000 / ≤820` 两档生效,`auto-fit` **只在真装不下时才缩** ⇒ 宽屏一个像素不动):
> ① 功能入口卡最小宽 `200 → 160px`(768 / 700 的卡由两行折行回到一行);② 统计条最小宽 `132 → 96px`(700 的 4 格由两行回到一行)。
> 外加一处**真缺陷**:移动档标签条里 16px 高的横向滚动条(压进 52px 高的条子里 ⇒ 三成高度是灰杠,还白吃 16px 主区)已藏轨 —— 这是 560 由 5 行到 6 行的那 1 行的来源。
>
> ⚠️ **上一版的错数已改正**:上一版把 **768×900 记成 7 行**,在**改前的版本上**实测是 **5 行 ❌**(首行顶 741px)⇒ 那条数字是错的;错因是旧取证通道的视口宽度歧义(768 恰好卡在卡片「3 列/2 列」阈值上,只差 7px),换成 CDP 声明式视口后不再有这个问题。
>
> 这张表本轮是当**对照**用的:同一台机器、同一套判据,跑了「改前(`_scratch/base.html`)」与「改后」两版各 11 个视口,**PASS/FAIL 逐格完全一致** —— 绿:1440 / 1024 / 1000 / 901 / 900 / 820 / 640;红:768 / 700 / 560 / 500。⇒ 卡长高 43px 这件事是**从别处把高度还回去**做到的,⛔ 不是拿密度换的。
>
> 还法(实测 P1 首行顶 740 → **701**,共 −39px):①删掉「功能入口」小标(−24.6)②统计条下边距 `8 → 6`(−2)③块标题与内容之间的间距 `.block-head` `12 → 8`(P1 上方有三处,−12)。`≤640` 一档另追加一条:卡内衬 `8/12 → 6/8`、图标 `18 → 16`、标题 `18 → 16`、`.block` 上边距 `32 → 24`(实测 724 → **700**,−24px)。
>
> ⚠️ **归属必须说清**:本轮修的是**我自己刚造成的**回归(改卡前 697/6 ✅ → 改完 740/5 ❌)。**768 / 700 / 560 / 500 这四个视口的红是改前就有的,与本轮无关** —— 768/700 的根因是卡块在 768 折成两行、统计条在 700 折成两行;500 是已知缺口。⛔ 本轮没有顺手改它们,免得把「本轮改了什么」和「本来就有什么」搅在一起。
>
> ⚠️ 中途出过一次**窄屏回归**,值得记:加图标那一轮只量了 1440(697px,6 行 ✅)就以为完事,回头跑逐视口表才发现 **640 由 5 行掉到 3 行** —— 原因是卡片变高又加上网格最小宽 180→200,608px 的主区装不下三张卡,折成两行、卡块高度翻倍。**只量契约视口、不回量窄屏,是会漏的。**(第七轮又犯了一次同类错:改完只量 1440,是逐视口表再次把它抓出来。)
成因仍是**页面外壳吃掉首屏**,不是行变肥:行高 31px、各行差 0px、块内分隔 1px,这三条在任何视口都 PASS。三条出路:①把支持宽度下限写成 ≥640px(依据:`1a §七` 已明确第一版不做移动端 App);②压掉每行的次级信息(那是②段定的档位,③段不许改 ⇒ 得回②段改);③动 500px 档的页面外壳。**这三条都要用户拍板,本段一条都没选。** 详见 `3d-审查报告.md` §三 B-15。
> **2026-10-08 第三轮实测:照搬外部参考版那版排版,到底要付什么代价。** 用户看过的外部参考版(`3c-GPT参考版.md`)P1 是**满宽表格顺排**:指标条 → 今日待处理表 → 账号矩阵表。上一轮试过「只改顺排、别的都不动」:**账号矩阵首行顶 724px、行距 67px ⇒ 一屏只装得下 2 行**。本轮把这一版**真的照搬了**(用户口径「gpt 给的布局……照着抄」),同时把每格压成一个短值、行级动作降到 22px 的 `.btn-micro`、行内衬收到 `4/8` ⇒ **行高 31px,首行顶 708px,一屏 6 行(达标)**。⇒ 结论是:**满宽表格顺排与「一屏 ≥6 行」可以兼得,但代价是行高必须压到 31px 上下**(参照物那版行高约 50px,照 50px 来只能装 3 行)。行里的次级信息按「一格一个短值」拆列保留(②段的档位一条没砍),截断掉的只是省略号,完整原文挂在 `title` 上。
8. **截图通道与 DOM 通道的视口口径不同(已修,记账)** —— 同一台机器、同一个 `--window-size`,`--dump-dom` 给的是「窗口 − 16×95」,`--screenshot` 给的就是窗口本身。本轮之前所有截图都因此比标称大 16×95(「1440×900」实际 1456×995)。现已按模式分开算,并要求每次截图后从 PNG 的 IHDR 读真实像素跟目标比,不等即报红。详见 `3b-实测记录.md` §五。
9. **3c 那次独立评审不是「外部 GPT 会诊」** —— 本会话没有对外模型通道,改用了隔离上下文的独立评审执行者(不看源码、不继承制作对话)。它符合 `visual-review.md` 对「隔离执行者」的要求,但与 `SKILL.md` §3c 的异厂商外部审查**不是同一条通道**。**未取得外部审查 ≠ 已通过。** 见 `3c-GPT会诊.md` §〇。
10. **外壳「整页不滚」曾等于「整页不能滚」(2026-10-08 已修,记账)** —— 只抄了 `html,body{height:100%;overflow:hidden}` 而没约束高度链,`.app` 跟着内容长高(1440×900 下 P1 实测 1543px)、`.view` 自己不滚,真正的滚动落在 `<body>` 上,而 body 是 hidden ⇒ **折叠线以下的内容永远拿不到,滚动条也没有**(异常值提示 / 本月表现最好 / 全局检索三块在真机里看不到)。修法:`.app{height:100vh}` + `.main{min-height:0;overflow:hidden}` + `.view{flex:1 1 auto;min-height:0;overflow:auto}`;新增判据「纵向滚动只由主区承担」(自检项数 81 → 82),并配变异 **M14** 证明它不是恒绿。同一处还牵出一个更坏的:自检在窄视口量到的密度**是假数**(守卫只复位了 `window`,实际滚的是 `<body>`)⇒ 旧版「≤767px 才不达标」的结论作废,真边界是 ≤900px。详见 `3b-实测记录.md` §六 第 16、17 条与 §五。
---
## 六、数值取证登记(3d 回填处)
下表「实测值」全部由原型自带的 `#/selftest` 算出来(DOM 取值 + 真实像素计算),⛔ 不是目测。取值口径写在「取法」列;复跑命令见 `3b-实测记录.md`。
| 项 | 契约值 | 实测值 | 取法 |
|---|---|---|---|
| 强调色填充面积占比 | ≤5% | **0.52%**(八页最高一页:创作台;1 个填充块) | DOM 取值:逐个元素比 `backgroundColor` ≡ `--accent`,与视口求交后累加 ÷ 视口面积;不含 选中项浅底(`color-mix` 调出的不算填充)/ 描边 / 文字色 |
| `--warn` `#8a5a00` 对 `--surface` 对比度 | ≥4.5:1 | **5.93:1** | 真实像素计算:WCAG 相对亮度 |
| `--accent-text` `#963dff` 对 `--surface` 对比度 | ≥4.5:1 | **4.76:1** | 同上 |
| `--ink-faint` `#8a887f` 对 `--surface` 对比度 | ≥3:1(仅非正文) | **3.55:1** | 同上 |
| 一屏可容纳记录行数(P1 账号矩阵) | ≥6 @900px 高(⛔ 原文不分档) | **6 行** @契约视口 1440×900(首行顶 697px、行距 31px) | DOM 取值:首屏可用高度 ÷ 行距。⚠️ 判据是「装得下几行」,不是「实际渲染几行」—— 示意数据只有 5 条,实际永远是 5 行(数据用尽,非被截断)。⛔ 逐视口的完整实测表只写在 §五 第 7 条一处,这里不重复 |
| 一屏可容纳记录行数(P2 对标列表) | ≥6 @900px 高 | **13 行** @1440×900(首行顶 471px、行距 31px) | 同上。⚠️ 该块本轮已由行式列表改成满宽表格 ⇒ 容量从 6 行跳到 14 行,**任何视口都达标** |
| P1 行高齐(本段追加判据) | 各行差 ≤2px | **31–31px,差 0px**(十三个视口一致) | DOM 取值:逐行 `getBoundingClientRect().height` |
| 视觉层间距 / 块内相邻行分隔 比值 | ≥2 | **32px / 1px = 32**(4 个视觉层) | DOM 取值。⚠️ 表格行的分隔线画在 `td` 的 `border-top` 上(不是 `.list-row` 自己的),取值要跳过首行、取各行的最大值;⚠️ 除数为 0 时判据作废,已加 0 守卫 |
| 实际在用字号档数(P1) | 4–6 | **6 档**:12 / 14 / 16 / 18 / 20 / 24 px(相邻差 2/2/2/2/4) | DOM 取值:叶子节点 computedStyle |
| 块间距 / 块内间距 比值 | ≥2 | **32 / 8–16 ⇒ 2.0–4.0** | 令牌登记值 + DOM 复核(`gap` 全部落在登记刻度内,9 个刻度) |
| 横向溢出 | 0 | **0**(十三个视口,八页逐页亦为 0) | DOM 取值:`scrollWidth − clientWidth` |
| 内联样式越权(本段追加判据) | 选中态 0 处 / 字号 0 处 | **八页全为 0** | DOM 取值:逐页数 `[style*=border-color]` + `[style*=color]` + `[style*=font-size]` |
| 浮层中性关闭出口 | 恰好 1 | **7 / 7 个浮层均为 1**(另有决策型关闭 0–1 个,单列报数,⛔ 不混进这个数) | DOM 取值:可见的 `[data-act="X-close"]` 计数 |
| 同屏主档按钮 | ≤1 | **逐页 1 个**;P1 无主档(本页只用弱档) | DOM 取值:逐页统计实底按钮 |
| 顶栏高度 | 未写死(只看有没有折行) | **49px**(单行;只放「产品名 + 随手记」两项,**任何宽度都不折行**)。⚠️ 旧值 69px / 93px 都是演示下拉还在的时候 | DOM 取值 |
**同轮实测的其它数值**(一并登记,供 3d 复核):
- P1 账号矩阵:首行顶 697px、行距 31px;块落位 今日待处理@333+249 / 账号矩阵列表@614+249(上下顺排)/ 异常值提示@895+201 / 全局检索与随手记@1128+231。
- P2:对标监控概览@143+121 / 对标内容列表@389+249 / 评论区洞察@670+316 / 灵感速记@1018+99;对标列表首行顶 471px、容量 13 行。
- P1 按钮高度集合 32px(本页主档不用实底;表格行内的动作走 22px 的 `.btn-micro`,⛔ 不进「按钮高度层级」这一档)。
- 控制台报错 **0 条**;量尺寸时四个滚动容器(window / html / body / `.view`)全在零点(两页均核)。
- 强调色填充块数只有 1 个 —— 工具型页面按要求把实底压到最少,主档按钮才用它。
- 侧栏实测(**第七轮**):栏 **64px** 宽、药丸盒高 **664px**(品牌 32 + 8 项 × 78 + 内衬 6 + 描边 2)垂直居中;导航项 **8 个**、每项 **56×78**、图标 `24×24`(`stroke-width 2`)、名字 `12px/500`;`#nav` 直接子元素**全是 `.nav-item`**(第二层 0 个)。`≤640` 转通栏横条后项高 **36px**。
- 功能入口卡实测(**第七轮重测**):**17 张**(八页各 2–3 张),每张=三段纵向「22px 图标/18px·600 标题/14px 描述」;网格 `minmax(200px,1fr)`、gap `16px`;**卡高 111px**(同视口 1249 下,参照物 113px —— 差 2px 来自「描述一行 vs 两行」的取舍,逐值对照见 `3d-审查报告.md` §十二)。
- 界面总宽度 1440 时(实测):`.view` clientWidth **1361**(内容宽 1297);统计条 4 格 × **312.25**(高 77.59);功能入口卡 3 张 × **421.66**(高 **111.19**:内衬 32 + 描边 2 + 图标 22 + 段间距 6 + 标题 24.3 + 段间距 6 + 描述 18.89);`.block-head` 与内容间距 **8px**、统计条下边距 **6px**;P1 十行数据行高 **30.5–31px**(差 ≤0.5px,扫表节奏齐)。
- 顶栏实测 **49px**,内容只有两项(产品名 + 随手记);主区 clientH 851px / scrollH 1356px。
> 契约里写了数字的,3d 已逐条实测回填,「契约值 / 实测值」并排列进 `3d-审查报告.md` §六。⛔ 不目测。
---
## 七、修订记录(收口后回填)
| 轮次 | 改了什么 | 为什么 |
|---|---|---|
| 3a 初版 | 契约、令牌、交互清单、假设标注、Gate-1 自检 | 本份首出 |
| 3d 收口 | ①§1.1 ⑨ 的实测覆盖从 4 个视口改成 7 个;②交互清单补 `CHECKOUT-CANCEL`、`STATE-NORMAL` 按钮文案改「回到正常内容」,并新写「中性出口 / 决策型关闭」的口径说明;③§四 里 P1 并排的反事实数按实测重填(604px→530px、3 行→5 行、209px→214px);④§五 第 7 条整条重写(撤掉自设分档,改成如实登记 ≤767px 的不达标),新增第 8、9 条;⑤§六 表内 8 处旧值按实测回填,并裁掉与 §五 重复的逐视口数 | 收口时逐条实测回填;同时把「同一事实只写一处」落实到密度这项上 |
| 按新技能口径重生成(2026-10-08) | ①§〇 供给口径改成「`oil-ui-pro` **基础层** + 其余**叠加层**」;②§1.1 第 4 条入场编排判据改成「⛔ 不做**逐区块**编排、`@keyframes` ≤1」;③§2.2 强调色允许位置去掉「左侧 3px 指示条」,改**整块浅底**;④§2.5 侧栏导航项改成整块浅紫底 + 字重 600;⑤§六「实际在用字号档数」判据 `≥3` → `4–6`;⑥§六 强调色取值口径去掉「3px 左侧标条」 | 全局技能包同日改了三处口径(左色条禁令、入场编排对齐基础层、在用字号档 4–6 档),本份是按旧口径出的 ⇒ 按新口径重生成 |
| 方案 A 补标题字体(2026-10-08) | §2.3 新增「标题字体」=**展示体**(宋体系);产物加 `--font-display` 令牌并应用到 `h1` / `h2` / `.brand`;§四 Gate-1 第 6 项(反 slop)同步 | 用户拍板方案 A:选定套只给一套系统黑体栈,标题没有自己的性格 —— 与基础层 `oil-ui-pro`「标题要有自己的性格」有距离,也不符「字族 2–3」的对照意图 |
| 外壳分板块 + P1 功能入口卡挪位(2026-10-08) | ①§1① ⑤ 补三条:导航层级(大功能板块 + 每板块一个主页面)、每块主页面的收口形态、P1 只落一处;②§2.3 组件表补「侧栏板块 / 主页标记 / 板块功能入口卡」三行;③§2.4 交互清单 G-01…G-05 注明「=该块主页面入口」「含四个主页面」;④§五 第 7 条下补一段实测(照搬外部参考版的满宽表格顺排 ⇒ 一屏 2 行,压到单行仍 4 行);⑤产物:`#nav` 补基础样式 + 板块间发丝线,导航项加「主页」小标,P1 的功能入口卡从统计条下面移到「今日待处理 + 账号矩阵」之后并排 | 用户 2026-10-08 口径「左侧导航分大功能板块,每个板块一个主页面」+「功能入口还是卡片的形式,并排放到数据下面」 |
| 导航收一层 + 照抄参考版左右布局(2026-10-08) | ①§1① ⑤「导航层级」改成**只有一层=四个大板块**;②同处「主页面的收口形态」改成**四个主页面全铺**;③§1 ⑨ 断点表加 `901–1000` 行、`640–900` 行补 `.grid-main-side`;④§2.3 组件表换成「侧栏板块项(只有这一层)/两栏分栏「.grid-main-side」/功能入口卡」;⑤§2.4 G-05 由「二级页项 P1–P8」改成「各主页面上的功能入口卡」;⑥§五 第 7 条整表重测替换(边界仍是 901px) | 用户 2026-10-08 口径「左侧功能导航 只有大板块的导航 只有一层」+「好好看看 gpt 的原型设计,哪里左右布局的功能照着抄」。产物侧:导航改一层;P1 异常值提示|本月最好、P2 评论区洞察|选题库、P4 工作区|产出+资产引用+版本、P6 记忆条目|关联内容、P7 左(待复盘项+表现数据)|右(归因+确认改判+回写)、P8 对账核对区|商单与收支 全部改两栏;宽比 1:1 → 3:2 |
| 外壳高度链 + 密度重测(2026-10-08) | ①§1 ⑨ 断点表加一行 `901–1024`,并新增「滚动容器」一段(高度链三件套);②§1 ⑨ 与 §五 第 7 条的密度表**整表重测替换**,边界由「768px」改成「901px」;③§五 新增第 10 条(整页不能滚的缺陷 + 窄视口密度是假数);④§五 第 7 条的三条出路里,①的门槛同步改成 ≥901px | 修外壳时牵出两个真缺陷:整页滚不动(内容拿不到)、自检在窄视口量密度是假数(假绿)。见 `3b-实测记录.md` §六 第 16、17 条 |
| 导航改 tiaoyue 图标栏 + 八页统一 P1 页壳 + 主列表表格化(2026-10-08 第三轮) | ①§1① ⑤ 重写:导航层级=**一层八个功能项**;新增「侧栏形态=照 tiaoyue `app-sidebar` 的 64px 图标栏(`nav-item`/`nav-icon`/`nav-tip`,悬停向右浮出名字)」;「主页面的收口形态」改成**八页统一**(页头 → 统计条 → 功能入口卡 → 满宽表格主数据块 → 一处两栏 → 尾块);②§1.1 ④ 四个列表由「行式列表」改「满宽表格」;③§1 ⑨ 断点表整表重写(侧栏 64px 定值、≤640 转带名字的横滚标签条);④§2.3 布局脚手架行改成 64px + 满宽表格;⑤§2.5 组件表把「侧栏导航项 / 侧栏板块项」两行换成「侧栏导航项(图标栏)/导航提示(`.nav-tips-layer`)/页面统计条/满宽表格/栏内表/行级微按钮」六行;⑥§2.4 G-05 改成「侧栏八个功能项 + 各页功能入口卡」;⑦§五 第 7 条密度表**第三轮整表重测替换**(边界 901px → **768px**,并记下「主区越窄反而越差」的反直觉实测);⑧§五 第 7 条下那段「照搬参考版要付什么代价」重写(已照搬,行高 31px 即可兼得);⑨§六 五处旧值按实测回填(10 行→6 行、67-68px→31-31px、5 档→6 档) | 用户 2026-10-08 两条口径:「左侧导航参考 tiaoyue 的导航」+「每个板块的首页 样式参考 MCN工作台首页」。产物侧:`NAV` 改图标栏(8 个内联 SVG + 视口级提示浮层)、`--nav-w` 240→64、八页各补统计条与功能入口卡、P2/P3/P5/P6/P7/P8 的主列表改满宽表格;配套修掉两处**假变异**(M2/M8 注入点跟着形态重指) |
| 顶栏清杂项(2026-10-08 第四轮) | ①§2.4 删掉 `G-07`/`G-09`/`G-11` 三行,`G-08` 改成「两处「假设」徽章」,`G-10` 改成「P1 内那一处」;表下新增「已撤销的 7 个 ID」说明;②§三 假设的兑现方式改成「徽章本身可点」(不再提顶栏入口);③§1 ⑨ 断点表删掉两处顶栏补丁,改成「顶栏不随断点变化」;④§五 第 7 条密度表**第四轮整表重测**(顶栏 49px 全宽度恒定;并**修正 P2 一列的旧数**:P2 已表格化 ⇒ 14 行,不是 6/7 行);⑤§六 三处旧值回填(顶栏 69px→49px、P1 首行顶 708→688、P2 6 行→14 行) | 用户 2026-10-08 口径「**页面顶上弄这么多乱七八糟的东西 是那个技能那个规则引起的 需要详细排查 定位 删除**」。逐样来源排查落在 `3d-审查报告.md` §十:六样里**没有一样是技能要求的** —— 收起侧栏与面包屑来自本项目参照物笔记、两个演示下拉是我造的、全局检索与②段 P1 页内重复、假设入口是我自己挂在顶栏的第二处;唯一被②段硬要求的是**随手记**(`2b` §286「任意页面一次点击内」)⇒ 留。产物侧:顶栏收成「产品名 + 随手记」两项,内衬 16→8 ⇒ 49px |
| 组件口径统一 + 新判据(2026-10-08 第五轮) | ①§1.1 ⑩ 新增第 6 条「⛔ 不用内联样式表达选中态或覆盖字号」,§四 Gate-1 第 7 项由「共 5 条」改「共 6 条」;②§2.5 新增四行组件:**分段控件(`.seg`/`.seg-item`)/表单字段(`.field`)/表格当前行(`.cell-name.is-on`)/两栏分栏**;③§六 新增一行实测「内联样式越权:八页全为 0」;④产物:`<style>` 里加 `.seg` / `.seg-item` / `.field` / `.cell-name.is-on` 四个组件;把**五处**分段控件(P2 分组 / P3 分区 / P5 账号多选 / P5 平台多选 / P5 版本 tab)从「`.btn btn-sm` + 内联 `border-color`」换成 `.seg-item.is-on`;把**四处**表格当前行从内联 `color` 换成 `.cell-name.is-on`;P7 三个数从 `.grid-cards` + 内联字号换成 `.home-stats`/`.stat-item`;P8 对账核对区表从宽松档 `.ds-table` 换成 `.tbl-side`;P6 与 P5 的表单字段从内联 `margin-bottom` 换成 `.field`;行级动作统一 `.btn-micro`(P2-06/07、P4-05/08、P2-09/10) | 用户 2026-10-08 口径「**参考 MCN 工作台的首页各个组件的样式,优化各功能页面首页组件样式**」。起因:全站选中态原有**三套画法**(侧栏浅紫底 / 分段控件内联描边变黑 / 表格当前行内联 accent 文字),字号也有内联覆盖 —— 都是「同一件事多个判定标准」,与用户长期口径冲突。新增的判据配了变异 **M15**(把 P2 分组改回内联写法 ⇒ 自检报红),证明它不是恒绿 |
| 学参照物的组件细节 + 语法门禁(2026-10-08 第六轮) | ①§2.5 新增两行组件(**图标(唯一出口 `navSvg`)/问答区 `.qa-block`**),并把「功能入口卡」那一行重写(补 **22px 图标 + 网格 200px + hover 阴影**);②产物:①**功能入口卡补图标** —— 17 张卡全部改成「22px 图标 + 标题」一行(图标=目标页自己的图标,复用侧栏那 8 个),图标线宽由 1.7 **改 2**(侧栏同步),网格最小宽 180→**200**,hover 补轻阴影;②P1 问答区加**虚线分隔**(`.qa-block`);③`≤640px` 补功能入口卡的紧凑档(内衬 `8/12`、图标 `18px`、最小宽 `160px`、隐小标);④**新增第 5 个门禁 `_tools/check_js.py`**(抠 `<script>` 跑 `node --check` + 多行扫描模板里 HTML 注释中的反引号) | 用户 2026-10-08 口径「**MCN 工作台里面每个组件的样式 高度 ICON 都是需要学习的,比如功能入口,感觉没有学到细节**」。逐件量的原值与我方差距(含**刻意不学**的 3 条与理由)落在 `3d-审查报告.md` §十一。⚠️ 新增门禁的起因:**「模板里的 HTML 注释带反引号」这个坑踩了第 4 次**(每次都在浏览器里才炸、`node --check` 整份 html 报不出来),已做成脚本并做了变异对照(注入反引号 ⇒ 报 FAIL 2 项、退出码 1) |
| 功能入口卡按参照物改三段纵向 + 密度还账 + 取证通道改造(2026-10-08 第七轮) | ①§2.5「功能入口卡」那一行重写(**三段纵向**:图标独占一行/内衬 `16/16`/段间距 `6px`/标题 `18px`/描述 `14px`/卡阴影 L1,卡高 66 → **111px**),新增「功能入口那一行(`.sect-nav`)」一行(**无小标**);②§2.5 统计条那行补 `margin-bottom:6px`、图标那行补 `≤640` 的 16px;③§1① ⑤ 收口形态注明「⛔ 不带小标」;④§五 第 6 条**作废**(390×844 已可测,见下)、第 7 条**第七轮整表替换**(11 个视口,并改正上一版把 768 记成 7 行的错数);⑤§六 功能入口卡与整页尺寸全部按 1440 实测回填;⑥产物:①`.data-card` 改三段纵向 + `.dc-line` 整块删除;②删掉八页的「功能入口」小标;③`.home-stats` 下边距 `8→6` 并**去掉七处内联 `margin-bottom`**(收进基类)、`.sect-nav` 七处内联同样收进基类、`.block-head` 下边距 `12→8`;④`≤640` 紧凑档收紧(内衬 `6/8`、图标 16、标题 16、`.block` 上边距 24);⑤**`_tools/cap.py` 改走 CDP `Emulation.setDeviceMetricsOverride`** —— 不再自起 headless Chrome,改连 9223 上已有的常驻实例,视口由声明式给定(顺带解除 500px 宽度下限,390×844 现已可测);⑥新增 `_tools/measure.py`(几何真值),⚠️ 写完后按其所属规则**已删除**(它自己起 Chrome,与⑤冲突) | 用户 2026-10-08 口径「**功能入口的高度还是没有 参考 MCN 的首页的功能入口 按钮的样式和布局**」+ 反过来点破取证方式「**为什么要重新开浏览器,先检查之前是否开过浏览能否复用**」,并要求把这条写进 `browser-harness` 技能(已写入其「🔴 本机(用户明令)」段)。⚠️ 这一轮最该记的是**顺序**:先按参照物把卡改到位,再逐视口跑判据、发现 1440 由 6 行掉到 5 行,然后回参照物**逐值量**(`style.css:387-392` + `app.js:332-336`)确认卡高 133px vs 我方 68px、差在主因「排布」;还账时**先跑改前基线(`_scratch/base.html`)**,确认 768/700/560/500 那四处红是改前就有的,再逐条还、逐条量 |
| 左侧导航样式对齐 tiaoyue 源站(2026-10-08 第七轮追加) | ①§1① ⑤「侧栏形态」由「64px 图标栏、名字只走悬停」**改成实测口径**「64px 药丸浮栏 + 项 56×78 + 图标 24 在上、2 字短名在下且常驻」;②§1.1 ⑨ 的 `≤640` 行重写(药丸那一套整段还原成通栏横条);③§2.3 断点行与布局脚手架行「图标栏」→「药丸浮栏」;④§2.4 G-05 当前项由「浅紫底」改「中性填充 + 满墨」;⑤§2.5 把「侧栏导航项」一行拆成「侧栏(`.sidebar`)/侧栏导航项(`.nav-item`)」两行并逐值写清,导航提示那行的**内容**由「名字」改「该页说明」;⑥§六 侧栏实测值回填(药丸盒高 664px、项 56×78、图标 24);⑦产物:`.sidebar` 改药丸浮栏、`.nav-item` 改 56×78 药丸(内衬 16/段间距 6/圆角 54/图标 24/名字常驻/中性状态)、`NAV` 短名一律收到 2 字并新增 `desc`、提示改读 `desc`、`≤640` 档补还原规则;⑧全篇「图标栏」改「药丸浮栏」(⛔ 历史修订行里的旧称保留) | 用户 2026-10-08 口径「**左侧导航 样式可以参考 tiaoyue的左侧导航**」。⚠️ 这条**当时没做完**:第三轮只做了形态,而且是照 `library.json` 的**计数**猜的(包里既没有导航几何、`design-system.html` 里也 `app-sidebar` 0 处)⇒ 猜出来的「纯图标栏、名字只走提示」与源站实测**正好相反**。本轮回源站量为:栏 64px 药丸(圆角 100/内衬 3/淡底+淡描边/⛔ 无右边线)、项 56×78 药丸、**图标 24 + 2 字短名都常驻**、当前项=中性填充+满墨、项间无 gap。逐条对照表在 `3d` §十三 |
| A 方案收密度 + 规则侧整改(2026-10-08 第八轮) | ①§1.1 ⑨ 断点表**整表校正**(原表 `901–1024` 与 `901–1000` **区间重叠**,已按代码实际断点拆成 `>1024` / `1001–1024` / `901–1000` / `821–900` / `641–820` / `≤640` 六档不重叠),并补上第八轮新加的两条:`≤1000` 卡最小宽 160px、`≤820` 统计条最小宽 96px;②§五 第 7 条密度表**第八轮整表替换**(768/700/560 三处转绿,只剩 500×844);③§2.5 统计条与功能入口卡两行补最小宽分档;④产物:`≤1000` 卡最小宽 `200→160px`、`≤820` 统计条最小宽 `132→96px`、移动档标签条**藏掉 16px 横向滚动轨**(真缺陷);⑤**规则侧**(`layouts-tooling.md`/`stage-delivery/SKILL.md`/`execution-runbook.md` 三份,见 `复盘-为什么第一版做得很差.md` §七):§5.5.2 判据由「栏宽 240–280px」改成「名字常驻可读」的实质判据、新增 §4.9 导航栏一档、§1 密度契约补适用范围与优先级、新增 §5.6 两条元规则、供给块补「定调与令牌的能力边界」与「craft 无供给时怎么办」、Gate-3 与完成标准补「视觉评分必须落盘」「人工项必须给机检或写死无机检」 | 用户 2026-10-08 三条口径:「1、不光是保持现状,要增加 agent 主导航规则,或优化现有规则」「2、A 方案」「不光是复盘,起反作用的规则要优化或清理」。⚠️ 顺带修掉全局技能包里**三条既有 FAIL**(不是本轮引入):停线规则的**权威写成了 `None`**(=连权威处也不许写,与本条自己的 `why` 矛盾)⇒ 改成 `SKILL.md` 并把规则补进「执行规则」;`stage-proto-doc` 与 `usage-scenario` 两处仍写①段**已废的 `strategy/` 路径** ⇒ 改成 `research/1d-产品策略.md` / `research/1e-使用场景.md` |
---
## 八、说人话自评(判据源 `humanizer-zh`,五维各 10 分)
| 维度 | 分 | 说明 |
|---|---|---|
| 直接性 | 9 | 每节开口就是结论或数值,没有铺垫段 |
| 节奏 | 8 | 以表格与短断言为主,句式偏单一 —— ⚠️ 这是本份的弱项 |
| 信任度 | 9 | 不下「已通过」这种模糊话,未清零的直接写未清零 |
| 真实性 | 10 | 通篇是具体数(161px→53px、530px/5 行)、具体文件、具体命令,没有一句万金油 |
| 精炼度 | 9 | 已按「同一事实只写一处」裁过一轮(密度逐视口表只在 §五 第 7 条出现) |
| **总分** | **45 / 50** | 门槛 ≥45,压线过。扣分点如实写在第 2、5 行,⛔ 不报「已过」了事 |
*(本份是原型的绑定规范:原型只许引本份登记的 token。)*
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

@@ -1,41 +1,74 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""无头 Chrome 取证小工具(③段 3b/3d 用)。
"""取证小工具(③段 3b/3d 用)。
--mode dom : 取渲染后的 DOM(自检输出、数值取证都从这里读)
--mode shot : 截图(视口帧或整页长图)
--mode dom : 取渲染后的 DOM(自检输出、数值取证都从这里读)
--mode shot : 截图(视口帧)
用法示例:
python _tools/cap.py --mode dom --route selftest --out _scratch/selftest.html
python _tools/cap.py --mode shot --route p/p1 --viewport 1440x900 --out _gate_shots/P1-1440.png
python _tools/cap.py --mode shot --route p/p1 --viewport 1440x900 --out _gate_shots/P1-1440.png
⚠️ 本机实测(Chrome 154 · headless=new)——**两条通道对 --window-size 的解释不一样**,
同一台机器、同一个窗口尺寸,拿到的是两个不同视口(探针页实测记录见 3b §五):
--window-size=656,995 ─┬─ --dump-dom ⇒ 视口 640 × 900 (mq<=640 true)
└─ --screenshot ⇒ 视口 656 × 995 (mq<=640 false)
即:dump-dom 通道会从窗口里扣掉滚动条与标题栏(16 / 95),截图通道不扣。
⇒ 想拿到「视口 W × H」,dom 模式要传 (W+16, H+95),shot 模式**原样传 (W, H)**。
⚠️ 视口宽度下限 500(窗口最小 516):`--window-size=390,844` 拿到的仍是 500×844。
要 390px 视口,本机 CLI 做不到(需要 CDP 的 setDeviceMetricsOverride),
所以窄视口只测到 500×844 —— 报告里⛔ 不许写成 390。
🔴 2026-10-08 改:**连已有浏览器实例,不再自己起 headless Chrome**。
旧写法是 `chrome.exe --headless=new --dump-dom/--screenshot`,两个后果:
① 违反本机明令(见 `skills/browser-harness/SKILL.md` 开头「先探测、能复用就复用」);
② 只能靠 `--window-size` 猜视口 —— 而且**两条通道对同一个 window-size 的解释不同**
(dom 通道会扣掉 16 / 95,截图通道不扣),还得在调用侧补偏移量;
更糟的是它有**视口宽度下限 500**(Chrome 窗口最小 516),390px 根本量不了。
现在改用 CDP 的 `Emulation.setDeviceMetricsOverride`:视口是**声明式的,要多少是多少**,
上下限与偏移量的坑一并消失(390px 现在能量了)。
实例地址默认 `http://127.0.0.1:9223`(可用环境变量 `BU_CDP_URL` 覆盖)。
⚠️ 实例没起来时**直接报错退出**,⛔ 不自动拉起浏览器 —— 拉起谁、拉几个,那是人的决定。
"""
import argparse, os, subprocess, sys
from urllib.parse import quote
import argparse, os, socket, subprocess, sys, tempfile
from urllib.parse import quote, urlparse
CHROME = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
HERE = os.path.dirname(os.path.abspath(__file__))
PROTO = os.path.abspath(os.path.join(HERE, "..", "mcn-workbench.html"))
FRAME_W, FRAME_H = 16, 95 # window-size 与视口的实测差值
MIN_VP_W = 500 # 视口宽度下限(Chrome 窗口最小 516)
HARNESS = os.path.expanduser("~/.local/bin/browser-harness.exe")
BU_URL = os.environ.get("BU_CDP_URL", "http://127.0.0.1:9223")
SCRIPT = r"""
import io, json
BU = {bu!r}
url = {url!r}
out = {out!r}
mode = {mode!r}
W, H = {w}, {h}
t = new_tab(url)
cdp("Emulation.setDeviceMetricsOverride", width=W, height=H, deviceScaleFactor=1, mobile=False)
wait_for_load()
wait(0.8)
if mode == 'dom':
vw = js("innerWidth"); vh = js("innerHeight")
assert (vw, vh) == (W, H), "视口不符:要 %dx%d,实到 %dx%d" % (W, H, vw, vh)
html = js("document.documentElement.outerHTML")
io.open(out, 'w', encoding='utf-8').write("<!DOCTYPE html>\n" + html)
print("VIEWPORT %dx%d" % (vw, vh))
else:
vw = js("innerWidth"); vh = js("innerHeight")
assert (vw, vh) == (W, H), "视口不符:要 %dx%d,实到 %dx%d" % (W, H, vw, vh)
capture_screenshot(path=out, full=False)
print("VIEWPORT %dx%d" % (vw, vh))
cdp("Emulation.clearDeviceMetricsOverride")
close_tab()
"""
def _probe(host="127.0.0.1", port=9223):
s = socket.socket()
s.settimeout(1.5)
try:
s.connect((host, port))
return True
except OSError:
return False
finally:
s.close()
def url(route, proto=None):
# Windows 盘符路径 -> file:///E:/...
p = (proto or PROTO).replace("\\", "/")
# ⚠️ 路由不带前导 #/ :本机 bash 是 Git Bash(MSYS),会把 "#/xxx" 当成路径改写成
# "#C:/.../PortableGit/xxx"(实测踩过)⇒ 这里由脚本自己拼 "#/"。
h = route.strip().lstrip("#").lstrip("/")
return "file:///" + quote(p, safe="/:") + ("#/" + h if h else "")
@@ -45,34 +78,44 @@ def main():
ap.add_argument("--mode", choices=["dom", "shot"], required=True)
ap.add_argument("--route", default="p/p1/ok", help="例:selftest / p/p4/empty(⛔ 不带 #/)")
ap.add_argument("--hash", default=None, help="兼容旧参数(不带 #/)")
ap.add_argument("--viewport", default="1440x900", help="目标 CSS 视口,例 1440x900 / 500x844")
ap.add_argument("--viewport", default="1440x900", help="目标 CSS 视口,例 1440x900 / 500x844 / 390x844")
ap.add_argument("--proto", default=None, help="要渲染的文件(默认本目录的 mcn-workbench.html;变异对照用)")
ap.add_argument("--out", required=True)
ap.add_argument("--budget", default="6000")
a = ap.parse_args()
route = a.hash or a.route
vw, vh = [int(x) for x in a.viewport.lower().replace(",", "x").split("x")]
vw = max(vw, MIN_VP_W)
# 🔴 dom 与 shot 两条通道对 --window-size 的解释不同(见文件头实测):截图通道原样等于视口,
# dump-dom 通道要补回被扣掉的 16 / 95。这里分开算,⛔ 别再用同一个偏移量。
win = ("%d,%d" % (vw + FRAME_W, vh + FRAME_H)) if a.mode == "dom" else ("%d,%d" % (vw, vh))
out = os.path.abspath(a.out)
os.makedirs(os.path.dirname(out), exist_ok=True)
cmd = [CHROME, "--headless=new", "--no-sandbox", "--disable-gpu", "--hide-scrollbars",
"--window-size=" + win, "--virtual-time-budget=" + a.budget,
"--run-all-compositor-stages-before-draw"]
if a.mode == "shot":
cmd += ["--screenshot=" + out]
else:
cmd += ["--dump-dom"]
cmd += [url(route, a.proto)]
r = subprocess.run(cmd, capture_output=True)
host = urlparse(BU_URL).hostname or "127.0.0.1"
port = urlparse(BU_URL).port or 9223
if not _probe(host, port):
sys.stderr.write("⛔ %s 上没有浏览器实例在跑。\n"
" 本工具**只连不起**(本机明令)。先把常驻实例起来,或者\n"
" 用 browser-harness 自带的 daemon 流程,再重跑本命令。\n" % BU_URL)
return 2
script = SCRIPT.format(bu=BU_URL, url=url(route, a.proto), out=out, mode=a.mode, w=vw, h=vh)
tf = tempfile.NamedTemporaryFile("w", suffix=".py", delete=False, encoding="utf-8")
tf.write(script)
tf.close()
env = dict(os.environ)
for k in ("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"):
env.pop(k, None)
env["NO_PROXY"] = "127.0.0.1,localhost"
env["BU_CDP_URL"] = BU_URL
r = subprocess.run([HARNESS], stdin=None, capture_output=True, env=env,
input=open(tf.name, "rb").read())
os.unlink(tf.name)
err = r.stderr.decode("utf-8", "replace")
ok = r.stdout.decode("utf-8", "replace")
if a.mode == "dom":
with open(out, "wb") as f:
f.write(r.stdout)
sys.stderr.write("viewport %dx%d → window %s | dom bytes=%d\n" % (vw, vh, win, len(r.stdout)))
sys.stderr.write("dom → %s | %s | bytes=%d\n"
% (out, ok.strip() or "(没说视口)", os.path.getsize(out) if os.path.exists(out) else -1))
else:
# 🔴 截图出来必须**当面对尺寸**:这条通道曾经因为偏移量算错,把 1456×995 当成
# 「1440×900」交付出去(同一份报告里 dump-dom 又按 640 说话 ⇒ 两份证据互相打架)。
@@ -89,10 +132,11 @@ def main():
else:
sys.stderr.write("shot ⛔ 尺寸不符:目标视口 %dx%d,PNG 实际 %dx%d ⇒ 别拿它当 %dx%d 的证据\n"
% (vw, vh, pw, ph, vw, vh))
err = r.stderr.decode("utf-8", "replace")
if "ERROR" in err.upper():
if "Traceback (most recent call last)" in err:
sys.stderr.write(err[-1500:] + "\n")
return 1
return 0
if __name__ == "__main__":
main()
sys.exit(main())
@@ -0,0 +1,102 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""原型 JS 与模板字面量的**语法门禁**(③段 3b/3d 用,只读原型,⛔ 不写盘)。
为什么需要它(不是"为了严谨",是同一个坑踩了 **4 次**的真实事故):
原型是单文件自包含,页面结构写在一堆 JS **模板字面量**里(反引号包起来的字符串)。
只要在模板里的 **HTML 注释**(`<!-- ... -->`)中写出一个反引号,模板字面量就会被提前闭合,
而后面那段被当成 JS 代码解析 —— 症状是**页面静默坏掉**(白屏 / `xxx is not defined` /
`Unexpected identifier`),而 `node --check 整份 html` 是**报不出来**的(html 不是 js),
于是它一路混到浏览器里才炸。
已经踩到的 4 次(每次都是「HTML 注释里带反引号」):
1. P1 的 `.grid.cols2` 注释 → 页面白屏
2. P2 的 `.home-stats` / `.stat-item` 注释 → `stats is not defined`,自检没跑完
3. P2 的 `.grid-cards` / `font-size` 注释 → `Unexpected identifier 'style'`
4. P1 的 `.qa-block` / `.func-card .qa{...}` 注释 → `Unexpected token '{'`
本脚本查两件事:
① **语法**:把 `<script>` 段抠出来交给 `node --check`(⛔ 不是查整份 html)。
② **模板里的反引号**:多行扫描 script 区内的每个 `<!-- ... -->` 块,块内出现反引号即报红。
⚠️ 必须**多行**扫:反引号常在注释的**续行**上(单行 grep 抓不到)。
用法:
python _tools/check_js.py # 查同目录的 mcn-workbench.html
python _tools/check_js.py --proto X.html
退出码:0 = 全过;1 = 有 FAIL。
"""
import argparse
import io
import os
import re
import subprocess
import sys
import tempfile
HERE = os.path.dirname(os.path.abspath(__file__))
DEFAULT_PROTO = os.path.abspath(os.path.join(HERE, '..', 'mcn-workbench.html'))
NODE = r"E:\ProgramData\.workbuddy\binaries\node\versions\22.22.2-6\node.exe"
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--proto', default=DEFAULT_PROTO)
a = ap.parse_args()
src = io.open(a.proto, encoding='utf-8').read()
fails = []
i = src.index('<script>') + len('<script>')
j = src.rindex('</script>')
js = src[i:j]
# ① 语法:把 script 抠出来给 node --check
node = NODE if os.path.exists(NODE) else 'node'
with tempfile.NamedTemporaryFile('w', suffix='.js', delete=False, encoding='utf-8', newline='') as f:
f.write(js)
tmp = f.name
try:
r = subprocess.run([node, '--check', tmp], capture_output=True)
if r.returncode == 0:
print('PASS 语法:<script> 段 ' + str(js.count(chr(10))) + ' 行,node --check 通过')
else:
err = r.stderr.decode('utf-8', 'replace').strip().split('\n')
# 把临时文件里的行号换算回原文件行号
base = src[:i].count('\n') + 1
head = [l for l in err if l.strip()][:4]
fails.append('语法不过:' + ' / '.join(head))
print('FAIL 语法:node --check 报错(下面的行号是 script 段内的,原文件约 +%d 行)' % base)
for l in head:
print(' ' + l)
finally:
os.unlink(tmp)
# ② 模板里的反引号(多行扫描每个 HTML 注释块)
bad = []
for m in re.finditer(r'<!--[\s\S]*?-->', js):
blk = m.group(0)
if '`' in blk:
line = js[:m.start()].count('\n') + src[:i].count('\n') + 2
first = blk.split('\n')[0][:70]
n_tick = blk.count('`')
bad.append('原文件第 %d 行附近:模板里的 HTML 注释含 %d 个反引号 —— 「%s」' % (line, n_tick, first))
if bad:
fails.extend(bad)
print('FAIL 模板里的反引号:')
for b in bad:
print(' ' + b)
else:
print('PASS 模板里的反引号:script 区内所有 <!-- --> 块(多行扫描)都不含反引号')
print()
if fails:
print('结论:FAIL %d 项 —— 上面每一条都会让**页面在浏览器里才炸**(node --check 整份 html 看不到)。' % len(fails))
print('修法:注释里的反引号一律去掉(用 .cls 或 「cls」代替 `.cls`)。')
return 1
print('结论:全过。')
return 0
if __name__ == '__main__':
sys.exit(main())
@@ -1,174 +1,201 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""变异对照:证明自检的判据不是「恒绿」。
做法:把原型复制一份,往里注入一处**已知的假病**,再跑一次自检,
要求它必须报红,并且红在**预期的那一条**上。测完即删临时件。
为什么要这个:一个永远 PASS 的自检等于没有自检。只有「注病 → 报红 → 复原 → 回绿」
这条链走通了,前面那串 PASS 才算证据。
用法:python _tools/mutate_test.py
"""
import os, re, subprocess, sys, tempfile, html
HERE = os.path.dirname(os.path.abspath(__file__))
UI = os.path.abspath(os.path.join(HERE, ".."))
PROTO = os.path.join(UI, "mcn-workbench.html")
PY = sys.executable
# (名称, 说明, 查找串, 替换串, 期望出现的报红片段, 视口[可选,默认 1440x900])
MUTANTS = [
("M1 死控件",
"把 P2-01「低粉爆款」的实现掏空 —— 点它不再有任何反馈",
"'P2-01':()=>{ S.benchFilter='低粉爆款'; paint(); },",
"'P2-01':()=>{},",
"P2-01"),
("M2 未登记的可点元素",
"在页面上塞一个没写进交互清单的 data-act",
"<span class=\"action-cell\"><button class=\"btn btn-sm\" data-act=\"P2-03\"",
"<span class=\"action-cell\"><button class=\"btn btn-sm\" data-act=\"ZZ-99\">野按钮</button><button class=\"btn btn-sm\" data-act=\"P2-03\"",
"未登记的 data-act"),
("M3 悬空声明",
"清单里声明了一个页面上根本不存在的 ID",
"'CHECKOUT-OK':()=>{",
"'ZZ-98':()=>{},\n 'CHECKOUT-OK':()=>{",
"声明了但页面里没有"),
("M4 骨架漂移",
"给 P3 多塞一个板块 —— ②段那份骨架是冻结的,这属于越界",
"${head('分区切换',",
"${head('多出来的板块', '')}<div class=\"panel\"><p class=\"meta\">越界加的块</p></div>${head('分区切换',",
"骨架与②段不一致"),
("M5 对比度越界",
"把 --ink-faint 换成偏白的灰,压到契约线以下",
"--t-ink-faint:#8a887f;",
"--t-ink-faint:#c9c7c0;",
"对比度 --ink-faint"),
("M6 点击无反馈(跳页不同步)",
"把 go() 退回「只改 hash」的写法 —— 点完状态不动,自检应判它没反应",
" S.route=page; S.pageState=st||'ok'; S.layer=null;\n const want='#/p/'+page+'/'+(st||'ok');\n if(location.hash!==want){ try{ location.hash=want; }catch(e){} }\n paint();",
" const want='#/p/'+page+'/'+(st||'ok');\n if(location.hash!==want){ try{ location.hash=want; }catch(e){} }",
"驱动了没反应"),
("M7 行高不齐(放开换行)",
"删掉「行内每段不许换行」这条规则 —— 窄视口里文字一折行,行高就随文字长短乱跳",
".list-row:not(.is-dense) .primary-cell > *,\n"
".list-row:not(.is-dense) .secondary-cell > *{\n"
" min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\n}",
"/* 变异:去掉不许换行 */",
"行高不齐", "768x900"),
("M8 密度退化(内衬变肥)",
"把列表行内衬从 12px 加到 36px —— 行变肥,一屏就装不下 6 行了",
" padding:var(--mg-12) var(--mg-8); border:0; border-top:1px solid var(--line-soft);",
" padding:36px var(--mg-8); border:0; border-top:1px solid var(--line-soft);",
"低于契约 6 行"),
("M9 量尺寸时页面不在零点",
"量 P1 之前先把页面滚下去 —— rect 取到的是相对视口的坐标,滚了之后 top 全变负,"
"「一屏装得下几行」的减法就会凭空变大(这条守卫盯的就是它)",
" guardScroll('P1');",
" window.scrollTo(0,300);\n guardScroll('P1');",
"被滚到", "768x900"),
("M10 行分隔线被关掉",
"把选择器退回成 `.list-row:first-child` —— 每行都包在 <li> 里,于是每行都是自己 <li> 的 "
"first-child,整张表的分隔线一起消失(原型里修掉过的真缺陷,原样退回)",
"li:first-child > .list-row{ border-top:0; }",
".list-row:first-child{ border-top:0; }",
"行分隔线根本没画出来"),
("M11 浮层没有遮罩",
"去掉遮罩层 —— 「点层外空白关掉浮层」这条通道就没了",
"const lh=layerHTML();\n $('#layer-root').innerHTML = lh ? `<div class=\"layer-mask\" data-act=\"X-mask\" aria-hidden=\"true\"></div>`+lh : '';",
"const lh=layerHTML();\n $('#layer-root').innerHTML = lh;",
"没有遮罩"),
("M12 关掉浮层后焦点不还回去",
"把 closeLayer 退回「只清状态」的写法 —— 焦点会掉回 body,键盘用户就断了",
" const back=layerTrigger;\n S.layer=null; paint();\n if(back){ const el=document.querySelector('[data-act=\"'+back+'\"]'); if(el) el.focus(); }",
" S.layer=null; paint();",
"关掉后焦点没回到"),
("M13 浮层多出一个中性关闭出口",
"给「随手记」再加一颗 ×(多一个 X-close)—— 一个层两个中性出口会让用户找不着北,"
"这条判据原先只数 .layer-close 类名,多出来的是同类,应当报红",
" const close=`<button class=\"layer-close\" data-act=\"X-close\" aria-label=\"关闭\">×</button>`;",
" const close=`<button class=\"layer-close\" data-act=\"X-close\" aria-label=\"关闭\">×</button><button class=\"layer-close\" data-act=\"X-close\" aria-label=\"再关一次\">×</button>`;",
"中性关闭出口 = 2"),
]
def read_out(dom_path):
s = open(dom_path, encoding="utf-8", errors="replace").read()
m = re.search(r'<div class="st-out" id="selftest-out">(.*?)</div>', s, re.S)
if not m:
return None
return html.unescape(re.sub(r"<[^>]+>", "", m.group(1)))
def run(proto, vp="1440x900"):
out = os.path.join(tempfile.gettempdir(), "mut-selftest.html")
r = subprocess.run([PY, os.path.join(HERE, "cap.py"), "--mode", "dom", "--route", "selftest",
"--viewport", vp, "--proto", proto, "--out", out],
capture_output=True, text=True)
if not os.path.exists(out):
return None
return read_out(out)
def headline(text):
m = re.search(r"自检结果:PASS (\d+) / FAIL (\d+)", text or "")
return (int(m.group(1)), int(m.group(2))) if m else None
def main():
src = open(PROTO, encoding="utf-8").read()
base = run(PROTO)
hb = headline(base)
print("基线(未注入):PASS %s / FAIL %s" % hb if hb else "基线读不到自检输出")
if not hb or hb[1] != 0:
print("⛔ 基线就不是全绿 ⇒ 先修原型,别急着做变异对照。")
return 2
bad = 0
for row in MUTANTS:
name, why, find, repl, expect = row[:5]
vp = row[5] if len(row) > 5 else "1440x900"
if find not in src:
print("⚠️ %s:找不到注入点,跳过(注入点失效本身也要修)" % name)
bad += 1
continue
tmp = os.path.join(tempfile.gettempdir(), "mut-proto.html")
with open(tmp, "w", encoding="utf-8") as f:
f.write(src.replace(find, repl, 1))
text = run(tmp, vp)
h = headline(text)
os.remove(tmp)
if not h:
print("❌ %s:注入后自检跑不出来(连输出都没有)" % name)
bad += 1
continue
caught = h[1] > 0 and expect in (text or "")
print("%s %s:注入(%s) ⇒ PASS %d / FAIL %d | %s" %
("✅" if caught else "❌", name, why, h[0], h[1],
"报红且红在预期处(%s,视口 %s)" % (expect, vp) if caught
else "**没在预期处报红(期望含「%s」,视口 %s)**" % (expect, vp)))
if not caught:
bad += 1
print()
print("变异对照:%d / %d 通过" % (len(MUTANTS) - bad, len(MUTANTS)))
if bad == 0:
print("⇒ %d 处假病全部被自检抓住,且基线回绿:这套判据不是恒绿的。" % len(MUTANTS))
return 0 if bad == 0 else 1
if __name__ == "__main__":
sys.exit(main())
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""变异对照:证明自检的判据不是「恒绿」。
做法:把原型复制一份,往里注入一处**已知的假病**,再跑一次自检,
要求它必须报红,并且红在**预期的那一条**上。测完即删临时件。
为什么要这个:一个永远 PASS 的自检等于没有自检。只有「注病 → 报红 → 复原 → 回绿」
这条链走通了,前面那串 PASS 才算证据。
用法:python _tools/mutate_test.py
"""
import os, re, subprocess, sys, tempfile, html
HERE = os.path.dirname(os.path.abspath(__file__))
UI = os.path.abspath(os.path.join(HERE, ".."))
PROTO = os.path.join(UI, "mcn-workbench.html")
PY = sys.executable
# (名称, 说明, 查找串, 替换串, 期望出现的报红片段, 视口[可选,默认 1440x900])
MUTANTS = [
("M1 死控件",
"把 P2-01「低粉爆款」的实现掏空 —— 点它不再有任何反馈",
"'P2-01':()=>{ S.benchFilter='低粉爆款'; paint(); },",
"'P2-01':()=>{},",
"P2-01"),
("M2 未登记的可点元素",
"在页面上塞一个没写进交互清单的 data-act。"
"⚠️ 2026-10-08 改:P2 的「对标内容列表」已由行式列表改成满宽表格,"
"原来那个注入点(.action-cell 里的 P2-03)**在文件里已经不存在了** —— 脚本本来会直接"
"判「找不到注入点、跳过」,那等于这条变异悄悄失效 ⇒ 注入点跟着形态换到表格那一行。",
"<td class=\"cell-act\"><button class=\"btn-micro\" data-act=\"P2-03\"",
"<td class=\"cell-act\"><button class=\"btn-micro\" data-act=\"ZZ-99\">野按钮</button><button class=\"btn-micro\" data-act=\"P2-03\"",
"未登记的 data-act"),
("M3 悬空声明",
"清单里声明了一个页面上根本不存在的 ID",
"'CHECKOUT-OK':()=>{",
"'ZZ-98':()=>{},\n 'CHECKOUT-OK':()=>{",
"声明了但页面里没有"),
("M4 骨架漂移",
"给 P3 多塞一个板块 —— ②段那份骨架是冻结的,这属于越界",
"${head('分区切换',",
"${head('多出来的板块', '')}<div class=\"panel\"><p class=\"meta\">越界加的块</p></div>${head('分区切换',",
"骨架与②段不一致"),
("M5 对比度越界",
"把 --ink-faint 换成偏白的灰,压到契约线以下",
"--t-ink-faint:#8a887f;",
"--t-ink-faint:#c9c7c0;",
"对比度 --ink-faint"),
("M6 点击无反馈(跳页不同步)",
"把 go() 退回「只改 hash」的写法 —— 点完状态不动,自检应判它没反应",
" S.route=page; S.pageState=st||'ok'; S.layer=null;\n const want='#/p/'+page+'/'+(st||'ok');\n if(location.hash!==want){ try{ location.hash=want; }catch(e){} }\n paint();",
" const want='#/p/'+page+'/'+(st||'ok');\n if(location.hash!==want){ try{ location.hash=want; }catch(e){} }",
"驱动了没反应"),
("M7 行高不齐(把某一行撑高)",
"只把表里**第一行**的单元格内衬撑大 —— 模拟「某一行被状态标或长文字撑高」这件事:"
"一旦行高不齐,扫表时节奏就乱了。"
"⚠️ 2026-10-08 改:P1 两块已由行式列表改成表格,原来那条「放开换行」的注入对表格无效"
"(表格列宽自适应、根本不折行,是假对照)⇒ 换成直接撑高一行。",
"table.ds-table.tbl-dense .cell-lead{ font-weight:600; }",
"table.ds-table.tbl-dense tbody tr:first-child td{ padding:20px var(--mg-8); }\ntable.ds-table.tbl-dense .cell-lead{ font-weight:600; }",
"行高不齐", "1440x900"),
("M8 密度退化(内衬变肥)",
"把表格行的内衬从 4px 加到 36px —— 行变肥,一屏就装不下 6 行了。"
"⚠️ 2026-10-08 改:密度判据量的已是 P1 那张满宽表格(.tbl-dense 的 td 内衬),"
"原来注在 .list-row 内衬上、对表格无效(假对照)⇒ 注入点换到表格的 td 内衬。",
"table.ds-table.tbl-dense td{ padding:var(--mg-4) var(--mg-8); vertical-align:middle; white-space:nowrap; }",
"table.ds-table.tbl-dense td{ padding:36px var(--mg-8); vertical-align:middle; white-space:nowrap; }",
"低于契约 6 行"),
("M9 量尺寸时页面不在零点",
"量 P1 之前先把主区滚下去 —— rect 取到的是相对视口的坐标,滚了之后 top 全变负,"
"「一屏装得下几行」的减法就会凭空变大(这条守卫盯的就是它)。"
"⚠️ 2026-10-08 改:注入点从 window.scrollTo 换成 .view.scrollTop —— 外壳修过之后"
"整页的滚动容器就是 .view,window 根本滚不动,拿 window 注入等于没注入(假对照)。",
" guardScroll('P1');",
" document.querySelector('.view').scrollTop=300;\n guardScroll('P1');",
"没回零点", "768x900"),
("M10 行分隔线被关掉",
"把表格行的分隔线(td 的 border-top)关掉 —— 一格一格的表读起来就没有行界了。"
"⚠️ 2026-10-08 改:判据现在量的是 P1 那张表的 td 边框,注入点也跟着从 `.list-row` 换过来"
"(原来那条注在 `.list-row:first-child` 上,对表格无效,是假对照)。",
"table.ds-table td{ padding:var(--mg-8); border-top:1px solid var(--line-soft); vertical-align:top; }",
"table.ds-table td{ padding:var(--mg-8); vertical-align:top; }",
"行分隔线根本没画出来", "1440x900"),
("M11 浮层没有遮罩",
"去掉遮罩层 —— 「点层外空白关掉浮层」这条通道就没了",
"const lh=layerHTML();\n $('#layer-root').innerHTML = lh ? `<div class=\"layer-mask\" data-act=\"X-mask\" aria-hidden=\"true\"></div>`+lh : '';",
"const lh=layerHTML();\n $('#layer-root').innerHTML = lh;",
"没有遮罩"),
("M12 关掉浮层后焦点不还回去",
"把 closeLayer 退回「只清状态」的写法 —— 焦点会掉回 body,键盘用户就断了",
" const back=layerTrigger;\n S.layer=null; paint();\n if(back){ const el=document.querySelector('[data-act=\"'+back+'\"]'); if(el) el.focus(); }",
" S.layer=null; paint();",
"关掉后焦点没回到"),
("M13 浮层多出一个中性关闭出口",
"给「随手记」再加一颗 ×(多一个 X-close)—— 一个层两个中性出口会让用户找不着北,"
"这条判据原先只数 .layer-close 类名,多出来的是同类,应当报红",
" const close=`<button class=\"layer-close\" data-act=\"X-close\" aria-label=\"关闭\">×</button>`;",
" const close=`<button class=\"layer-close\" data-act=\"X-close\" aria-label=\"关闭\">×</button><button class=\"layer-close\" data-act=\"X-close\" aria-label=\"再关一次\">×</button>`;",
"中性关闭出口 = 2"),
("M14 外壳高度链没约束住(整页滚不动、折叠线以下拿不到)",
"把 .app 的 height:100vh 退回 min-height:100vh —— 就是 2026-10-08 修掉的那个真缺陷的原样:"
"主区跟着内容长高、自己不滚,滚动落回 <body>,而 body 是 overflow:hidden,"
"于是内容掉到折叠线以下就永远拿不到",
"grid-template-rows:minmax(0,1fr); height:100vh; }",
"grid-template-rows:minmax(0,1fr); min-height:100vh; }",
"高度链没约束住"),
("M15 用内联 style 表达选中态(组件口径被破坏)",
"把 P2 选题库分组那个分段控件改回「`.btn btn-sm` + 内联 border-color:var(--ink)」的写法 ——"
"这正是 2026-10-08 统一掉的那套旧画法:选中态一旦能被内联样式随便盖,"
"全站就会出现第三套、第四套画法,而「选中态只有一套」这件事就没人看着了。"
"⚠️ 这条变异是给新增判据「组件口径」(自检第 84 项)配的对照 —— "
"没有它,那条判据是不是恒绿就无从证明。",
"<button class=\"seg-item ${S.topicGroup===g?'is-on':''}\" data-act=\"P2-08\"",
"<button class=\"seg-item ${S.topicGroup===g?'is-on':''}\" style=\"border-color:var(--ink)\" data-act=\"P2-08\"",
"内联 style 越权"),
]
def read_out(dom_path):
s = open(dom_path, encoding="utf-8", errors="replace").read()
m = re.search(r'<div class="st-out" id="selftest-out">(.*?)</div>', s, re.S)
if not m:
return None
return html.unescape(re.sub(r"<[^>]+>", "", m.group(1)))
def run(proto, vp="1440x900"):
out = os.path.join(tempfile.gettempdir(), "mut-selftest.html")
r = subprocess.run([PY, os.path.join(HERE, "cap.py"), "--mode", "dom", "--route", "selftest",
"--viewport", vp, "--proto", proto, "--out", out],
capture_output=True, text=True)
if not os.path.exists(out):
return None
return read_out(out)
def headline(text):
m = re.search(r"自检结果:PASS (\d+) / FAIL (\d+)", text or "")
return (int(m.group(1)), int(m.group(2))) if m else None
def main():
src = open(PROTO, encoding="utf-8").read()
base = run(PROTO)
hb = headline(base)
print("基线(未注入):PASS %s / FAIL %s" % hb if hb else "基线读不到自检输出")
if not hb or hb[1] != 0:
print("⛔ 基线就不是全绿 ⇒ 先修原型,别急着做变异对照。")
return 2
bad = 0
for row in MUTANTS:
name, why, find, repl, expect = row[:5]
vp = row[5] if len(row) > 5 else "1440x900"
if find not in src:
print("⚠️ %s:找不到注入点,跳过(注入点失效本身也要修)" % name)
bad += 1
continue
tmp = os.path.join(tempfile.gettempdir(), "mut-proto.html")
with open(tmp, "w", encoding="utf-8") as f:
f.write(src.replace(find, repl, 1))
text = run(tmp, vp)
h = headline(text)
os.remove(tmp)
if not h:
print("❌ %s:注入后自检跑不出来(连输出都没有)" % name)
bad += 1
continue
caught = h[1] > 0 and expect in (text or "")
print("%s %s:注入(%s) ⇒ PASS %d / FAIL %d | %s" %
("✅" if caught else "❌", name, why, h[0], h[1],
"报红且红在预期处(%s,视口 %s)" % (expect, vp) if caught
else "**没在预期处报红(期望含「%s」,视口 %s)**" % (expect, vp)))
if not caught:
bad += 1
print()
print("变异对照:%d / %d 通过" % (len(MUTANTS) - bad, len(MUTANTS)))
if bad == 0:
print("⇒ %d 处假病全部被自检抓住,且基线回绿:这套判据不是恒绿的。" % len(MUTANTS))
return 0 if bad == 0 else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,227 @@
# 复盘:为什么「结构全对但仍然难看」,哪些技能与规则起了反作用
> 2026-10-08 · 用户口径:「现在有设计的感觉了,为什么一开始 用了 oil-ui-pro 和 tiaoyue 的设计样式,界面设计和排版都很差呢,哪些技能和规则起了反作用,需要从头到尾详细复盘」
> 本份是**归因复盘**,不是辩护。凡"我"字开头的都是我的操作责任,与技能无关的会明说。
---
## 〇、三句话结论
1、**技能早就写了治这个病的判据,而且它自己预言了本次事故。** `layouts-tooling.md` §5.5 五条反「实习生审美」硬判据,文末原话:「**§5.5 五条过不了就别交付,它们正是「结构全对但仍然难看」的缺口所在**」—— 这句话就是本次事故的诊断书。病不在"没写",在**这五条被挂成人工勾选项、没有任何取值实现**,而我在 `3d` §九 收口清单里给了 `✅ 自检机核` ⇒ **把"没检查"写成了"已通过"**。这是第一责任。
2、**③段整套验收体系里,「好看」没有载体。** Gate-3 那八项目眼项(裁切 / 重叠 / 失真 / 失效控件 / 缺状态 / 响应式破损 / 控制台报错 / 字体回退异常)**全是"有没有坏"**;runbook §7 完成标准二十几条里**没有一条要求视觉评分**。唯一有"好评判"的是 `oil-ui-pro` 的 10 分制评审(目标 9 分、最多三轮)+「模型默认审美自查」,而它**没有被挂进 ③段的任何一个 Gate** —— 于是它一次都没跑。⇒ **制度上,"丑"不会被任何一关拦下。**
3、剩下是**四条规则被用偏**:供给把"有令牌"当成"有设计"(tiaoyue 包只到调色板级);自建令牌刻度反过来否决参照物原值;密度契约(§1 四条判定要点之一)被升格成全局否决权;「⛔ 不许编」被用成了"少做"。
---
## 一、时间轴:13 轮里,第 8 轮之后全是修正轮
| # | 轮次 | 当时以为的依据 | 事后看的问题 |
|---|---|---|---|
| 1 | 3a 初版 | 供给三处在位、D0 契约十二字段 | 契约本身把"几何"留成了空白(供给里没有几何来源) |
| 2 | 3d 收口 | 收口清单逐条勾 | **§5.5 五条记了 ✅ 但没跑** |
| 3 | 按新技能口径重生成 | 全局技能包改了三处口径 | 追着技能跑,不是在看着界面跑 |
| 4 | 方案 A 补标题字体 | 字阶定值表 | — |
| 5 | 外壳分板块 + P1 功能入口卡挪位 | 用户口径「功能入口还是卡片的形式,并排放到数据下面」 | 自造物料笔记从此进入依据链(C1) |
| 6 | 导航收一层 + 照抄参考版左右布局 | 用户口径「只有大板块的导航 只有一层」+「哪里左右布局的功能照着抄」 | 把"参考版"当成另一套权威,与 tiaoyue 并列 |
| 7 | 外壳高度链 + 密度重测 | 密度契约 | 密度从此变成硬闸 |
| 8 | **第三轮:导航改 tiaoyue 图标栏 + 八页统一 P1 页壳 + 主列表表格化** | 用户口径「左侧导航参考 tiaoyue 的导航」+「每个板块的首页 样式参考 MCN工作台首页」 | **直接违反 `§5.5.2`**(把导航做成纯图标栏、标签隐藏),且这个冲突没报出来 |
| 9 | **第四轮:顶栏清杂项** | 用户点破「页面顶上弄这么多乱七八糟的东西」 | 7 项杂物里 2 项来自我自己写的笔记(C1) |
| 10 | **第五轮:组件口径统一 + 新判据** | 用户口径「参考 MCN 工作台的首页各个组件的样式」 | 选中的态有三套画法 —— 前期从没查过 |
| 11 | **第六轮:学参照物组件细节 + 语法门禁** | 用户点破「样式 高度 ICON 都是需要学习的,感觉没有学到细节」 | 功能入口卡高差 65px 就在这时被量出来,但只当"细节"补,没追根因 |
| 12 | **第七轮:功能入口卡三段纵向 + 密度还账 + 取证通道** | 用户点破「功能入口的高度还是没有 参考…」 | 卡高 68→111px,**主因是排布不是字号** —— 第一版压根没量 |
| 13 | **第七轮追加:左侧导航样式对齐 tiaoyue 源站** | 用户追问「左侧导航 参考 tiaoyue 这个事处理了吗」 | 发现第三轮的导航形态是**照 `library.json` 的计数猜的**,与源站正好相反 |
**读法**:第 8–13 轮共 6 轮,**全部是修正轮,且每一轮都由用户点破触发**。前 7 轮里没有一轮是"用户看完说不错"——界面从来没在任何一个节点被"看过并认可"。
---
## 二、四类反作用(逐条:规则原文 → 它导致了什么 → 证据)
### A 类|判据存在,但没有取值手段(制度缺口 · 3 条)
**A1 §5.5 五条挂在人工勾选项里,其中一条还明确要求「DOM 取值」**
- 规则原文(`execution-runbook.md` §7 完成标准):
`- [ ] 页型已判(营销页 / 工具型,给了依据);工具型页面零 .eyebrow / 零 .lead / 零 .hero,且 layouts-tooling.md §5.5 五条逐条过完(含「标题区零从属小字」的 DOM 取值)`
⇒ 它自己写着要 **DOM 取值**,但**全包没有任何脚本实现这五条**。
- 实测现状(grep 原型 `mcn-workbench.html`):`标题区` **0** / `从属` **0** / `注脚` **0** / `主次` **0** / `主角` **0** / `假装分组` **0**。
⇒ 自检 84 项里,**§5.5.1/§5.5.3/§5.5.4 三条零覆盖**;§5.5.5(无假控件)被自检第 6/7/8 条覆盖;§5.5.2(导航带标签)被**反向违反**。
- 而 `3d` §九 收口清单写着:`| 页型已判;工具型三零 + §5.5 五条逐条过完 | ✅ 自检机核 |`
⇒ **假绿**。这一格是整个事故的开关。
- 后果实例(**现在仍然存在**):
- P1 上 4 张统计卡(实测各 312.25 × 77.59)+ 3 张入口卡(各 421.66 × 111.19)**宽高全等、内部最大字号也全等** ⇒ 正撞 §5.5.3「同屏并列 ≥3 张卡片时,必须有且仅有一张主卡;宽高全部相等且内部最大字号也相等 ⇒ 判不过」。
- 统计条做成了**一个一个白底 + 1px 描边 + 圆角**的卡 ⇒ 正撞 §5.5.4 点名的反例:「**Boxes instead of space** —— Bordering every card to fake grouping」「给每个条目套一个圆角描边卡(本原型 P1/P2 都有)」。
**A2 §5.5.2 明说「主导航默认必须带文字标签」,我做了正相反的事**
- 规则原文(`layouts-tooling.md` §5.5.2):
`主导航默认必须带文字标签(宽 ~240–280px),⛔ 不许一上手就是 52px 纯图标栏`
`允许 64px 纯图标,仅当它有一个明确的可展开入口(折叠按钮),且默认是展开态`
- 我做的(第三轮):**64px 图标栏**,并把 `.nav-label` 设成 `display:none`,宽屏只靠悬停提示给名字。
⇒ 既不是「240–280px 带标签」,也不是「64px 带展开入口」——**两条路都不占**。
- 更关键的是:**这一步是用户口径与技能判据的正面冲突**(用户说「参考 tiaoyue 的导航」,技能说不许一上手就是纯图标栏),而**我当时既没发现、也没把冲突报出来做裁决**。
- 今天的第七轮追加才把它收回一半:2 字短名恢复常驻,但**仍是 64px 窄栏** ⇒ §5.5.2 仍不完全满足。(见文末待拍板 1)
**A3 工艺数值判据的 13 份(`open-design/craft/`)在未装时"无供给来源",流程只要求"明说"**
- 规则原文(`execution-runbook.md` §2):`craft 独有的那几项明说「本次无供给来源」`
- 结果:反 AI 味 / 无障碍 / 动效纪律 / 表单校验这几把尺子**本次一把都没有**。
- 而它们量的恰恰是「像不像给人用的」。⇒ 供给表把"可选件"标清楚了,但**没有给替代判据**,"明说"之后就没有下文。
### B 类|规则本身有反作用(用法走偏 · 4 条)
**B1 供给把「有令牌」当成了「有设计」—— 最伤的一条**
- 供给表原文:`| 定调与令牌 | assets/design-systems/(当前 design-system-tiaoyue) | … | 3a 判据、3d 终检 |`
- 实质:这个包**只到调色板级** —— 7 个语义色、圆角 `14/16/26`、字体栈、按钮与输入框令牌。**零几何、零版式、零组件规格。** 三轮实测证据:
- `assets/tokens.css`(43 令牌):**没有一条导航几何**(今天实测)
- `references/design-system.html`(1.4 MB):`app-sidebar` **0 处** —— 它是 clipper 生成的**样例页**,不含源站侧栏
- `references/library.json`:`nav-item` 81 / `nav-icon` 81 / `nav-tip` 81 … **只有计数,没有尺寸**(`summary.tailwind: 659` ⇒ 源站把几何写在 **class 名**里)
- 后果:**"用 tiaoyue" 退化成"用它的颜色"**。几何、间距、组件规格全是我猜的;猜错**还查不出来**,因为没有参照物数值可比。
- 功能入口卡高差 65px(68 vs 133)—— 猜了一个月才被用户点破
- 导航形态猜反("纯图标栏、名字只走提示" vs 源站"图标+2 字名都常驻")—— 第三轮埋、第七轮才挖出来
- **这类"名义供给"比没有供给更坏**:它让人以为答案已经有了,于是不再去量。
**B2 自建令牌刻度反过来否决参照物原值**
- 规则:叠加层只许「更严、更具体」,⛔ 不许放宽基础层。我们因此自建了间距刻度(2/4/6/8/12/16/24/32)、字阶(12/14/16/18/20/24/30)、圆角(14/16/24)。
- 实际用法:**凡是参照物原值不在刻度上的,一律"就近落位"并记一条理由** ——
圆角 12→**16**、网格 gap 14→**16**、内衬 `16px 18px`→**`12px 16px`**、标题 17→**16**、描述 14→**12**、面板内衬 24→**12**。
- 后果:**每一条都合理,累积起来就是"不像"。** 参照物成了可协商的,刻度成了不可逾越的。功能入口卡 65px 高差里,光内衬与字号就占了 12px,剩下 65px 才是排布——但第一版**连排布都没量**。
**B3 密度契约(§1 四条判定要点之一)被升格成全局否决权**
- 原文(`layouts-tooling.md` §1,行式列表的判定要点之一):
`一屏可见行数 ≥ 6(900px 高时)。低于 6 说明行高或内衬过肥 ⇒ 工具型页面一屏放不下东西。`
⇒ 它是一条**版式要点**,不是全站铁律,也没说"它优先于一切"。
- 实际用法:我做成了硬闸(自检第 31/35 条),**只在 P1 账号矩阵 / P2 对标列表上量**,并让它压过一切:
行高压到 **31px**、`≤1000` **隐掉功能入口卡的描述**、删掉「功能入口」小标、面板内衬 24→**12**、功能入口卡从参照物的**三段纵向压成两段**(第二版 68px 就是这么来的)。
- 三个附带缺陷:
① 判据按**当前视口**算 ⇒ 15 个视口里 **4 个永远红**,成了长期背景噪音(人对长期红会脱敏);
② 没定义 `cap` 与数据条数 `n` 的关系,P1 只有 5 条示意数据 ⇒ "数据用尽"也被判红;
③ 每次改外观都要**"还账"**,形成打地鼠(第七轮为了让卡长高,被迫删小标、收统计条边距、收块标题边距,共 39px)。
**B4 「⛔ 不许编 / 不许越界」被用成了"少做"**
- 这是对的禁令。但它落到几何上,变成了:「18px 不在刻度里 ⇒ 用 16」「12px 圆角不在我方体系 ⇒ 用 16」「参照物的 8 色相图标不学」……
- 而且每一条都被写进文档的「刻意不学」,**读起来像是有意识的取舍,实际上是把"省略"制度化**。
- 事后回看,`3d` §十一 里的「刻意不学」至少有一条**不是审美取舍、是规则违反**:统计条「参照物无框靠竖分隔线 vs 我方白底描边卡」—— 那是 §5.5.4 点名的反例,被写成了"品牌层不串"。
### C 类|自造物料冒充技能依据(1 条)
**C1 我自己写的参照物笔记,被当成技能依据写进了交互清单**
- `布局排版参考-mcn-work-shop.md` 是我写的笔记,里面有两处**技能里根本没有**的要求:顶栏「收起侧栏」、面包屑。
- 而交互清单 `G-11` 的证据栏原文写着:「**来源是本项目参照物笔记**」—— 一个自造件冒充了判据来源。
- 后果:顶栏堆到 **7 项**杂物,直到第四轮用户点破「页面顶上弄这么多乱七八糟的东西 是那个技能那个规则引起的」,才逐项排查、删掉 5 项。
### D 类|我自己的操作错误(4 条,与技能无关)
**D1 把"没检查"写成"已通过"** —— 已在 §〇 说明,是第一责任。**收口清单里出现没有取值手段的 ✅,那一刻起后面所有"全绿"都失去了意义。**
**D2 用脚本读数顶替看图评审。** `oil-ui-pro` 要求:新界面/整体改版**选定方向之后**做「截图、评审、修改循环,**10 分制,目标 9 分,默认最多三轮**」,并按视觉语言过三遍(「克制」做减法 / 「细节」在 100%、200% 下看形状对齐状态 / 「模型默认审美自查」看整页截图,出现三项以上没有理由的默认做法就回方向重定主构图)。
它自己还写着「**截图保存成功不等于已经看过**」「只有静态截图,证明不了动效」。
我实际交付的是「84 项断言全绿」——**脚本顶替了眼睛**,而脚本量的不是美。
**D3 改完只量主视口,同一毛病犯了两次。** 第六轮 640 由 5 行掉到 3 行;第七轮改完卡只量 1440(看着 ✅),是逐视口表把"改后四个视口全红"抓出来的。
**D4 量到差异却不接判据。** 统计条「无框 vs 白底描边卡」我量到了、写进了 `3d` §十一 11.2,**却连判定格都是空的**。⇒ 量到了 ≠ 过过判据。
---
## 三、为什么「五道闸门全绿」和「界面很难看」能同时成立
**逐条看五道闸门量的是什么:**
1. **骨架冻结** —— 板块数 / 顺序 / 名字与②段一致 ⇒ 量"结构没漂"
2. **自检 84 项** —— 无死控件 / 无悬空声明 / 状态覆盖 / 行高齐 / 密度 / 对比度 / 内联样式口径 / 外壳高度链 ⇒ 量"完整性 + 不退化"
3. **变异 15/15** —— 上面那套判据不是恒绿 ⇒ 量"判据本身可信"
4. **命名一致性** —— 技能树里的命名与单一可信源 ⇒ 量"文档一致"
5. **语法门禁** —— `node --check` + 模板里的反引号 ⇒ 量"能跑"
⇒ **五条里没有一条量「像不像给人用的」。** 全绿只能证明"这个原型没有坏、没有漂、能跑",**证明不了它好看**。
**而 ③段的验收标准里也确实没有"好看"的位置:**
- Gate-3 的门槛原文是「真实渲染后**肉眼过八项**:裁切 / 重叠 / 失真 / 失效控件 / 缺状态 / 响应式破损 / 控制台报错 / 字体回退异常」—— **八项全是"有没有坏"**。
- runbook §7 完成标准二十几条里,与"外观"相关的只有一句:「工具型页面零 `.eyebrow` / 零 `.lead` / 零 `.hero`」—— 那是**排除营销页三段式**,不是"好看"。
- 唯一有"好评判"的是 `oil-ui-pro` 的评分闭环,**它没有被挂进 ③段的任何 Gate**,也没有任何落盘要求(完成标准里 3c 只要求「含提问原文、参考版原文、四列对照表」)。
**最刺眼的一条证据**:技能作者知道这个缺口,并写进了文档 ——
> `layouts-tooling.md` §6 落地前自检第 4 条:「⭐ §5.5 五条逐条过(标题区无注脚 / 导航带标签 / 并列卡有主次 / 分组不靠边框 / 无假控件)—— **这五条过不了就别交付,它们正是「结构全对但仍然难看」的缺口所在**。」
**缺的不是判据,是把判据变成一条能跑的取值。** 它停在"人工勾选",而人工勾选在没有机械支撑时,退化成了一次 ✅。
---
## 四、已修 / 仍欠
**已修(第 8–13 轮陆续补掉)**
- 功能入口卡形态:从两段压扁的 68px 恢复到参照物的三段纵向 **111px**(参照物同宽 113px)
- 导航:从"纯图标栏 + 名字藏起来"恢复到 **64px 药丸浮栏 + 图标 24 + 2 字短名常驻 + 中性填充当前态**
- 顶栏:7 项杂物 → **2 项**(产品名 + 随手记)
- 选中态:三套画法 → **一套**(并配了变异 M15)
- 取证通道:改成「只连已有实例」,顺带解除 500px 视口下限(390×844 已可测)
- 文档错数:改正 10 处(P2 真值 14 行、768 真值 5 行等)
**仍欠(本次复盘新暴露 + 前次遗留)**
- **§5.5.3 并列卡主次**:P1 上 7 张等权卡(4 统计 + 3 入口)——未处理
- **§5.5.4 分组不靠边框**:统计条 4 张同款描边卡 ——未处理
- **§5.5.2 导航宽度**:现在是 64px 带 2 字名,既非"240–280px 带全名"、也非"64px 带展开入口" ——待拍板 1
- **§5.5 五条无机检**:这是最该补的,补法见 §五 第 2 条
- **craft 13 份无供给来源**:反 AI 味 / 无障碍 / 动效纪律 / 表单校验本次无尺子
- **密度红视口 4 个**(768/700/560/500)——待拍板 2
---
## 五、这次要立的三条(**2026-10-08 第八轮已落地**,见 §七)
1、**闸门必须声明它"不量什么"。** 每条 Gate / 自检项旁边写清本条不管什么,⛔ 不许只写"管什么"。理由:这次事故的本质是"五道闸门全绿"被当成了"已经验收",而闸门从来没有声称自己管好看 —— **它没说的那句话,被我默默补成了"应该都管"**。
2、**凡挂"人工项",必须同时给机检实现;给不出,就在清单里写死"本条无机检"并 ⛔ 不许记 ✅。**
落法:把 §5.5 五条补成自检第 85–89 项 —— ① 标题正下方 8px 内是否有纯说明文字(DOM 取值);② 导航项是否有常驻文字标签(DOM 取值);③ 并列 ≥3 卡是否有一张主卡(宽或字号 ≥1.3×);④ 非控件元素里 `border + border-radius` 在**同一分组用途**上的出现次数 <3(须先声明数哪些元素,控件层排除);⑤ 无假控件(已有第 6/7/8 条,直接引)。
⚠️ **一补上就会红**:③④ 两条当前不合格,得一起改 —— 这是我的实现决策,排在下一步动手。
3、**参照物原值与我方令牌刻度冲突时,冲突必须报出来,⛔ 不许默默"就近落位"。**
落法(第七轮已经用过一次,把它固化成规矩):先量到数值 → 把差异列成表 → 逐条写「学 / 不学 + 理由 + 代价」→ 只有走完这三步才算"参考过参照物"。理由:B2 那 6 处"就近落位"每一处都有理由,**合起来就是"不像"**;没有对照表的"参考"等于没参考。
---
## 六、一句话收束
**这次难看的根因不是"技能没给判据",是"判据没有被执行,而我把它记成了已执行"。**
前半段(技能侧)的缺口是:`§5.5` 停在人工勾选、供给把调色板当设计系统、好评价闭环没挂进 Gate;
后半段(我侧)的缺口是:**在一个没有"好看"载体的验收体系里,我用脚本全绿冒充了验收**。
---
## 七、第八轮:规则侧实际改了什么(逐处清单 · 2026-10-08)
> 用户口径:「**不光是复盘,起反作用的规则要优化或清理**」+「**不光是保持现状,要增加 agent 主导航规则,或优化现有规则**」。
> 下面每一条都改了文件,⛔ 不是只写在复盘里。
**改 `layouts-tooling.md`(③段工具型判据的唯一定稿处)**
- **§5.5.2 判据订正**:从「主导航默认必须带文字标签(**宽 ~240–280px**)」改成「**名字必须常驻可读**」——原判据把**手段(栏宽)当成了目的(名字可读)**,导致 64px 药丸栏 + 2 字常驻短名这种产品上成立的形态判不过,还引出了"把标签设成 `display:none`"的反向事故。新判据判三件事:名字常驻可见 / 字号 ≥12px 不截断 / 图标单独出现只在「有默认展开的展开入口」或「次级工具条」两种情形成立。
- **新增 §4.9 导航栏一档**(§0 形态表同步加「导航型(外壳)」行):把这两轮量到的源站真值写成**两套合规形态**(64px 药丸栏 / 240–280px 宽栏)+ 当前项只改颜色 / 项间距 / 窄屏整段换形态 / **横滚条不许画滚动轨** / 图标一处出口 / 悬停提示写说明不重播名字 / ⛔ 不许照组件清单的计数反推形态。
- **§1 密度契约补适用范围**:明确它只管「行式列表/表格式清单」两档的**主数据块**;给出 `cap = floor((视口高−首行顶)/行距)` 的口径(**与示意数据条数无关**);🔴 **⛔ 不许拿它否决参照物形态**(压卡、砍内衬、删小标三件都点名禁止);**只量一档视口不算过**。
- **新增 §5.6 两条元规则**:① 参照物原值与我方令牌刻度冲突时走三步(量到数值 → 差异列表 → 逐条「学/不学+理由+代价」),⛔ 不许默默"就近落位",且「刻意不学」不得用于掩盖规则违反;② **自造物料(参照物笔记、临时对照表)⛔ 不得作为判据来源**,证据栏只许写「技能原文的 文件:小节」「源站/源文件实测读数」「用户原话」三者之一。
**改 `stage-delivery/SKILL.md` 的供给块(供给的唯一权威处)**
- 「定调与令牌」行补**能力边界**:自带样式库实测只到**调色板级**(语义色/圆角/字体栈/按钮与输入框令牌),**几何与版式不在包内**;⛔ 不许把"供给在位"读成"已经有设计系统了"。
- 「工艺数值判据」行补**无供给时怎么办**:未选可选档时,反 AI 味/无障碍/动效纪律/表单校验四项无来源 ⇒ 必须在 3d 里记为**证据缺口**,⛔ 不许默不作声跳过。
- 「版式骨架」行档数 八 → **九**(追加导航栏)。
**改 `execution-runbook.md`(③段执行手册)**
- **Gate-3 补两条硬要求**:① **「看过」必须有落盘记录**(`oil-ui-pro` 的 10 分制评分闭环写进 3d),⛔ 不许用「自检脚本 N 项全绿」顶替「看过并满意」;② **人工项必须给机检实现,否则写死「本条无机检」**,🔴 **⛔ 不许在没有取值手段的条目上打 ✅**。
- **§7 完成标准补三条勾选项**:视觉评分有落盘记录 / §5.5 五条每条附取值记录 / 供给能力边界已核对且四项缺口已记。
**顺手修掉全局技能包里三条既有 FAIL**(不是本轮引入,复跑闸门时暴露)
- ① `check_naming.py` 的 AUTHORITY:「停线规则」的 `authority` 写成了 **`None`** ⇒ 检查器当成"全包禁写、**连权威处也不许写**",与本条自己的 `why`(口径在本包 `SKILL.md` 的「执行规则」)**自相矛盾**;而 `SKILL.md` 里**根本没有这条规则** ⇒ 内容一处都没落。已把 authority 改成 `SKILL.md` 并把规则补进「执行规则」,`stage-proto-doc` 那句复述改成引用。
- ②③ `stage-proto-doc/SKILL.md:22` 与 `stage-discovery/references/usage-scenario.md:103` 仍写①段**已废的 `strategy/` 路径** ⇒ 改成 `research/1d-产品策略.md` / `research/1e-使用场景.md`。
- 结果:`通过 2057 / 失败 3` ⇒ **`通过 2060 / 失败 0 / 提示 27`**。
**还欠一件(我决定排下一步做,不是等发话)**
- §5.5 五条的**机检实现**还没写:标题注脚 / 导航带标签 / 并列卡主次 / 分组不靠边框 / 无假控件(最后一条已被自检第 6/7/8 条覆盖)。
补成自检第 85–89 项之后,**③④ 两条会立刻报红**(P1 上 4 张统计卡+3 张入口卡宽高与字号全等;统计条是一格一格的描边卡)⇒ 两处要一起改。
@@ -0,0 +1,46 @@
# 布局排版参考 · AI 内容工作台(小曾 · 两视频关键帧)
> 来源:`参考资料/AI内容工作台_功能点与截图/`(16 张关键帧截图 + `AI内容工作台_功能点梳理.md`)。
> 两视频=Bilibili `BV1gsHn6AEk6`(工作台 3.0)+ YouTube `jVHyoCYidLM`(工作台 2.0)。
> 用途:与本项目同品类(内容运营工作台)的**重点布局/风格参照**。⛔ 是参照物,不是照抄目标。
---
## 一、外壳与导航
- **顶部横向 Tab 导航**(⛔ 不是左侧栏):十个 Tab,按创作工作流排序 —— 首页 / 对标与热点 / 选题 / 拆解与沉淀 / 创作 / 发布与经营 / 计划 / 常用助手 / 画板 / 收支。
- 主体是**居中的单列宽内容区**,顶部放一个**全局搜索框**(「搜索选题、文案和资料…」)。
- 子层用**胶囊子 Tab**:如 精选总览 / 对标动态 / AI 热点 / Twitter 动态;创作台内 聊思路 / 写文案 / 起标题 / 做封面 / 发布检查。
## 二、首页
- **Hero 区**=问候 + 大钟(「上午好 11:55」)+ 日期 + 手绘插画底;右侧一张**日历卡**。
- 首页下半:本月之星(本月表现最好的作品)、作品与机会陈列。
## 三、数据与列表
- **指标卡一排**:四张等宽卡,**各自一个色相**(绿 / 紫 / 蓝 / 土黄),卡内=标签 + 大数字 + 单位小字。
- **资产库=表格**:三列(文案原文含标题 / 这类角度叫什么 / 原文怎么写);上方一行说明「18 条资产 · 左右滚动查看各维度,点击名称查看完整拆解」。
- 对标内容:卡片带「N 倍平时互动」的倍数徽标。
## 四、创作流水线
- 顶部子 Tab 本身就是流水线;**发布检查**页给了明确的**分步指示**「1 导入文案 → 2 检查问题 → 3 处理建议 → 4 复核后发布」。
- 主体=左(表单与动作:发布平台 / 正文 / 封面 / 开始检查)+ 右(内容正文预览)。
- 主按钮是**橙色药丸**(更新动态 / 开始检查),次按钮描边。
## 五、视觉调性(这份参考自己的)
- **深色底**(墨绿、近黑),圆角面板约 10–14px,阴影克制。
- **多色强调**:每张指标卡一个色相;主按钮用**橙**。
- 手绘插画(Hero 底、图标)。
- 数字用近似等宽的字形。
## 六、我们能借什么、得先定什么(供③段取舍)
- **可借(风格中性)**:顶部按工作流排序的 Tab、居中宽列 + 顶部搜索、胶囊子 Tab、指标卡一排大数字、创作环节的分步指示、资产用三列表格。
- **⚠️ 冲突(须先定)**:① 深色底 vs 我们的浅色纸感;② **多色指标卡** vs 基础层 `oil-ui-pro` 的「同一层级保持一致重量、避免每张普通卡片用不同强调色」;③ 橙色主按钮 vs 我们的品牌紫。
---
(配套:同目录 16 张截图可逐屏核对;与 `ui/布局排版参考-mcn-work-shop.md` 同形,可并读。)
@@ -0,0 +1,112 @@
# 布局排版参考 · mcn-work-shop(已上线的那套界面)
> 来源(只读取证,⛔ 未改对方任何文件):
> `E:/ProgramData/AIProject/mcn-short-video/project/短视频脚本创作/V1.0/mcn-work-shop/public/`
> —— `index.html`(1.8 KB) + `style.css`(56 KB) + `app.js`(54 KB) + `data-pages.js`(173 KB)。
> 用户 2026-10-08 指令:「AGENT 工具先按照这个界面布局排版」。
> 本份只取**布局排版**(外壳怎么分、内容怎么排、间距与层级),⛔ 不抄它的业务内容。
---
## 一、外壳(三段,但侧栏不是常驻)
- **顶栏 `.topbar`**:品牌位(图标)+ **面包屑 `.crumbs`** + 右侧操作组 `.top-actions`(首页/帮助/设置,三个 ghost 按钮)。
⇒ **导航靠面包屑,不靠固定侧栏**。
- **主区 `main#view`**:单容器装 `.panel`;`.panel` 内衬 24px、自己滚(`overflow:auto`)。
- **整页不滚**:`html, body { height:100%; overflow:hidden }`(注释明写:消除顶栏 1px 边导致的第二层滚动条,滚动统一由 `main#view` 承担)。
- **侧栏只在需要时出现**:产出浏览页才是 `.files-layout`(flex)= `.sidebar`(320px 固定) + `.content-view`(flex:1,预览)。
⛔ 与我们现原型的差别:我们是「240px 固定侧栏常驻 + sticky 顶栏」,八页一律同一外壳;它是**顶栏为主、侧栏按需**。
## 二、首页形态(这一条最值得照搬)
- `.func-grid`:`max-width:900px; margin:0 auto; grid-template-columns:1fr; gap:14px` ⇒ **单列、居中、限宽**。
- `.func-card`:白底 + 1px 边 + **圆角 12px** + 内衬 `16px 18px` + 轻阴影 ⇒ 一个功能一张卡,卡独占一行。
- 🔴 `.qa-row`:**问答行是首页的一等公民** —— `.q` 用强调色(橙)加粗、`.a` 用次级色(灰)缩进;
可复制行 hover 变浅底并出现复制图标。
⇒ **AI 交互以「一问一答的行」呈现**,⛔ 不是把 AI 塞进某个角落的按钮里。
⛔ 我们的原型:八页都是"卡片堆说明文字",**没有问答行这种形态**,AI 只在 P4 有一个产出区(本轮刚补的)。
## 三、内容页形态
- **树 + 预览**:`.sidebar`(320px) 内 `.file-tree` → `.tree-node` / `.tree-row` / `.tree-children`;右侧 `.content-view` → `.preview`。
- **有图表**:`index.html` 直接引 `vendor/echarts.min.js` ⇒ 数据是真画图的。
- 文件类型有各自标记(`.ext-md` / `.ext-json` / `.ext-xlsx` / `.ext-txt`)⇒ **列表项有类型标识**。
⛔ 我们的原型:`<svg>` 0、`<canvas>` 0、`chart` 0 ⇒ 一处图都没有。
## 四、令牌(它的取值)
```css
--bg:#f5f6f8; --panel:#ffffff; --border:#e3e6ea;
--text:#24292f; --dim:#6b7280;
--primary:#2f6fed; --primary-soft:#eaf1fe; /* 蓝 */
--accent:#e8590c; --danger:#d93026; /* 橙 / 红 */
--shadow:0 1px 3px rgba(0,0,0,.08);
font-family:"Microsoft YaHei","PingFang SC","Segoe UI",sans-serif; font-size:16px;
```
⛔ 与我们现用(tiaoyue)的差别:
| 项 | 它 | 我们现在(tiaoyue) |
|---|---|---|
| 底色 | 冷灰白 `#f5f6f8` | 暖纸白 `#faf9f5` |
| 主色 | 蓝 `#2f6fed` | 紫 `#9E4CFF` |
| 强调色 | 橙 `#e8590c` | 无(紫兼作强调) |
| 卡片圆角 | 12px | 24px |
| 阴影 | 极轻一层 | L1/L2/L3 三层 |
| 正文字号 | 16px | 14–16px |
## 五、落地清单(③段重做时逐条照做)
1、外壳改「顶栏 + 面包屑 + 主区」,侧栏**按需出现**(文件/资产浏览时才用 320px 侧栏),⛔ 不再八页一律固定侧栏。
2、`html/body` 禁止整页滚动,滚动只由主区承担。
3、首页(P1)改成**限宽居中单列卡片流**(max-width 900、gap 14、卡圆角 12),一个功能一张卡。
4、补 **AI 问答行**形态:问=强调色、答=次级色缩进、可复制 ⇒ 让 AI 出现在首页,而不只在创作台。
5、内容页补**图表**(直接引 echarts 或等价轻量库),列表项补**类型标识**。
6、卡片内衬收到 16–18、圆角收到 12、阴影只留一层 ⇒ 从"大留白纸感"换成"紧凑工具感"。
⚠️ 第 4 条(配色换不换成它这套)需用户拍板 —— 见主会话转出的待拍板项。
---
## 六、组件细节实测(2026-10-08 补,用户口径「每个组件的样式 高度 ICON 都是需要学习的」)
> 上一版这份笔记只记了「有没有这个组件」和几个粗值 —— 用户点的就是这个:**细节没量到底**。
> 本轮回源站 `public/style.css` + `public/app.js` **逐件量**,带行号。全量对照(含「刻意不学」的 3 条与理由)在 `3d-审查报告.md` §十一,这里只留最要紧的几条。
**① 功能入口卡(`.data-card`,`style.css:387-392` + `app.js:332-336`)—— 这是重点**
- ⚠️ **它有三个子元素,不是一个**:`.data-card-icon` + `.data-card-title` + `.data-card-desc`。
- 🔴 **图标是有的,而且规格明确**:`<span class="data-card-icon">${svgIcon(c.icon, **22**)}</span>` ⇒ **22px 单色图标**,颜色 `var(--primary)`。
- 卡内布局:`flex; flex-direction:column; align-items:flex-start; gap:**6px**` ⇒ **图标 / 标题 / 描述 三段纵向**。
- 内衬 `padding:**16px 18px**`;圆角 `12px`;`border:1px solid`;`box-shadow`。
- 标题 `17px/600`;描述 `14px/dim`。
- 网格 `.data-cards`:`repeat(auto-fill, minmax(**200px**,1fr))`;`gap:14px`;`margin:18px 0 24px`。
- hover:`border-color:主色` + **`transform:translateY(-2px)`** + `box-shadow:0 4px 12px rgba(主色,.15)` + `transition:all .15s`。
- 🔴 **渲染出来的实测高**(2026-10-08 第七轮补;同视口 1249×1277 并排量,原始读数 `_scratch/ref-measure.txt`):**卡高 133px**(描述折两行时)/同宽下 **113px**(描述一行时)。拆开正是 `内衬 16+16` + `描边 2` + `图标 22` + `间距 6` + `标题 25` + `间距 6` + `描述 40 或 20` = 133 / 113。
- 子元素实测:`.data-card-icon` **22×22**(里头的 `<svg>` 也是 22,`stroke-width=2`);`.data-card-title` 高 **25px**(`17px` × `normal`,即 1.47);`.data-card-desc` 高 **40px**(`14px` × 2 行)/**20px**(1 行)。
- ⚠️ **这张卡「看起来厚」有四个来源,缺一个都不像**:①三段纵向 ②内衬 `16/18` ③字号 `17` 与 `14` ④**卡片自带阴影** `0 1px 3px rgba(0,0,0,.08)`。
- 同视口下我方第一版只有 **68px**(图标与标题并成一行、内衬 `12/16`、字号 `16/12`、**无阴影**)⇒ 差 **65px**。**主因是排布(少一段 + 少两次 6px 段间距),不是字号。**
**② 图标系统(`svgIcon()`,`app.js:196-207`)**
- 规格:`viewBox 24` / `fill:none` / `stroke:currentColor` / **`stroke-width 2`** / `stroke-linecap:round` / `stroke-linejoin:round`(lucide 风格)。
- 尺寸用法:功能卡标题 **18**、数据卡 **22**、按钮默认 **16**。
- 颜色:`ICON_COLORS` 给 8 个图标配了 **8 个色相**(`trending-up #e8590c` / `users #2f6fed` / `pen #ec4899` / `flask #0ea5e9` / `lightbulb #d99a2b` / `refresh #0f7f8f` / `chart #d6336c` / `wrench #5b6470`)。
**③ 统计条(`.home-stat-item`,`style.css:383-386`)**
- **无框**:`flex:1; padding:2px 12px; border-right:1px solid rgba(主色,.16)` ⇒ 靠**竖分隔线**分格,不是一个一个白底卡。
- 值 `**26px / 700 / 主色**`;标签 `13px / dim`;gap `5px`。
**④ 问答区(`.qa-row` / `.func-card .qa`,`style.css:78-84`)**
- `.qa-row{padding:6px 8px; font-size:15px; line-height:1.55}`;`.q` 主色 500;`.a` dim 缩进 `1.2em`。
- **可复制的行**:hover 变浅底 + 尾部出现 📋 图标。
- 问答区上方一条 **`border-top:1px dashed`** 虚线 + `padding-top:8px`。
**⑤ 其他**:顶栏 `.topbar{padding:10px 20px; gap:20px}`(高约 52px);次级按钮 `.ghost{padding:6px 14px; radius 8px; font-size 15px; gap 6px}`;面板 `.panel{padding:24px}`。
**⚠️ 三条刻意不学**(与基础层 / 本项目令牌冲突,理由在 `3d` §十一):它的**冷灰蓝品牌色**、**8 色相图标**、**圆角 12px 体系**。