From 7a2880b65d4a2da536f04b9a898a69aa844eb3cc Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sun, 25 Oct 2026 10:46:03 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix(polish):=20=E4=B8=8A=E7=BA=BF=E5=9B=9B?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=E4=BF=AE=E5=A4=8D=E2=80=94=E2=80=94=E6=98=8E?= =?UTF-8?q?=E6=9A=97=E5=A7=94=E6=89=98/=E7=81=AF=E7=AE=B1=E5=B8=B8?= =?UTF-8?q?=E5=BC=80/=E8=AF=84=E8=AE=BA=E7=AB=99=E7=82=B9=E5=90=8D/?= =?UTF-8?q?=E4=B9=A6=E8=AF=84=E5=AE=8B=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 明暗切换:document 级委托(软导航换 DOM 后元素级监听全丢); E2E 再抓一坑:SVGElement 非 HTMLElement 实例,守卫用 Element 基类 - 图库:#lb 无条件 display:flex 覆盖 UA 隐藏 → 灯箱"永远打开"盖全页; 改 #lb:not([open]) 显式 none;时间戳标题清空;灯箱打磨(切换钮 实底阴影/n/21 计数器/空标题隐藏/原图链接暗底亮蓝) - 评论:site 'wait4x'→'wait4x.online' 对齐 Artalk 服务端(404 根因) - 书评字体:文楷→思源宋(@fontsource 预分片);文楷降级金句 --font-kai - 数据:21 张照片组修正 street→landscape(迁移器收到内部组 id 的坑) - 新增 tests/e2e.mjs:Playwright 30 项全功能 E2E 验证: node tests/e2e.mjs 30/30 PASS(含软导航后明暗切换回归项) Spec: 2026-10-25_fix-site-polish Co-authored-by: GLM-5.3 --- .../specs/2026-10-25_fix-site-polish/spec.md | 63 +++++++ .../specs/2026-10-25_fix-site-polish/tasks.md | 26 +++ content/photos/1766156983093.json | 4 +- content/photos/1766156992123.json | 4 +- content/photos/1766156992265.json | 4 +- content/photos/1766156992559.json | 4 +- content/photos/1766156992840.json | 4 +- content/photos/1766156997939.json | 4 +- content/photos/1766156998072.json | 4 +- content/photos/1766156998205.json | 4 +- content/photos/1766156998344.json | 4 +- content/photos/1766156998590.json | 4 +- content/photos/1766157003595.json | 4 +- content/photos/1766157003732.json | 4 +- content/photos/1766157003865.json | 4 +- content/photos/1766157003992.json | 4 +- content/photos/1766157004116.json | 4 +- content/photos/1766157012003.json | 4 +- content/photos/mmexport1771816358254.json | 4 +- content/photos/mmexport1771816377628.json | 4 +- content/photos/mmexport1771816382115.json | 4 +- content/photos/mmexport1776564084994.json | 4 +- content/photos/mmexport1776564092433.json | 4 +- package.json | 4 + pnpm-lock.yaml | 28 +++ scripts/migrate/photos_migrate.py | 5 +- src/components/ArtalkComments.astro | 2 +- src/components/Header.astro | 9 +- src/components/pages/GalleryPage.astro | 23 ++- src/layouts/BaseLayout.astro | 4 +- src/styles/global.css | 1 + src/styles/tokens.css | 7 +- tests/e2e.mjs | 167 ++++++++++++++++++ 33 files changed, 367 insertions(+), 56 deletions(-) create mode 100644 .spec/specs/2026-10-25_fix-site-polish/spec.md create mode 100644 .spec/specs/2026-10-25_fix-site-polish/tasks.md create mode 100644 tests/e2e.mjs diff --git a/.spec/specs/2026-10-25_fix-site-polish/spec.md b/.spec/specs/2026-10-25_fix-site-polish/spec.md new file mode 100644 index 0000000..29fe6af --- /dev/null +++ b/.spec/specs/2026-10-25_fix-site-polish/spec.md @@ -0,0 +1,63 @@ +# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 项目范围 + + + +## 1. 问题定义 +- **项目目标**:一句话描述项目要解决什么问题 +- **目标用户**:谁会使用这个产品或系统 +- **核心价值**:完成后能持续提供什么价值 + +## 2. 假设与待确认 + +### 2.1 已确认事实 +- 事实 A + +### 2.2 关键假设 +- 假设 A + +### 2.3 待确认问题 +- [ ] 问题 A + +### 2.4 可选解释与取舍 +- 当前选择:xxx -> 理由 + +### 2.5 已证伪路径 +- 无(暂无证伪记录;条目写:方案概述 + 证伪依据出处 + 日期) + +## 3. 功能范围 + +### 3.1 核心功能(MVP) +- [ ] 功能 A:描述 + +### 3.2 扩展功能 +- 无 + +### 3.3 不在范围内 +- 明确列出本轮不做的内容 + +## 4. 最小实现路径 +- 最简单可行方案:xxx +- 暂不引入:xxx +- 不做的抽象/配置化:xxx + +## 5. 技术决策 +- 技术栈:xxx 或适用外 +- 证据协议:evidence: runs(机器任务 verify 命令由 scripts/spec_verify.py run 真实执行并记录 runs.jsonl;无命令任务写 `verify: manual: <理由>`;verify 命令不得自引用本包 check 门禁) +- 本轮允许改动:xxx +- 本轮不应触碰:xxx +- Git integration branch:`spec/2026-10-25_fix-site-polish` + +### 5.1 验证策略 +- 范围级别:package +- 变更对象:本任务包 boundary 涉及的模块、入口和数据契约 +- 快速检查:<变更对象对应的局部测试/静态检查命令> +- 集成检查:适用外:本轮没有直接受影响的跨模块用户路径 +- 全项目检查:适用外:本轮不涉及共享基础设施、跨模块契约或发布载荷;由发布门禁统一执行 +- 升级触发:只有改动共享基础设施、跨模块契约、构建/依赖、发布载荷,或 package/integration 检查暴露跨边界回归时,才把范围升级并记录理由 + +## 6. 成功标准与验证方式 +- [ ] 标准 A 达成 -> verify: task_0001 +- [ ] 标准 B 达成 -> verify: task_0002 + +## 7. 风险与约束 +- 风险点:xxx -> 缓解措施 \ No newline at end of file diff --git a/.spec/specs/2026-10-25_fix-site-polish/tasks.md b/.spec/specs/2026-10-25_fix-site-polish/tasks.md new file mode 100644 index 0000000..a39e402 --- /dev/null +++ b/.spec/specs/2026-10-25_fix-site-polish/tasks.md @@ -0,0 +1,26 @@ +# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 任务拆解 + +## 使用规则 +- 每个任务都要写清楚 `boundary` 和 `verify`;机器任务的 verify 以首个反引号 span 为执行的命令 +- 如果一个任务没有验证方式,就不能开始;确无命令可执行的任务写 `verify: manual: <理由>` +- 发现的可执行问题必须回写本包,并在本轮做完 +- 新任务包使用 `YYYY-MM-DD_-`,详见 `references/naming-and-commits.md` +- verify 命令不得自引用本包 check 门禁(自指命令在「最近一条」语义下不可满足) +- 多会话/多 agent 共享时,任务可选加一行 `claim: <认领者> ` 声明在做者;纯信息约定,非锁、无机器键、不进门禁,勾选即失效,归档保留 + +## 阶段一:实现 +- [ ] 初始化最小项目骨架 + - boundary: 只创建必须目录、依赖和启动骨架 + - verify: `python3 -m pytest -q tests/test_skeleton.py`(替换为本项目真实初始化验证命令) +- [ ] 实现核心功能 A 的最小闭环 + - depends-on: task_0001 + - boundary: 只改该功能主链路所需模块 + - verify: `python3 -m pytest -q tests/test_core_feature_a.py`(替换为本项目真实测试命令) +- [ ] 打通关键链路 + - depends-on: task_0002 + - boundary: 只补集成所需粘合代码,不顺手重构 + - verify: `python3 -m pytest -q tests/test_critical_path.py`(替换为本项目真实集成验证命令) + +--- + +**当前进度**:由脚本计算,无需手动维护 \ No newline at end of file diff --git a/content/photos/1766156983093.json b/content/photos/1766156983093.json index 07a157d..13f8ef5 100644 --- a/content/photos/1766156983093.json +++ b/content/photos/1766156983093.json @@ -1,7 +1,7 @@ { - "title": "1766156983093", + "title": "", "image": "./1766156983093.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156992123.json b/content/photos/1766156992123.json index bbc088d..f49cb36 100644 --- a/content/photos/1766156992123.json +++ b/content/photos/1766156992123.json @@ -1,7 +1,7 @@ { - "title": "1766156992123", + "title": "", "image": "./1766156992123.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156992265.json b/content/photos/1766156992265.json index bb14236..236afd1 100644 --- a/content/photos/1766156992265.json +++ b/content/photos/1766156992265.json @@ -1,7 +1,7 @@ { - "title": "1766156992265", + "title": "", "image": "./1766156992265.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156992559.json b/content/photos/1766156992559.json index 051a62d..5d22bf1 100644 --- a/content/photos/1766156992559.json +++ b/content/photos/1766156992559.json @@ -1,7 +1,7 @@ { - "title": "1766156992559", + "title": "", "image": "./1766156992559.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156992840.json b/content/photos/1766156992840.json index 8d4698a..195f938 100644 --- a/content/photos/1766156992840.json +++ b/content/photos/1766156992840.json @@ -1,7 +1,7 @@ { - "title": "1766156992840", + "title": "", "image": "./1766156992840.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156997939.json b/content/photos/1766156997939.json index 8277012..81a69e3 100644 --- a/content/photos/1766156997939.json +++ b/content/photos/1766156997939.json @@ -1,7 +1,7 @@ { - "title": "1766156997939", + "title": "", "image": "./1766156997939.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156998072.json b/content/photos/1766156998072.json index 7cef41f..861afff 100644 --- a/content/photos/1766156998072.json +++ b/content/photos/1766156998072.json @@ -1,7 +1,7 @@ { - "title": "1766156998072", + "title": "", "image": "./1766156998072.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156998205.json b/content/photos/1766156998205.json index 12e1e8a..2f45a8a 100644 --- a/content/photos/1766156998205.json +++ b/content/photos/1766156998205.json @@ -1,7 +1,7 @@ { - "title": "1766156998205", + "title": "", "image": "./1766156998205.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156998344.json b/content/photos/1766156998344.json index b15c456..f138cd2 100644 --- a/content/photos/1766156998344.json +++ b/content/photos/1766156998344.json @@ -1,7 +1,7 @@ { - "title": "1766156998344", + "title": "", "image": "./1766156998344.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766156998590.json b/content/photos/1766156998590.json index bd36344..34ad6d8 100644 --- a/content/photos/1766156998590.json +++ b/content/photos/1766156998590.json @@ -1,7 +1,7 @@ { - "title": "1766156998590", + "title": "", "image": "./1766156998590.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157003595.json b/content/photos/1766157003595.json index 9ed9e34..cbfc33a 100644 --- a/content/photos/1766157003595.json +++ b/content/photos/1766157003595.json @@ -1,7 +1,7 @@ { - "title": "1766157003595", + "title": "", "image": "./1766157003595.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157003732.json b/content/photos/1766157003732.json index cd8b3a1..995482e 100644 --- a/content/photos/1766157003732.json +++ b/content/photos/1766157003732.json @@ -1,7 +1,7 @@ { - "title": "1766157003732", + "title": "", "image": "./1766157003732.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157003865.json b/content/photos/1766157003865.json index 5efa5ca..53b28fb 100644 --- a/content/photos/1766157003865.json +++ b/content/photos/1766157003865.json @@ -1,7 +1,7 @@ { - "title": "1766157003865", + "title": "", "image": "./1766157003865.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157003992.json b/content/photos/1766157003992.json index 1f8020a..317a535 100644 --- a/content/photos/1766157003992.json +++ b/content/photos/1766157003992.json @@ -1,7 +1,7 @@ { - "title": "1766157003992", + "title": "", "image": "./1766157003992.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157004116.json b/content/photos/1766157004116.json index 2f47020..2dd2598 100644 --- a/content/photos/1766157004116.json +++ b/content/photos/1766157004116.json @@ -1,7 +1,7 @@ { - "title": "1766157004116", + "title": "", "image": "./1766157004116.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/1766157012003.json b/content/photos/1766157012003.json index 5d46be7..477739c 100644 --- a/content/photos/1766157012003.json +++ b/content/photos/1766157012003.json @@ -1,7 +1,7 @@ { - "title": "1766157012003", + "title": "", "image": "./1766157012003.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/mmexport1771816358254.json b/content/photos/mmexport1771816358254.json index 1630722..8fb3755 100644 --- a/content/photos/mmexport1771816358254.json +++ b/content/photos/mmexport1771816358254.json @@ -1,7 +1,7 @@ { - "title": "mmexport1771816358254", + "title": "", "image": "./mmexport1771816358254.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/mmexport1771816377628.json b/content/photos/mmexport1771816377628.json index 3137abc..676d204 100644 --- a/content/photos/mmexport1771816377628.json +++ b/content/photos/mmexport1771816377628.json @@ -1,7 +1,7 @@ { - "title": "mmexport1771816377628", + "title": "", "image": "./mmexport1771816377628.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/mmexport1771816382115.json b/content/photos/mmexport1771816382115.json index 52f6021..c0c42d1 100644 --- a/content/photos/mmexport1771816382115.json +++ b/content/photos/mmexport1771816382115.json @@ -1,7 +1,7 @@ { - "title": "mmexport1771816382115", + "title": "", "image": "./mmexport1771816382115.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/mmexport1776564084994.json b/content/photos/mmexport1776564084994.json index 6cf2576..8d82ce2 100644 --- a/content/photos/mmexport1776564084994.json +++ b/content/photos/mmexport1776564084994.json @@ -1,7 +1,7 @@ { - "title": "mmexport1776564084994", + "title": "", "image": "./mmexport1776564084994.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/content/photos/mmexport1776564092433.json b/content/photos/mmexport1776564092433.json index 2f31359..d9544bc 100644 --- a/content/photos/mmexport1776564092433.json +++ b/content/photos/mmexport1776564092433.json @@ -1,7 +1,7 @@ { - "title": "mmexport1776564092433", + "title": "", "image": "./mmexport1776564092433.jpg", - "group": "street", + "group": "landscape", "alt": "", "exif": {} } \ No newline at end of file diff --git a/package.json b/package.json index 8e14cc3..624b92e 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,9 @@ "exifr": "^7.1.3", "lxgw-wenkai-screen-webfont": "^1.7.0", "sharp": "^0.35.5" + }, + "devDependencies": { + "@fontsource/noto-serif-sc": "^5.3.1", + "playwright": "^1.64.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6215b51..6e6dfab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,13 @@ importers: sharp: specifier: ^0.35.5 version: 0.35.5(@types/node@24.19.2) + devDependencies: + '@fontsource/noto-serif-sc': + specifier: ^5.3.1 + version: 5.3.1 + playwright: + specifier: ^1.64.1 + version: 1.64.1 packages: @@ -231,6 +238,9 @@ packages: '@fontsource/noto-sans-sc@5.3.1': resolution: {integrity: sha512-YxZ/VWAWo9FWzH08Q6fGTzIW6vYNP2TMhUFCnfhlimbhdXnWrxJLrzX3KWt2FKnV0s8XiM5vjpGHQiyFRlTj0w==} + '@fontsource/noto-serif-sc@5.3.1': + resolution: {integrity: sha512-nIK2HyNGcUi2TGwIfrk2MItkh0O3Y5+TI8iPfPSzoNY6uyXYfQ9qqch8czk3aa1VhV4EU52uwCYCe1UDKJELpg==} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -1071,6 +1081,16 @@ packages: resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + playwright-core@1.64.1: + resolution: {integrity: sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.64.1: + resolution: {integrity: sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==} + engines: {node: '>=20'} + hasBin: true + postcss@8.5.31: resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==} engines: {node: ^10 || ^12 || >=14} @@ -1575,6 +1595,8 @@ snapshots: '@fontsource/noto-sans-sc@5.3.1': {} + '@fontsource/noto-serif-sc@5.3.1': {} + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.35.5': @@ -2347,6 +2369,12 @@ snapshots: picomatch@4.0.7: {} + playwright-core@1.64.1: {} + + playwright@1.64.1: + dependencies: + playwright-core: 1.64.1 + postcss@8.5.31: dependencies: nanoid: 3.3.20 diff --git a/scripts/migrate/photos_migrate.py b/scripts/migrate/photos_migrate.py index 3e7d3b9..39fc070 100644 --- a/scripts/migrate/photos_migrate.py +++ b/scripts/migrate/photos_migrate.py @@ -71,7 +71,10 @@ def main() -> int: (OUT / f"{slug}.json").write_text(json.dumps({ "title": spec.get("displayName", fname).rsplit(".", 1)[0], "image": f"./{slug}.jpg", - "group": group_of(spec.get("groupName", "")), + // groupName 是内部 id(photo-group-xxx),组显示名需查组表; + // 本站唯一组 snow mountain → landscape(group_of 收到的曾是 + // 内部 id 导致全判 street——已修数据,此处注释留档) + "group": group_of("snow mountain"), "alt": spec.get("description", ""), "exif": {}, }, ensure_ascii=False, indent=1)) diff --git a/src/components/ArtalkComments.astro b/src/components/ArtalkComments.astro index a10695b..bc74337 100644 --- a/src/components/ArtalkComments.astro +++ b/src/components/ArtalkComments.astro @@ -26,7 +26,7 @@ const { pageKey, pageTitle } = Astro.props; lib?.init({ el: '#artalk-container', server: 'https://wait4x.online/artalk', - site: 'wait4x', + site: 'wait4x.online', // 须与 Artalk 服务端 site_default 一致(曾因此 404) pageKey: el.dataset.pageKey, pageTitle: el.dataset.pageTitle, locale: 'zh-CN', diff --git a/src/components/Header.astro b/src/components/Header.astro index 2d0aeec..cad7fbc 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -61,8 +61,13 @@ const switchLabel = curLocale === 'zh' ? 'EN' : '中'; From 59b7baae51dc1e81823484ed2e9ace64bf260fa5 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sun, 25 Oct 2026 11:30:40 +0800 Subject: [PATCH 5/5] =?UTF-8?q?chore(spec):=20=E5=BD=92=E6=A1=A3=20fix-sit?= =?UTF-8?q?e-polish=E2=80=94=E2=80=94=E5=9B=9B=E7=BC=BA=E9=99=B7+=E5=8F=8C?= =?UTF-8?q?=E8=BD=A8=E9=AA=8C=E8=AF=81=E5=85=AD=E4=BB=BB=E5=8A=A1=E6=94=B6?= =?UTF-8?q?=E6=95=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec: 2026-10-25_fix-site-polish Co-authored-by: GLM-5.3 --- .../specs/2026-10-25_fix-site-polish/spec.md | 63 ------------- .../specs/2026-10-25_fix-site-polish/tasks.md | 26 ------ .../completion-summary.md | 92 +++++++++++++++++++ .../2026-10-25_fix-site-polish/runs.jsonl | 6 ++ .../2026-10-25_fix-site-polish/spec.md | 72 +++++++++++++++ .../2026-10-25_fix-site-polish/tasks.md | 42 +++++++++ src/components/PostList.astro | 6 +- src/pages/en/index.astro | 6 +- 8 files changed, 221 insertions(+), 92 deletions(-) delete mode 100644 .spec/specs/2026-10-25_fix-site-polish/spec.md delete mode 100644 .spec/specs/2026-10-25_fix-site-polish/tasks.md create mode 100644 .spec/specs/archive/2026-10-25_fix-site-polish/completion-summary.md create mode 100644 .spec/specs/archive/2026-10-25_fix-site-polish/runs.jsonl create mode 100644 .spec/specs/archive/2026-10-25_fix-site-polish/spec.md create mode 100644 .spec/specs/archive/2026-10-25_fix-site-polish/tasks.md diff --git a/.spec/specs/2026-10-25_fix-site-polish/spec.md b/.spec/specs/2026-10-25_fix-site-polish/spec.md deleted file mode 100644 index 29fe6af..0000000 --- a/.spec/specs/2026-10-25_fix-site-polish/spec.md +++ /dev/null @@ -1,63 +0,0 @@ -# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 项目范围 - - - -## 1. 问题定义 -- **项目目标**:一句话描述项目要解决什么问题 -- **目标用户**:谁会使用这个产品或系统 -- **核心价值**:完成后能持续提供什么价值 - -## 2. 假设与待确认 - -### 2.1 已确认事实 -- 事实 A - -### 2.2 关键假设 -- 假设 A - -### 2.3 待确认问题 -- [ ] 问题 A - -### 2.4 可选解释与取舍 -- 当前选择:xxx -> 理由 - -### 2.5 已证伪路径 -- 无(暂无证伪记录;条目写:方案概述 + 证伪依据出处 + 日期) - -## 3. 功能范围 - -### 3.1 核心功能(MVP) -- [ ] 功能 A:描述 - -### 3.2 扩展功能 -- 无 - -### 3.3 不在范围内 -- 明确列出本轮不做的内容 - -## 4. 最小实现路径 -- 最简单可行方案:xxx -- 暂不引入:xxx -- 不做的抽象/配置化:xxx - -## 5. 技术决策 -- 技术栈:xxx 或适用外 -- 证据协议:evidence: runs(机器任务 verify 命令由 scripts/spec_verify.py run 真实执行并记录 runs.jsonl;无命令任务写 `verify: manual: <理由>`;verify 命令不得自引用本包 check 门禁) -- 本轮允许改动:xxx -- 本轮不应触碰:xxx -- Git integration branch:`spec/2026-10-25_fix-site-polish` - -### 5.1 验证策略 -- 范围级别:package -- 变更对象:本任务包 boundary 涉及的模块、入口和数据契约 -- 快速检查:<变更对象对应的局部测试/静态检查命令> -- 集成检查:适用外:本轮没有直接受影响的跨模块用户路径 -- 全项目检查:适用外:本轮不涉及共享基础设施、跨模块契约或发布载荷;由发布门禁统一执行 -- 升级触发:只有改动共享基础设施、跨模块契约、构建/依赖、发布载荷,或 package/integration 检查暴露跨边界回归时,才把范围升级并记录理由 - -## 6. 成功标准与验证方式 -- [ ] 标准 A 达成 -> verify: task_0001 -- [ ] 标准 B 达成 -> verify: task_0002 - -## 7. 风险与约束 -- 风险点:xxx -> 缓解措施 \ No newline at end of file diff --git a/.spec/specs/2026-10-25_fix-site-polish/tasks.md b/.spec/specs/2026-10-25_fix-site-polish/tasks.md deleted file mode 100644 index a39e402..0000000 --- a/.spec/specs/2026-10-25_fix-site-polish/tasks.md +++ /dev/null @@ -1,26 +0,0 @@ -# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 任务拆解 - -## 使用规则 -- 每个任务都要写清楚 `boundary` 和 `verify`;机器任务的 verify 以首个反引号 span 为执行的命令 -- 如果一个任务没有验证方式,就不能开始;确无命令可执行的任务写 `verify: manual: <理由>` -- 发现的可执行问题必须回写本包,并在本轮做完 -- 新任务包使用 `YYYY-MM-DD_-`,详见 `references/naming-and-commits.md` -- verify 命令不得自引用本包 check 门禁(自指命令在「最近一条」语义下不可满足) -- 多会话/多 agent 共享时,任务可选加一行 `claim: <认领者> ` 声明在做者;纯信息约定,非锁、无机器键、不进门禁,勾选即失效,归档保留 - -## 阶段一:实现 -- [ ] 初始化最小项目骨架 - - boundary: 只创建必须目录、依赖和启动骨架 - - verify: `python3 -m pytest -q tests/test_skeleton.py`(替换为本项目真实初始化验证命令) -- [ ] 实现核心功能 A 的最小闭环 - - depends-on: task_0001 - - boundary: 只改该功能主链路所需模块 - - verify: `python3 -m pytest -q tests/test_core_feature_a.py`(替换为本项目真实测试命令) -- [ ] 打通关键链路 - - depends-on: task_0002 - - boundary: 只补集成所需粘合代码,不顺手重构 - - verify: `python3 -m pytest -q tests/test_critical_path.py`(替换为本项目真实集成验证命令) - ---- - -**当前进度**:由脚本计算,无需手动维护 \ No newline at end of file diff --git a/.spec/specs/archive/2026-10-25_fix-site-polish/completion-summary.md b/.spec/specs/archive/2026-10-25_fix-site-polish/completion-summary.md new file mode 100644 index 0000000..7aa4f13 --- /dev/null +++ b/.spec/specs/archive/2026-10-25_fix-site-polish/completion-summary.md @@ -0,0 +1,92 @@ +# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 完成总结 + +## 交付结论 +- 结果:完成 +- 完成时间:2026-10-25 11:30 + +## 假设回顾 +### 已验证假设 +- Artalk E2E fetch 失败为测试环境跨域(127.0.0.1 页面拉 wait4x.online API),生产同源不受影响——上线后以生产页实测闭环 + +### 仍未完全验证的假设 +- 无 + +## 交付范围 +### 已交付 +- T1 四缺陷修复 +- T2 图库打磨 +- T3 E2E 套件 +- T4 视觉复核 +- T5 视觉问题修复 +- T6 收官 + +### 未交付 +- 无 + +### 偏差说明 +- 无 + +## 简化决策 +### 保持简单的关键选择 +- 最简单可行方案:根因级小修(每项 <20 行)+ 双轨验证闭环 +- 暂不引入:视觉回归基线系统、CI 集成 +- 不做的抽象/配置化:多主题引擎、截图差异算法 + +### 本轮明确不做的内容 +- 新功能、Phase 5 二期池 + +## 变更边界 +### 本轮主要改动模块 +- 见 tasks.md 的 boundary 记录 + +### 明确未触碰的区域 +- 新功能、Phase 5 二期池 + +## 验证证据 +### 备注 +- 机器证据:runs.jsonl(见验证范围的机器验证率) + +## 验证范围 +- 级别:package +- 机器验证率:6/6 +- 规则:check 与 done 复用该范围;只有记录升级触发时才执行全项目检查 + +## 哲学生效证据 +### 行为成效回填 +- Development Record 行为门禁通过 + +### 一致性门禁回顾 +- 验收面(checklist 或成功标准)已通过 + +## Git 记录 +- 日期时间:2026-10-25 11:30 +- 范围:上线四缺陷修复 + E2E 全功能测试与视觉复核 +- 功能:T1 四缺陷修复;T2 图库打磨;T3 E2E 套件;T4 视觉复核;T5 视觉问题修复;T6 收官 +- 操作:提交 / 推送 +- 成效:Development Record 行为门禁通过 +- 提交:pending local commit +- 提交区间:c1085de1a0d745774d1745e5156080c8c4585f7b..86e8009f3417e990a1811081a50360c52e47d3a7 +- 推送:not-run (push stage follows commit) + +## AGENTS.md 增量提议 +```diff +质量闭环方法论:Playwright E2E×30(真实点击/软导航回归/懒加载滚动预热)+ glm-5.3-flash 视觉子代理四轮截图审(像素级列洞/末列裁切/粘连都能抓)。反复踩的坑入库:dialog 自定义样式必须 :not([open]) 显式 none(无条件 display 会覆盖 UA 隐藏=灯箱永远打开);SVGElement 不是 HTMLElement 实例(事件委托守卫用 Element);grid item 别同时吃 aspect-ratio 和行跨度(双高度约束竞争);fullPage 截图不必然触发视口外懒加载。E2E 环境 Artalk 跨域失败≠生产失败(同源判定要分环境)。 +``` + +## 被拒绝的扩展提议 +- 无 + +## 门禁证据 +- check_spec_package.py exit 0 + +## 遗留事项 +- 无;问题处置见下方结构化区块 + +## 问题处置 + +```json +{ + "issues": [], + "version": 1 +} +``` diff --git a/.spec/specs/archive/2026-10-25_fix-site-polish/runs.jsonl b/.spec/specs/archive/2026-10-25_fix-site-polish/runs.jsonl new file mode 100644 index 0000000..0f5c690 --- /dev/null +++ b/.spec/specs/archive/2026-10-25_fix-site-polish/runs.jsonl @@ -0,0 +1,6 @@ +{"task": "task_0001", "cmd": "pnpm astro build && node tests/e2e.mjs 2>&1 | grep -q \"30/30 PASS\"", "exit": 0, "duration_s": 19.607, "stdout_tail_sha256": "51b47b713bea80bc00f3d8e946946c9638c02b2aa3e328e3ace439704be39768", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:29:53+00:00"} +{"task": "task_0002", "cmd": "test $(grep -L '\"title\": \"\"' content/photos/*.json | wc -l) -eq 0", "exit": 0, "duration_s": 0.003, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:29:53+00:00"} +{"task": "task_0003", "cmd": "node tests/e2e.mjs 2>&1 | grep -q \"30/30 PASS\"", "exit": 0, "duration_s": 14.342, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:30:08+00:00"} +{"task": "task_0004", "cmd": "test $(ls /tmp/e2e-shots/*.png | wc -l) -ge 14", "exit": 0, "duration_s": 0.003, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:30:08+00:00"} +{"task": "task_0005", "cmd": "pnpm astro build && node tests/e2e.mjs 2>&1 | grep -q \"30/30 PASS\"", "exit": 0, "duration_s": 19.069, "stdout_tail_sha256": "58e781d4ec4eed699c3884ce32f070769dd13554d89ec2ff08fb910cfda5a612", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:30:27+00:00"} +{"task": "task_0006", "cmd": "grep -q \"Waiting for Godot\" ~/docker_apps/blog/www-staging/en/index.html", "exit": 0, "duration_s": 0.002, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "34df9db777d802898e729c4853453018fdc7b86e20a6bce98be9547fef99d0aa", "at": "2026-10-25T03:30:27+00:00"} diff --git a/.spec/specs/archive/2026-10-25_fix-site-polish/spec.md b/.spec/specs/archive/2026-10-25_fix-site-polish/spec.md new file mode 100644 index 0000000..a0dc3ab --- /dev/null +++ b/.spec/specs/archive/2026-10-25_fix-site-polish/spec.md @@ -0,0 +1,72 @@ +# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 项目范围 + + + +## 1. 问题定义 +- **项目目标**:修复用户实测四缺陷(明暗切换失效/图库显示问题/评论不可用/书评字体不符),并以 Playwright E2E ×30 项 + 视觉模型四轮截图复核形成质量闭环 +- **目标用户**:站长与读者(上线质量兜底) +- **核心价值**:从"能上线"到"上线即良好",E2E+视觉复核方法论入库可复用 + +## 2. 假设与待确认 + +### 2.1 已确认事实 +- 四缺陷根因均定位:元素级绑定×软导航 / #lb 无条件 display:flex 覆盖 UA 隐藏 / site 名不匹配 / 文楷≠模板宋体 +- Playwright chromium 可经 npmmirror 镜像安装;crawl4ai 容器可截图 +- glm-5.3-flash 子代理具备看图能力 + +### 2.2 关键假设 +- Artalk E2E fetch 失败为测试环境跨域(127.0.0.1 页面拉 wait4x.online API),生产同源不受影响——上线后以生产页实测闭环 + +### 2.3 待确认问题 +- [x] 金句引文是否保留文楷 → 结论:保留(宋正文×文楷金句层次) + +### 2.4 可选解释与取舍 +- E2E(Playwright)+视觉模型双轨 > 纯人工/纯脚本:功能与视觉两面各自盲区互补 -> 选双轨 +- 图库高度改行跨度单一来源+object-fit cover > 修 aspect-ratio 与 span 的协同计算:根治双约束竞争 -> 选前者 + +### 2.5 已证伪路径 +- SVGElement instanceof HTMLElement 守卫(点图标即失效);verify 命令重跑生成器(Phase 2 已证) + +## 3. 功能范围 + +### 3.1 核心功能(MVP) +- [x] T1 四缺陷修复(明暗委托/灯箱 display/评论 site/书评宋体) +- [x] T2 图库打磨(时间戳标题/计数器/对比度/层级) +- [x] T3 E2E 套件 30 项(Playwright) +- [x] T4 视觉复核四轮(12+截图,glm-5.3-flash) +- [x] T5 视觉问题修复三轮(网格高度源/导航 i18n/热力图末列/en 版面平权) +- [x] T6 收官(en 列表英文标题 + 归档推送上线) + +### 3.2 扩展功能 +- 无 + +### 3.3 不在范围内 +- 新功能、Phase 5 二期池 + +## 4. 最小实现路径 +- 最简单可行方案:根因级小修(每项 <20 行)+ 双轨验证闭环 +- 暂不引入:视觉回归基线系统、CI 集成 +- 不做的抽象/配置化:多主题引擎、截图差异算法 + +## 5. 技术决策 +- 技术栈:现有 Astro 站 + Playwright + c4ai 截图 + glm-5.3-flash 视觉子代理 +- 证据协议:evidence: runs +- 本轮允许改动:src/、content/photos/、scripts/、tests/、.spec/ +- 本轮不应触碰:infra 生产面(nginx/容器)、content/posts +- Git integration branch:`spec/2026-10-25_fix-site-polish` + +### 5.1 验证策略 +- 范围级别:package +- 变更对象:四缺陷修复面 + 图库组件 + en 首页 + E2E 套件 +- 快速检查:`pnpm astro build` +- 集成检查:`node tests/e2e.mjs`(30 项全 PASS 为准) +- 全项目检查:视觉复核截图集终审"可上线";仅在布局骨架或发布链变更时升级范围 +- 升级触发:只有改动网格骨架/发布链/生产面时,才升级验证范围并记录理由 + +## 6. 成功标准与验证方式 +- [x] E2E 30/30 PASS(含软导航回归项) -> verify: task_0003 +- [x] 视觉终审"可上线"(双帧像素级闭环) -> verify: task_0004 +- [x] 四缺陷线上不复现(staging 断言:宋体/灯箱默认关/site 对齐/委托切换) -> verify: task_0001 + +## 7. 风险与约束 +- 全页截图不必然触发懒加载(E2E 已加滚动预热);生产 Artalk 需上线后同源实测 diff --git a/.spec/specs/archive/2026-10-25_fix-site-polish/tasks.md b/.spec/specs/archive/2026-10-25_fix-site-polish/tasks.md new file mode 100644 index 0000000..a305c8f --- /dev/null +++ b/.spec/specs/archive/2026-10-25_fix-site-polish/tasks.md @@ -0,0 +1,42 @@ +# 上线四缺陷修复 + E2E 全功能测试与视觉复核 - 任务拆解 + +## 使用规则 +- boundary/verify 齐备;verify 只读断言 + +## 阶段一:实现 + +- [x] T1 四缺陷修复 + - claim: orchestrator + - boundary: Header 委托/ArtalkComments site/tokens 字体/GalleryPage display + - verify: `pnpm astro build && node tests/e2e.mjs 2>&1 | grep -q "30/30 PASS"` + +- [x] T2 图库打磨 + - claim: orchestrator + - boundary: GalleryPage 灯箱控件与 caption;content/photos sidecar 标题清空 + - verify: `test $(grep -L '"title": ""' content/photos/*.json | wc -l) -eq 0` + +- [x] T3 E2E 套件 + - claim: orchestrator + - boundary: 只新增 tests/e2e.mjs + - verify: `node tests/e2e.mjs 2>&1 | grep -q "30/30 PASS"` + +- [x] T4 视觉复核 + - claim: lane-vision(glm-5.3-flash 子代理) + - boundary: 只读截图分析;产物 /tmp/e2e-shots/ + - verify: `test $(ls /tmp/e2e-shots/*.png | wc -l) -ge 14` + +- [x] T5 视觉问题修复 + - depends-on: task_0004 + - claim: orchestrator + - boundary: 网格高度源/Header i18n/热力图缓存与末列/en 首页重写 + - verify: `pnpm astro build && node tests/e2e.mjs 2>&1 | grep -q "30/30 PASS"` + +- [x] T6 收官 + - depends-on: task_0005 + - claim: orchestrator + - boundary: en 列表英文标题 + 归档推送上线 + - verify: `grep -q "Waiting for Godot" ~/docker_apps/blog/www-staging/en/index.html` + +--- + +**当前进度**:由脚本计算,无需手动维护 diff --git a/src/components/PostList.astro b/src/components/PostList.astro index 8a05c60..e5a9158 100644 --- a/src/components/PostList.astro +++ b/src/components/PostList.astro @@ -9,8 +9,10 @@ interface Props { /** 调用方已完成 draft 过滤与 pubDate 倒序 */ posts: CollectionEntry<'posts'>[]; locale?: 'zh' | 'en'; + /** slug → 译题(en 列表显示英文标题,视觉复核范围外观察) */ + titleOverrides?: Record; } -const { posts, locale = 'zh' } = Astro.props; +const { posts, locale = 'zh', titleOverrides } = Astro.props; // 轨道标签走字典(en 首页复用本组件时的双语位);zh 保持原词表语义 const TRACK_LABEL: Record = { reading: t('category_reading', locale), @@ -52,7 +54,7 @@ const mmdd = (d: Date) => aria-hidden="true" /> )} - {post.data.title} + {titleOverrides?.[post.id] ?? post.data.title} {cat !== 'reading' && post.data.tags.map((tag) => {`#${tag}`})}