Files
Jyotisha/docs/tasks/TASK-unified-loading-20260902.md
T
Jesse_ChenandClaude Fable 5.1 8db71aaf81 docs: product-level README, AGENTS.md split into code/reading parts, add CLAUDE.md, move task briefs to docs/tasks
- README.md is now the product/repo front door (architecture, repo map,
  local dev, test tiers, delivery flow, doc map). Engine positioning,
  VedAstro/Codex setup and the oracle/benchmark command reference move
  verbatim to docs/engine/README.md, docs/engine/vedastro-gateway.md and
  docs/benchmark/README.md. Capability badges realigned with the registry
  (91/78/8/0); tests/test_readme_badges.py was red on staging.
- AGENTS.md: Part A (environment truth, delivery, worktrees, record
  placement, bug workflow, growth freeze, frontend red lines, privacy,
  pre-work check, test tiers) and Part B (reading-rigor constraints).
  GitHub issue-tracker/triage boilerplate removed: GitHub is a read-only
  mirror. All strings locked by tests/ are preserved.
- CLAUDE.md added: roles, three working modes, task-brief sections,
  acceptance criteria, session discipline; imports AGENTS.md.
- 50 tracked TASK-*/PROGRESS-* files and 3 never-committed briefs move to
  docs/tasks/ with an index; REPO_LAYOUT.md merged into README.

Docs-only change (no gated path touched).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-03 06:56:06 +00:00

83 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 任务书 · 首页加载统一:一次等待、一次揭幕(2026-09-02)
基线:`origin/staging` 最新。**前置条件:`codex/streaming-ux-20260901`(c846c44a)必须先合入**——它改了消息区渲染链路,本轮改揭幕时机,两者同时改 `page.tsx` 渲染路径必然冲突。未合入前不得开工,登记 `BLOCKED.md`。与其它改 `page.tsx` 的轮次不得并行。
产品要求原话:"外面一层加载进去之后里面组件又有加载动画"→ 改成"外层加载显示不同状态,进去之后直接显示完整的,不加组件加载动画"。
---
## 为什么要做(事故实证)
行号基于 `701d4f92`,按符号定位。
1. **外层加载只等三样。** `page.tsx:862``Promise.all` 只拉账户、模型目录、会话列表,拿到就 `setHydrated(true)` 揭幕(`main.app-loading` 在 1503)。
2. **揭幕后还有四处各自转圈**
- **当前会话消息**:BUG-464 后列表不带消息,揭幕时当前会话(默认最近一条或 `?c=` 指定)的消息尚未加载,`ensureSessionMessages`485487 的 effect)才开始拉,消息区先显示 `session-messages-loading` + `InlineSpinner`(1867–1868)。**这是用户最先看见的第二层等待**。
- **starter 推荐问题**profile 完整时 11531187 的 effect 拉 `/api/onboarding`,期间显示 `starter-loading`1836)。
- **每日星语**1205 起拉 `fetchDailyStarlanguage`,卡片 `aria-busy``starter-home.tsx:88``dailyStarlanguageBusy` 630634)。
- **校正入口摘要**523 拉 `entry-summary`,影响校正卡文案;打开校正时 `BirthTimeRectification` 动态分包还有一行"正在加载出生时间评估..."230235)。
3. 这些请求彼此独立,全部可以在揭幕前并行完成——现在是串行体验(先等外层、再逐个等内层),并非数据依赖所迫。
## 决策记录(产品授权,2026-09-02)
1. **单一加载动画**:全站首页只保留 `AppLoadingIndicator`(轨道动画)这一种加载表现。揭幕后不得再出现任何 spinner/骨架/"正在加载"文案,**流式回答的生成中状态除外**(那是内容本身在生成,不是加载)。
2. **两阶段揭幕**:阶段一(账户/模型/会话列表)→ 阶段二并行(当前会话消息、starter 问题、每日星语、校正入口摘要、校正分包预热 `import()`)→ 全部就绪才揭幕。外层加载屏的 `detail` 文案随阶段切换(例如"正在读取账户…"→"正在准备对话…"),文案由执行方按现有 `AppLoadingIndicator` 的 title/detail 口径拟,浅深两套主题下检查。
3. **超时降级,不无限等**:阶段二整体上限 **4 秒**(常量,可配)。超时未到的项一律进入其**静态最终态**,不是加载态:starter 用现有安全默认问题(1836 附近已有"个性化问题暂时不可用"路径)、每日星语用非个性化"查看今日运势"文案、校正卡用无摘要文案、当前会话消息未到则揭幕后**静默补上**(消息区空白但不转圈,到达即渲染)。阶段一失败仍走现有 `app-loading-error`
4. **后续切换会话**:揭幕后在后台按侧栏顺序预取最近 5 条会话的消息(低优先级、串行、复用 `ensureSessionMessages` 与 hydrated 缓存),让常见切换零等待;缓存未命中时消息区**不显示 spinner**,仅保留静态占位(无动画)直到消息到达。这一条是折中,产品若要"未命中也完全空白"可在验收时改口。
5. 打开校正的动态分包 loading 文案保留为兜底(分包已预热,正常不会看到)。
## 硬红线
1. **外层加载屏的 DOM 合同不变**`main.app-loading[aria-busy="true"]``main.app-loading-error` 选择器被 `stale-client-recovery.tsx:34-35` 依赖,必须原样保留。
2. 阶段二**不得阻塞阶段一的错误处理**;401 仍走 `redirectToLogin``?c=` 恢复、sessionStorage 回跳(BUG-465)语义不变。
3. 揭幕后不得新增任何 `InlineSpinner` / `role="status"` 加载态;被移除的加载态所对应的合同测试(先 `grep -rn 'starter-loading\|session-messages-loading\|dailyStarlanguageBusy\|正在加载出生时间' frontend/tests tests`)按例外条款修改,注明原值与原因;其余断言不得改。
4. 不得手写 `useCallback` / `useMemo``npm run lint` 0 errorBUG-470 后 react-hooks 规则已能分析 Homeeffect 内同步 setState、render 写 ref 都会被拦)。
5. `./node_modules/.bin/tsc --noEmit` 通过;测试总数不低于开工时 `origin/staging` 实测(Docker 环境 fail=0/skipped=0,无 Docker 逐条比对既有缺口);`next build``/``○ Static`;首屏 gzip ±2%。
6. 不改 `.gitea/workflows/**`;不动数据库;不在脏工作树切分支;不自行提升 main。
让步顺序:功能与测试不回归 > 一次揭幕的体验 > 揭幕耗时 > 代码整洁。
## 开工前置
```bash
git fetch origin --prune
git worktree add -b codex/unified-loading-20260902 \
../.worktrees/unified-loading-20260902 origin/staging
```
确认 streaming-ux 已合入。读 `pre_work_error_ledger.md``frontend/AGENTS.md``docs/BUG_HISTORY.md` 的 BUG-464/465/470。先读:`page.tsx` 启动 effect840960)、`ensureSessionMessages``use-session-management.ts`)、starter/每日星语/入口摘要三个 effect、`app-loading-indicator.tsx``starter-home.tsx`
## 任务分解
### 任务 1(P0)· 两阶段揭幕
- 启动 effect 改为:阶段一现有 `Promise.all` → 计算选中会话(复用 `resolveBootstrapSessionSelection`)→ 阶段二 `Promise.allSettled` 并行拉当前会话消息、starter 问题(仅 profile 完整时)、每日星语、校正入口摘要,并 `void import("@/components/birth-time-rectification")` 预热 → 4 秒上限 → `setHydrated(true)`
- 加载屏 `detail` 按阶段切换文案。
- 原来揭幕后才触发的三个 effect 改为"若已在阶段二拿到则跳过",避免重复请求(观测:首屏网络面板同一端点不得出现两次)。
### 任务 2(P0)· 移除揭幕后的加载态
- 删除首屏路径上的 `session-messages-loading``starter-loading`、每日星语首屏 `aria-busy`;按决策记录 3 落各自的静态最终态。
- 保留:流式生成中的状态;校正分包兜底文案。
### 任务 3P1)· 切换预取
- 揭幕后按侧栏顺序串行预取最近 5 条会话消息;缓存未命中时的静态占位(决策记录 4)。
### 任务 4P1)· 合同测试
- 锁:阶段二包含四项请求与预热;4 秒上限常量存在;揭幕后 `page.tsx` + `starter-home.tsx``InlineSpinner`/`role="status"` 加载态(流式区除外);`stale-client-recovery` 依赖的选择器仍在。
## 总验收
1. tsc / lint / 测试基线 / `/` Static / gzip(红线 45)。
2. 首屏时序说明写进 PROGRESS:阶段一、阶段二各自耗时(本地测量即可),并附网络面板截图或请求清单证明无重复请求。
3. 行为:登录后从加载屏到完整界面**只有一次揭幕**,消息、推荐问题、每日星语、校正卡同时就位;断网或慢速(DevTools 节流 Slow 3G)下 4 秒后揭幕且各项为静态兜底态、无任何转圈。无登录态环境则合同测试覆盖并如实标注。
## 明确不做
- 不改流式回答的生成中表现(streaming-ux 轮已定)。
- 不改校正会话面内部的加载/busy 语义(`rectification-agentic-chat``aria-busy` 是生成中,不是加载)。
- 不做骨架屏——产品要的是"不显示,直到完整"。
- 不动报告页、会员页的加载表现(另议)。