diff --git a/.agents/skills/mpx2skyline-workspace/benchmark.md b/.agents/skills/mpx2skyline-workspace/benchmark.md
new file mode 100644
index 0000000000..8387d64cd0
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/benchmark.md
@@ -0,0 +1,7 @@
+# Mpx2Skyline 测试集
+
+当前有效定义:v4,4个case、37条断言,尚未执行。
+
+[设计](test-design.md) · [定义](iteration-4/evals.json) · [评分标准](iteration-4/grading-standard.md)
+
+[iteration-3历史结果](iteration-3/benchmark.md)属于旧任务上下文,分数不迁移至v4。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/README.md b/.agents/skills/mpx2skyline-workspace/iteration-4/README.md
new file mode 100644
index 0000000000..3234f626b8
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/README.md
@@ -0,0 +1,11 @@
+# 当前测试集 v4
+
+4个case/37条断言,未执行。原case 4合并到1并统一为orders.mpx页面输入,原case 3合并到2并统一为user-list.mpx组件输入(保留外部row.wxml和logo.svg);新case 3为仅提供需求的任务看板页面创建。
+
+原始产物与评分保留在iteration-3。新版外层input只保留一份,不复制Skill,不预建执行目录。定义详见evals.json,迁移关系见assertion-migration.json。
+
+从Mpx仓库根目录执行定义校验:
+
+```sh
+node node_modules/jest/bin/jest.js --config '{"rootDir":"./.agents/skills/mpx2skyline-workspace/iteration-4","testMatch":["**/validate-suite.test.cjs"],"testEnvironment":"node","transform":{}}' --runInBand --watchman=false
+```
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json b/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json
new file mode 100644
index 0000000000..3ee4c9b5e2
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json
@@ -0,0 +1,315 @@
+{
+ "from_suite": 3,
+ "to_suite": 4,
+ "old_total": 31,
+ "preserved": 21,
+ "added": 6,
+ "new_total": 37,
+ "items": [
+ {
+ "assertion_id": "s0_00",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。",
+ "previous_verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。"
+ },
+ {
+ "assertion_id": "s0_01",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。",
+ "previous_verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。"
+ },
+ {
+ "assertion_id": "s0_02",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。",
+ "previous_verification": "追踪实际活动节点 class 与颜色声明的匹配关系。"
+ },
+ {
+ "assertion_id": "s0_03",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。",
+ "previous_verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。"
+ },
+ {
+ "assertion_id": "s0_04",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。",
+ "previous_verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。"
+ },
+ {
+ "assertion_id": "s0_05",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。",
+ "previous_verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。"
+ },
+ {
+ "assertion_id": "s0_06",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。",
+ "previous_verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。"
+ },
+ {
+ "assertion_id": "s0_07",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。",
+ "previous_verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。"
+ },
+ {
+ "assertion_id": "s0_08",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。",
+ "previous_verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。"
+ },
+ {
+ "assertion_id": "s0_09",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。",
+ "previous_verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。"
+ },
+ {
+ "assertion_id": "s0_10",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。",
+ "previous_verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。"
+ },
+ {
+ "assertion_id": "s0_11",
+ "from_case": 0,
+ "to_case": 0,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。",
+ "previous_verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。"
+ },
+ {
+ "assertion_id": "s1_00",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 页面主体使用具有明确可滚动高度的 scroll-view,显式选择type=list,订单项作为列表的直接子节点。",
+ "previous_verification": "检查列表直接子节点与高度约束链;使用超出容器高度的订单数据核对滚动结构。"
+ },
+ {
+ "assertion_id": "s1_01",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 通过 bindrefresherrefresh 启动刷新,refresher-triggered 关联刷新状态,并在请求成功和失败后结束容器刷新态。",
+ "previous_verification": "触发容器刷新事件,分别模拟请求resolve/reject,检查触发态最终为false。"
+ },
+ {
+ "assertion_id": "s1_02",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 通过 scroll-view 的 bindscrolltolower 连接原分页加载方法,容器触底后显示追加的订单。",
+ "previous_verification": "从实际模板事件绑定调用分页方法,核对下一页结果进入同一滚动列表。"
+ },
+ {
+ "assertion_id": "s1_03",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 通过 scroll-view 的 bindscroll 读取 event.detail.scrollTop 并更新滚动位置展示。",
+ "previous_verification": "向实际滚动处理器传入detail.scrollTop,核对展示状态对应更新。"
+ },
+ {
+ "assertion_id": "s1_04",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。",
+ "previous_verification": "解析页面JSON并检查真实导航节点和主体布局关系。"
+ },
+ {
+ "assertion_id": "s1_05",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。",
+ "previous_verification": "解析 app.json 并检查顶层属性值。"
+ },
+ {
+ "assertion_id": "s1_06",
+ "from_case": 1,
+ "to_case": 1,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。",
+ "previous_verification": "逐项解析五个字段的层级、类型和值。"
+ },
+ {
+ "assertion_id": "s1_07",
+ "from_case": 4,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 外层纵向滚动采用type=nested,内层滚动显式选择list/custom,并通过associative-container=nested-scroll-view建立关联。",
+ "previous_verification": "沿模板父子关系检查nested祖先、内层类型和关联值。",
+ "source_assertion_id": "s4_00"
+ },
+ {
+ "assertion_id": "s1_08",
+ "from_case": 4,
+ "to_case": 1,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。",
+ "previous_verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。",
+ "source_assertion_id": "s4_01"
+ },
+ {
+ "assertion_id": "s1_09",
+ "from_case": 4,
+ "to_case": 1,
+ "disposition": "adapted-to-unified-page",
+ "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。",
+ "previous_text": "Skyline 分支使用sticky-section/sticky-header实现组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应的CSS sticky实现。",
+ "previous_verification": "分别选择renderer分支,检查sticky节点关系、背景与WebView样式;真机吸顶另记验证状态。",
+ "source_assertion_id": "s4_02"
+ },
+ {
+ "assertion_id": "s1_10",
+ "from_case": 4,
+ "to_case": 1,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。",
+ "previous_verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。",
+ "source_assertion_id": "s4_03"
+ },
+ {
+ "assertion_id": "s2_00",
+ "from_case": 2,
+ "to_case": 2,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。",
+ "previous_verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。"
+ },
+ {
+ "assertion_id": "s2_01",
+ "from_case": 2,
+ "to_case": 2,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。",
+ "previous_verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。"
+ },
+ {
+ "assertion_id": "s2_02",
+ "from_case": 2,
+ "to_case": 2,
+ "disposition": "adapted-to-unified-component",
+ "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。",
+ "previous_text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。",
+ "previous_verification": "从查询目标追踪其enhanced属性及node().exec后的scrollTo({top:0})调用。"
+ },
+ {
+ "assertion_id": "s2_03",
+ "from_case": 2,
+ "to_case": 2,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。",
+ "previous_verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。"
+ },
+ {
+ "assertion_id": "s2_04",
+ "from_case": 2,
+ "to_case": 2,
+ "disposition": "preserved",
+ "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。",
+ "previous_text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。",
+ "previous_verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。"
+ },
+ {
+ "assertion_id": "s2_05",
+ "from_case": 3,
+ "to_case": 2,
+ "disposition": "adapted-to-unified-component",
+ "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。",
+ "previous_text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。",
+ "previous_verification": "检查微信输出实际 span 容器的省略属性、图片 display、renderer 分支及父级宽度和收缩约束;使用超长标题核对图标与文字共同截断的实现路径。普通 text 的省略属性不能替代此混排容器检查。",
+ "source_assertion_id": "s3_00"
+ },
+ {
+ "assertion_id": "s2_06",
+ "from_case": 3,
+ "to_case": 2,
+ "disposition": "adapted-to-unified-component",
+ "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。",
+ "previous_text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。",
+ "previous_verification": "追踪真实圆点节点的关键帧、fill-mode与周期,确认尺寸颜色及opacity变化对应原效果。",
+ "source_assertion_id": "s3_01"
+ },
+ {
+ "assertion_id": "s2_07",
+ "from_case": 3,
+ "to_case": 2,
+ "disposition": "adapted-to-unified-component",
+ "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。",
+ "previous_text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。",
+ "previous_verification": "追踪按下/松开/取消绑定到Skyline状态及CSS,核对scale(.96)、opacity(.7)与恢复值。",
+ "source_assertion_id": "s3_02"
+ }
+ ],
+ "new_assertions": [
+ "n3_00",
+ "n3_01",
+ "n3_02",
+ "n3_03",
+ "n3_04",
+ "n3_05"
+ ],
+ "adapted": 10,
+ "retained_ids": 31,
+ "id_renames": {
+ "s3_00": "s2_05",
+ "s3_01": "s2_06",
+ "s3_02": "s2_07",
+ "s4_00": "s1_07",
+ "s4_01": "s1_08",
+ "s4_02": "s1_09",
+ "s4_03": "s1_10"
+ }
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json
new file mode 100644
index 0000000000..05c821996b
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json
@@ -0,0 +1,190 @@
+{
+ "eval_id": 0,
+ "eval_name": "style-layout",
+ "title": "样式与布局",
+ "description": "适配组件样式、间距、视觉效果及字体兼容。",
+ "task_type": "adaptation",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/style-card.mpx",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "s0_00",
+ "text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。",
+ "rule_id": "skyline.text-ellipsis",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "文本溢出省略适配"
+ },
+ "verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。",
+ "source_assertions": [
+ "e0_01",
+ "e0_02",
+ "e6_06",
+ "e7_08",
+ "e8_05"
+ ]
+ },
+ {
+ "id": "s0_01",
+ "text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。",
+ "rule_id": "skyline.equal-columns",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "布局、盒模型与层叠差异"
+ },
+ "verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。",
+ "source_assertions": [
+ "e0_03",
+ "e6_07"
+ ]
+ },
+ {
+ "id": "s0_02",
+ "text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。",
+ "rule_id": "skyline.class-selector",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "选择器支持"
+ },
+ "verification": "追踪实际活动节点 class 与颜色声明的匹配关系。",
+ "source_assertions": [
+ "e0_04"
+ ]
+ },
+ {
+ "id": "s0_03",
+ "text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。",
+ "rule_id": "skyline.responsive-padding",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "@media screen 替换方案"
+ },
+ "verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。",
+ "source_assertions": [
+ "e0_06",
+ "e0_07",
+ "e0_08"
+ ]
+ },
+ {
+ "id": "s0_04",
+ "text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。",
+ "rule_id": "skyline.parent-spacing",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "垂直 margin 折叠处理"
+ },
+ "verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。",
+ "source_assertions": [
+ "e5_00"
+ ]
+ },
+ {
+ "id": "s0_05",
+ "text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。",
+ "rule_id": "skyline.sibling-spacing",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "垂直 margin 折叠处理"
+ },
+ "verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。",
+ "source_assertions": [
+ "e5_02"
+ ]
+ },
+ {
+ "id": "s0_06",
+ "text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。",
+ "rule_id": "skyline.layered-shadows",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "背景、边框与遮罩差异"
+ },
+ "verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。",
+ "source_assertions": [
+ "e5_04"
+ ]
+ },
+ {
+ "id": "s0_07",
+ "text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。",
+ "rule_id": "skyline.layered-filters",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "滤镜差异"
+ },
+ "verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。",
+ "source_assertions": [
+ "e5_05"
+ ]
+ },
+ {
+ "id": "s0_08",
+ "text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。",
+ "rule_id": "skyline.font-resolution",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "字体 PostScript name 兼容"
+ },
+ "verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。",
+ "source_assertions": [
+ "e5_06",
+ "e5_07"
+ ]
+ },
+ {
+ "id": "s0_09",
+ "text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。",
+ "rule_id": "skyline.single-shadow",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "背景、边框与遮罩差异"
+ },
+ "verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。",
+ "source_assertions": [
+ "e5_03"
+ ]
+ },
+ {
+ "id": "s0_10",
+ "text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。",
+ "rule_id": "skyline.single-filter",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "滤镜差异"
+ },
+ "verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。",
+ "source_assertions": [
+ "e5_05"
+ ]
+ },
+ {
+ "id": "s0_11",
+ "text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。",
+ "rule_id": "skyline.content-box-width",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "非标准默认值"
+ },
+ "verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。",
+ "source_assertions": [
+ "e5_01"
+ ]
+ }
+ ]
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx
new file mode 100644
index 0000000000..11b3ff67b0
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx
@@ -0,0 +1,37 @@
+
+
+ {{title}}
+ 包邮次日达
+ 活动
+ 内容
+ 第一块第二块
+ 单阴影单滤镜
+ 双阴影复合滤镜
+ 品牌A品牌B
+
+
+
+
+
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md
new file mode 100644
index 0000000000..95108f3023
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md
@@ -0,0 +1,5 @@
+# 样式与布局
+
+适配 style-card.mpx。保持长标题单行省略、两列等宽标签和红色活动文案。两种renderer在屏宽≤320px时卡片padding为12rpx,否则24rpx,按当前屏宽即可。child盒子的顶部距outer上外沿20px,这段距离由outer的padding-top实现;child保持四周10px padding,因此其内容顶部距outer上外沿30px。child内容宽100px、含padding外宽120px,两块垂直间距16px;呈现原有单个rgba阴影、双阴影、独立blur滤镜、复合滤镜及品牌字体效果。宿主已配置defaultDisplayBlock/defaultContentBox。字体二进制由宿主提供,City-Semibold有当前独立字体族,Trip-Medium来自宿主;字体核验信息和机型风险写入report.md,视觉调整需沿用已确认设计。
+
+交付所有输入业务文件的完整适配版本与report.md。多个组件分别保持自身接口与业务语义,无需为合并测试额外构造父子调用关系。评分目标为微信Skyline/glass-easel;WebView保持需求中的体验,其他目标分支可采用各自合法实现。验证证据放配置run-1/。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json
new file mode 100644
index 0000000000..9771dac58a
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json
@@ -0,0 +1,186 @@
+{
+ "eval_id": 1,
+ "eval_name": "page-scroll-sticky-layer-config",
+ "title": "页面滚动、吸顶与层级配置",
+ "description": "适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。",
+ "task_type": "adaptation",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/app.json",
+ "input/orders.mpx",
+ "input/service.js",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "s1_00",
+ "text": "Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。",
+ "rule_id": "skyline.list-scroll",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。",
+ "source_assertions": [
+ "e1_01",
+ "e2_08",
+ "e8_04"
+ ]
+ },
+ {
+ "id": "s1_01",
+ "text": "Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。",
+ "rule_id": "skyline.container-refresh",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。",
+ "source_assertions": [
+ "e1_02",
+ "e1_05",
+ "e8_03"
+ ]
+ },
+ {
+ "id": "s1_02",
+ "text": "Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。",
+ "rule_id": "skyline.container-bottom",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。",
+ "source_assertions": [
+ "e1_03",
+ "e8_03"
+ ]
+ },
+ {
+ "id": "s1_03",
+ "text": "Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。",
+ "rule_id": "skyline.container-scroll",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。",
+ "source_assertions": [
+ "e1_04"
+ ]
+ },
+ {
+ "id": "s1_04",
+ "text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。",
+ "rule_id": "skyline.page-renderer-navigation",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "适配参考"
+ },
+ "verification": "解析页面JSON并检查真实导航节点和主体布局关系。",
+ "source_assertions": [
+ "e1_06",
+ "e1_07",
+ "e8_06",
+ "e8_07"
+ ]
+ },
+ {
+ "id": "s1_05",
+ "text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。",
+ "rule_id": "skyline.lazy-components",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "app.json 顶层配置"
+ },
+ "verification": "解析 app.json 并检查顶层属性值。",
+ "source_assertions": [
+ "e1_08",
+ "e8_08"
+ ]
+ },
+ {
+ "id": "s1_06",
+ "text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。",
+ "rule_id": "skyline.renderer-baseline",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "rendererOptions.skyline 配置项"
+ },
+ "verification": "逐项解析五个字段的层级、类型和值。",
+ "source_assertions": [
+ "e1_09",
+ "e8_08"
+ ]
+ },
+ {
+ "id": "s1_07",
+ "text": "Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。",
+ "rule_id": "skyline.nested-association",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-component-reference.md",
+ "section": "Skyline 必填属性与结构约束"
+ },
+ "verification": "沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。",
+ "source_assertions": [
+ "e4_00",
+ "e4_01"
+ ]
+ },
+ {
+ "id": "s1_08",
+ "text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。",
+ "rule_id": "skyline.horizontal-list",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-component-reference.md",
+ "section": "Skyline 相对 WebView 的高频差异补充"
+ },
+ "verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。",
+ "source_assertions": [
+ "e4_02",
+ "e7_06",
+ "e7_07"
+ ]
+ },
+ {
+ "id": "s1_09",
+ "text": "Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。",
+ "rule_id": "skyline.sticky-structure",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "sticky 吸顶替代方案"
+ },
+ "verification": "核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。",
+ "source_assertions": [
+ "e4_03",
+ "e4_04",
+ "e4_05"
+ ]
+ },
+ {
+ "id": "s1_10",
+ "text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。",
+ "rule_id": "skyline.fixed-layer",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "z-index 与层叠适配"
+ },
+ "verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。",
+ "source_assertions": [
+ "e4_06",
+ "e4_07"
+ ]
+ }
+ ]
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json
new file mode 100644
index 0000000000..c61fe53e69
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json
@@ -0,0 +1 @@
+{"pages":["pages/home","pages/orders"],"window":{"navigationBarTitleText":"演示"},"rendererOptions":{"webview":{}}}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx
new file mode 100644
index 0000000000..b2da500718
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx
@@ -0,0 +1,56 @@
+
+
+ 订单概览滚动位置:{{scrollTop}}
+
+
+
+
+ {{entry.name}}
+
+
+ 关闭订单说明
+
+ 订单说明
+
+
+
+
+
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js
new file mode 100644
index 0000000000..7ca6b6bb77
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js
@@ -0,0 +1,11 @@
+export function fetchOrders (page, shouldFail = false) {
+ if (shouldFail) return Promise.reject(new Error('订单加载失败'))
+ return Promise.resolve(Array.from({ length: 4 }, (_, groupIndex) => ({
+ id: `group-${page}-${groupIndex}`,
+ title: `订单分组 ${page}-${groupIndex}`,
+ items: Array.from({ length: 8 }, (_, index) => ({
+ id: `order-${page}-${groupIndex}-${index}`,
+ name: `订单 ${page}-${groupIndex}-${index}`
+ }))
+ })))
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md
new file mode 100644
index 0000000000..6d469b4456
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md
@@ -0,0 +1,24 @@
+# 页面滚动、吸顶与层级配置
+
+将给定orders.mpx适配为完整的分组订单页面,更新app.json,保留service.js提供的数据接口。当前输入中的滚动事件仍走页面生命周期,需要将实际交互与目标滚动区域接通。所有业务在同一个页面内,范围已确认。
+
+## 同一页面的布局与滚动
+
+- 页面标题为“订单”,实际显示自定义导航;概览区高120px,展示主订单区域的滚动位置。
+- 导航下方为有界外层纵向滚动区域,概览可随外层滚动离开视口;内层为可独立纵向滚动的分组订单主体,内外层需要嵌套滚动关联。适配后依据页面可用高度安排滚动区,输入中的400px仅为原布局尺寸。
+- sections为[{id,title,items:[{id,name}]}]。每组标题在主订单区域内吸顶;组内横向展示订单,单项宽120px且可横向滚动。WebView和Skyline均提供对应体验。
+- 主订单纵向区域统一承接下拉刷新、触底分页和滚动位置展示。外层只承接概览与主体之间的嵌套滚动,横向区域只负责浏览该组订单。
+
+## 数据与交互
+
+- 初次进入调用fetchOrders(1),渲染4个分组,每组8条订单;分组和订单有稳定唯一id。
+- 主订单区域下拉刷新重新请求第1页并替换sections;刷新成功和失败都结束刷新反馈。fetchOrders(page,true)可注入失败;刷新失败保留原列表,继续操作。
+- 同一主订单区域触底时请求下一页,将新分组追加到sections;原分组与组内订单保留,页号成功后推进。
+- 主订单区域滚动时,通过概览显示该区域scrollTop;内外纵向及横向滚动的事件归属应清晰。
+- “订单说明”悬浮按钮打开全屏弹层,弹层覆盖该按钮;点击弹层关闭。
+
+## 交付与验证
+
+交付orders.mpx、app.json、service.js及report.md;原首页、window与WebView配置继续使用。输入中的页面滚动生命周期、CSS sticky及层级写法是待适配内容。采用适合嵌套与吸顶的滚动结构,保持上述业务语义。
+
+评分目标为微信Skyline/glass-easel,WebView保留对应体验,其他平台分支可采用自身合法实现。验证刷新成功/失败、连续两次分页及主滚动位置更新,并记录真实证据到run-1/。真机嵌套滚动、吸顶与手势未验证时标记not_run。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json
new file mode 100644
index 0000000000..1b8fd1ccad
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json
@@ -0,0 +1,138 @@
+{
+ "eval_id": 2,
+ "eval_name": "template-runtime-inline-animation",
+ "title": "模板运行时、图文混排与动画",
+ "description": "适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。",
+ "task_type": "adaptation",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/logo.svg",
+ "input/row.wxml",
+ "input/task.md",
+ "input/user-list.mpx"
+ ],
+ "assertions": [
+ {
+ "id": "s2_00",
+ "text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。",
+ "rule_id": "skyline.loop-data",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[必须] 确保 wx:for 数据始终为 Array 或 Object"
+ },
+ "verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。",
+ "source_assertions": [
+ "e2_03",
+ "e2_04"
+ ]
+ },
+ {
+ "id": "s2_01",
+ "text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。",
+ "rule_id": "skyline.scoped-selector",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[推荐] 用 this.createSelectorQuery 替代 wx.createSelectorQuery"
+ },
+ "verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。",
+ "source_assertions": [
+ "e2_05",
+ "e2_07"
+ ]
+ },
+ {
+ "id": "s2_02",
+ "text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。",
+ "rule_id": "skyline.scroll-context",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[必须] ScrollViewContext:开启 enhanced 属性"
+ },
+ "verification": "从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。",
+ "source_assertions": [
+ "e2_06"
+ ]
+ },
+ {
+ "id": "s2_03",
+ "text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。",
+ "rule_id": "skyline.loop-template",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "[必须] wx:for 内嵌 <include> 时改为 <template>"
+ },
+ "verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。",
+ "source_assertions": [
+ "e2_09"
+ ]
+ },
+ {
+ "id": "s2_04",
+ "text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。",
+ "rule_id": "skyline.navigator-children",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "navigator 嵌套限制"
+ },
+ "verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。",
+ "source_assertions": [
+ "e5_08",
+ "e5_09"
+ ]
+ },
+ {
+ "id": "s2_05",
+ "text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。",
+ "rule_id": "skyline.inline-flow",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "图文混排"
+ },
+ "verification": "检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。",
+ "source_assertions": [
+ "e3_00",
+ "e3_01",
+ "e3_02",
+ "e3_03"
+ ]
+ },
+ {
+ "id": "s2_06",
+ "text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。",
+ "rule_id": "skyline.node-animation",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "动画与过渡差异"
+ },
+ "verification": "追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。",
+ "source_assertions": [
+ "e3_04",
+ "e3_05"
+ ]
+ },
+ {
+ "id": "s2_07",
+ "text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。",
+ "rule_id": "skyline.state-transition",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "animation API 不支持 → 使用 CSS transition"
+ },
+ "verification": "追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。",
+ "source_assertions": [
+ "e3_06",
+ "e3_07",
+ "e3_08",
+ "e6_08"
+ ]
+ }
+ ]
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg
new file mode 100644
index 0000000000..6ba82ab4ea
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg
@@ -0,0 +1 @@
+
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml
new file mode 100644
index 0000000000..2b7eb9185e
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml
@@ -0,0 +1 @@
+{{index}}:{{item.name}}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md
new file mode 100644
index 0000000000..b37a139245
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md
@@ -0,0 +1,18 @@
+# 模板运行时、图文混排与动画
+
+将给定user-list.mpx适配为完整的用户列表组件,同时处理标题图文、提示圆点及回到顶部按钮的交互反馈。row.wxml是循环内使用的外部行片段,logo.svg是标题图标;两者继续作为组件资源交付。宿主页已接入Skyline/glass-easel,范围已确认。
+
+## 一个组件内的完整交互
+
+- 组件标题为label,允许长文案;图标和label在同一行展示,并在可用宽度不足时作为同段图文共同单行截断。
+- 标题旁的提示圆点保持8px、#f50,按原1秒周期在透明度0.3与1之间循环变化。
+- setRows接收{items:Array|null};初次渲染、数据返回前及null时显示空列表,正常数据仅展示visible用户。每行通过外部row.wxml展示过滤后行号与姓名。
+- “回到顶部”是同一个可按压按钮:按下缩放0.96且透明度0.7,松开或取消恢复1,过渡150ms;点击后操作实际用户列表滚回顶部。旁边other滚动容器用于区分查询目标。
+- 两个详情入口均到/pages/detail:一个是简单文本入口,一个是卡片内容入口,均保持可用。
+- 保留label/payload接口及config.default数据。现有数字开头id、include循环片段、未保护的循环数据、伪元素动画和动画API是待适配内容。
+
+## 交付与验证
+
+交付user-list.mpx、row.wxml、logo.svg及report.md。所有模板、运行时查询、图文与动画适配都在这一个组件及其外部片段中完成。
+
+评分目标为微信Skyline/glass-easel;WebView保持对应体验,其他平台分支可采用自身合法实现。验证初始化/null/数组更新、过滤行数据、实际查询目标及回顶调用、两个详情跳转、长label共同截断、按下/松开/取消状态。测试和审计证据放run-1/;真机渲染与实际滚动未验证时标记not_run。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx
new file mode 100644
index 0000000000..2df19142c6
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx
@@ -0,0 +1,57 @@
+
+
+ {{label}}
+
+
+
+
+
+ 回到顶部
+ 详情
+ 卡片详情
+
+
+
+
+
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json
new file mode 100644
index 0000000000..544dfb8807
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json
@@ -0,0 +1,106 @@
+{
+ "eval_id": 3,
+ "eval_name": "new-task-board-page",
+ "title": "从零创建任务看板页面",
+ "description": "仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。",
+ "task_type": "creation",
+ "prompt": "请读取input/task.md,根据产品需求从零创建Mpx任务看板页面并更新宿主配置,兼容微信Skyline与WebView。范围已确认,交付完整文件和验证报告。",
+ "files": [
+ "input/app.json",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "n3_00",
+ "text": "Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。",
+ "rule_id": "skyline.creation-page-config",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "适配参考"
+ },
+ "verification": "解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_04",
+ "s1_05",
+ "s1_06"
+ ]
+ },
+ {
+ "id": "n3_01",
+ "text": "Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。",
+ "rule_id": "skyline.creation-scroll-layout",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_00"
+ ]
+ },
+ {
+ "id": "n3_02",
+ "text": "Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。",
+ "rule_id": "skyline.creation-refresh",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_01"
+ ]
+ },
+ {
+ "id": "n3_03",
+ "text": "Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。",
+ "rule_id": "skyline.creation-pagination",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_02"
+ ]
+ },
+ {
+ "id": "n3_04",
+ "text": "Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。",
+ "rule_id": "skyline.creation-title-ellipsis",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "文本溢出省略适配"
+ },
+ "verification": "检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s0_00"
+ ]
+ },
+ {
+ "id": "n3_05",
+ "text": "Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。",
+ "rule_id": "skyline.creation-press-feedback",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "animation API 不支持 → 使用 CSS transition"
+ },
+ "verification": "追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s2_07"
+ ]
+ }
+ ]
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json
new file mode 100644
index 0000000000..4494c3e852
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json
@@ -0,0 +1,11 @@
+{
+ "pages": [
+ "pages/home"
+ ],
+ "window": {
+ "navigationBarTitleText": "演示"
+ },
+ "rendererOptions": {
+ "webview": {}
+ }
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md
new file mode 100644
index 0000000000..4112f37b6d
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md
@@ -0,0 +1,19 @@
+# 从零创建任务看板页面
+
+没有现成页面代码。请根据以下产品需求从零创建 pages/task-board.mpx,并交付更新后的 app.json。页面面向微信 Skyline/glass-easel,同时保持微信 WebView 的对应体验。范围已确认,宿主首页继续保留。
+
+## 数据与交互
+
+- 初始任务为[{taskKey:'t1',title:'整理本周跨团队协作事项与上线验收清单',category:'工作',completed:false},{taskKey:'t2',title:'购买周末出行用品',category:'生活',completed:false},{taskKey:'t3',title:'完成每日阅读',category:'生活',completed:true}]。
+- 顶部显示“任务看板”和当前筛选结果数量,提供“全部/工作/生活”分类,当前分类有选中态。通过页面category参数选择初始分类,非法值回到全部。
+- 点击任务切换完成状态;无匹配任务时显示“暂无任务”。标题无论多长都显示一行,超出部分省略。
+- 页面主体数据增多时可纵向滚动,顶部标题和筛选区域保持可见;窄屏仍有明确的滚动区域。
+- 下拉刷新恢复初始任务。模拟异步请求,并提供可注入失败的测试入口;请求结束后刷新反馈结束,失败时原列表仍可继续使用。
+- 滚动到底部追加2条当前分类的未完成任务,使用唯一taskKey;全部分类时追加工作任务。每次触底后列表继续显示已存在任务。
+- 分类按钮按下时缩放到0.96、透明度0.7,松开或取消恢复1;过渡150ms。
+
+## 实现与交付
+
+使用Mpx组合式API及script setup,样式使用组件内语义class。宿主未提供原子CSS工具链。通过所给app.json接入页面,保留首页和现有window/WebView设置;页面配置与导航由你完成,确保可用于Skyline和WebView。
+
+交付pages/task-board.mpx、app.json及report.md。记录真实验证及未执行项;测试与证据放配置run-1/。验证内容包括参数初始化、筛选、完成状态、空列表、刷新成功/失败、连续分页及触摸取消。当前专项评分只评价Skyline适配要求,通用Mpx语法与业务行为单独验证。其他目标平台可采用自身合法分支。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json b/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json
new file mode 100644
index 0000000000..977c47d8e1
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json
@@ -0,0 +1,675 @@
+{
+ "skill_name": "mpx2skyline",
+ "suite_version": 4,
+ "iteration": 4,
+ "status": "cases-ready-not-run",
+ "description": "4个case:三个存量适配综合场景和一个从零创建页面场景,共37条Skyline正向断言。",
+ "scoring_scope": "仅评价微信Skyline/glass-easel实际生效实现,WebView仅用于对应兼容要求;RN分支按自身规则实现。",
+ "comparison": {
+ "purpose": "独立Skill与合并Skill在同一新版测试集上的不劣化比较",
+ "groups": [
+ {
+ "id": "mpx2skyline",
+ "skill": ".agents/skills/mpx2skyline/SKILL.md",
+ "status": "not_run"
+ },
+ {
+ "id": "no_skill",
+ "skill": null,
+ "status": "not_run"
+ },
+ {
+ "id": "merged_skill",
+ "skill": null,
+ "status": "path-to-be-specified-before-execution"
+ }
+ ]
+ },
+ "runner": {
+ "prompt_templates": "prompt_templates.json",
+ "grading_standard": "grading-standard.md",
+ "subagent_config": {
+ "model": "must_match_parent",
+ "reasoning_effort": "must_match_parent",
+ "fork_turns": "none"
+ }
+ },
+ "evals": [
+ {
+ "id": 0,
+ "name": "style-layout",
+ "title": "样式与布局",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/style-card.mpx",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "s0_00",
+ "text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。",
+ "rule_id": "skyline.text-ellipsis",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "文本溢出省略适配"
+ },
+ "verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。",
+ "source_assertions": [
+ "e0_01",
+ "e0_02",
+ "e6_06",
+ "e7_08",
+ "e8_05"
+ ]
+ },
+ {
+ "id": "s0_01",
+ "text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。",
+ "rule_id": "skyline.equal-columns",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "布局、盒模型与层叠差异"
+ },
+ "verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。",
+ "source_assertions": [
+ "e0_03",
+ "e6_07"
+ ]
+ },
+ {
+ "id": "s0_02",
+ "text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。",
+ "rule_id": "skyline.class-selector",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "选择器支持"
+ },
+ "verification": "追踪实际活动节点 class 与颜色声明的匹配关系。",
+ "source_assertions": [
+ "e0_04"
+ ]
+ },
+ {
+ "id": "s0_03",
+ "text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。",
+ "rule_id": "skyline.responsive-padding",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "@media screen 替换方案"
+ },
+ "verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。",
+ "source_assertions": [
+ "e0_06",
+ "e0_07",
+ "e0_08"
+ ]
+ },
+ {
+ "id": "s0_04",
+ "text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。",
+ "rule_id": "skyline.parent-spacing",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "垂直 margin 折叠处理"
+ },
+ "verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。",
+ "source_assertions": [
+ "e5_00"
+ ]
+ },
+ {
+ "id": "s0_05",
+ "text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。",
+ "rule_id": "skyline.sibling-spacing",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "垂直 margin 折叠处理"
+ },
+ "verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。",
+ "source_assertions": [
+ "e5_02"
+ ]
+ },
+ {
+ "id": "s0_06",
+ "text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。",
+ "rule_id": "skyline.layered-shadows",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "背景、边框与遮罩差异"
+ },
+ "verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。",
+ "source_assertions": [
+ "e5_04"
+ ]
+ },
+ {
+ "id": "s0_07",
+ "text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。",
+ "rule_id": "skyline.layered-filters",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "滤镜差异"
+ },
+ "verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。",
+ "source_assertions": [
+ "e5_05"
+ ]
+ },
+ {
+ "id": "s0_08",
+ "text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。",
+ "rule_id": "skyline.font-resolution",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "字体 PostScript name 兼容"
+ },
+ "verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。",
+ "source_assertions": [
+ "e5_06",
+ "e5_07"
+ ]
+ },
+ {
+ "id": "s0_09",
+ "text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。",
+ "rule_id": "skyline.single-shadow",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "背景、边框与遮罩差异"
+ },
+ "verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。",
+ "source_assertions": [
+ "e5_03"
+ ]
+ },
+ {
+ "id": "s0_10",
+ "text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。",
+ "rule_id": "skyline.single-filter",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "滤镜差异"
+ },
+ "verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。",
+ "source_assertions": [
+ "e5_05"
+ ]
+ },
+ {
+ "id": "s0_11",
+ "text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。",
+ "rule_id": "skyline.content-box-width",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "非标准默认值"
+ },
+ "verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。",
+ "source_assertions": [
+ "e5_01"
+ ]
+ }
+ ],
+ "description": "适配组件样式、间距、视觉效果及字体兼容。",
+ "task_type": "adaptation",
+ "source_cases": [
+ 0
+ ]
+ },
+ {
+ "id": 1,
+ "name": "page-scroll-sticky-layer-config",
+ "title": "页面滚动、吸顶与层级配置",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/app.json",
+ "input/orders.mpx",
+ "input/service.js",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "s1_00",
+ "text": "Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。",
+ "rule_id": "skyline.list-scroll",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。",
+ "source_assertions": [
+ "e1_01",
+ "e2_08",
+ "e8_04"
+ ]
+ },
+ {
+ "id": "s1_01",
+ "text": "Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。",
+ "rule_id": "skyline.container-refresh",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。",
+ "source_assertions": [
+ "e1_02",
+ "e1_05",
+ "e8_03"
+ ]
+ },
+ {
+ "id": "s1_02",
+ "text": "Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。",
+ "rule_id": "skyline.container-bottom",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。",
+ "source_assertions": [
+ "e1_03",
+ "e8_03"
+ ]
+ },
+ {
+ "id": "s1_03",
+ "text": "Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。",
+ "rule_id": "skyline.container-scroll",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。",
+ "source_assertions": [
+ "e1_04"
+ ]
+ },
+ {
+ "id": "s1_04",
+ "text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。",
+ "rule_id": "skyline.page-renderer-navigation",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "适配参考"
+ },
+ "verification": "解析页面JSON并检查真实导航节点和主体布局关系。",
+ "source_assertions": [
+ "e1_06",
+ "e1_07",
+ "e8_06",
+ "e8_07"
+ ]
+ },
+ {
+ "id": "s1_05",
+ "text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。",
+ "rule_id": "skyline.lazy-components",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "app.json 顶层配置"
+ },
+ "verification": "解析 app.json 并检查顶层属性值。",
+ "source_assertions": [
+ "e1_08",
+ "e8_08"
+ ]
+ },
+ {
+ "id": "s1_06",
+ "text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。",
+ "rule_id": "skyline.renderer-baseline",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "rendererOptions.skyline 配置项"
+ },
+ "verification": "逐项解析五个字段的层级、类型和值。",
+ "source_assertions": [
+ "e1_09",
+ "e8_08"
+ ]
+ },
+ {
+ "id": "s1_07",
+ "text": "Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。",
+ "rule_id": "skyline.nested-association",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-component-reference.md",
+ "section": "Skyline 必填属性与结构约束"
+ },
+ "verification": "沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。",
+ "source_assertions": [
+ "e4_00",
+ "e4_01"
+ ]
+ },
+ {
+ "id": "s1_08",
+ "text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。",
+ "rule_id": "skyline.horizontal-list",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-component-reference.md",
+ "section": "Skyline 相对 WebView 的高频差异补充"
+ },
+ "verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。",
+ "source_assertions": [
+ "e4_02",
+ "e7_06",
+ "e7_07"
+ ]
+ },
+ {
+ "id": "s1_09",
+ "text": "Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。",
+ "rule_id": "skyline.sticky-structure",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "sticky 吸顶替代方案"
+ },
+ "verification": "核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。",
+ "source_assertions": [
+ "e4_03",
+ "e4_04",
+ "e4_05"
+ ]
+ },
+ {
+ "id": "s1_10",
+ "text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。",
+ "rule_id": "skyline.fixed-layer",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "z-index 与层叠适配"
+ },
+ "verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。",
+ "source_assertions": [
+ "e4_06",
+ "e4_07"
+ ]
+ }
+ ],
+ "description": "适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。",
+ "task_type": "adaptation",
+ "source_cases": [
+ 1,
+ 4
+ ]
+ },
+ {
+ "id": 2,
+ "name": "template-runtime-inline-animation",
+ "title": "模板运行时、图文混排与动画",
+ "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。",
+ "files": [
+ "input/logo.svg",
+ "input/row.wxml",
+ "input/task.md",
+ "input/user-list.mpx"
+ ],
+ "assertions": [
+ {
+ "id": "s2_00",
+ "text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。",
+ "rule_id": "skyline.loop-data",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[必须] 确保 wx:for 数据始终为 Array 或 Object"
+ },
+ "verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。",
+ "source_assertions": [
+ "e2_03",
+ "e2_04"
+ ]
+ },
+ {
+ "id": "s2_01",
+ "text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。",
+ "rule_id": "skyline.scoped-selector",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[推荐] 用 this.createSelectorQuery 替代 wx.createSelectorQuery"
+ },
+ "verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。",
+ "source_assertions": [
+ "e2_05",
+ "e2_07"
+ ]
+ },
+ {
+ "id": "s2_02",
+ "text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。",
+ "rule_id": "skyline.scroll-context",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-runtime-practice.md",
+ "section": "[必须] ScrollViewContext:开启 enhanced 属性"
+ },
+ "verification": "从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。",
+ "source_assertions": [
+ "e2_06"
+ ]
+ },
+ {
+ "id": "s2_03",
+ "text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。",
+ "rule_id": "skyline.loop-template",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "[必须] wx:for 内嵌 <include> 时改为 <template>"
+ },
+ "verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。",
+ "source_assertions": [
+ "e2_09"
+ ]
+ },
+ {
+ "id": "s2_04",
+ "text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。",
+ "rule_id": "skyline.navigator-children",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "navigator 嵌套限制"
+ },
+ "verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。",
+ "source_assertions": [
+ "e5_08",
+ "e5_09"
+ ]
+ },
+ {
+ "id": "s2_05",
+ "text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。",
+ "rule_id": "skyline.inline-flow",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "图文混排"
+ },
+ "verification": "检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。",
+ "source_assertions": [
+ "e3_00",
+ "e3_01",
+ "e3_02",
+ "e3_03"
+ ]
+ },
+ {
+ "id": "s2_06",
+ "text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。",
+ "rule_id": "skyline.node-animation",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-style-reference.md",
+ "section": "动画与过渡差异"
+ },
+ "verification": "追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。",
+ "source_assertions": [
+ "e3_04",
+ "e3_05"
+ ]
+ },
+ {
+ "id": "s2_07",
+ "text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。",
+ "rule_id": "skyline.state-transition",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "animation API 不支持 → 使用 CSS transition"
+ },
+ "verification": "追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。",
+ "source_assertions": [
+ "e3_06",
+ "e3_07",
+ "e3_08",
+ "e6_08"
+ ]
+ }
+ ],
+ "description": "适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。",
+ "task_type": "adaptation",
+ "source_cases": [
+ 2,
+ 3
+ ]
+ },
+ {
+ "id": 3,
+ "name": "new-task-board-page",
+ "title": "从零创建任务看板页面",
+ "description": "仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。",
+ "task_type": "creation",
+ "prompt": "请读取input/task.md,根据产品需求从零创建Mpx任务看板页面并更新宿主配置,兼容微信Skyline与WebView。范围已确认,交付完整文件和验证报告。",
+ "files": [
+ "input/app.json",
+ "input/task.md"
+ ],
+ "assertions": [
+ {
+ "id": "n3_00",
+ "text": "Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。",
+ "rule_id": "skyline.creation-page-config",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-configuration.md",
+ "section": "适配参考"
+ },
+ "verification": "解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_04",
+ "s1_05",
+ "s1_06"
+ ]
+ },
+ {
+ "id": "n3_01",
+ "text": "Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。",
+ "rule_id": "skyline.creation-scroll-layout",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_00"
+ ]
+ },
+ {
+ "id": "n3_02",
+ "text": "Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。",
+ "rule_id": "skyline.creation-refresh",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_01"
+ ]
+ },
+ {
+ "id": "n3_03",
+ "text": "Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。",
+ "rule_id": "skyline.creation-pagination",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "页面滚动替代方案"
+ },
+ "verification": "从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s1_02"
+ ]
+ },
+ {
+ "id": "n3_04",
+ "text": "Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。",
+ "rule_id": "skyline.creation-title-ellipsis",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "文本溢出省略适配"
+ },
+ "verification": "检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s0_00"
+ ]
+ },
+ {
+ "id": "n3_05",
+ "text": "Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。",
+ "rule_id": "skyline.creation-press-feedback",
+ "scope": "skyline",
+ "source": {
+ "file": "references/skyline-layout-practice.md",
+ "section": "animation API 不支持 → 使用 CSS transition"
+ },
+ "verification": "追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。",
+ "source_assertions": [],
+ "related_adaptation_assertions": [
+ "s2_07"
+ ]
+ }
+ ],
+ "design_references": [
+ "mpx2rn-workspace/iteration-17/eval-6-new-rating-component",
+ "mpx2rn-workspace/iteration-17/eval-7-new-segmented-control",
+ "mpx2rn-workspace/iteration-17/eval-8-new-task-board-page"
+ ]
+ }
+ ]
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json b/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json
new file mode 100644
index 0000000000..c156b8b171
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json
@@ -0,0 +1,8 @@
+{
+ "note": "保留未改造业务输入的原始哈希;case 1页面及case 2组件已按合并需求重组,由语义测试验证。",
+ "files": {
+ "eval-0-style-layout/input/style-card.mpx": "02971adbcf26eea73fdb3b249f04307a3cd9dc86e35d0db4a3890fc700c50370",
+ "eval-2-template-runtime-inline-animation/input/logo.svg": "c71a85400c9d1bc64393103364611c9370076caec60d65bc20fdcfdd97f6d29d",
+ "eval-2-template-runtime-inline-animation/input/row.wxml": "80f43cf55dbaf032920128f167d8b324b588e4dc01cbaa66e5f4063c394c876d"
+ }
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md b/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md
new file mode 100644
index 0000000000..d53884509c
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md
@@ -0,0 +1,21 @@
+# Skyline 专项评分标准 v4
+
+4个case,共37条正向断言,分母依次为12、11、8、6。evals.json是唯一评分定义,各eval_metadata.json保持一致。
+
+仅评价实际微信Skyline/glass-easel路径;WebView按明确的兼容要求检查,RN分支可采用自身合法实现。每条满足全部条件得1分,证据不足得0分。允许规则支持的语义等价实现;按verification追踪真实节点与执行链路。
+
+原31条适配断言保留覆盖目标;case 1的6条滚动断言按统一页面修订,case 2的4条验证方法明确指向统一组件中的实际节点,迁移表保留前版内容。新增6条创建断言用于验证“需求到方案”的独立入口,与迁移case共享能力规则但不同任务触发;related_adaptation_assertions显式标记对应能力,不能宣称37条是37种互不重叠的能力。每个case内部按不同适配结果计分。case 1的主订单区域使用custom承载吸顶,外层nested负责嵌套,横向list/custom负责组内订单;刷新、分页和位置监听都验证主区域的真实绑定。另列迁移31条和创建6条分数,避免综合分掩盖任一入口劣化。
+
+交付完整性、props/API/script setup/defineExpose语法、页面注册、参数筛选、普通状态与事件、稳定key及资源完整性记录于validation.json,不单独占Skyline分数。真实编译错误使目标实现不可执行时,对应断言仍失败。
+
+新建case实际执行参数初始化、空分类、完成切换、刷新成功/失败、两次分页与触摸取消的业务验证;事件与Skyline容器/动画的衔接按专项断言评分。静态或mock通过不等于真机通过。应用构建、微信模板编译、真机渲染分别记录,未执行为not_run。
+
+产物位于eval-*//outputs/;评分、验证、执行、耗时和Token证据位于run-1/。输入统一读取eval-*/input/,Skill读取中央路径,记录执行前后输入和Skill版本/哈希,缺失Token/精确耗时用unavailable。
+
+独立Skill、no_skill及未来合并Skill采用相同输入、模型参数和验证方式,只有Skill读取权限不同。比较逐条通过转失败及分入口分数;本版尚未执行,不复用iteration-3分数。
+
+case 2的外部row.wxml与logo.svg继续保留,以验证外部模板作用域与真实图文混排;回顶按钮的查询结果和CSS反馈分别计分,所有证据应来自同一个user-list组件。
+
+Case 2断言统一编号为s2_00–s2_07;原s3_00/s3_01/s3_02依次迁移为s2_05/s2_06/s2_07,旧ID保存在迁移表source_assertion_id中。断言正文及验证方法不变。
+
+Case 1断言统一编号为s1_00–s1_10;原s4_00/s4_01/s4_02/s4_03依次迁移为s1_07/s1_08/s1_09/s1_10,旧ID保存在迁移表source_assertion_id中。评分要求不变。
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json b/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json
new file mode 100644
index 0000000000..f1a7da4fba
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json
@@ -0,0 +1,16 @@
+{
+ "variables": {
+ "TASK_PROMPT": "eval.prompt",
+ "INPUT_PATHS": "当前eval外层input文件绝对路径;共享读取",
+ "OUTPUT_DIR": "eval-*//outputs绝对路径",
+ "WORKDIR": "eval-*//run-1绝对路径",
+ "SKILL_PATH": "当前配置中央Skill路径;执行前指定"
+ },
+ "template": "任务:{{TASK_PROMPT}}\n输入:{{INPUT_PATHS}},先读task.md。\n先完整读取{{SKILL_PATH}},按需阅读关联参考。当前目标是微信Skyline/glass-easel,其他平台分支可采用各自合法实现。\n工作目录:{{WORKDIR}};业务产物与report.md写入{{OUTPUT_DIR}},测试和审计证据放工作目录。输入和Skill共享只读,不复制到run目录。\n仅读取任务输入及当前配置允许的Skill,保持评分文件和历史产物隔离。范围已确认,直接实施。记录真实验证与未验证项,单测失败最多尝试3次修复。",
+ "archive_rules": [
+ "执行前后记录输入、Skill逐文件哈希和模型参数。",
+ "产物完整性、语法编译、业务回归另记validation.json;Skyline得分仅来自evals.json。",
+ "独立Skill与合并Skill采用同一模板、输入、模型参数和验证方法。"
+ ],
+ "no_skill_template": "任务:{{TASK_PROMPT}}\n输入:{{INPUT_PATHS}},先读task.md。\n本组不读取任何Skill或Skill参考资料,仅依据输入和已有知识完成。当前目标是微信Skyline/glass-easel,其他平台分支可采用各自合法实现。\n工作目录:{{WORKDIR}};业务产物与report.md写入{{OUTPUT_DIR}},测试和审计证据放工作目录。输入和Skill共享只读,不复制到run目录。\n仅读取任务输入及当前配置允许的Skill,保持评分文件和历史产物隔离。范围已确认,直接实施。记录真实验证与未验证项,单测失败最多尝试3次修复。"
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json
new file mode 100644
index 0000000000..d83027fd64
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json
@@ -0,0 +1,8 @@
+{
+ "status": "not_run",
+ "suite_version": 4,
+ "cases": 4,
+ "assertions": 37,
+ "historical_baseline": "../iteration-3",
+ "baseline_reuse": "合并任务改变上下文,新建任务增加创建入口;新版需重新执行两组,旧评分不迁移。"
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json b/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json
new file mode 100644
index 0000000000..61c2d14567
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json
@@ -0,0 +1,30 @@
+{
+ "status": "definition-only",
+ "files": {
+ "run-metadata.json": "af00d55a3dcfc624e1936da6d8d2b4e8a1099b25c7de3ac2c9c270085b0eef41",
+ "fixture-provenance.json": "765bc5058b6e0703b68094c00a1dd00b508b899b1d4c32f75b36d381091adf32",
+ "grading-standard.md": "7f451565d85d3f1f0a1a4f8133a46ba6defd99f81ede9d08bd341ed47312b952",
+ "evals.json": "69cd93daf51ff3e3da3a7d5c02e0e7063f89319921e849abd9e8c01b200dcecb",
+ "prompt_templates.json": "34504f40ce661883354785a1091cba0c7dc3e793898d1c8a99f36bf1f631051a",
+ "README.md": "e5dad33a70648d452b99221e64e152373f28f934622522eccb12efb13b5f100b",
+ "assertion-migration.json": "6fc54abc5f97a583ed48f5fdf62e79dd5cae65f031e50faf155d068993a57f77",
+ "validate-suite.test.cjs": "5dff42924895d258a1d7e7028cc6d1a75b238d2511507f9500914e11e84f5c8c",
+ "eval-3-new-task-board-page/eval_metadata.json": "092dc91a23645b36e05913857ff54cb1f45985b3a36e67f2693c832b307ed85f",
+ "eval-1-page-scroll-sticky-layer-config/eval_metadata.json": "1615c69f86f8f983af32b8d733fd02dd39dd6beec977385398cca36ef05f452a",
+ "eval-0-style-layout/eval_metadata.json": "d83839636bcc95b3c81cc0c4cfbeb64608e3802b6da945bd9024841927655962",
+ "eval-2-template-runtime-inline-animation/eval_metadata.json": "970d2b8dfd396cb274b0dfd8034fb8e28c2c10a2699851ab196e80f90d13a0cb",
+ "eval-2-template-runtime-inline-animation/input/row.wxml": "80f43cf55dbaf032920128f167d8b324b588e4dc01cbaa66e5f4063c394c876d",
+ "eval-2-template-runtime-inline-animation/input/user-list.mpx": "508fe0ecaa078cb526de50a5d8a0be13209401ee36feed974fea1c450f422e11",
+ "eval-2-template-runtime-inline-animation/input/task.md": "820cd9daddb3bdb88cb7ef386f42ab63385953ac528be86b15e768875bf17c38",
+ "eval-2-template-runtime-inline-animation/input/logo.svg": "c71a85400c9d1bc64393103364611c9370076caec60d65bc20fdcfdd97f6d29d",
+ "eval-0-style-layout/input/style-card.mpx": "02971adbcf26eea73fdb3b249f04307a3cd9dc86e35d0db4a3890fc700c50370",
+ "eval-0-style-layout/input/task.md": "2d3e10c639fd4715bdcd80fe4a221519a80f4cd9c5d7ed49a709ee335c01ca5f",
+ "eval-1-page-scroll-sticky-layer-config/input/orders.mpx": "6e0df185e713f033af82368b5acf069c43812259509b2a381d3ce946de0b60ad",
+ "eval-1-page-scroll-sticky-layer-config/input/app.json": "08b6c0c8a67d9602540f6eba281fd3649e75b8aee175ce2640a7dd3a714cf1ac",
+ "eval-1-page-scroll-sticky-layer-config/input/service.js": "977d51816125ab91147f6e3b4bf9b764046fefc7ad958495285cd4489e3bf164",
+ "eval-1-page-scroll-sticky-layer-config/input/task.md": "f91ca5b0a218c2c50ce008a605568a762f4a62ab96bb1f08c37309d0de6aba34",
+ "eval-3-new-task-board-page/input/app.json": "29beeb70b987df710a8381437d21a137ff68b9cab73eddace62ca26c1fa54dca",
+ "eval-3-new-task-board-page/input/task.md": "97a423449478347cb8068eb755544a9fcf1cb12d06a0459ac8725120e7899286"
+ },
+ "note": "记录新版定义和输入;执行时另记录实际Skill版本/哈希。"
+}
diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs b/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs
new file mode 100644
index 0000000000..0352de60c0
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs
@@ -0,0 +1,151 @@
+const fs = require('fs')
+const path = require('path')
+const repo = process.cwd()
+const read = file => JSON.parse(fs.readFileSync(file, 'utf8'))
+const manifest = read(path.join(__dirname, 'evals.json'))
+const assertions = manifest.evals.flatMap(item => item.assertions)
+
+test('four cases preserve all 31 adaptation assertions and add six creation assertions', () => {
+ expect(manifest.evals.map(item => item.assertions.length)).toEqual([12, 11, 8, 6])
+ expect(assertions).toHaveLength(37)
+ expect(new Set(assertions.map(item => item.id)).size).toBe(37)
+ const migration = read(path.join(__dirname, 'assertion-migration.json'))
+ expect(migration.items).toHaveLength(31)
+ expect(new Set(migration.items.map(item => item.assertion_id)).size).toBe(31)
+ migration.items.forEach(move => {
+ const current = assertions.find(value => value.id === move.assertion_id)
+ expect(current).toBeDefined()
+ expect(manifest.evals[move.to_case].assertions).toContain(current)
+ if (move.disposition !== 'preserved') {
+ expect(move.previous_text.length).toBeGreaterThan(0)
+ expect(move.previous_verification.length).toBeGreaterThan(0)
+ expect([1, 2]).toContain(move.to_case)
+ } else {
+ expect(current.text).toBe(move.previous_text)
+ expect(current.verification).toBe(move.previous_verification)
+ }
+ })
+})
+
+test('metadata, shared inputs and rule references resolve', () => {
+ const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser'))
+ const babel = require(path.join(repo, 'node_modules/@babel/core'))
+ manifest.evals.forEach(item => {
+ const dir = path.join(__dirname, `eval-${item.id}-${item.name}`)
+ const metadata = read(path.join(dir, 'eval_metadata.json'))
+ expect(metadata.assertions).toEqual(item.assertions)
+ expect(metadata.files).toEqual(item.files)
+ item.files.forEach(file => {
+ const target = path.join(dir, file)
+ expect(fs.existsSync(target)).toBe(true)
+ if (file.endsWith('.mpx')) {
+ const sfc = parse(fs.readFileSync(target, 'utf8'), { filePath: target, mode: 'wx' })
+ expect(sfc.template.content.length).toBeGreaterThan(0)
+ expect(() => babel.parseSync(sfc.script.content, { configFile: false, babelrc: false, sourceType: 'module' })).not.toThrow()
+ expect(() => JSON.parse(sfc.json.content)).not.toThrow()
+ }
+ if (file.endsWith('.json')) expect(() => read(target)).not.toThrow()
+ })
+ item.assertions.forEach(assertion => {
+ expect(assertion.scope).toBe('skyline')
+ expect(assertion.text).toContain('Skyline')
+ expect(assertion.text).not.toMatch(/不得|禁止|不能|不依赖|不要|无Worklet|不引入/)
+ const reference = fs.readFileSync(path.join(repo, '.agents/skills/mpx2skyline', assertion.source.file), 'utf8')
+ expect(reference).toContain(assertion.source.section)
+ })
+ })
+})
+
+test('merged fixtures are intact and creation starts from requirements', () => {
+ const crypto = require('crypto')
+ const provenance = read(path.join(__dirname, 'fixture-provenance.json'))
+ Object.entries(provenance.files).forEach(([file, digest]) => {
+ expect(crypto.createHash('sha256').update(fs.readFileSync(path.join(__dirname, file))).digest('hex')).toBe(digest)
+ })
+ const creation = manifest.evals[3]
+ expect(creation.task_type).toBe('creation')
+ expect(creation.files).toEqual(['input/app.json', 'input/task.md'])
+ creation.assertions.forEach(item => item.related_adaptation_assertions.forEach(id => {
+ expect(assertions.some(assertion => assertion.id === id)).toBe(true)
+ }))
+ expect(manifest.status).toBe('cases-ready-not-run')
+ expect(read(path.join(__dirname, 'run-metadata.json')).status).toBe('not_run')
+ expect(fs.existsSync(path.join(__dirname, 'benchmark.json'))).toBe(false)
+})
+
+
+test('unified orders fixture appends grouped pages and retains data on refresh failure', async () => {
+ const vm = require('vm')
+ const dir = path.join(__dirname, 'eval-1-page-scroll-sticky-layer-config/input')
+ expect(fs.readdirSync(dir).sort()).toEqual(['app.json', 'orders.mpx', 'service.js', 'task.md'])
+ const service = fs.readFileSync(path.join(dir, 'service.js'), 'utf8')
+ const fetchOrders = vm.runInNewContext(service.replace('export function', 'function') + '; fetchOrders')
+ const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser'))
+ const file = path.join(dir, 'orders.mpx')
+ const sfc = parse(fs.readFileSync(file, 'utf8'), { filePath: file, mode: 'wx' })
+ let options
+ const stop = jest.fn()
+ vm.runInNewContext(sfc.script.content.replace(/^import .*$/gm, ''), {
+ createPage: value => { options = value },
+ fetchOrders,
+ wx: { stopPullDownRefresh: stop }
+ })
+ const state = Object.assign({}, options.data, options.methods)
+ await state.reload()
+ expect(state.sections).toHaveLength(4)
+ expect(state.sections.every(section => section.items.length === 8)).toBe(true)
+ await state.loadMore()
+ await state.loadMore()
+ expect(state.sections).toHaveLength(12)
+ expect(state.pageNo).toBe(3)
+ expect(new Set(state.sections.map(section => section.id)).size).toBe(12)
+ const orders = state.sections.flatMap(section => section.items)
+ expect(new Set(orders.map(order => order.id)).size).toBe(96)
+ const previous = state.sections
+ await expect(state.reload(true)).rejects.toThrow('订单加载失败')
+ expect(state.sections).toBe(previous)
+ expect(stop).toHaveBeenCalledTimes(2)
+ state.open()
+ expect(state.opened).toBe(true)
+ state.close()
+ expect(state.opened).toBe(false)
+ const byId = Object.fromEntries(manifest.evals[1].assertions.map(item => [item.id, item]))
+ expect(byId.s1_07.text).toContain('type=custom')
+ expect(byId.s1_00.text).not.toContain('type=list')
+ ;['s1_01', 's1_02', 's1_03'].forEach(id => expect(byId[id].text).toContain('主订单纵向scroll-view'))
+})
+
+
+test('unified user-list connects heading, external rows and feedback to the same component', () => {
+ const vm = require('vm')
+ const dir = path.join(__dirname, 'eval-2-template-runtime-inline-animation/input')
+ expect(fs.readdirSync(dir).sort()).toEqual(['logo.svg', 'row.wxml', 'task.md', 'user-list.mpx'])
+ const file = path.join(dir, 'user-list.mpx')
+ const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser'))
+ const sfc = parse(fs.readFileSync(file, 'utf8'), { filePath: file, mode: 'wx' })
+ let options
+ let selected
+ const scrollTo = jest.fn()
+ const query = { in () { return this }, select (id) { selected = id; return this }, node () { return this }, exec (cb) { cb([{ node: { scrollTo } }]) } }
+ const createAnimation = config => {
+ const result = { duration: config.duration }
+ return { scale (value) { result.scale = value; return this }, opacity (value) { result.opacity = value; return this }, step () { return this }, export () { return result } }
+ }
+ vm.runInNewContext(sfc.script.content.replace(/^import .*$/gm, ''), {
+ createComponent: value => { options = value },
+ wx: { createSelectorQuery: () => query, createAnimation }
+ })
+ const state = Object.assign({}, options.data, options.methods)
+ state.setRows({ items: [{ id: 'a', name: '甲', visible: true }, { id: 'b', name: '乙', visible: false }] })
+ expect(options.computed.visibleItems.call(state).map(item => item.id)).toEqual(['a'])
+ state.scrollTop()
+ expect(selected).toBe('#1users')
+ expect(scrollTo).toHaveBeenCalledWith({ top: 0 })
+ state.press()
+ expect(state.animationData).toEqual({ duration: 150, scale: 0.96, opacity: 0.7 })
+ state.release()
+ expect(state.animationData).toEqual({ duration: 150, scale: 1, opacity: 1 })
+ expect(sfc.template.content).toMatch(/]*logo.svg[^>]*\/>{{label}}<\/text>/)
+ expect(sfc.template.content).toContain('')
+ expect(sfc.template.content).toMatch(/]*bindtap="scrollTop"[^>]*bindtouchstart="press"[^>]*bindtouchend="release"[^>]*bindtouchcancel="release"/)
+})
diff --git a/.agents/skills/mpx2skyline-workspace/test-design.md b/.agents/skills/mpx2skyline-workspace/test-design.md
new file mode 100644
index 0000000000..9a66893c6b
--- /dev/null
+++ b/.agents/skills/mpx2skyline-workspace/test-design.md
@@ -0,0 +1,99 @@
+# Skyline 适配测试集设计 v4
+
+当前为4个case、37条Skyline正向断言,尚未执行。旧[iteration-3结果](iteration-3/benchmark.md)保持历史归属。
+
+| Case | 名称 | 断言数 | 来源 |
+| --- | --- | ---: | --- |
+| 0 | 样式与布局 | 12 | 原case 0 |
+| 1 | 页面滚动、吸顶与层级配置 | 11 | 原case 1,4 |
+| 2 | 模板运行时、图文混排与动画 | 8 | |
+| 3 | 从零创建任务看板页面 | 6 | 新建需求场景 |
+
+## 合并与计分边界
+
+case 1将订单与分类面板合并为单个orders.mpx输入,数据接口统一返回分组订单;case 2将推广卡片的图文与动画并入user-list组件,保留row.wxml及logo.svg作为必要外部资源。旧31条断言保留能力覆盖,其中case 1的6条按统一主滚动区域修订,case 2的4条验证方法指向同一组件;前版正文与验证方法记录在迁移表。来源章节名称与当前Skill对齐。
+
+新增case通过仅提供需求而不提供待修复页面,验证从零实现Skyline适配。业务与通用Mpx语法单独验证,不纳入专项断言。创建入口与迁移入口有意复用核心能力,分开报告31条迁移分数和6条创建分数。
+
+## Case 0:样式与布局
+
+适配组件样式、间距、视觉效果及字体兼容。
+
+[需求](iteration-4/eval-0-style-layout/input/task.md)
+
+| 断言 | Skyline适配要求 | 验证方法 |
+| --- | --- | --- |
+| `s0_00` | Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。 | 检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。 |
+| `s0_01` | Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。 | 检查父子布局关系及 flex basis/width,计算两列可用宽度。 |
+| `s0_02` | Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。 | 追踪实际活动节点 class 与颜色声明的匹配关系。 |
+| `s0_03` | Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。 | 分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。 |
+| `s0_04` | Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。 | 检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。 |
+| `s0_05` | Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。 | 计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。 |
+| `s0_06` | Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。 | 追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。 |
+| `s0_07` | Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。 | 检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。 |
+| `s0_08` | Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。 | 结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。 |
+| `s0_09` | Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。 | 核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。 |
+| `s0_10` | Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。 | 追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。 |
+| `s0_11` | Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。 | 结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。 |
+
+## Case 1:页面滚动、吸顶与层级配置
+
+适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。
+
+[需求](iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md)
+
+| 断言 | Skyline适配要求 | 验证方法 |
+| --- | --- | --- |
+| `s1_00` | Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。 | 检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。 |
+| `s1_01` | Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。 | 定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。 |
+| `s1_02` | Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。 | 从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。 |
+| `s1_03` | Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。 | 给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。 |
+| `s1_04` | Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。 | 解析页面JSON并检查真实导航节点和主体布局关系。 |
+| `s1_05` | Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。 | 解析 app.json 并检查顶层属性值。 |
+| `s1_06` | Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。 | 逐项解析五个字段的层级、类型和值。 |
+| `s1_07` | Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。 | 沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。 |
+| `s1_08` | Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。 | 检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。 |
+| `s1_09` | Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。 | 核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。 |
+| `s1_10` | Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。 | 追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。 |
+
+## Case 2:模板运行时、图文混排与动画
+
+适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。
+
+[需求](iteration-4/eval-2-template-runtime-inline-animation/input/task.md)
+
+| 断言 | Skyline适配要求 | 验证方法 |
+| --- | --- | --- |
+| `s2_00` | Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。 | 检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。 |
+| `s2_01` | Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。 | 关联模板id、组件查询作用域和select字符串,核对查询目标一致。 |
+| `s2_02` | Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。 | 从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。 |
+| `s2_03` | Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。 | 检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。 |
+| `s2_04` | Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。 | 检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。 |
+| `s2_05` | Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。 | 检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。 |
+| `s2_06` | Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。 | 追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。 |
+| `s2_07` | Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。 | 追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。 |
+
+## Case 3:从零创建任务看板页面
+
+仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。
+
+[需求](iteration-4/eval-3-new-task-board-page/input/task.md)
+
+| 断言 | Skyline适配要求 | 验证方法 |
+| --- | --- | --- |
+| `n3_00` | Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。 | 解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。 |
+| `n3_01` | Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。 | 检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。 |
+| `n3_02` | Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。 | 沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。 |
+| `n3_03` | Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。 | 从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。 |
+| `n3_04` | Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。 | 检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。 |
+| `n3_05` | Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。 | 追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。 |
+
+## 后续执行
+
+使用同一模型/参数先建立独立Skill与no_skill基线,再比较合并Skill。保存输入、Skill哈希和实际执行证据。本次只更新测试定义,未执行模型评测。
+
+[完整定义](iteration-4/evals.json) · [评分标准](iteration-4/grading-standard.md) · [迁移表](iteration-4/assertion-migration.json)
+
+Case 2断言统一编号为s2_00–s2_07;原s3_00/s3_01/s3_02依次迁移为s2_05/s2_06/s2_07,旧ID保存在迁移表source_assertion_id中。断言正文及验证方法不变。
+
+Case 1断言统一编号为s1_00–s1_10;原s4_00/s4_01/s4_02/s4_03依次迁移为s1_07/s1_08/s1_09/s1_10,旧ID保存在迁移表source_assertion_id中。评分要求不变。
diff --git a/.agents/skills/mpx2skyline/SKILL.md b/.agents/skills/mpx2skyline/SKILL.md
new file mode 100644
index 0000000000..cd4f1d5692
--- /dev/null
+++ b/.agents/skills/mpx2skyline/SKILL.md
@@ -0,0 +1,225 @@
+---
+name: mpx2skyline
+description: |
+ 基于 Mpx 开发实现的微信小程序 WebView 适配 Skyline 渲染引擎指南,覆盖布局、样式、组件、配置四大维度。
+ 当用户要求对已有微信小程序页面或组件进行 Skyline 适配、创建符合 Skyline 兼容规范的页面或组件、
+ 排查 Skyline 下样式不生效/组件不渲染/布局异常/层级错乱等问题、或查询某项能力在
+ Skyline 下的支持情况时强制调用。当用户问题不涉及 Skyline 适配时不应调用,如
+ Mpx 输出 RN 问题、支付宝小程序问题、纯微信原生小程序、纯 WebView 小程序开发问题等。
+metadata:
+ version: "1.0.1"
+---
+
+# Mpx 输出 Skyline 渲染引擎的开发&适配指南
+
+## 背景介绍
+
+Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展支持的跨端开发框架,支持将同一套代码输出到小程序(微信、支付宝、百度等)、Web 和 React Native 平台。
+
+Skyline 是微信小程序新一代渲染引擎,旨在替代 WebView 渲染以获得更接近原生的性能和体验。与 WebView 模式相比,Skyline 在布局模型、层叠机制、样式能力、组件支持、页面行为上存在系统性差异。
+
+### 适用场景
+
+本 SKILL 是 Mpx WebView 适配 Skyline 渲染引擎的统一指南,覆盖布局、样式、组件、配置四大维度。涉及 Mpx Skyline 适配的任务均应在动笔前阅读本 SKILL 的[通用约束与适配原则](#通用约束与适配原则),包括但不限于:
+
+- **技术方案设计**:评估需求在 Skyline 下的可行性、跨渲染模式(WebView 与 Skyline)兼容方案选型、是否需要通过 `this.renderer === 'skyline'` 进行运行时模式隔离等;
+- **WebView 页面 Skyline 适配改造**:对已基于 WebView 模式编写、未适配 Skyline 的存量页面进行兼容性补齐(参见下文[任务一](#任务一对已有-webview-页面或组件进行-skyline-适配改造));
+- **页面 / 组件开发迭代**:从零编写或迭代符合 WebView 与 Skyline 双模式兼容规范的 `.mpx` 页面与组件(参见下文[任务二](#任务二创建符合-skyline-兼容规范的页面或组件));
+- **运行时报错与异常排查**:定位 Skyline 下样式不生效(如不支持选择器/属性静默失效)、组件不渲染(如 `scroll-view` 缺失 `type`)、布局异常(如默认 `display: flex` / `border-box` 引发的差异)、层级错乱(z-index 无层叠上下文)、模板转义、SelectorQuery 数字开头等问题;
+- **能力查询**:查询基础组件、属性、样式、API、滚动 API 在 Skyline 下的支持情况、版本要求与 WebView 差异;涉及 Worklet 动画、手势系统、自定义路由、共享元素时,本 SKILL 仅判断 Mpx 双模式接入边界,具体能力回源[微信官方 Skyline Skills](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills);
+- **Code Review**:以本 SKILL 的[通用约束与适配原则](#通用约束与适配原则)为标准对照检查 Skyline 兼容性与跨渲染模式兼容性。
+
+### 不适用场景
+
+以下场景与 Mpx Skyline 适配无关,**不应调用**本 SKILL:
+
+- 仅面向微信小程序 WebView 的开发和适配问题(不涉及 Skyline 适配,无需 Skyline 兼容性约束);
+- 支付宝、百度、抖音等其他小程序平台的开发问题(Skyline 是微信小程序专属渲染引擎,不适用于其他厂商);
+- Skyline only 项目的开发问题(本 SKILL 强调 Mpx 框架下 WebView 与 Skyline 双模式兼容,纯 Skyline 项目应直接参考 [微信官方 Skyline Skills](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills));
+- Mpx 跨端输出 RN(Mpx2RN / Mpx2DRN)相关问题;
+- Mpx 跨端输出 Web(Mpx2Web)相关问题;
+- 不经 Mpx 框架编译的纯微信原生小程序开发问题。
+
+## 知识库索引
+
+| 知识库 | 说明 |
+| --- |----------------------------------------------------------------------------------------|
+| [Skyline 组件不支持与差异参考](./references/skyline-component-reference.md) | 查询 WebView 迁移 Skyline 时的组件差异,覆盖不支持组件、WebView-only 属性/取值、必填属性、结构约束与高频行为差异;不是完整组件手册,未收录能力需回源确认 |
+| [Skyline 样式支持程度与兼容方案](./references/skyline-style-reference.md) | 查询 Skyline 样式与 Web/W3C CSS 标准不一致的部分,覆盖默认值、选择器、值类型、布局层叠、文本、背景遮罩、滤镜、动画等差异 |
+| [Skyline 布局与样式适配实践](./references/skyline-layout-practice.md) | 进行视图层适配改造时读取,覆盖布局/层叠、页面滚动、图文混排、sticky、文本省略、flex、媒体查询与 SVG 展示限制等改造方案 |
+| [Skyline 运行时适配实践](./references/skyline-runtime-practice.md) | 进行运行时常见问题或者性能相关问题时读取,覆盖渲染模式判断、SelectorQuery、组件实例方法、Scroll API、常见报错与性能优化等 |
+| [Skyline 配置项与接入规范参考](./references/skyline-configuration.md) | 接入项目级与页面级配置时读取;按需点查 app.json 顶层配置、rendererOptions.skyline、页面配置示例与 Worklet Babel 插件配置 |
+| [Skyline 适配检查矩阵](./references/skyline-audit-matrix.md) | 适配完成前强制执行的审计矩阵,覆盖扫描 pattern、判定、修复、例外与验证要求 |
+
+### Skyline 高级能力
+
+Worklet 动画、手势系统、自定义路由、共享元素均属于 Skyline 高级能力。本 SKILL **只负责方案路由与 Mpx 接入边界**,具体 API、事件参数、版本要求、线程模型或完整实现规则参考以下官方 SKILL:
+
+| 能力 | 官方来源 | 本 SKILL 负责 |
+| --- | --- | --- |
+| Worklet 动画 | [skyline-worklet](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills/skyline-worklet) | 判断是否确需 UI 线程驱动;补充 Mpx Babel 构建配置、`renderer === 'skyline'` 隔离与 WebView 降级方案 |
+| 手势系统 | [gesture-system](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/gesture/gesture-system.md) / [gesture-negotiation](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/gesture/gesture-negotiation.md) | 判断是否需要 Skyline 手势能力;处理 Mpx 模板与脚本接入、跨渲染模式隔离 |
+| 自定义路由 | [skyline-route](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills/skyline-route) | 判断转场需求与 Mpx 页面配置、生命周期及 WebView 降级边界 |
+| 共享元素 | [share-element](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/special/share-element.md) | 判断是否采用共享元素方案;处理 Mpx 页面结构、双模式隔离与降级边界 |
+
+处理上述能力时,先读取对应官方 Skill 确认能力约束与实现方案,再应用本 SKILL 的 Mpx 编译接入和 WebView 与 Skyline 兼容约束。官方 Skill 未明确支持的能力不得依据本地经验推断;两者冲突时,Skyline 能力事实以官方 Skill 为准,Mpx 接入方式以本 SKILL 为准。
+
+### 知识库使用建议
+
+参考文档体量较大,**不要一次性预读全部参考**,按需取用即可:
+
+1. **入口只读本 SKILL.md**:完整读完本文档(含下方通用约束与任务流程)足以覆盖 80% 常见场景的判断;不要在动笔前预读 references 目录。
+2. **触发式读取**:只在任务流程或通用约束中**明确指向**某份参考时读取,且仅读取与当前问题相关的小节(参考文档均含目录与章节锚点,使用 `rg` / 锚点跳读,不要整文件 Read)。
+3. **典型任务的最小阅读集**:
+ - 已有 WebView 页面 Skyline 适配改造:识别问题维度后再读对应能力参考的相关小节,通常 1–2 份足够(如样式能力差异查 `skyline-style-reference.md`,布局或模板结构改造查 `skyline-layout-practice.md`,组件差异查 `skyline-component-reference.md`,运行时问题查 `skyline-runtime-practice.md`)。未收录的组件或能力不要反推结论,需回源确认。
+ - 新建 WebView / Skyline 双模式兼容页面或组件:先按本 SKILL.md 的通用约束起手,遇到能力存疑(某属性是否支持、某 API 是否存在)时再点查对应参考。
+ - 项目级配置接入:app.json 顶层项查 [`app.json 顶层配置`](./references/skyline-configuration.md#appjson-顶层配置),`rendererOptions.skyline` 查 [`rendererOptions.skyline 配置项`](./references/skyline-configuration.md#rendereroptionsskyline-配置项),页面配置示例查 [`适配参考`](./references/skyline-configuration.md#适配参考),Worklet 构建配置查 [`Worklet Babel 插件`](./references/skyline-configuration.md#worklet-babel-插件)。
+ - Worklet 动画、手势系统、自定义路由或共享元素:按[高级能力](#skyline-高级能力)读取对应官方 Skill,不预读无关高级能力参考。
+4. **何时读取 `skyline-audit-matrix.md`**:仅在适配完成前检查或 Code Review 时读取,并按要求执行完整矩阵;不要在方案设计或编码前预读。
+
+### 内容职责与同步规则
+
+- **本 SKILL.md**:维护任务流程、决策优先级、高频跨维度约束、知识路由与人工验收,确保只读入口即可完成常见判断;不复制扫描 pattern、规则 ID 或完整能力枚举。
+- **`references/`**:维护能力事实、适用条件、实现细节与示例。能力支持情况或实现方案变化时,先更新对应 reference。
+- **审计矩阵**:维护可扫描规则的 ID、level、候选 pattern、判定、修复与例外。reference 中的变化可被源码扫描或结构复核发现时,再同步更新矩阵。
+- 仅当变化影响通用决策、知识路由或人工验收时才同步本 SKILL.md;任务流程引用通用约束或 reference,不重复具体规则。内容冲突时,能力事实以 reference 为准,扫描与分级以审计矩阵为准,执行顺序与确认门禁以本 SKILL.md 为准。
+
+## 通用约束与适配原则
+
+适配改造、新建页面或组件、重构与 Code Review 均须遵循本节约束。应用本 Skill 的具体规则时,按以下优先级处理:
+
+- 规则明确指向知识库或外部文档时,先读取与当前问题相关的小节,再实施改动;
+- 规则已给出明确实现(属性值、CSS 片段、组件属性写法等)时,默认直接采用,不自行扩展替代方案;
+- Skill 未给出替代方案、规则含义不明确或文档存在歧义时,不推断实现,先说明不确定点并请求确认;
+- Skill 方案与更简写法、邻近代码风格或其他实现冲突时,先验证语义是否等价,以及 Skill 方案是否覆盖了未显式声明的上下文;验证后仍需偏离 Skill 方案的,说明差异并确认后再改。
+
+### 跨渲染模式兼容约束
+
+产物代码须在 WebView 与 Skyline 下均正常运行,按以下顺序选择方案:
+
+- **优先采用通用方案**:新方案若同时兼容 WebView、Skyline 与 RN,直接统一为新方案,无需按渲染模式分支;
+- **隔离 Skyline-only 方案**:仅 Skyline 可用的新逻辑默认通过 `this.renderer === 'skyline'` 运行时隔离。仅当细则明确要求该逻辑在 WebView 下保留,或已确认其在 WebView 下无副作用时,才可不作隔离;
+- **保留在 Skyline 下静默失效的 WebView 方案**:既有 WebView 方案若在 Skyline 下静默失效,确认其在 Skyline 下无副作用后可保留原逻辑,仅新增 Skyline 兼容实现。静默失效不等于无副作用;无法确认时,仍须按渲染模式隔离;
+- **不处理 Skyline 低版本兼容**:通过 Skyline 开量开关控制最低基础库版本,未达到要求的版本降级为 WebView 渲染。
+
+运行时隔离方式见 [判断当前渲染模式](./references/skyline-runtime-practice.md#判断当前渲染模式)。上述原则贯穿模板 / 脚本 / 样式 / JSON 四个维度。
+
+### 布局(layout)约束
+
+1. **先对齐默认布局基线**:在 `rendererOptions.skyline` 中开启 `defaultDisplayBlock` 与 `defaultContentBox`,分别对齐 WebView 的 `display: block` 和 `box-sizing: content-box`;需要静态定位时仍须显式声明 `position: static`。配置位置见 [rendererOptions.skyline 配置项](./references/skyline-configuration.md#rendereroptionsskyline-配置项),其余默认值差异见 [非标准默认值](./references/skyline-style-reference.md#非标准默认值)。
+2. **不依赖 BFC 与 margin 合并**:Skyline 没有 BFC 和 margin 合并机制,`overflow: hidden` 仅用于裁剪。容器外沿空间用父容器 `padding` 表达,兄弟间距只由一侧承担;复杂存量布局按 [不要依赖 BFC 和 margin 合并](./references/skyline-layout-practice.md#不要依赖-bfc-和-margin-合并) 改造。
+3. **页面滚动统一迁移到 scroll-view**:Skyline 不支持页面滚动,`onPullDownRefresh` / `onReachBottom` / `onPageScroll` 不会触发。页面声明 `disableScroll: true`,使用 `scroll-view` 承载滚动,并根据直接子节点结构选择 `list` / `custom` / `nested`,常见为列表模式 `type="list"`。原生命周期同步迁移到 `bindrefresherrefresh` / `bindscrolltolower` / `bindscroll`,WebView 对齐同一事件链路;详见 [页面滚动替代方案](./references/skyline-layout-practice.md#页面滚动替代方案)。
+4. **按 normal-context / fixed-context 设计层级**:Skyline 没有 WebView 层叠上下文,非 fixed 节点最终比较共同父级下的兄弟分支;fixed 节点会全局提升并按自身 `z-index` 排序,整体高于非 fixed 内容。`transform` / `opacity` 不会抬升层级,`scroll-view` 直接子节点的 `z-index` 不生效。需要比较层级的节点应调整为可比较的兄弟结构,避免依赖负 `z-index`;详见 [z-index 与层叠适配](./references/skyline-layout-practice.md#z-index-与层叠适配)。
+5. **吸顶逻辑双分支保留**:Skyline 不支持 `position: sticky`,Skyline 分支使用 `sticky-section` / `sticky-header`,WebView 分支保留 CSS sticky。`sticky-header` 必须是 section 的第一个子节点且显式设置背景色,完整结构见 [sticky 吸顶替代方案](./references/skyline-layout-practice.md#sticky-吸顶替代方案)。
+6. **使用自定义导航**:Skyline 页面声明 `navigationStyle: 'custom'` 并实现自定义导航栏,不依赖默认导航;页面配置见 [适配参考](./references/skyline-configuration.md#适配参考)。
+
+### 样式(style)约束
+
+1. **只使用受支持的选择器**:不使用通配选择器和属性选择器;伪元素只使用 `::before` / `::after`,其他伪类按 [选择器支持](./references/skyline-style-reference.md#选择器支持) 核对版本与替代方案,不能用时改为模板动态类或真实节点。
+2. **值类型按稳定范围使用**:长度优先使用 `rpx` / `px` / `rem`;百分比仅用于 [百分比支持情况](./references/skyline-style-reference.md#百分比支持情况) 明确记录的属性,Flex 子节点不能依赖百分比 `min-width` 撑开或等分。`calc()` 只用于非嵌套的长度计算,不用于角度等类型;详见 [长度、函数与单位](./references/skyline-style-reference.md#长度函数与单位)。
+3. **滚动与特殊布局改用组件或显式布局**:不使用 `overflow: auto` / `scroll`、`overflow-x` / `overflow-y`、`display: grid` / `flow-root` 或 `position: sticky`;分别改用 `scroll-view`、Flex / `grid-view`、sticky 组件。其他布局差异按 [布局、盒模型与层叠差异](./references/skyline-style-reference.md#布局盒模型与层叠差异) 处理。
+4. **文本省略同时保留两端实现**:保留 WebView 的 `text-overflow` / `-webkit-line-clamp` 等样式,并在承载文本的组件上新增 `max-lines` 与 `overflow` 供 Skyline 使用;新增或替换为 `text` 时将插值紧贴标签,避免字面空白影响截断。完整规则见 [文本溢出省略适配](./references/skyline-layout-practice.md#文本溢出省略适配)。
+5. **字体与文本能力先核对再替换**:`font-weight: 500/600` 在部分机型不生效,命中时先检查字体资源与 PostScript name,再确认是否改为 `bold` / `700`,未确认时保留并说明风险。`white-space`、`word-break`、`text-decoration` 等能力按 [文本与字体差异](./references/skyline-style-reference.md#文本与字体差异) 处理;`text-decoration-line` 多值按 [多值适配](./references/skyline-layout-practice.md#text-decoration-line-多值适配) 拆分节点。
+6. **背景、边框、遮罩与滤镜遵循层数和值域限制**:圆角非 0 时四边边框颜色和样式保持一致;多层背景、遮罩或阴影超出支持范围时拆节点;`mask-image` 不使用渐变;`filter` / `backdrop-filter` 不使用 `url()`、`drop-shadow()` 或多函数组合。具体值域见 [背景、边框与遮罩差异](./references/skyline-style-reference.md#背景边框与遮罩差异) 与 [滤镜差异](./references/skyline-style-reference.md#滤镜差异)。
+7. **媒体查询保留 WebView、补 Skyline 动态类**:Skyline 会忽略 `@media screen` 条件但可能保留内部规则,不能直接删除或全局覆盖。WebView 继续使用原媒体查询,Skyline 通过运行时状态类表达条件,并在媒体查询后补 Skyline 默认类兜底;详见 [@media screen 替换方案](./references/skyline-layout-practice.md#media-screen-替换方案)。
+8. **未支持属性按跨渲染原则处理**:命中未支持或静默失效的 CSS 时,先在 [Skyline 不支持能力及兼容方案](./references/skyline-style-reference.md#skyline-不支持能力及兼容方案) 查询替代方案;确认原 WebView 样式在 Skyline 下无副作用后可保留,仅新增 Skyline 实现。没有等效方案或副作用不明确时,说明风险并请求确认。
+
+### 组件(component)约束
+
+组件参考只记录 WebView 迁移 Skyline 的差异,不是完整组件手册;未收录的组件、属性或事件不得反推为支持,需回源确认。
+
+1. **scroll-view 必须显式选型**:每个 `scroll-view` 都声明 `type`。`type="list"` 仅用于列表项是直接子节点的场景,单一外层 wrapper 会使按需渲染退化;嵌套滚动时外层使用 `type="nested"`,内层显式使用 `list` / `custom` 并设置 `associative-container="nested-scroll-view"`。选型与结构约束见 [Skyline 必填属性与结构约束](./references/skyline-component-reference.md#skyline-必填属性与结构约束)。
+2. **scroll-view 行为按需补齐**:横向滚动同时开启 `enable-flex` 并设置横向布局;自定义下拉刷新节点声明 `slot="refresher"`;需要内容撑高时开启 `enableScrollViewAutoSize`。通过 `NodesRef.node()` 获取 `ScrollViewContext` 时,目标滚动容器必须开启 `enhanced`;详见 [组件高频差异](./references/skyline-component-reference.md#skyline-相对-webview-的高频差异补充) 与 [ScrollViewContext](./references/skyline-runtime-practice.md#必须-scrollviewcontext开启-enhanced-属性)。
+3. **不支持组件采用替代或降级**:命中 `web-view`、富文本编辑、可移动视图等不支持能力时,按 [不支持或不建议使用的组件](./references/skyline-component-reference.md#skyline-不支持或不建议使用的组件) 选择替代组件、独立 WebView 页面或 renderer 降级;复杂交互无明确等效方案时说明风险并请求确认。
+4. **WebView-only 属性与取值不得作为 Skyline 方案**:例如 `image` 的 WebView-only 裁剪模式、`text` 的 `space` / `decode`、输入组件的 `placeholder-class` 等,确认在 Skyline 下无副作用后可保留给 WebView,并补充 Skyline 实现;存在副作用时替换为双端支持写法或按 renderer 隔离,不明确时说明风险并请求确认。完整范围见 [WebView-only 属性、取值与行为](./references/skyline-component-reference.md#webview-only-属性取值与行为)。
+5. **遵守组件子节点结构**:`navigator` 只能嵌套 `text` 或纯文本,`text` 只能嵌套 `text`;复杂卡片改为外层点击事件。图标、图片与文本处于同一行时使用 `span` 方案,并补齐 Skyline 的内联布局与截断属性;详见 [图文混排](./references/skyline-layout-practice.md#图文混排)。
+6. **模板结构按 glass-easel 规则改造**:数据绑定外的引号使用 XML 实体,数据绑定内不使用反斜杠转义;`wx:for` 子树中的 `` 改为 `` + `` 并显式传入 `item` / `index`。详见 [模板结构适配](./references/skyline-layout-practice.md#模板结构适配)。
+7. **节点查询使用合法选择器**:id 不以数字开头;glass-easel 组件实例内优先使用 `this.createSelectorQuery()`。详见 [SelectorQuery 约束](./references/skyline-runtime-practice.md#必须-selectorquery-选择器不再支持以数字开头) 与 [SelectorQuery 推荐](./references/skyline-runtime-practice.md#推荐-用-thiscreateselectorquery-替代-wxcreateselectorquery)。
+8. **`
+
+
+
+
+
+
+
+
+```
+
+适配要点:
+
+1. `isSkyline` 用运行时判断注入模板,只在 Skyline 下切换 `whitespace-nowrap`、`inline-block`、`inline-flex` 等兼容样式,非 Skyline 保持不变。
+2. 图标、`rich-text`、分隔符同属一段图文混排时,放在同一个 `mpxTagName@wx="span"` 容器内;同时兼容 RN 侧时需用 `mpxTagName@ios|android|harmony="text"` 和 `numberOfLines` 对齐单行截断。
+
+### 页面滚动替代方案
+
+Skyline 不支持页面滚动,`onPullDownRefresh` / `onReachBottom` / `onPageScroll` 不会触发。需要滚动的页面必须使用 `scroll-view` 替代页面滚动,页面 json 同时声明 `disableScroll: true`。
+
+```html
+
+
+
+
+```
+
+**原页面生命周期需迁移到 scroll-view 对应事件**(不要只删不补,否则下拉刷新/触底加载/滚动监听等业务逻辑会静默失效):
+
+| 原页面生命周期 | scroll-view 事件 | 备注 |
+| --- | --- | --- |
+| `onPullDownRefresh` | `bindrefresherrefresh` | 需同时开 `refresher-enabled` |
+| `onReachBottom` | `bindscrolltolower` | 可配合 `lower-threshold` 调阈值 |
+| `onPageScroll(e.scrollTop)` | `bindscroll(e.detail.scrollTop)` | 高频事件,按需节流 |
+
+WebView 直接对齐 Skyline 写法(统一走 scroll-view 事件),避免双份实现带来的维护成本与行为漂移。
+
+```html
+
+
+ 11
+ 22
+
+
+```
+
+```js
+createPage({
+ onRefresh() {
+ // 原 onPullDownRefresh 的逻辑
+ },
+ onLoadMore() {
+ // 原 onReachBottom 的逻辑
+ },
+ onScroll(e) {
+ const scrollTop = e.detail.scrollTop // 原 onPageScroll 的 e.scrollTop
+ }
+})
+```
+
+### z-index 与层叠适配
+
+Skyline 没有层叠上下文(stacking-context)的概念。`z-index` 默认值为 `0`,**只在兄弟节点间生效**,节点的最终层级由两套机制决定:**normal-context**(非 fixed 节点)和 **fixed-context**(fixed 节点)。
+
+**核心差异**:
+
+| 维度 | WebView | Skyline |
+| --- | --- | --- |
+| 层叠上下文 | 有,子节点 z-index 在不同层叠上下文间不可比较 | 无,z-index 只在兄弟节点间直接比较 |
+| 跨父级层级 | 由各自所属层叠上下文的层级决定 | 向上回溯到「共同父级下的那对兄弟节点」,比较这对兄弟的 z-index |
+| fixed 节点 | 参与正常层叠上下文 | 全局提升到 fixed-context,整体层级永远高于 normal-context |
+| 相同 z-index | 层叠水平 + 文档顺序决定 | DOM 靠后的层级更高 |
+| `transform` / `opacity` | 会创建新层叠上下文,影响 z-index 比较 | 不创建层叠上下文,对层级无影响 |
+
+**normal-context 机制**(非 fixed 节点):
+
+```
+ a
+ b c
+ ↓ ↓
+ d e
+ ↓ ↓
+ f g
+```
+
+比较 f 和 g 的层级时,并不直接比较 f、g 自身的 z-index,而是向上回溯到它们在同一父级下的祖先分支 b 和 c,比较 b 与 c 的 z-index——谁更大,其整条子树的层级就更高。若 b、c 的 z-index 相同,则 DOM 靠后的层级更高。
+
+**fixed-context 机制**(fixed 节点):
+
+不关心 fixed 节点在 DOM 中的父子层级,所有 fixed 节点在全局范围内统一提升到 fixed-context 上渲染:DOM 结构保持不变,但渲染时全部「拍平」为兄弟节点,再仅依据各自的 z-index 排序。
+
+```
+fixed-a (z-index: 2)
+ fixed-b (z-index: 3)
+ fixed-c (z-index: 1)
+ fixed-d (未设置 → 0)
+fixed-e (z-index: 4)
+
+渲染层级排序:fixed-d(0) < fixed-c(1) < fixed-a(2) < fixed-b(3) < fixed-e(4)
+```
+
+注意 fixed-c 虽然 DOM 上嵌套最深,但因 z-index 最小(1),渲染层级反而靠下;fixed-b 的 z-index(3) 高于其父 fixed-a(2),但因整体拍平比较,仍能盖住 fixed-a。
+
+**适配方案**:
+
+1. **把需要层级控制的节点重构为兄弟节点结构**:页面内非全屏元素用 `relative` + `absolute`,按 normal-context 规则确定层级;全屏元素(弹窗、弹层、toast)按需用 `fixed`,按 fixed-context 规则确定层级,且层级天然高于所有非 fixed 内容。
+2. **不要依赖层叠上下文机制做层级控制**:WebView 上用 `transform` / `opacity` / `will-change` 隐式开启层叠上下文来抬升层级的技巧,在 Skyline 下完全失效。
+3. **`z-index` 不能用在 `scroll-view` 的直接子节点上**:该位置设置 `z-index` 不生效;如需对滚动项做层级控制,应在其内部再包一层节点,或借助 fixed 元素提升到 fixed-context。
+
+### sticky 吸顶替代方案
+
+`position: sticky` 在 Skyline 下不可用,需用 `sticky-header` / `sticky-section` 组件替代。但 `sticky-header` / `sticky-section` 是 Skyline 专属组件,WebView 下不识别,而 WebView 的 `position: sticky` 本就可用,属于「Skyline 支持但 WebView 不需要」的写法,**不要替换 WebView 原生写法**,而是用 [运行时 renderer 判断](./skyline-runtime-practice.md#判断当前渲染模式) 隔离两条分支。
+
+```html
+
+
+
+
+ 吸顶标题
+ 列表内容
+
+
+
+ 吸顶标题
+ 列表内容
+
+
+```
+
+```css
+/* 两端都需显式背景色,避免吸顶时透字穿透 */
+.sticky-title { background: #fff; }
+/* WebView 专属:position: sticky 在 Skyline 下静默失效,仅 WebView 分支使用 */
+.webview-sticky { position: sticky; top: 0; }
+```
+
+```js
+// isSkyline 写入 data 供模板 wx:if 使用
+createPage({
+ onLoad() {
+ this.isSkyline = this.renderer === 'skyline'
+ }
+})
+```
+
+**Skyline 分支结构约束**:
+
+- `sticky-header` 必须是 `sticky-section` 的**第一个子节点**;每个 `sticky-section` 仅允许一个 `sticky-header`。
+- `sticky-section` 必须放在 `scroll-view type="custom"` 内(不可裸用)。
+- `sticky-header` **必须显式声明背景色**(`background` / `background-color`)。Skyline 下 `sticky-header` 默认透明,吸顶时下层列表内容会透字穿透,常见症状是"吸顶后文字与列表叠在一起"。
+
+### scroll-view 高度自适应
+
+Skyline 下 `scroll-view` 默认不会按内容高度自动撑开。迁移时优先使用全局配置方案;只有在业务明确需要把内容实际高度写入 `scroll-view` 内联样式时,才使用动态测量方案。
+
+**推荐方案:全局配置 + max-height**
+
+在 `app.json` 的 `rendererOptions.skyline` 下开启 `enableScrollViewAutoSize`,让 `scroll-view` 按内容撑开;组件上继续保留 `max-height` 作为滚动区域上限。内容未超过上限时容器随内容高度变化,超过上限后由 `scroll-view` 承载滚动。
+
+```json
+{
+ "rendererOptions": {
+ "skyline": {
+ "enableScrollViewAutoSize": true
+ }
+ }
+}
+```
+
+```html
+
+
+
+
+
+
+```
+
+**兜底方案:动态测量内容高度**
+
+仅在要求明确动态计算 `scroll-view` 的实际高度时,再在内容渲染后通过 `createSelectorQuery` 查询内容节点高度,并将结果绑定到 `scroll-view` 的 `style`。
+
+```ts
+// 工具函数
+import { nextTick, ref } from '@mpxjs/core'
+
+export function getScrollViewHeight(context, query, defaultHeight = 0) {
+ // height 初始为空(或传入兜底高度),格式为内联 style 字符串
+ const height = ref(defaultHeight ? `height:${defaultHeight}px;` : '')
+
+ const updateHeight = () => {
+ // 必须在 nextTick 后查询,确保内容已渲染到 DOM
+ nextTick(() => {
+ context.createSelectorQuery()
+ .select(query)
+ .boundingClientRect(rect => {
+ height.value = `height:${Math.ceil(rect?.height || 0)}px;`
+ })
+ .exec()
+ })
+ }
+
+ return { height, updateHeight }
+}
+```
+
+```ts
+// 组件 setup 中使用(仅 Skyline 模式下启用)
+import { getCurrentInstance, nextTick, watch, ref } from '@mpxjs/core'
+import { getScrollViewHeight } from 'useSkyline'
+
+const context = useContext()
+
+const isSkyline = () => getCurrentInstance().proxy.renderer === 'skyline'
+
+// isSkyline() 为 false(WebView)时退化为空实现,不影响 WebView 逻辑
+const { height, updateHeight } = isSkyline()
+ ? getScrollViewHeight(context, '#scrollContent')
+ : {
+ height: ref(''),
+ updateHeight: () => {}
+ }
+
+// 在内容加载完成后调用 updateHeight,确保可正常获取到内容高度
+// isShow 为控制弹窗展示的变量
+watch(isShow, (val) => {
+ if (val) {
+ nextTick(() => {
+ updateHeight()
+ })
+ }
+})
+```
+
+```html
+
+
+
+
+
+
+```
+
+## 样式适配
+
+### 文本溢出省略适配
+
+文本溢出省略,或者文本超长打点,在 Skyline 下需要在对应的 `view`/`text`/`rich-text`/`special-text` 组件上增加 `max-lines`/`overflow` 属性
+
+> **完整扫描要求**:适配时须扫描组件/页面内**所有**包含文本省略样式(`text-overflow: ellipsis` / `-webkit-line-clamp` / `overflow: hidden` + `white-space: nowrap` 组合)的节点,逐一为其补齐 `max-lines`/`overflow`。
+
+> 注意事项
+>
+> **新增/替换 `text` 节点时务必把插值压回单行**:`` 会折叠首尾空白,`` 则字面保留。开闭标签之间留下换行 + 缩进会被当作前导/尾随空格渲染出来,影响 `max-lines`/`overflow` 的截断点与视觉对齐。属性多到必须折行时,只折属性、把插值紧贴 `>`
+> **WebView 样式与 Skyline 属性共存**:原 WebView 的 webkit 省略样式(`-webkit-line-clamp`/`-webkit-box-orient`/`display:-webkit-box`/`text-overflow:ellipsis`/`white-space: nowrap`/`overflow: hidden;`)**保留不删**(WebView 仍需要),同时在承载文本的 `view` / `text` / `rich-text` / `special-text` 节点**新增** `max-lines`/`overflow` 属性给 Skyline 使用。两者共存互不冲突。
+
+**单行省略**:
+
+```html
+
+
+ {{title}}
+
+
+
+{{title}}
+```
+
+```css
+.ellipsis {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+```
+
+**多行省略**:
+
+> 注意:文本省略场景下不要删除原 WebView 下的文本省略样式,尤其是 `display: -webkit-box;`
+
+```html
+{{title}}
+```
+
+```css
+.ellipsis {
+ display: -webkit-box;
+ overflow: hidden;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ text-overflow: ellipsis
+}
+```
+
+### 字体 PostScript name 兼容
+
+部分机型可能不支持 `font-weight: 500` / `600` 等数值加粗,但直接改为 `bold` / `700` 可能改变 WebView 视觉表现。命中时先澄清确认是否调整字重;确认后再统一修改,未确认时保留原值并说明 Skyline 兼容风险。涉及自定义字体时,先检查字体资源与 PostScript name 映射,再确定替代写法。
+
+确认需要调整后,可参考以下自定义字体 PostScript name 映射:
+
+| PostScript name | CSS 写法 | 备注 |
+| --- | --- | --- |
+| `xx-Medium` | `font-family: xx; font-weight: bold;` | 若已通过 `@font-face` 将 `xx-Medium` 单独定义为 `font-family`,则无需更改 |
+| `xx-Semibold` | `font-family: xx; font-weight: bold;` | 若已通过 `@font-face` 将 `xx-Semibold` 单独定义为 `font-family`,则无需更改 |
+| `xx-Bold` | `font-family: xx; font-weight: bold;` | 若已通过 `@font-face` 将 `xx-Bold` 单独定义为 `font-family`,则无需更改 |
+
+例如,以下写法已将 `XX-Medium` 定义为独立字体,使用 `font-family: 'XX-Medium'` 时无需更改;`XX-Semibold`、`XX-Bold` 同理:
+
+```css
+@font-face {
+ font-family: 'XX-Medium';
+ src: url('XX.otf');
+}
+```
+
+> Skyline 支持的自定义字体格式有:ttf/otf/woff2
+
+### 伪元素不支持的 animation 需替换为真实节点
+
+Skyline 下伪元素的 `animation` 不生效,需要改用真实节点。
+
+**使用真实节点 + CSS animation**
+
+```css
+/* ❌ Bad — 伪元素 animation 在 Skyline 不生效 */
+.loading::after {
+ content: '';
+ animation: spin 1s linear infinite;
+}
+
+/* ✅ Good — 使用真实节点 animation */
+.loading-spinner {
+ animation: spin 1s linear infinite;
+}
+```
+
+### animation API 不支持 → 使用 CSS transition
+
+Skyline 不支持 `wx.createAnimation` API(`animation` 属性赋值方式),需要改用 CSS `transition` 或 Worklet 动画。
+
+```js
+// ❌ Bad — wx.createAnimation 在 Skyline 下无效
+const animation = wx.createAnimation({
+ duration: 300,
+ timingFunction: 'ease'
+})
+const animationData = ref(animation.opacity(0).step().export())
+```
+
+```css
+/* ✅ Good — 使用 CSS transition 替代 */
+.fade-element {
+ transition: opacity 0.3s ease;
+}
+.fade-element.hidden {
+ opacity: 0;
+}
+```
+
+### text-decoration-line 多值适配
+
+Skyline 下 `text-decoration-line` 只取单值,`underline line-through` 这类双值组合会被截断为单值(实际只渲染其中一条线),WebView 则正常叠加两条线。删除线 + 下划线常见于「划线价 + 强调」类价格文案,直接迁移会丢失一条装饰线。
+
+由于 Skyline 下装饰线只能由 `text` 节点单值承载,**双值需拆成嵌套 `text` 节点,每层承担一条装饰线**。用 [运行时 renderer 判断](./skyline-runtime-practice.md#判断当前渲染模式) 区分:Skyline 下增加一层 `text` 节点,WebView 维持单节点双值,避免给 WebView 引入无谓的嵌套。
+
+```html
+
+{{price}}
+```
+
+```css
+.dual-decoration {
+ text-decoration-line: underline line-through;
+}
+```
+
+```html
+
+
+{{price}}
+{{price}}
+```
+
+```css
+/* WebView:单节点双值即可叠加两条线 */
+.dual-decoration { text-decoration-line: underline line-through; }
+/* Skyline:外层节点画下划线,内层节点画删除线,嵌套后两条线同时生效 */
+.underline { text-decoration-line: underline; }
+.line-through { text-decoration-line: line-through; }
+```
+
+```js
+// isSkyline 来自 renderer 判断,在生命周期里写入 data 供模板使用
+createPage({
+ data: {
+ isSkyline: false
+ },
+ onLoad() {
+ this.isSkyline = this.renderer === 'skyline'
+ }
+})
+```
+> 嵌套的内外层只设 `text-decoration-line`,字号/颜色等由外层继承,避免重复声明导致两层样式打架。两条装饰线归属哪层不影响最终视觉,但内层文本节点要紧贴标签写,防止 `text` 字面保留空白把价格文案撑出多余间距。
+
+### flex 布局的子节点 min-width 百分比撑开失效
+
+Skyline 下 flex 布局子节点依赖百分比 `min-width` 撑开或等分时,百分比无法按预期生效,节点会按内容收缩。
+这个 case 中,外层 `.estimate-form` 的 `min-width: 100%` 未能撑满一屏,子项 `.form-item` 的 `min-width: 25%` 也未能按四等分撑开。典型表现是业务工具栏在 WebView 下 4 个按钮均分一屏,但 Skyline 下子项宽度按内容收缩,导致间距和滚动范围异常。
+
+```html
+
+
+
+
+
+ {{item.title}}
+
+
+
+```
+
+```stylus
+/* ❌ Bad — flex 布局内的 min-width 百分比在 Skyline 下不生效 */
+.estimate-form
+ display flex
+ // Skyline 下这里也未能按一屏宽度撑开
+ min-width 100%
+ box-sizing border-box
+ min-height 38px
+ color #444
+ .form-item
+ position relative
+ display flex
+ justify-content center
+ align-items center
+ padding 0 10px
+ flex 1 0 auto
+ // Skyline 下这里也未能按四等分宽度撑开
+ min-width 25%
+ max-width 100%
+ box-sizing border-box
+```
+
+```html
+
+
+
+
+
+
+ {{item.title}}
+
+
+
+
+```
+
+```stylus
+/* ✅ Good — 用 rpx 固定换算值替代百分比 min-width */
+.estimate-form
+ display flex
+ flex-shrink 0
+ box-sizing border-box
+ min-height 38px
+ color #444
+ // ✅ Good — min-width 100% 换算为 min-width 750rpx
+ min-width 750rpx
+ justify-content space-around
+ .form-item
+ position relative
+ display flex
+ justify-content center
+ align-items center
+ padding 0 10px
+ flex 1 0 auto
+ // ✅ Good — min-width 25% 换算为 min-width 187rpx
+ min-width 187rpx
+ max-width 100%
+ box-sizing border-box
+```
+
+适配要点:
+1. 不再依赖 `min-width` 百分比撑开,按实际基准宽度换算为 `rpx` / `px` 等明确长度单位。若基准宽度是一屏,750rpx 代表屏宽,25% 可写为 187rpx。
+2. 若外层内容容器预期至少撑满一屏,使用 `min-width: 750rpx`;若基准不是一屏,应按实际容器设计宽度换算,不要机械套用 750rpx。
+
+### flex 布局的子节点文本超出未自动换行
+
+Skyline 下 flex 布局的子节点文本超出后可能无法自动换行,因为此时子节点宽度由文本内容决定,需要显式指定宽度。
+
+```html
+
+ 测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案
+ 测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案
+ 测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案测试文案
+
+```
+
+```css
+/* ❌ Bad — .content 未定义 width,Skyline 下未能自动换行 */
+.wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+```
+
+```css
+/* ✅ Good — .content 显式定义 width 来支持自动换行 */
+.wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+.content {
+ width: 100%;
+}
+```
+
+### @media screen 替换方案
+
+Skyline 不支持 `@media screen` 的条件判断:`@media screen and (...)` 外层条件会被忽略,但内部样式仍会生效,等价于把媒体查询内的规则裸写到全局样式里。因此,原本依赖 `@media screen` 区分大小屏的逻辑,在 Skyline 下必须改为运行时动态类。
+
+适配目标是:**WebView 继续使用原生 `@media` 实时响应屏幕变化;Skyline 只使用运行时类控制大小屏状态**。因此需要用 [运行时 renderer 判断](./skyline-runtime-practice.md#判断当前渲染模式) 隔离 WebView 与 Skyline,并在 Skyline 分支额外提供一个默认类,用来覆盖 `@media screen` 内部规则泄漏后的默认态。
+
+❌ Bad — Skyline 下 `@media screen` 条件被忽略,内部规则全局生效
+```html
+
+```
+
+```css
+@media screen and (max-width: 320px) {
+ .wrapper { display: none; }
+}
+```
+
+✅ Good — 用 `isSkyline` 门控 Skyline 默认类与状态类,WebView 仍走原生 `@media`
+```html
+
+
+```
+
+```js
+// isSkyline 来自 renderer 判断;isSmall 为屏宽快照
+const isSmall = ref(mpx.getWindowInfo().screenWidth <= 320)
+```
+
+```css
+/* 默认态先声明,WebView 大屏与 Skyline 默认态都以此为基准 */
+.wrapper {
+ display: block;
+}
+
+/* WebView:原生 @media 实时响应横竖屏/resize */
+@media screen and (max-width: 320px) {
+ .wrapper { display: none; }
+}
+
+/*
+ * Skyline:上面的 @media 条件会被忽略,.wrapper { display: none; } 会泄漏为全局规则。
+ * 必须在 @media 之后声明 Skyline 默认类,把非小屏状态覆盖回默认样式。
+ */
+.wrapper-skyline {
+ display: block;
+}
+
+/* Skyline 小屏态 */
+.wrapper-skyline.small { display: none; }
+```
+
+- WebView:`isSkyline=false` → 动态类永不加 → `@media` 生效,保留原生响应式。
+- Skyline:`isSkyline=true` → `.wrapper-skyline` 先覆盖 `@media` 泄漏的默认态,`.small` 再表达小屏态。
+
+> `@media` 与 `.small` 两份规则需同步(阈值 / 样式改动要两处一起改)。`getWindowInfo` 是一次性快照,若 Skyline 下需响应运行时屏宽变化(横竖屏),要再用 `wx.onWindowResize` / 页面 `onResize` 更新 `isSmall`。
+> ⚠️ 声明顺序陷阱:不要直接把 `.wrapper { display: block; }` 写在 `@media` 后面覆盖泄漏规则,这会在 WebView 小屏下同样覆盖原生 `@media`。需要使用 `isSkyline` 门控的 Skyline 默认类(如 `.wrapper-skyline`)放在 `@media` 后面,只覆盖 Skyline 分支。
+
+## 模板结构适配
+
+### [必须] 模板中数据绑定外的转义改为标准 XML 转义
+
+数据绑定**外**的引号须改用 XML 实体转义;数据绑定**内**无需再转义。
+
+```html
+
+
+
+
+
+```
+
+### [必须] wx:for 内嵌 <include> 时改为 <template>
+
+在 `wx:for` 中使用 `` 时,被引入的模板中的 `item` / `index` 变量不再有效,需改为 `` + `` 方案。
+
+```html
+
+
+
+
+
+
+{{ index }}. {{ item }}
+```
+
+```html
+
+
+
+
+
+
+
+
+ {{ index }}. {{ item }}
+
+```
+
+### navigator 嵌套限制
+
+Skyline 下 `` 内**只能嵌套 `` 组件或纯文本节点**,**不能嵌套** `` / `` / `` 等任意其他组件。WebView 下常见的“navigator 内放图标 + 文字”业务结构会让 Skyline 静默渲染异常(图标不显示,或点击区域错位)。
+
+```html
+
+
+
+
+ 联系客服
+
+
+
+
+
+ 联系客服
+
+```
+
+### SVG 在 Skyline 下的限制与适配
+
+**1. 不支持 `
+
+
+
+
+
+```
+
+**2. 不支持 `rgba()` 颜色格式**
+
+SVG 属性中的 `rgba()` 颜色值在 Skyline 下不生效,需拆分为颜色值 + `fill-opacity` / `stroke-opacity`。
+
+```xml
+
+
+
+
+
+```
+
+> 建议用 [SVGO 在线工具](https://jakearchibald.github.io/svgomg/) 优化 SVG,可自动清理冗余属性、合并路径,减小体积并降低兼容性风险。
diff --git a/.agents/skills/mpx2skyline/references/skyline-runtime-practice.md b/.agents/skills/mpx2skyline/references/skyline-runtime-practice.md
new file mode 100644
index 0000000000..2ca8f2b464
--- /dev/null
+++ b/.agents/skills/mpx2skyline/references/skyline-runtime-practice.md
@@ -0,0 +1,302 @@
+# Skyline 运行时与性能适配实践
+
+本文记录 WebView 迁移 Skyline 时偏运行时的改造方案,包括常见问题与性能优化等改造方案。
+
+## 目录
+
+- [常见问题](#常见问题)
+ - [判断当前渲染模式](#判断当前渲染模式)
+ - [[必须] SelectorQuery 选择器不再支持以数字开头](#必须-selectorquery-选择器不再支持以数字开头)
+ - [[必须] Skyline 不支持的组件实例方法](#必须-skyline-不支持的组件实例方法)
+ - [[推荐] 用 this.createSelectorQuery 替代 wx.createSelectorQuery](#推荐-用-thiscreateselectorquery-替代-wxcreateselectorquery)
+ - [[必须] ScrollViewContext:开启 enhanced 属性](#必须-scrollviewcontext开启-enhanced-属性)
+ - [[必须] properties 默认值使用 value 而非 default](#必须-properties-默认值使用-value-而非-default)
+ - [[必须] 确保 wx:for 数据始终为 Array 或 Object](#必须-确保-wxfor-数据始终为-array-或-object)
+ - [[必须] properties 声明类型与实际值保持一致](#必须-properties-声明类型与实际值保持一致)
+ - [wxs 跨包引用错误](#wxs-跨包引用错误typeerror-rwxsstringify4ccc0480-is-not-a-function)
+- [性能优化](#性能优化)
+ - [列表用 list / custom 模式按需渲染](#列表用-list--custom-模式按需渲染)
+ - [cache-extent 预渲染(按需启用)](#cache-extent-预渲染按需启用)
+ - [预加载 Skyline 环境](#预加载-skyline-环境)
+
+---
+
+## 常见问题
+
+### 判断当前渲染模式
+
+在页面或组件实例上可读取 `renderer` 成员,取值为 `webview` 或 `skyline`。如果在模板中要判断,可以拿到值后设置到 data 上。
+
+在生命周期(如 `onLoad`/`attached`)中赋值到 data,供模板使用:
+
+```js
+// 选项式 API
+createComponent({
+ data: {
+ isSkyline: false
+ },
+ attached() {
+ this.isSkyline = this.renderer === 'skyline'
+ }
+})
+```
+
+```js
+//