AGENTS.md@.github/apps/timeline-web · git:20261025.3c17b73 · 2026-10-25 · sha256 a45b1facae8227b2

AGENTS.md@.github/apps/timeline-web git:20261025.3c17b73A

Immutable. This exact content never changes and is served at /api/v1/blob/a45b1facae8227b2.

# AGENTS.md - timeline-web

## 目录用途

本目录是八字时辰时间轴的独立 React 体验壳:时辰时间沿纵轴连续展开,登记字段沿横轴投影;只消费 timeline 机器契约,不计算命理事实。

## 目录结构

```text
timeline-web/
├── AGENTS.md
├── .node-version
├── index.html
├── package.json
├── package-lock.json
├── playwright.config.ts
├── tsconfig.json
├── vite.config.ts
├── src/
│   ├── App.test.tsx
│   ├── App.tsx
│   ├── WorkbenchToggle.tsx
│   ├── api.ts
│   ├── grid-state.test.ts
│   ├── grid-state.ts
│   ├── main.tsx
│   ├── styles.css
│   ├── types.ts
│   ├── url-state.test.ts
│   ├── url-state.ts
│   ├── vite-env.d.ts
│   ├── window-state.test.ts
│   └── window-state.ts
└── tests/
    ├── performance.spec.ts
    ├── point.spec.ts
    └── window.spec.ts
```

## 职责边界

- `.node-version` 与 `package-lock.json` 固定本地、CI、Docker 的 Node 22.23.2 和完整依赖图;禁止使用浮动 Node 或未锁依赖构建发布资产。
- `api.ts` 只传输 Point/Window/Track Catalog contract,以 15 秒 native abort 上界约束网络等待,并把非 2xx Problem 显式抛出。
- `grid-state.ts` 定义二维键盘移动、结构化复制文本、registry renderer 对应的只读中文值投影,以及内容驱动的列宽、表头高与行高估算;可以解释既有 track value 结构,但不得计算或改写命理事实。
- `url-state.ts` 只保存可分享的时间、地点、口径和轨道;`coordinate` 是每次请求必带的时间行头元数据,不是可切换投影列;natal context 永不进入 URL。
- `App.tsx` 只把现有产品结构装入三层工作台:Top 放独立开关,Middle 放定位/字段/候选控制,Bottom 放全视口时间轴;首屏直接查询纵向时辰网格,任意时间输入负责定位,并用 Point 的精确时点值覆盖锚点行的 Window 代表值。上下滚动自动续接有界 Query 页,横向字段由 registry 驱动并双轴虚拟化,不复制四柱、节气、十神或边界算法。
- `WorkbenchToggle.tsx` 是 Top 唯一 owner:以继承的 `32px` 字号在透明 Canvas 中测量并裁剪 Emoji 可见 Ink,按按钮真实底部加 `4px` 派生内容起点;开合状态只修改 Middle 的可见性与可访问性,不得进入 App 查询状态、改变 Bottom 几何、触发 renderer 重建或重新请求。
- 投影单元格只显示用户可读的具体命理文本,禁止渲染原始 JSON、英文 typed-state 或机器字段名;unknown/conflict/candidate_set/not_applicable 必须转换成明确中文状态,结构化 JSON 仅允许通过键盘复制进入剪贴板。
- 时辰名、区间、帧内断点与公历/命理时由时间行头合并展示;断点中的机器 track ID 必须通过 catalog 转成稳定字段名。`coordinate` 不得重复出现在横向投影网格或字段菜单。四柱、藏干、十二长生按“年/月/日/时柱 = 值”逐行展示,十神按“年/月/日/时干/支 = 值”逐行展示,节气只显示节气名,五行按“元素 = 数量(占比)”逐行展示。
- 时间轴所有用户可见结构化文本统一使用一行一个“字段 = 值”,禁止使用中点分隔符拼接字段。左上角是第一列的语义列头,只显示“时间”;横向投影关系由字段列头和网格 ARIA 表达,不重复显示轴向说明。纵轴时间行头必须使用 `role="rowheader"`;横轴字段表头必须使用 `role="columnheader"` 且只显示稳定字段名。普通投影值继续使用 `role="gridcell"`,不得用样式 class 冒充表头语义。
- `uncertainty` 是候选/未知/冲突的状态语义,不是独立命理投影列;前端必须从默认选择、deep-link 恢复、字段菜单和网格四处排除它,但不得删除 typed value 或候选分辨契约。
- Track Catalog 分组只用于字段控制面的单次逻辑分组,不得进入横轴字段表头或单元格 ARIA 名称。成功态不保留诊断状态栏,时间行头显示地支、紧凑民用时间范围、断点摘要与时间坐标,完整区间通过原生 `title` 保留。
- 网格尺寸必须由 `grid-state.ts` 的同一内容模型派生:列宽读取字段表头和当前有界窗口的格式化值,按 `8px` 步进限制在 `160px..360px`,并在同一候选会话内只增不减;表头高度以 `72px` 为下限按标题换行计算;时辰行高以 `120px` 为下限,按每个单元格在真实列宽下的换行数取最大值。总行宽是时间行头宽加全部投影列宽,总列高是表头高加全部时辰行高。禁止按 track ID 写十神等字段的尺寸特例,禁止单元格内滚动条或内容裁切。
- `window-state.ts` 只负责窗口页去重排序与纵向 prepend/eviction 后的像素 anchor 恢复;尺寸变化导致 anchor 行收缩时必须把像素偏移限制在该行内。轴算法使用 axis-neutral 命名,不解释 cursor。
- `${HOME}/.codex/Design.md` 对本图形探索页部分适用:DOM 必须使用原生标题、表单、链接、段落、列表、`details` 和 ARIA 语义;禁止自定义颜色、品牌字体、视觉间距、装饰边框、圆角、阴影、动画、响应式美化和装饰 class。`styles.css` 除双轴虚拟化必需的尺寸、定位、滚动、裁切、层叠、换行和 sticky 系统 `Canvas` 背景外,只允许三层工作台的精确结构属性:`4px` edge gap、按钮真实 Ink 盒、Middle 独立滚动/系统背景、Bottom 全视口和窄屏 Middle 全宽。动态行内样式另只允许 virtualizer 坐标与按钮测量变量;这些规则只属于独立 `/timeline`,不得泄漏到 `/web`。
- 每个 DOM class 必须一一对应现存的虚拟化结构规则;没有 CSS、脚本、测试或机器解析用途的 class 必须删除。即使完全移除 CSS,原生表单、标题、候选、时辰与命理文本仍须保持可读顺序;无 JavaScript 时 `noscript` 必须提供真实 `/web` 入口。
- `tests/` 以 mock contract 验证三层开合不改变 Bottom 几何或请求计数、窄屏默认收起、首屏纵向时间轴、上下滚动边缘自动续页、纵向锚点保持、sticky 时间行头、字段列表头、精确 Point 锚点覆盖、逐行等式文本、内容驱动双轴尺寸、无行内滚动条、二维交互和 `Design.md` 零美化边界;测试必须扫描整个页面,确保中点分隔符与机器 track ID 不会进入用户可见内容。显式加载按钮不能替代滚动验收,真实计算正确性由 fate-core 回归负责。
- `tests/performance.spec.ts` 用合成 1000 帧/100 轨道和真实 Chromium 采集 10 秒滚动、long-task、DOM、Query 页数与 CDP 内存证据;不得读取真实命主数据。

## 依赖方向

- `.github/apps/timeline-web -> /api/v1/timeline/{point,window,tracks} + .github/contracts/fate/bazi-formalization/timeline`
- 禁止 `.github/domains/*` 反向导入本目录。