mcpField
R
rollout

rollout

github.com/adobe云与 DevOps316270 次安装今天更新
代码仓库

关于 rollout

rollout 是 Stardust 技能,用于将整个已迁移网站交付到 AEM Edge Delivery Services。它面向分阶段、可增量的网站交付,通过追踪页面覆盖情况扩展现有 deploy 流程,不负责重新设计页面。

主要功能

  1. 01全站页面清点
  2. 02区块去重规划
  3. 03增量且可恢复的覆盖追踪
  4. 04仅原型类型交付模式
  5. 05导入前与交付检查

适用场景

  1. 01逐页交付已完整迁移的网站
  2. 02在同类页面内容就绪前发布原型区块代码
  3. 03恢复交付并查找尚未完成的页面

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/adobe/skills --skill rollout

安装后在 Claude Code 中输入/rollout确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

reference/
audit-sources.md
checks.md
coverage-model.md
delivery-gates.md
delivery-lint.md
multilingual.md
operational-learnings.md
schemas/
rollout-blocks.schema.json
rollout-config.schema.json
rollout-findings.schema.json
rollout-pages.schema.json
rollout-scorecard.schema.json
rollout-templates.schema.json
scripts/
assemble.mjs
autofix-aem.mjs
blocks.mjs
dashboard.mjs
delivery-lint.mjs
done-check.mjs
findings.mjs
inventory.mjs
lib.mjs
media-reconcile.mjs
optimize.mjs
plan.mjs
section-fidelity.mjs
seed-redirects.mjs
scripts/test/
assemble.test.mjs
delivery-lint.test.mjs
done-check.test.mjs

详细介绍

stardust:rollout — 整个网站 → AEM(Edge Delivery Services)

deploy 会将一个页面转换为 AEM。rollout 交付整个网站:它会清点 migrate 的非平台特定输出,然后逐页运行 deploy,跟踪交付覆盖情况,让你随时了解已完成和待完成的内容。

rollout 仅负责交付,不会重新设计。逐页重新设计流程(extract → direct → prototype → migrate)和 deploy 本身均保持不变;rollout 是覆盖所有页面的上层流程。设计依据、覆盖模型和阶段安排见 notes/rollout/PLAN.md。以下流程按 A→I 运行。

适用场景

完整模式 — 用户已完成整个网站的迁移,文件位于 stardust/migrated/(包含 stardust migrate 生成的逐页 HTML 和 _meta.json),并且已有 EDS/AEM 项目和 DA 目标(与 deploy 所需的目标相同),希望以增量、可恢复的方式交付整个网站。

仅原型模式 — 用户为每种模板准备了一个已迁移原型,并在 stardust/state.json 中记录了完整的页面清单(每页都有 type),希望无需等待所有页面迁移完毕,就立即发布所有区块代码。同类型的其他页面会登记为 content-pending,之后通过单独的流程补充其内容。

如果完全没有 stardust/migrated/ 目录,建议先对至少原型页面运行 stardust migrate。如果只有单个页面,请直接使用 stardust deploy。

设置

  1. 运行主技能的设置步骤(skills/stardust/SKILL.md § 设置)。**流程保护:**如果用户要求迁移时 stardust/state.json 中没有 flow,则不要执行全站交付;打印主技能的双流程表,并交回其路由流程(skills/stardust/reference/state-machine.md § 流程键)。
  2. 确认 stardust/migrated/ 存在,且至少包含一个 *.html 页面(完整模式:包含所有页面;仅原型模式:包含原型,以及 type 已填充的 state.json)。如果不满足,建议先对原型运行 stardust migrate,然后停止。门控原型前置条件(flow: replica)。读取 stardust/replica/progress.json:只有当某页面类型的原型在每个已配置断点上都有门控结果,且结果为 pass: true,或达到门槛且每条剩余差异都带有 cause 时,才能发布该页面类型(skills/replica/reference/source-fidelity-gate.md § 剩余差异记录格式——有记录的剩余差异视为带星号的通过)。从未经过门控的原型,或虽达到门槛但没有剩余差异条目的页面类型,均为阻塞状态:列出其原型 slug 和门控命令($stardust replica <archetype>),且不得扩展到其同类型页面,也不得对这些页面执行 POST /live/。在无人介入模式下接受已记录的剩余差异,不代表可以绕过原型门控。门槛保持不变,仍以门控要求为准。(记录:曾有 2,207 个页面在差异率为 24–28% 且原型从未通过门控的情况下发布;一次随机抽查发现问题后,重新导入了 3,366 个页面,而门控本可以提前发现这些问题。)
  3. 按照 deploy 的要求,确认 EDS/AEM 目标已就绪(项目脚手架、DA_TOKEN、可推送的代码分支)。rollout 不会增加新的传输方式。
  4. 如果 state.json.handsOff 为 true(skills/stardust/SKILL.md § 无人介入模式),则运行全自动模式:各阶段之间不暂停。以下所有门控和验证步骤照常执行——无人介入模式只会取消等待,不会取消验证。

流程

阶段 A — 清点(构建覆盖范围)
node skills/rollout/scripts/inventory.mjs --site-url <source-url>
# defaults: --migrated stardust/migrated  --out stardust/rollout
# archetypes-only mode: add the full page roster from state.json
node skills/rollout/scripts/inventory.mjs --site-url <source-url> --state stardust/state.json

写入 coverage/pages.json(每页一行:slug、交付的 path、templateId、blocks、sourceHash、delivery 状态)、coverage/templates.json(按模板分组的页面)和 rollout.json(目标 + DA 配置 + lastRun)。

仅原型模式(--state):带有 _meta.json 的页面与完整模式一样进行初始化;仅存在于 state.json 中的页面使用 type 中的 templateId、原型 sidecar 中的 blocks 和 delivery.status: content-pending 进行初始化。

清点具有幂等性且支持增量更新:保留交付状态;已交付后迁移 HTML 发生变化的页面会重新标记为 stale(绝不固定某行:副本的首页优先)。如果未能推断,请在 rollout.json 中填写 DA 坐标(site.da.org、site.site、site.da.ref、site.liveHost)。

阶段 B — 区块去重计划(首要环节,在任何转换之前)
node skills/rollout/scripts/blocks.mjs   # → coverage/blocks.json (the dedup unit)
node skills/rollout/scripts/plan.mjs     # → plan.json + a readable conversion plan
  • blocks.mjs 将每个区块实例(每页的 modules、widgets + chrome)合并为去重后的集合,为每个区块分配规范的 edsBlockName(kebab 命名,防止使用保留类名),并记录 usedByPages / instanceCount。Chrome(header/nav/footer)的类型为 kind: chrome → 全站编写的文档(/nav、/footer)。小部件(kind: widget,来自 sidecar 的 widgets[] {id, href})无需文档行:其代码位于 widgets/<path>/<name>.html,页面包含一个 /widgets/…html 链接(#133)。仅原型模式下,原型 sidecar 决定区块集合;content-pending 页面不添加任何区块。映射到 EDS 默认内容(标题、文本、图像、按钮、分隔线)的模块无需区块:使用 update-coverage.mjs --block <id> --status converted --eds-name default-content 记录;无论状态如何,此类行都不会计为待处理。
  • plan.mjs 按每个模板的代表页面优先排列页面,并为每个不同区块指定一个唯一转换点:第一个使用该区块的页面负责转换,之后的每个页面都按名称复用。每页的 convert/reuse 列表是 deploy 的第 7 步简报输入。content-pending 页面始终为 convert: []。

扩展已交付的网站:先审查 blocks/ 和 widgets/——“新模板”通常只是它们的新组合(reference/operational-learnings.md)。

阶段 B2 — 动态功能范围(导入前关卡 — 验证清点结果)

在阶段 C 之前。 stardust/dynamic-features.md(来自 prepare-migration 4.5 或副本阶段 2)必须存在,且每一行都必须有处置结论;在此处使用最新证据进行核验 — dynamics-detect.mjs --from-state … --reach stardust/current 和 dynamics-plan.mjs --target-origin <live host> --migrated stardust/migrated(绑定主机的 API、捕获流程已交付的行)。新证据 → 新增行。列表契约(每种类型的 <meta> 字段 + helix-query.yaml)由阶段 C 的 deploy 为每页生成简报时输出:对已发布页面补充元数据将成为第二次迁移。清点缺失 → 现在运行 stardust dynamics 技能的阶段 1–3。契约:skills/dynamics/reference/triage.md、reference/listings.md。

阶段 C — 交付网站(按计划逐页运行 deploy)

依赖阶段 B2 完成 — 交付时将每页的元数据契约写入其元数据区块,确保索引在导入时内容丰富。

按顺序遍历 plan.json.steps(代表页面优先)。对于每个页面:

  1. 转换并推送迁移后的 HTML(source.migratedHtml),按照 deploy 方法部署到 AEM。将计划步骤传入 deploy 的 brief:只创建 convert 中的区块;对于 reuse 中的每个区块,根据其 edsBlockName 复用现有区块(不要重新创建)。brief 必须包含 Experience Workspace 可编辑性约定(deploy SKILL.md § 8,EW1–EW10):每个转换后的区块都要将创作元素移入包装器(绝不根据文本重建),并通过 EW 门禁(block-roundtrip --ew)后才算交付——某个 brief 缺少此约定,导致真实网站的 27/27 个区块都跳过了该约定。brief 还必须包含原型的 captureState[].restoreAtDelivery 列表(副本 progress.json):门禁要求的冻结状态(视频处于第 0 帧、轮播处于第 1 张幻灯片)是需要交付的行为,绝不是规范(../replica/reference/recreation-procedure.md § Carousels)。

    先部署,再基于预览源站评判。 本地测试框架(build-harness.mjs → qa-gate.mjs、block-roundtrip.mjs --ew)只提供结构断言;所有像素或视觉评判——副本的源站保真度门禁、页眉/页脚的 crop-compare 色带,以及部署后的目视检查——都要针对页面的预览 URL,在 PUT → preview 之后运行,绝不能在首次 PUT 之前针对测试框架运行(deploy SKILL.md § 部署前本地 QA、§ 步骤 10)。某次记录的交付会话在整个预算内都针对本地测试框架的像素差异迭代 CSS,却没有交付任何页面。

    Chrome 和片段文档必须带有 Robots | noindex。 content/nav.html、 content/footer.html、每种语言区域对应的 nav-*/footer-* 文档,以及所有不是页面的语言区域外壳,都要在写入时多加一行元数据—— <div><div>Robots</div><div>noindex</div></div>(渲染为 <meta name="robots" content="noindex">)。否则,平台的已发布文档索引及其提供的 /sitemap.xml 会将它们列为页面:某次记录的非干预运行中,一个 36 页的网站生成了 58 个站点地图 URL(每个页面加 22 个 Chrome 文档)。阶段 D 会验证提供的站点地图。

    content-pending 页面(仅原型):没有迁移后的 HTML——完全跳过文档推送(不创建外壳/占位内容),记录 content-pending,并显示为“等待内容工作流”。其区块代码已通过原型部署。

  2. 静态约定检查(PUT 前,确定性)。 推送前,运行交付约定检查器——它会离线捕获低成本、确定性的错误(包装器、每个 <p> 一个 CTA、尾部斜杠、路径安全、/img/ src、about:error),确保损坏的页面永远不会进入预览环境。具体操作见 reference/delivery-lint.md。P0/P1 会阻止 PUT。

    node skills/rollout/scripts/delivery-lint.mjs --file <html> --path </da/path>
    node skills/rollout/scripts/media-reconcile.mjs --file <html> --deploy-host <branch>--<repo>--<owner>.aem.live [--media-ledger <file>] [--apply]
    

    media-reconcile 会联网解析每张非托管图片,并决定优化/保留/重写/省略(skills/migrate/reference/media-reconciliation.md)——这是下方图片保真度门禁的权威形式。内容托管 URL(content.da.live)则采用 hosted 决策:根据媒体清单离线检查(--media-ledger <file>,自动检测),绝不匿名获取(按设计会返回 401);清单中缺少该项会导致门禁失败。

  3. 运行交付门禁,然后再将页面状态改为 deployed。这里每项规则都用一行说明;具体机制和辅助工具见 reference/delivery-gates.md:

    • 源内容一致性——不要添加源内容中没有的章节;绝不可捏造事实。运行 node skills/rollout/scripts/section-fidelity.mjs --file <html> --source <url> (这是对编写文件进行的静态大纲检查——与副本在发布源站上(deployed 之后)运行的像素级源内容一致性门禁不同。)
    • 图片一致性——每个编写的 <img> src 都必须返回 200,否则就省略;绝不可发布 <img src="about:error">。运行 media-reconcile.mjs(步骤 2)。
    • 路径安全——参见 reference/delivery-gates.md § Gate 3;在 stardust/redirects.tsv 中记录 原始路径→规范化路径。(delivery-lint 会标记违规情况。)
    • 源内容清理——跳过失效的源 URL;对于正文为空或仅含 PDF 的源,编写简略但忠实的内容(层级为 thin, 参见 skills/migrate/reference/fidelity-tiers.md),不要用编造的文字凑内容。
    • 声明一致性层级——记录每个页面的 fidelityTier (archetype/sibling/thin),以便在覆盖情况中显示哪些经过了制作门禁,哪些是克隆的 (skills/migrate/reference/fidelity-tiers.md)。
  4. 使用 state-writer 记录结果(绝不可手动编辑台账):

    node skills/rollout/scripts/update-coverage.mjs <slug> --status converting
    node skills/rollout/scripts/update-coverage.mjs --block <id> --status converted --eds-name <name>
    node skills/rollout/scripts/update-coverage.mjs --block <id> --status converted --eds-name default-content   # maps to default content, no block
    node skills/rollout/scripts/update-coverage.mjs <slug> --status deployed --url <branch-preview-url>
    node skills/rollout/scripts/update-coverage.mjs <slug> --status content-pending   # no document push
    

    在发布流程中完成发布(PUT → preview → live),不要止步于预览——任何查询索引(Phase D2)都基于线上树构建,因此仅交付预览会导致索引为空。失败时:使用 --status failed --error "<reason>",然后继续(单个页面失败绝不可中止整个发布流程)。

基础优先门禁(硬性阻断,每次发布流程执行一次)。 当第一个原型页面的状态变为 deployed 时,先停下来验证基础环境,再编写第二个页面:针对其原型运行 stardust diff 技能(两项探测),并在无头渲染中检查计算样式不变量——网格容器计算出的值应为 display: grid(而不是堆叠成单列),设计要求的区段应铺满整个宽度,CTA/按钮类应确实应用了样式(参见 stardust/runtime-contract.json、skills/deploy/SKILL.md § Runtime-detection probe)。deployed 指 PUT + 预览之后:该门禁的探测必须针对页面的预览 URL 运行,绝不可使用本地测试环境——部署前测试环境中的像素差异不属于此门禁。错误的运行时假设(区块包装器类、按钮类)会悄无声息地影响整个站点——虽然字体排版看起来正常,但所有网格都会堆叠成单列。这一道门禁的差别在于只需修复一个页面,还是必须重建所有模板。相同门禁还会针对源站运行 qa.mjs --checks metadata:favicon-default 表示站点图标从未发布(部署步骤 3 § 网站图标)——已记录的首次通过检查中,页面提供的还是样板图标,尽管 /favicon.ico 返回了 200。每种模板先部署原型页面,再处理其余页面(#126):该模板的原型页面必须先完成部署,并在预览 URL 上通过完整门禁行(gate-all.mjs --only,最多 3 轮修复),然后才能渲染或转换该模板的任何同类页面——记录中的单元 C-archetype(交接契约 § 3,C 行)。 执行模型:波次。 以并行的仅负责编写的 Agent 分波交付——每个 Agent 抓取自己的源页面并仅写入文件,绝不部署或编辑区块——并发处理模板集群(页面互不重叠),先处理代表页面,确保区块已创建,可供复用;然后按页面进行中央部署;再分批在后台运行,并为每个页面记录 OK/FAIL 台账,仅重新驱动 FAIL 项。对于包含 6–20+ 个同级页面的集群,完整流程见 reference/delivery-gates.md § 批量交付(其中也列出了唯一一种由集群 Agent 自行部署的变体——replica 的 Phase 5 扇出、按集群划分的部署台账,以及支持安全加锁的共享台账)。中央部署步骤应运行打包好的可恢复驱动程序,而不是串行循环: node skills/deploy/scripts/deploy-batch.mjs --org <org> --repo <repo> --branch <branch> --content <dir>(并发池、持久化台账(跳过已上线页面)、重试/退避、仅追加日志,以及已交付的 .plain.html 检查)。 驱动程序和每次批量运行都在后台执行;其日志和台账就是进度文件。最多每 4 分钟检查一次,并且绝不要使用 5 分钟或更长的固定 sleep(提示缓存窗口)——这是主技能的等待规范;记录在案的批次等待 9–10 分钟,每次都重写了约 650k 的前缀。发生暂时性故障后,重新运行相同命令——它只会重新驱动 FAIL 项。然后使用 update-coverage.mjs 将台账同步到覆盖率数据。 先打好基础: 在启动第一个 Agent 之前,先 lint 并提交 styles.css、页眉/页脚 CSS 和契约文件;扇出后不得重命名 token 或自定义属性(有记录显示,在三个 Agent 正在运行时进行重命名,耗费了七条协调消息)。互不相交的集群并发启动——波次只需等待实际依赖项(有记录显示,第二波因一个无关的第一波而空等了 14 分钟)。每次工具调用都必须少于 4 分钟,包括主 Agent 的调用(提示缓存保留 5 分钟;耗时 5.2 和 6.6 分钟的调用会重写整个上下文,主 Agent 有一次在前台运行了 338 秒,在部署批次启动并等待的同时执行像素循环,也造成了同样的问题):长时间运行的操作(门禁轮次、像素循环、Playwright 捕获、部署批次)应通过 run-bg.mjs start 在后台运行,并将 wait 作为下一次工具调用——它会在 --max 指定的时间内返回(默认 100 秒);绝不要在同一轮中并行调用两个长时间运行的操作,也绝不要在同一条命令中调用两次 wait。

阶段 D — 站点组装(全站产物)
node skills/rollout/scripts/assemble.mjs   # → rollout/site/{sitemap.xml,robots.txt,manifest.json} — the EXPECTED set
node skills/rollout/scripts/assemble.mjs --verify-origin https://<branch>--<repo>--<owner>.aem.live   # vs the SERVED /sitemap.xml; exit 1 on a mismatch

根据已交付路径生成全站产物:sitemap.xml + robots.txt,以及一个片段清单,将页面框架区块映射到编写的页面框架文档 (content/nav.html、content/footer.html)及其 canon/*.html 源文件 (deploy 通过常规内容链编写 + 部署这些文档 — 它们 MUST 已发布,否则页面框架在整个站点上都会返回 404)。

组装的站点地图绝不是实际提供的站点地图。 stardust/rollout/ 位于 .hlxignore 中,因此 site/sitemap.xml 是本地产物 — 即预期的 URL 集合。 平台会提供自己的 /sitemap.xml,它根据所有已发布文档的索引构建,其中包括页面框架文档,除非每个文档都带有 Robots | noindex(阶段 C)。一次有记录的人工运行读取了本地文件,报告“站点地图有 36 个 URL”,但实际提供的站点地图有 58 个(36 个页面 + 22 个 nav / footer 文档)。有两种补救方法,第一种为必需:

  • 编写内容: 每个页面框架/片段文档 — /nav、/footer、每个区域设置对应的 nav-* / footer-*,以及非页面的区域设置外壳 — 都带有元数据行 Robots | noindex;已发布但未添加此行的文档必须重新编写 并重新发布(preview → live),然后才能进行下方检查。
  • 配置(替代方案,可叠加使用): 当代码分支可写时,在项目根目录添加 helix-sitemap.yaml(sitemaps.default.include: ['/**']、 exclude: ['/nav', '/footer', '/**/nav*', '/**/footer*', '/fragments/**']、 properties.lastmod: lastModified),即使文档缺少此行,也能将页面框架排除在实际提供的站点地图之外;同样的 exclude glob 也应加入 helix-query.yaml(阶段 D2),这样索引也不会包含它们。

验证实际提供的站点地图,绝不要验证本地文件。 assemble.mjs --verify-origin <live-origin> 会获取 <origin>/sitemap.xml(若为站点地图索引,则会继续跟进), 将其 <loc> 路径与覆盖范围行进行比较,打印实际提供与组装的数量,并列出所有额外和缺失路径,将结果记录到 site/manifest.json(servedSitemap),若有任何差异则以状态码 1 退出。额外路径表示页面框架文档没有 noindex,或有在已迁移树之外构建、且没有覆盖范围行的页面(update-coverage.mjs --new,阶段 D2);缺失路径表示页面未在正式环境发布。修复后重新运行,直到以状态码 0 退出。D-site 台账的 end 行应记录实际提供的数量,而绝不是组装的数量 — 例如 --detail "sitemap served 36 = assembled 36; redirects wired; / 200"。

D-site 检查清单(全部在 D-site end 行之前完成):assemble.mjs --verify-origin 以状态码 0 退出 · 每个页面框架文档都带有 Robots | noindex 且已发布 · 重定向表已发布(见下文)· curl -sIL <origin>/ 最终返回 200。

重定向: 如果阶段 C 的路径安全检查生成了 stardust/redirects.tsv,请在此处将其接入 EDS 重定向机制,以免原始入站 URL 返回 404 — 重定向表位于内容根目录(对于由 DA 支持的站点,路径为 /redirects.json,列为 Source / Destination;通过管理 API 执行 PUT,然后像发布页面一样预览 + 发布)。根路径 MUST 按以下方式响应:当源站根路径提供页面时,将其作为根 index 文档交付(流水线会通过它提供 / — /index ≡ /;绝不能同时添加 / Source 行,否则会将其覆盖);只有当源站根路径本身重定向时(curl -sI <source-url>,跟随 Location 链),表格才包含 / 和 /index.html → 着陆页。然后验证 curl -sIL https://<branch>--<repo>--<owner>.aem.page/ 最终返回 200:即使所有阶段都已通过,/ 返回 404 仍会导致整个交付失败(已有记录 — 表格中每个 .html 路径都有一行,但 / 没有)。

阶段 D2 — 动态功能(dynamics 阶段 4–5)

实现模式目录(skills/dynamics/reference/patterns.md)中可复现性 self 对应的行:基于索引的列表和搜索、模态加载器、媒体作为 URL、客户端计算区块、面向所有者的标签配置(禁用)、站外数据层级、表格同步;将其他每一行作为一个所有者决策批次输出,并交付其中的过渡层级。 查询索引基于已发布的树构建——在阶段 C 按页面发布,然后轮询 total。 每项功能都要在 stardust/dynamics/parity.json 中添加一条一致性检查记录,并附上可重放的检查;阶段 H 之前运行 dynamics-check.mjs --origin <live host>,并在报告中附上其表格。 重放失败时记录为 dynamic-gap / api-dependency 学习项,绝不能静默通过。

基于索引的列表以文档优先的方式交付(手动编写条目,索引提供非文本内容和补充条目——dynamics/reference/listings.md);部署的 AI 可读性门禁会在每个列表页面上运行。

缺少查询索引是代码分支问题,而非配置服务问题。 /query-index.json 返回 404,表示项目未提供 helix-query.yaml。请在代码分支根目录编写该文件(规范中的 knowledge/helix-query.yaml 是草稿),发布页面至 LIVE 并轮询:参见 skills/dynamics/reference/listings.md § 获取索引。配置服务返回 403 是预期情况;只有代码分支不可写时,才交付基于表格的过渡索引(记录为 interim,并注明决策名称)。

搜索一致性检查比对的是数量和标题,而非是否存在。 结果区块优先对标题匹配项排序;仅当标题命中少于 N 项时,才会查询描述,然后查询正文文本(N = 探测词在源页面中可见的条目数);按标题 + 描述去重,并将预输入结果限制为 N 项——在检测期间从 SOURCE 读取 N、排名靠前的标题和一条已知命中项,并记录到 search-query 检查(expectCount、expectTitles、expectIncludes);若数量不匹配,dynamics-check.mjs 会判定检查失败(skills/dynamics/reference/patterns.md § 基于搜索索引)。

在此构建的页面也要纳入覆盖范围。 结果页面(或任何没有捕获记录的页面)没有清单行,因此不会纳入 verify.mjs --all、optimize.mjs 和汇总站点地图,除非进行注册:

node skills/rollout/scripts/update-coverage.mjs --new search --path /search --template search --origin dynamics --title "Search"

然后像其他页面一样记录其状态。inventory.mjs 在重新运行时会保留此类行(source.migratedHtml 中的来源标记可识别它们;状态保持不变),因此这行命令只需运行一次。

阶段 D3 — 多语言(按语言划分的树)——可选

当源站包含按语言划分的树(/fr/…、/en/…)时,将它们作为并行内容树添加,并复用相同的区块库——只需更改手动编写的内容和少量连接配置(按语言路由的框架文档、按语言划分的索引、按语言划分的路径安全设置)。 参见 reference/multilingual.md。

阶段 E — 全站验证
node skills/rollout/scripts/verify.mjs            # uses rollout.json site.liveHost
# or: --base <url>   (explicit host)   |   --root <dir>   (offline, against a local export)

对于每个已交付页面,verify 会确认 HTTP 200、没有 about:error(部署 #75),并且每个内部 href="/…" 都指向已知的交付路径,然后将每个页面设为 verified 或 failed。如果任何页面失败,则以非零状态码退出。

无头渲染检查(按模板)。 即使 .plain.html 返回 200,页面仍可能渲染为空白——装饰效果故障(缺少脚本、区块包装器类错误、chrome 404)无法通过文本检查发现。对于每种模板的第一个已交付页面(包括主页),在无头浏览器中加载线上 URL,并断言装饰效果已运行:运行时的 body.appear 类已设置(参见 stardust/runtime-contract.json),main .section 数量 > 0,pageerror 事件数量为 0,损坏图像数量为 0,并且模板的原型中每个 restoreAtDelivery 条目都满足要求:至少四分之一可见的 autoplay <video> 正在播放(!paused,且 currentTime 持续推进——不能只是存在),轮播无需交互即可切换。

针对清单的已发布源站门禁(#125)。 verify 可证明页面能够渲染;DELIVERY 判定结果由 replica 的 gate-all.mjs 给出(对每个已部署页面检查像素、高度、裁剪和内容,参见 ../replica/reference/source-fidelity-gate.md § 全页面已发布源站门禁)。update-coverage.mjs --gate stardust/replica/gates/all-<w>/summary.json 会将每一行写入 delivery.gate,并将失败页面设为 failed;门禁未通过时,verify 绝不会将页面标记为 verified——完成状态只从一个来源判定,绝不只看像素数。在 C-deliver 中,清单运行的记录单位为 gate-all(交接契约 § 3,C 行)。

Phase E2 — 链接审计完整性

verify.mjs 会检查已交付页面上的链接;本阶段补齐由清单驱动的批次遗漏的链接目标 (reference/operational-learnings.md § 两项 verify 检查):

  • 导航栏、页脚和落地页目标不是同类页面的兄弟页面。 枚举 /nav 和 /footer 文档以及各个分区的索引页/落地页中的每个 href,并确认每个目标都已部署 + 发布 + 验证,同时确认导航栏和页脚文档本身也已发布;否则这些页面会被 提交却从未发布,链接会返回 404,而仪表板仍会显示 100%。
  • 在部署阶段本地化源站跳转链接,不要手动处理: node skills/deploy/scripts/localize-links.mjs --source-host <live-host> --content content --redirects stardust/redirects.tsv 会将所有路径存在于内容树中的源站 href(包括页眉/页脚/主页) 重写为规范的根相对形式,并列出仍保留为绝对链接的项(没有本地页面——跳转到源站总好过返回 404)。每轮之后都要对整个 树重新运行:只有后续批次发布了新目标,早期批次的页面才会出现新有效目标。--check 是门禁(退出码 2 = 仍有可本地化的链接)。
  • 按页面实际提供服务的 URL 链接到每个内部页面(deploy/scripts/eds-path.mjs): 不带 .html,只有文件夹索引页才带斜杠(/x/)。.html 和叶子页面末尾的斜杠都会返回 404,而 .plain.html 可以正常访问。对于没有本地页面的 .html 链接,应改为可用的源站 URL。
  • 审计会针对线上树中的每个 href 发起 GET 请求:仅凭台账会遗漏斜杠和大小写错误。
  • 采集内容中缺失的目标。 两种情况都必须在 direction.md 中作为具名决策记录,并附上列表:方向文件声明的范围本应包含的目标属于采集缺口——先抓取,再迁移,再通过门禁(只能按“采集 → 迁移 → 门禁”流程处理,绝不可根据线上页面内容直接编写);当缺口不超过 12 个页面时交付,否则改回源站链接,并列入范围欠账;超出声明范围的目标属于范围扩展——无论数量多少都改回源站链接。外部目标:改回源站链接;其他语言版本的目标:仅当该语言版本的根目录从未采集时才改回源站链接。任何已采集的页面——包括 stardust/state.json 中的记录、duplicateOf 占位页和语言版本根目录——都在范围内,必须交付,绝不能改回源站链接(不超过 12 个的规则仅适用于未采集页面;曾有一次已记录的运行以此为由丢弃了 10 个已采集的语言版本根目录)。绝不能留下 404(一次有记录的审计发现 10 个未采集但在范围内的页面——交付这些页面才是正确做法)。
阶段 F — 优化:多源审计 + 门禁(交付质量)

流程内的质量门禁。optimize 将现有审计技能的发现汇总到一个台账(optimize/findings.json + optimize/scorecard.json),按可修复性为每项发现添加标签,并对发布设置门禁。来源(完整映射见 reference/audit-sources.md):

  1. rollout:baseline — 内置确定性检测器:
    node skills/rollout/scripts/optimize.mjs        # uses rollout.json site.liveHost
    # or: --base <url> | --root <dir> | --slug <s> | --all
    
  2. impeccable:critique + impeccable:audit — 设计质量 + a11y/性能。
  3. 营销 SEO 技能 — seo-audit、schema、ai-seo、 site-architecture。
  4. stardust:tensions — 来自 stardust/current/brand-review.html 的机械式设计张力。

来源对等。 当存在提取捕获数据时(stardust/current/pages/<slug>.json 及其渲染侧车文件;使用 --current <dir> 指向其他位置),标记 SOURCE 也存在的基线发现——相同的 <title>、SOURCE 上也没有描述、SOURCE 上也没有 JSON-LD、相同页面共享相同标题——并设置标签 fixability: out-of-scope,证据前缀为 source parity:,并列入单独的报告部分:仅供参考,不计入健康度评分和未解决的 P1/P2/P3 数量,不触发门禁,也不会自动修复。一次有记录的人工免干预运行手动接受了 63 项此类发现。其他所有发现仍按原方式处理(reference/checks.md § 来源对等)。

使用写入器将各来源的发现规范化并写入台账:

node skills/rollout/scripts/findings.mjs record \
  --source marketing:seo-audit --layer seo --check thin-content \
  --severity P2 --fixability platform-migration \
  --scope-ids blog/post --evidence "…" --recommend "…"
node skills/rollout/scripts/findings.mjs resolve <id> --status accepted --note "…"

所有来源共用一个 ID 空间、去重机制、评分卡和检测 → 修复 → 验证循环:重新运行某个来源会解决该来源中已消失的发现;回归的 fixed 发现会重新打开;人工设置的 accepted/wontfix 状态会保留。可修复性路由: platform-migration → 自动修复 / 重新部署;design-pass → 上游处理(仅显示);out-of-scope → 仅供参考。门禁只要存在任何未解决且在范围内的 P1,就会以非零状态退出——只有验证通过且台账中没有未解决的 P1,页面才算交付无误。

在约 1k 页的规模下:head.html 级别的修复需要全站重新发布才能生效并更新各页面的发现;optimize 门禁只审计 coverage/pages.json 中的页面;而忠实迁移的平行源树会产生合理的重复标题发现(这是规范链接决策,不是错误)。参见 reference/operational-learnings.md。

判断层(brand-tensions、design-ux、content-conversion)的评分为 null,直到 impeccable/tensions 来源填充数据为止——评分卡会显示“尚未评估”,而不是伪造分数。

阶段 G — AEM 自动修复(闭环)
node skills/rollout/scripts/autofix-aem.mjs --project <eds-root>   # [--dry-run] [--slug s] [--check c]

平台自动修复引擎(AEM-EDS,v1 — 激进模式)。对于每项 check 已注册 EDS 修复器的未解决发现,它会编辑 EDS 项目文件,在 finding.autofix 中记录更改,并将该发现暂存为 in-progress:

  • 确定性 — eds-fix-h1(恰好一个 <h1>)、站点地图(重新组装)。
  • 内容草稿(记录以供审核)— eds-metadata-title / eds-metadata-description、eds-alt-draft、eds-disambiguate-title。
  • 手动处理(准备指导说明/负载)— eds-jsonld(使用 marketing:schema)、 eds-canonical、eds-landmark-main。

先使用 --dry-run。应用更改后,重新部署编辑过的页面,然后重新运行 验证 + 优化——暂存的发现会变为 fixed。design-pass 发现会显示出来,但不会自动修复。

阶段 H — 报告

将动态一致性表(来自阶段 D2 的 stardust/qa/dynamics-report.md)与交付台账放在一起:逐项列出功能的类别、覆盖范围、状态、负责人决定和回放检查——让报告如实反映网站 实际能做什么,而不仅仅是 展示了什么。

读取 rollout.json.lastRun + optimize/scorecard.json(或重新运行 inventory.mjs):

rollout — <site> → aem-eds
==================================================
Pages       <N> total · <v> verified · <d> deployed · <p> pending · <cp> content-pending · <s> stale
Templates   <T> (per-template delivered/total)
Blocks      <B> total · <c> converted · <p> pending
Quality     health <H>/100 · open P1 <n> / P2 <n> / P3 <n>
Pixel table prototypes <p>/<P> PASS · deployed <d>/<D> PASS (pixel-only <x>/<D>) — gates/{prototypes,all}-1440/summary.md
To deliver  <list of remaining slugs>
Content     <cp> pages awaiting content track (block code deployed, document not yet pushed)

将 pending/stale/failed 明确列为「缺少项」。像素表格行的数据来自两个 summary.json 中的总数(pass、pixelOnlyPass、pages);未出现在 all-1440/summary.json 中的已部署页面未受门控,应列入该清单(#125)。content-pending 页面单独列出——它们不是失败;其区块代码已生效,在 migrate 生成其 HTML 并重新运行 inventory 后,会自动推进到 pending。

还要按照 skills/stardust/reference/learnings.md 编写/更新 stardust/learnings.md:本次运行发现的每种失败类别各写一条记录(证据、建议更改的技能及章节、status: pending)。 插件维护者会将待处理记录整理成技能差异——这样,本次运行中来之不易的修复就不必反复摸索。

阶段 I — 仪表板
node skills/rollout/scripts/dashboard.mjs    # → dashboard/index.html + data.json

一个独立运行、不依赖外部 JS的仪表板,以项目的设计风格呈现(从已迁移页面的 :root 读取品牌令牌)。核心是一个包含所有已识别页面的页面树,按 URL 路径嵌套,每个节点按其达到的最高生命周期阶段着色:

identified → prototyped → deployed → optimised

阶段涵盖 state.json(rostered/extracted/directed → 已识别,prototyped/approved/migrated → 已完成原型),rollout 覆盖情况(deployed/verified → 已部署),以及 optimize(optimised = 已验证且没有未解决的问题)。content-pending 同级页面仍处于 identified(它在台账中,因此可以跟踪交付进度,但尚无设计稿)。图例计数为累计值。模板原型标记为 T;存在未解决问题的页面会显示红色计数。还包括模板表和质量评分卡。dashboard/data.json 是可检查的快照——每次迭代结束时都要重新生成。(state.json 为只读且可选。)

**完成只有一个判定标准:**运行 node skills/rollout/scripts/done-check.mjs 并以 0 退出,才表示 rollout 已完成;否则,它会逐行打印一个缺口。

输入

输入来源用途
stardust/migrated/*.htmlmigrate要交付的页面(只读)
stardust/migrated/**/_meta.jsonmigratetemplateId(template;若某原型的 template: null,则按其自身 slug 分组;否则使用 type)、blocks(modules——清单报告会统计侧车文件中列表为空的情况:在阶段 B 前补齐)、widgets(widgets[] {id, href})、title
stardust/state.jsonstardust core*(仅原型模式)*完整页面清单,以及尚未迁移页面的 type
stardust/rollout/rollout.jsonrollout / 用户DA 目标坐标

输出

路径用途
stardust/rollout/coverage/pages.json逐页交付台账(架构:schemas/rollout-pages.schema.json)
stardust/rollout/coverage/templates.json模板分组与汇总(架构:schemas/rollout-templates.schema.json)
stardust/rollout/coverage/blocks.json区块去重台账与 EDS 映射(架构:schemas/rollout-blocks.schema.json)
stardust/rollout/plan.json由去重结果驱动的交付顺序,以及逐页转换/复用简报
stardust/rollout/optimize/findings.json多来源质量问题台账(架构:schemas/rollout-findings.schema.json)
stardust/rollout/optimize/scorecard.json质量评分卡与历史记录(架构:schemas/rollout-scorecard.schema.json)
stardust/rollout/rollout.json配置与 lastRun 摘要(架构:schemas/rollout-config.schema.json)
stardust/rollout/site/{sitemap.xml,robots.txt,manifest.json}站点级组装产物
stardust/rollout/dashboard/{index.html,data.json}自包含的进度仪表板与快照
对 EDS 项目 的编辑(content/**、styles/)由 autofix-aem 应用(rollout 在 stardust/rollout/ 之外写入的唯一文件)
已交付的 EDS 站点由 deploy 按页面生成(blocks/、widgets/、content/、fragments — 归 deploy 管理)

rollout 会写入 stardust/rollout/,并且仅通过 autofix-aem 写入其交付到的 EDS 项目。它绝不会修改通用核心、state.json 或 migrated/——这些都是只读输入。

依赖项(审计来源 — 引用,不随附)

optimize 通过调用来协调现有审计技能;这些技能必须已安装:

  • impeccable(critique、audit)——已是 stardust 的依赖项。
  • marketing skills — seo-audit、schema、ai-seo、site-architecture。 可选;若缺失,则显示提示。
  • stardust tensions — 由 extract 在仓库内生成(brand-review.html)。

使用 findings.mjs record 将各项输出规范化并写入台账。参见 reference/audit-sources.md。

rollout 不会做什么

  • 不进行上游重新设计。 此处会展示 design-pass 的问题,但不会修复。 autofix 只会处理 EDS 项目中可通过平台修复的问题。
  • 不采用新的传输方式。 交付仍使用 deploy 的 DA Source API 路径,不作更改。
  • 不重新设计通用核心。 不会改动 extract/direct/prototype/migrate 和 deploy。
  • 不要求完整预迁移。 仅原型模式是首要支持模式:区块代码从原型部署; 其余页面会随着 migrate 生成其 HTML,从 content-pending 进入 deployed——无需重启 rollout。

脚本

  • scripts/inventory.mjs — 将迁移后的目录树映射到页面 + 模板覆盖情况(幂等,支持检测过时项)。--state <path> 可启用仅处理原型的模式。
  • scripts/blocks.mjs — 不同区块的去重台账(blocks.json)。
  • scripts/plan.mjs — 由去重结果驱动的交付顺序 + 各页面的转换/复用说明。
  • scripts/update-coverage.mjs — 页面和区块的确定性交付状态写入器;重新推导所有汇总数据。--new <slug> --path --template --origin 可注册在迁移后的目录树之外构建的页面(D2),使其纳入覆盖范围。
  • scripts/section-fidelity.mjs — 源内容保真度门禁脚手架(已编写的章节与源标题大纲对照;为门禁提供参考,但不会自动作出判断)。
  • scripts/assemble.mjs — 站点级 sitemap / robots / fragments 清单(EXPECTED 集);--verify-origin <live-origin> 会将已提供的 /sitemap.xml 与其进行比较,不匹配时以 1 退出。
  • scripts/verify.mjs — 全站结构验证(HTTP 或离线 --root)。
  • scripts/optimize.mjs — rollout:baseline 检测器 + 多来源门禁;存在未解决的 P1 时以非零状态退出。与源捕获内容一致的发现项会标记为 source parity: — 仅供参考,不计分,也不纳入门禁。
  • scripts/findings.mjs — 记录/解决来自外部审计来源的发现项。
  • scripts/autofix-aem.mjs — AEM 自动修复引擎(编辑 EDS 项目)。
  • scripts/dashboard.mjs — 设计标识仪表板 + data.json 快照。
  • scripts/done-check.mjs — 完成情况判定(Phase I);退出状态为 0 表示已完成。
  • scripts/lib.mjs — IO + 汇总 + 页面加载 + 自动修复注册表的共享辅助程序。

参考资料

  • notes/rollout/PLAN.md — 设计、覆盖模型、阶段划分、待解决的问题。
  • reference/delivery-gates.md — Phase C 门禁 + 批量规模化交付流程。
  • skills/dynamics/SKILL.md + 其 reference/ — 动态界面:类、分流维度、列表契约 + 查询索引机制、模式目录、保真度报告(B2/D2)。
  • reference/multilingual.md — 按语言划分的目录树(D3)。
  • reference/operational-learnings.md — 规模化发布的注意事项(扩展、重新发布、验证)。
  • reference/audit-sources.md — 审计来源 → 层级 → 可修复性 → 自动修复映射。
  • reference/checks.md — rollout:baseline 检查目录。
  • skills/stardust/reference/learnings.md — 报告阶段写入的每次运行学习记录。
  • skills/migrate/reference/fidelity-tiers.md — Phase C 记录的原型/同级页面/精简页面层级契约。
  • skills/migrate/reference/media-reconciliation.md — 图像保真度解析器的决策表。
  • skills/deploy/SKILL.md — 发布流程采用的单页转换方法。
  • skills/deploy/da-deploy-protocol.md — DA Source API 传输方式。
  • skills/migrate/SKILL.md — 生成 migrated/ + _meta.json 输入。
  • schemas/*.schema.json — 覆盖 + 配置契约。

评论

支持 Markdown