fix(ci): 出生时间旅程合同改读 (app)/page.tsx(BUG-939)
This commit is contained in:
+17
-1
@@ -12193,7 +12193,7 @@
|
||||
- 修复:四条按「原值 / 新值 / 原因」改写,分别断 layout 与 homepage 注册两端,不得删测试。
|
||||
- 验证:上述四文件;全量 `npm test` 相对 `cc1a8980` 少这 4 条红。
|
||||
- 防复发:见 BUG-927。
|
||||
- 相关记录:BUG-927、BUG-745
|
||||
- 相关记录:BUG-927、BUG-745、BUG-939
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -12285,3 +12285,19 @@
|
||||
- 相关记录:BUG-214、BUG-268、BUG-282、BUG-937
|
||||
- 复发自:无
|
||||
- 修复版本:`8b11ae7d`
|
||||
|
||||
## BUG-939 | 出生时间旅程合同仍读已搬走的 `app/page.tsx`,staging 门禁全红
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-18
|
||||
- 最近更新:2026-09-18
|
||||
- 影响面:`tests/test_birth_time_journey_contract.py` `_home_surface`;Gitea `backend-quality-gate` `validate`;staging 无法发布 `e4e73f56` 之后的提交
|
||||
- 用户现象:staging 门禁从会话列表单起连续失败,最新一次 [run 2763](https://git.copse.top/root/Jyotisha/actions/runs/2763) 停在 Python 快速门。线上仍停在上次绿灯 `dc2f2a16`。
|
||||
- 触发条件:push 到 `staging` 且命中门禁路径。pytest 跑 `test_web_onboarding_uses_the_deterministic_free_journey`。
|
||||
- 根因:`e4e73f56` 把首页从 `frontend/src/app/page.tsx` 搬进 `(app)` 路由组。BUG-933/934 改了前端四条合同和两条 Python 入口合同,漏了这条已列入 `CORE_PYTEST_TARGETS` 的文件。`_home_surface()` 对缺失文件 `if path.exists()` 静默跳过,于是断言变成「拼盘里找不到 `<BirthTimeRectification`」,而组件仍在 `frontend/src/app/(app)/page.tsx`。
|
||||
- 修复:首页表面改为必读 `(app)/page.tsx`,hooks 仍可选。新增路径锁:`PAGE.parts` 必须以 `(app)/page.tsx` 结尾,旧路径不得存在。
|
||||
- 验证:`pytest tests/test_birth_time_journey_contract.py tests/test_session_management_entrypoints.py tests/test_supabase_user_data_contract.py tests/test_daily_and_rectification_entrypoints.py` 25 passed。未改产品代码。
|
||||
- 防复发:扫首页源码的 Python 合同必须必读 `(app)/page.tsx`,不得对首页文件 `exists()` 跳过。外壳再搬家时,`CORE_PYTEST_TARGETS` 里所有 `_home_surface` 都要一起改。
|
||||
- 相关记录:BUG-927、BUG-933、BUG-934
|
||||
- 复发自:BUG-933
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# PROGRESS · 出生时间旅程合同跟着外壳搬家(2026-09-18)
|
||||
|
||||
工作树:`.worktrees/birth-time-journey-page-path-20260918`
|
||||
分支:`codex/birth-time-journey-page-path-20260918`
|
||||
基线:`origin/staging` @ `5a1dcbd2`
|
||||
合入提交:待推送
|
||||
|
||||
## 任务状态
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 路径搬家 BUG-939 | 完成 | `_home_surface` 必读 `(app)/page.tsx`;hooks 仍可选 |
|
||||
| 路径锁 | 完成 | `PAGE.parts[-2:] == ("(app)", "page.tsx")`;旧路径不得存在 |
|
||||
| 记录 | 完成 | BUG-939(复发自 BUG-933);BUG-933 相关记录补本条 |
|
||||
|
||||
未改 `page.tsx`、产品行为、Skill、workflow。
|
||||
|
||||
## 断言三栏
|
||||
|
||||
| 位置 | 原值 | 新值 | 原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| `_home_surface` 首页文件 | `frontend/src/app/page.tsx`,缺失则 `exists()` 跳过 | 必读 `frontend/src/app/(app)/page.tsx` | `e4e73f56` 已搬家;静默跳过把失败伪装成「找不到 `<BirthTimeRectification`」 |
|
||||
| 新增 `test_home_surface_requires_the_app_route_group_page` | 无 | 锁定 `(app)/page.tsx` 存在、旧路径不存在 | 防复发:下一次再搬文件会 FileNotFound,而不是子串断言 |
|
||||
|
||||
## 测试
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `pytest tests/test_birth_time_journey_contract.py tests/test_session_management_entrypoints.py tests/test_supabase_user_data_contract.py tests/test_daily_and_rectification_entrypoints.py` | **25 passed** |
|
||||
| 前端 tsc / lint / npm test / next build | 未改前端,未跑 |
|
||||
| 门禁 | 推 staging 后以 `backend-quality-gate` 为准 |
|
||||
|
||||
## 环境缺口
|
||||
|
||||
无登录态、无 Chrome、无 Docker。本单只修合同路径,不需要浏览器验收。
|
||||
@@ -134,6 +134,7 @@
|
||||
| `TASK-consult-followup-tool-contract-fix-20260917.md` | `PROGRESS-consult-followup-tool-contract-fix-20260917.md` | **P0**。部署 `dc2f2a16` 后再聊天仍 `runtime_contract_incomplete`,回执只有 skill + retry。主根因(推断):BUG-923 把本命/窗口第 0 步改成 `toolChoice: required`,而首轮固定开 thinking,BUG-282 实证 thinking 模式供应商拒收非 auto 的 tool_choice → 每一轮咨询在第 0 步就被拒(BUG-937,复发自 BUG-282)。次根因(确定):咨询流不处理 Mastra `error` 块,拒收在回执/事件/日志三处都不可见,合同 retry 照跑同一参数(BUG-938)。T1 撤回 required 只留 activeTools + auto;T2 error 块 → 可诊断错误码、不进合同 retry;T4 部署后取证 | 待验收 | `codex/consult-followup-tool-contract-fix-20260917` |
|
||||
| `TASK-session-list-single-source-20260917.md` | `PROGRESS-session-list-single-source-20260917.md` | 会话列表一处数据源:本地 PG 兼容层 `order()` 只保留最后一键,`/api/sessions` 实际按 `id` 排、与游标不一致;`/` 与次级页两份数据源、`/` 每次回来重启动(产品拍板:首页与三个次级页进同一路由组,侧栏外壳与列表 provider 常驻 layout,不做 store);空「新对话」落库堆积(首页 50 条里 28 条);标题类别在后、同名靠墙钟 HH:MM。串行在 composer-guard 单之后。BUG 段 926 起 | 验收未通过 | `e4e73f56`(实现按任务书落地:多键排序 / `(app)` 路由组常驻外壳 / provider / 空会话不入列 + draft 复用 / 标题类别在前;两条让步任务书允许。**P1:4 条针对 `page.tsx` 的源码合同没跟着外壳搬家,`npm test` 在门禁里 `set -e` 下必红,staging 至今停在 `dc2f2a16`**。另:进度记录报「tsc 0 错」实为 2 错,只跑了定向测试。修复单 `TASK-session-list-single-source-fix-20260917.md`) |
|
||||
| `TASK-session-list-single-source-fix-20260917.md` | `PROGRESS-session-list-single-source-fix-20260917.md` | 验收修复单:F1 四条源码合同搬到 `(app)/layout.tsx` 两端对断(BUG-933);F2 两条陈旧 Python 入口断言(BUG-934,既有欠账);F3 无活跃会话时输入框静默吞发送(BUG-935);交付前必须跑全量测试 | 待验收 | `codex/session-list-single-source-fix-20260917` |
|
||||
| — | `PROGRESS-birth-time-journey-page-path-20260918.md` | **P0 门禁**:`test_birth_time_journey_contract` 仍读已搬走的 `app/page.tsx`,`exists()` 静默跳过导致 CORE pytest 红,staging 停在 `dc2f2a16`(BUG-939,复发自 BUG-933) | 执行中 | `codex/birth-time-journey-page-path-20260918` |
|
||||
| `TASK-first-paint-dead-screen-fallback-20260917.md` | — | 真机:首页永远停在「正在载入账户」,兜底全在没跑起来的 bundle 里(BUG-936 investigating)。根 layout 加与 bundle 无关的内联兜底 + 去掉本仓正则后行断言 | 待领取 | — |
|
||||
| `TASK-consultation-answer-start-anchor-20260917.md` | `PROGRESS-consultation-answer-start-anchor-20260917.md` | 主会话回答落在结尾:`useConversationScrollAnchor` 是贴底跟随,流式期间视口钉在最后一个字,回答开头滚出视口;改为发送后问题钉顶、回答向下长、长出视口显示「跳到最新」、末尾动态留白;产品追加拍板:校正面同一语义(推翻 BUG-041/048 贴底),本轮开头 = 用户行或新助手行。BUG 段 930 起 | 已验收(经修复单) | `worktree/green-harbor-5be3` |
|
||||
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | `PROGRESS-consultation-answer-start-anchor-fix-20260917.md` | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 已验收 | `cc1a8980`(Claude 验收:tsc 0 / lint 0 error / npm test 3457 条 39 红与 11c0028d 逐条一致、新增 2 条绿 / `next build --webpack` 通过、`/` Static、首屏 gzip 591,242(较 09-16 基线 582,800 +1.45%,含会话列表单)/ Chrome 真实布局 S1–S6 全部通过,S6 新助手行距顶 16px 且增高不动,S5 不再写留白);真机六条欠 |
|
||||
|
||||
@@ -126,23 +126,32 @@ def test_rectification_cases_are_owner_scoped_and_auditable() -> None:
|
||||
assert "grant delete" not in sql
|
||||
|
||||
|
||||
PAGE = FRONTEND / "src" / "app" / "(app)" / "page.tsx"
|
||||
HOME_SURFACE_FILES = (
|
||||
PAGE,
|
||||
FRONTEND / "src" / "lib" / "home-types.ts",
|
||||
FRONTEND / "src" / "lib" / "home-profile.ts",
|
||||
FRONTEND / "src" / "lib" / "home-cloud-sync.ts",
|
||||
FRONTEND / "src" / "components" / "birth-location-fields.tsx",
|
||||
FRONTEND / "src" / "components" / "profile-fields.tsx",
|
||||
FRONTEND / "src" / "components" / "onboarding-chat-message.tsx",
|
||||
FRONTEND / "src" / "components" / "chart-library-panel.tsx",
|
||||
FRONTEND / "src" / "components" / "starter-home.tsx",
|
||||
)
|
||||
OPTIONAL_HOME_HOOKS = (
|
||||
FRONTEND / "src" / "hooks" / "use-session-management.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-consultation-run.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-profile-onboarding.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-rectification-surface.ts",
|
||||
)
|
||||
|
||||
|
||||
def _home_surface() -> str:
|
||||
files = [
|
||||
FRONTEND / "src" / "app" / "page.tsx",
|
||||
FRONTEND / "src" / "lib" / "home-types.ts",
|
||||
FRONTEND / "src" / "lib" / "home-profile.ts",
|
||||
FRONTEND / "src" / "lib" / "home-cloud-sync.ts",
|
||||
FRONTEND / "src" / "components" / "birth-location-fields.tsx",
|
||||
FRONTEND / "src" / "components" / "profile-fields.tsx",
|
||||
FRONTEND / "src" / "components" / "onboarding-chat-message.tsx",
|
||||
FRONTEND / "src" / "components" / "chart-library-panel.tsx",
|
||||
FRONTEND / "src" / "components" / "starter-home.tsx",
|
||||
FRONTEND / "src" / "hooks" / "use-session-management.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-consultation-run.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-profile-onboarding.ts",
|
||||
FRONTEND / "src" / "hooks" / "use-rectification-surface.ts",
|
||||
]
|
||||
return "".join(path.read_text(encoding="utf-8") for path in files if path.exists())
|
||||
parts = [path.read_text(encoding="utf-8") for path in HOME_SURFACE_FILES]
|
||||
parts.extend(
|
||||
path.read_text(encoding="utf-8") for path in OPTIONAL_HOME_HOOKS if path.exists()
|
||||
)
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def _mastra_consultation_surface() -> str:
|
||||
@@ -155,6 +164,12 @@ def _mastra_consultation_surface() -> str:
|
||||
)
|
||||
|
||||
|
||||
def test_home_surface_requires_the_app_route_group_page() -> None:
|
||||
assert PAGE.is_file()
|
||||
assert PAGE.parts[-2:] == ("(app)", "page.tsx")
|
||||
assert not FRONTEND.joinpath("src", "app", "page.tsx").exists()
|
||||
|
||||
|
||||
def test_web_onboarding_uses_the_deterministic_free_journey() -> None:
|
||||
page = _home_surface()
|
||||
route = (
|
||||
|
||||
Reference in New Issue
Block a user