计划与资产检查(组件评审 v3)¶
Comp 主导的构建失败代价最高的情况是:代理判定某个绘制的区域(一幅插画、一种金属质感、一张照片)可以用代码画出来,随后却画出一个简笔画或 CSS 条纹。这个判定在区域映射(comp-spec)中就做出了,远早于任何代码存在。因此,编写代码之前的人工检查点要审查两件事:生成的栅格资产,以及其他一切内容的生产计划。它不再要求提供文本、控件和 chrome 的 HTML/CSS 预览;这些将在组装完成的首屏审查中、结合上下文来判断。
所在位置¶
comps → spec → plates → [plan and asset review] → hero → [first-viewport review] → sections → motion → responsive → review
一旦每个栅格区域都有了自己的 plate,评审即开始。在此之前,页面中没有任何内容被写出来。来自 plates 或 hero 的 build-phase advance(以及 record hero)会拒绝继续,除非当前构建旅程的评审已被接受、其已评审的 spec 摘要等于当前的 .impeccable/build/spec.json,并且它固定的 plates 未发生改变。后续的 spec 变更(例如区域被重新分类)或替换了 plate 都需要新一轮评审;未变化的决定会延续。在打开评审之前先对 plates 打分,这样为 gate 修复过的 plate 不会重新触发评审。
数据包:schemaVersion 3,阶段 components¶
该阶段保留其名称,以便宿主和 lifecycle --require components hero 继续工作。模型不编写此数据包。impeccable component-review plan 根据 spec、comp 和 plate 文件写入 .impeccable/review/components.json,并且只要有任何栅格区域缺少 plate,它就会拒绝(列出所有缺失的 plate)。
{
"schemaVersion": 3,
"stage": "components",
"id": "<from spec/build journey>",
"title": "<surface title>",
"comp": {"path": "<approved comp>", "width": 1440, "height": 900},
"specSha256": "<sha256 of .impeccable/build/spec.json>",
"components": [
{
"id": "hero-figure", "name": "Hero figure", "kind": "plate", "role": "asset",
"box": {"x": 0.52, "y": 0.1, "w": 0.4, "h": 0.6},
"note": "Illustrated fisherman mending a net",
"medium": "raster",
"preview": {"kind": "image", "path": "assets/hero-figure.png"},
"dependencies": []
},
{
"id": "brushed-panel", "name": "Brushed panel", "kind": "chrome", "role": "plan",
"box": {"x": 0, "y": 0.7, "w": 1, "h": 0.1},
"note": "Brushed steel band under the nav",
"medium": "code",
"preview": {"kind": "comp-crop"},
"flags": [{"id": "painted-pixels", "message": "Looks painted: 41 colours beyond its two main tones and soft shading across 47% of it. Drawn in code, this becomes a flat copy."}],
"codeDrawn": false,
"dependencies": []
}
],
"codeRegions": [
{"id": "headline", "name": "Headline", "kind": "text", "box": {"x": 0.06, "y": 0.2, "w": 0.4, "h": 0.2}, "note": "A little closer to the sea."}
]
}
role: "asset":每个栅格区域(plate、image、texture)。预览是其 plate 文件,并像现在一样由哈希固定。role: "plan":需要人工决策的代码区域(text、control、chrome):它带有flags条目,或codeDrawn: true,或者是非容器chrome且其surface既不是flat也不是rules。预览为comp-crop(无文件;UI 会按box裁剪固定的 comp)。codeRegions:所有其他代码区域。为使映射完整且在地图上可点击而列出,但不需要决策。容器(container: true)和条带区列在这里。components的顺序:带标记的项优先(带flags或codeDrawn的 plan 项,以及带flags的 assets),按 spec 顺序;然后是其余 assets,再是其余 plan 项。asset 原样传递其flags。- v3 中不使用
reviewGroup。每个 component 的revision按现有方式计算(component JSON 加上固定的文件哈希再加上specSha256)。
决策¶
每个 component:{revision, action, feedback, split: false},另加用于 reclassify 的 kind:
approve(批准):asset 看起来正确 / 代码是合适的媒介。revise(修订):对于 asset,使用feedback重新生成。使用split: true(仅 assets;feedback 可选)时,该 asset 是一个已合成(baked)的复合图,应返回为分层形式:一个在同一 box 处有透明开口的框架 plate,开口处作为独立图像区域的视图,以及每个移动部分各自的 plate。对于 plan 项,feedback必填,并描述一种两种媒介都无法修复的区域映射变更(例如,邻近照片的图案延伸到代码区域:将该照片延伸到其下方,或将材料拆分为独立 plate)。该区域的 kind 可以保持不变。reclassify(重新分类)(plan 项,以及任何codeRegionsid):kind为plate、image或texture;feedback可选。允许用于codeRegions中没有 component 条目的 id;这些 id 会进入submission.reclassify: [{id, kind, feedback}]。
missing 和 inventoryConfirmed 保持不变。当用户在未标记任何缺失的情况下批准时,UI 会设置 inventoryConfirmed: true(批准按钮上会如此提示)。任何包含 revise、reclassify 或 missing 条目的提交都是 changes-requested。批准要求每个 component 都被批准,且没有重新分类。
捕获¶
v3 不需要浏览器。component-review capture 为每个 asset 记录栅格源证明(与现在相同),并为每个 plan 项记录一条 comp-crop 证明(comp 哈希加 box)。verify 和 lifecycle 对 v3 应用 capture_intact:blob 匹配哈希,源匹配,每个数据包 component 都有证明,栅格预览与其栅格源证明匹配,且 specSha256 与固定的 spec 匹配。
收到反馈后¶
代理会应用回执:对于 reclassify,在 regions 文件中更改区域的 kind(和 note),重新运行 comp-spec --comp <comp.png> --regions <regions.json>,生成新的 plates;对于 asset 上的 revise,使用 feedback 重新生成 plate;对于 plan 项上的 revise,按 feedback 所说的更改 regions 文件,重新运行 comp-spec --comp <comp.png> --regions <regions.json> 并生成任何新的 plates。然后再次运行 component-review plan、capture、serve。未变化的决定会延续。
首屏¶
首屏审查在形式上保持不变。有两条规则变更:
- 三次首屏尝试失败后,关卡的提示消息会要求呈现首屏审查,而不是继续迭代。当首屏已经被接受时,提示会要求恢复用户已接受的内容。
- 对当前捕获的已接受首屏审查会终结数值之争:总体条、调色板检查以及所有数值读数都变成建议项,在首屏关卡以及同一视口的响应式和最终复检中均如此。只有实质性否决项仍然严格:缺失或未被引用的图版、SVG 插图、有机形状裁剪、被裁剪的图版、虚构的墨迹,以及渲染呈现失败。批准与捕获绑定:已批准的截图必须与当前首屏帧匹配(总体至少 95%,无缺失或矛盾),因此过期的批准不豁免任何内容。绑定是视觉层面的,而非源码字节:分区、动效和响应式工作可以自由编辑共享 CSS,只要首屏看起来仍与已接受的截图一致,豁免就持续有效。当它发生可见变化时,关卡会提示首屏与用户已接受的内容不同,并要求恢复该内容(此前的读数一直适用),而不是引用原始分数。一旦首屏审查被接受,它绝不会再要求新的首屏审查:审查存储会返回已接受的会话,因此该请求会陷入循环。三次失败的消息遵循同样的规则。某个平铺地面,其重复图案无法落在设计稿位置上——这就是上述规则存在的场景。
没有栅格区域的首个视口(所有区域都用代码绘制,Operate 屏幕的常见情况)采用合成页审查捕获页面的方式,从首屏审查清单为其声明的依赖项(在清单存在之前的静态清单)中捕获,因此关卡可以读取它;而对它的已接受审查会像其他任何审查一样绑定并终结数值之争。页面绝不会被提供设计稿;一个通过路径、复制或 data URI 显示设计稿或已批准截图的页面会被拒绝而不是匹配。由于规范声明没有栅格区域,图片在视口中的绘制面积可能低于 15%,并以实际绘制的内容来衡量:被裁剪、隐藏和信箱模式显示的图片只计入其可见画面,SVG 蒙版和图案属于代码(logo 和图标可通过);较大的图片、重新编码的设计稿或如实绘制的图表等都会被拒绝,并附带一条消息,要求将其声明为栅格区域或在代码中绘制。此前,原生首屏捕获会直接拒绝此类页面,导致已接受的审查无法绑定,运行卡在首屏。
绘制像素标记(comp-spec)¶
对于每个 text、control 和 chrome 区域(包括容器),comp-spec 会测量设计稿裁剪区域,并排除栅格区域内的像素;当它看起来像绘制出来的,就添加 flags: [{"id":"painted-pixels","message":...}]。这是标记而非拒绝,codeDrawn 不会抑制它。
读数在 64px 窗口上取得(半窗口步长;较小的裁剪区算作一个窗口),以最强窗口为准,因此一个绘制的补丁在紧凑的盒子和宽裕的盒子中读数一致,而容器则根据其栅格子项之间显示的内容来判断。每个窗口:colours(在 2 倍平均后的副本上,偏离窗口两种主色调之间连线的不同颜色数量)和 soft(在其 8x8 块中具有任何对比度的中间调像素占比)。窗口在 (colours, soft) 至少为 (18, 0.44) 或 (28, 0.38),或单独 60 种颜色时,读取为已绘制。
校准:来自 12 个评估设计稿的 556 个区域,加上 24 轮回放。每张照片和大约一半的图版在作为代码区域评分时都会读为已绘制(漏掉的是小的单色装饰枝和看起来像文字的扁平牌匾)。没有哪个只显示文字的 text 或 control 区域会触发标记;会触发标记的确实含有绘制材料(导航栏上的枝叶、绘制的快门按钮、一块牌匾)。
存储的 message 是给审查者的观察提示(“看起来是绘制的:35 种超出其两种主色调的颜色,以及覆盖 45% 的柔和阴影。用代码绘制后,这会变成一份扁平复制品。”)。给代理的指示只存在于 comp-spec 打印的 FLAG <id> painted-pixels: ... 行中。
烘焙合成标记(comp-spec)¶
栅格区域(plate、image、texture)的注释先命名一个框架,再命名一个通向内容的开口,就会获得 flags: [{"id":"baked-composite","message":...}]。框架词:surround, frame, framing, window, doorway, door, arch, archway, shutter, cartouche, portal, niche, alcove, mirror, porthole, casement, proscenium。开口词(必须出现在第一个框架词之后):view, vista, showing, reveals, looking out/through/into, inside, interior, through, beyond, opening onto, glimpse, "photograph/scene/picture/image of"。"Full-frame" 和 "full-bleed" 不计为框架。两种情况永远不会触发标记:注释的开头从句是内容本身("photograph through window: guest room, balcony doors open to the sea"),后续出现的框架词只是主题内容;以及一个栅格区域至少有一半被另一个图版覆盖,且该图版的注释命名了一个带有自身开口的框架("window surround ..., transparent opening"),因为该合成已经被拆分了。
顺序规则让“框架即内容”的案例保持清晰:"a photograph of a window"、"coast photograph seen through a carriage window" 和 "sea window photo" 都不会触发标记。"Framed portrait photo" 也不会触发标记:其中没有任何信息说明框架是一个独立对象、肖像在其后面,而不是照片本身的构图;如果对所有带框照片都触发标记,就会掩盖真正的案例。在来自校准设计稿、24 轮回放和 plan-review 评估工作区的 128 条栅格注释上进行了检查:11 个命中(酒店运行中的三个窗口、七个绘制的房间窗口 "showing a bright hotel bedroom interior"、一个 "painted window ... photograph of stone terrace"),全部是真实的框架加视图合成,没有误报。没有使用像素信号;在这些数据上,注释本身已足够。
这条消息是给审阅者的观察陈述,并在备注含有一个可动部件时点名该部件:“此处的框架与视图是一张图片,因此页面无法单独调换视图或移动遮片。”打印出的 FLAG 行会为代理补充指令:一块带透明开口的框架板、其下方作为独立图像区域的视图,以及作为独立板层的可动部件,在页面中合成。这是标记,不是拒绝。
表面解读(comp-spec)¶
每个代码区域还会获得 "surface": {"flat": bool, "rules": bool},并在其自身像素上进行度量:栅格区域以及其中更小的区域(其文本、其控件)会被排除在外。
flat:这些像素中不足 2% 偏离主色调。即素净的底色:导航栏区域、区块背景。rules:盒子的短边至多 6px,或者其墨迹中至少 80% 落在笔直的水平或垂直线段上,长度为 12px 或以上、厚度至多 6px。即边框边缘、刻度线、分隔线、发丝网格。
component-review plan 仅在非容器 chrome 既不是 flat 也不是 rules 时,才将其保留为计划项,因此徽章、标记、图标和装饰物会留在审阅中,而底色和规则线则移入 codeRegions。被标记(flagged)或 codeDrawn 的区域无论何种情况都是计划项。在此解读规则之前编写的规范不会携带 surface,并保留所有非容器 chrome。
引擎说明¶
引擎会敲定上述各节留待明确的具体细节(完整措辞见 docs/CLI-CONTRACT.md 中的 “Component review”):
- 数据包标识:每一轮的
id都是components,因此各轮共享同一会话,决策得以延续;当构建状态给出工件名时,title为Plan and asset review,并附加· <artifact>。name由区域 id 派生。 - v3 捕获证据拥有自己的模式
plan-review-proof-v1,因此浏览器捕获永远不能替代它,反之亦然。计划项不携带context或thumbnail;资产获得的thumbnail等于其预览。 - 决策为每个操作保留当前所要求的
feedback字符串(允许为空);feedback仅在submission.reclassify条目中为可选项。 - 若规范既没有栅格区域也没有计划项,就没有可审阅的内容:
plan会拒绝写入空数据包,构建阶段的门槛也不会等待。 - 托管会话(设置了
IMPECCABLE_COMPONENT_REVIEW_TOOL)会将审阅保存在宿主的存储中。宿主在IMPECCABLE_COMPONENT_REVIEW_SESSIONS中列出其可信的会话目录(一个操作系统路径列表,与lifecycle --hosted --session-dir所接受的目录相同),门槛会将本地规则应用于这些目录:接受的首个视口,或一项已接受、捕获完整且specSha256与当前规范匹配的 v3 审阅。没有该变量时,托管会话会被拒绝(失败关闭)。IMPECCABLE_COMPONENT_REVIEW_PENDING在此门槛中不起作用;只有托管捕获服务会读取它。 --force对板层的规则未变,也未放宽:一条能通过它的理由(带引号的用户对 comp 的降级说明)会连同板层读数一起豁免审阅理由,并被记录。record hero没有强制力(force)。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 im/impeccable