Skip to content

Commit 0c9b673

Browse files
committed
docs: record rollout stabilization closure
1 parent 65298e3 commit 0c9b673

9 files changed

Lines changed: 442 additions & 6 deletions

File tree

.agents/skills/gettokens-domain-engineering/SKILL.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ This skill unifies the technical rules for building, styling, and debugging GetT
4040
3. keep deep-link restoration and detail hash behavior intact while changing layout
4141
4. lock the new density with focused tests that assert structure, module ordering, and route restoration
4242
- For account detail surfaces, keep top-of-page runtime summaries limited to live operational signals. Quota, balance, raw auth content, and export/route controls should live in their own sections rather than repeating in the runtime strip.
43+
- Detail modals backed by frame hash state must update their local detail state synchronously when opening or closing before relying on `hashchange`. If close only clears `selectedAccount` while the old `detail` value is still in local state, the hydration effect can reopen the modal and make the close button require two clicks.
4344

4445
## 2. Feature / Page Boundary
4546
- **Pages**: `frontend/src/pages/*` should be route wrappers, not long-lived business implementation files.
@@ -156,8 +157,10 @@ This skill unifies the technical rules for building, styling, and debugging GetT
156157
- For streaming / active / reconnecting requests without `completedAt`, project `totalDurationMs` from `nowMs - startedAt` with a bounded safety cap. Do not mutate the original request or invent first-event / first-token timings.
157158
- Only the current active request is allowed to use `nowMs - startedAt` projection in the timing trend. Historical request rows that still carry `streaming` / `reconnecting` from cache or stale sidecar state must keep their recorded `timing.totalDurationMs` or `completedAt - startedAt`; otherwise every total-duration point will grow together.
158159
- Trend chart x positions should use request timestamps inside a fixed recent window, not array index spacing or request min/max auto-fit. The default frontend window is 5 minutes: filter out older request points, set the x-domain to `latestStartedAt - windowMs` through `latestStartedAt`, and compute y-axis maxima only from points still inside the window.
159-
- Trend chart viewport should follow the latest request sample only when the user has not panned history. New request points may auto-scroll to the right edge; time-based refresh without new request timestamps must not move the x viewport. If the user horizontally scrolls or drags the chart away from the right edge, pause auto-follow until they scroll back to the latest edge.
160+
- Trend chart viewport should be a fixed, non-scrollable heartbeat strip chart. Keep a stable time density with the latest request anchored near the right edge: wider surfaces can reveal more of the recent window, narrower surfaces show fewer recent samples. Do not reintroduce horizontal panning or auto-scroll follow logic.
160161
- Keep the live-session chart visually inside the page section, not as a nested card. Use the existing Swiss-industrial chart tokens, footer summaries below the graph, and live markers such as dashed strokes/rings for in-flight samples.
162+
- Request timing trend visuals should read closer to an ECG / request heartbeat than a smooth finance area chart. Keep the data-driven timestamp x-axis and metric values, but render the selected timing metric as angular pulse segments with no filled area; use stroke weight, opacity, color, and live rings to distinguish the active metric from the others.
163+
- The request timeline inside the detail pane is a recent-scan surface, not the full history list. Render only the latest 15 sorted request rows and keep the visible row count aligned with that cap; rely on history/detail data for deeper inspection.
161164
- Browser preview data for timing charts must include multiple completed requests plus one in-flight request, so `#frame=codex&workspace=live-sessions` exercises curve shape, latest sample footer, and live marker behavior without a Wails runtime.
162165
- Regression coverage for this class should include pure trend model tests, source-structure tests for live refresh / timestamp x-axis, preview multi-sample assertions, `typecheck`, `build`, focused `model.test.mjs`, and at least one browser/DevTools DOM or screenshot check that the chart renders nonblank.
163166
- **Account Route Guard & WebSocket Hot Switch**:
@@ -287,7 +290,7 @@ This skill unifies the technical rules for building, styling, and debugging GetT
287290
- Preferred module flow is `AccountDetailBody -> AccountDetailOverviewGrid(runtime + evidence) -> AccountDetailModuleStack -> AccountDetailSection`.
288291
- Module headers must use the standardized `AccountDetailSectionHeader` path inside `AccountDetailSection`; do not hand-roll per-module eyebrow/title/meta/action headers in account detail body modules.
289292
- Header-level module actions such as add-row/add-model belong in `AccountDetailSection` `actions` so they render at the module header's top right. Do not leave primary row-creation actions at the bottom of dense editor sections.
290-
- Wide detail modals should use `AccountDetailModuleStack layout="cards"` for editable modules so sections can occupy multiple columns. Single-column module stacks waste space on detail-sized modals.
293+
- Wide detail modals should usually use `AccountDetailModuleStack layout="cards"` for editable modules so sections can occupy multiple columns. Use `cardColumns={1}` when a variant is a dense form/editor surface, such as OpenAI-compatible provider detail, where two-column cards create large empty regions or squeeze row controls.
291294
- Use `span="wide"` for modules with horizontal data, tables, textareas, rule rows, quota/billing editors, or model catalogs so the card grid does not compress operational controls.
292295
- Runtime information that already exists on account cards (recent requests, tokens, cached tokens, latency, quota windows, balance) should be shown in details through `AccountRuntimeSnapshotSection`, not by embedding account cards inside the modal. In the runtime section, quota and balance should share the `quota-balance` resource grid so wide modals can compare them side by side.
293296
- Runtime snapshot and evidence should sit together in `AccountDetailOverviewGrid` near the top of the detail body, instead of sending evidence to a disconnected secondary sidebar. The runtime and evidence sections must stretch to equal height in wide overview rows.
@@ -296,6 +299,7 @@ This skill unifies the technical rules for building, styling, and debugging GetT
296299
- Save actions for detail-page modules should follow the page/modal footer when the edit affects persistent account configuration. Individual sections may keep local actions such as add row, delete draft row, verify, fetch models, or copy.
297300
- OpenAI-compatible and Codex route-row details are account detail variants; keep them visually aligned with `UnifiedAccountDetailModal` even when their controller/state logic remains separate.
298301
- Account creation/configuration modals such as `UnifiedComposeModal` should reuse account detail primitives instead of hand-rolled form shells. Keep configuration flows in named sections, localize visible menu labels and section eyebrows, and preserve the existing submit callbacks while changing layout.
302+
- OpenAI-compatible provider details should defer runtime/evidence split until very wide viewports and keep model rows responsive: model and alias inputs may split at medium width, but destructive row actions must stay horizontal and only join the row when there is enough width.
299303
- **Rotation Cards**: `AccountRotationModal` is a variant of the account card, not a second visual system. Reuse the account-card content hierarchy and only replace the bottom action strip plus rotation-only affordances such as rank rail and drag marker.
300304
- **Rotation Disable Semantics**:
301305
- Disabled accounts stay in the saved rotation order.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ frontend/node_modules
1313
node_modules/
1414
.playwright-cli
1515
.playwright-mcp/
16+
output/
1617
output/playwright/
1718
.local/
1819
tmp/
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# 2026-05-27 Account Detail Close & OpenAI-Compatible Layout Session Distillation
2+
3+
## 背景
4+
5+
本轮处理 `#frame=accounts` 账号详情弹层的两个浏览器评论:
6+
7+
1. `关闭面板` 按钮第一次点击后弹层会重新出现,需要第二次点击才关闭。
8+
2. OpenAI-compatible provider detail 的 `MODEL CATALOG` 与运行快照在中窄视口下布局不自适应,出现大片空白、内容被挤压和删除按钮竖排。
9+
10+
## 根因
11+
12+
- 账号详情弹层由 `selectedAccount` 和 frame hash 中的 `detail` 共同驱动。关闭时只清空 `selectedAccount`,但本地 `accountDetailIDFromHash` 仍保留旧值;后续 hydration effect 会按旧 detail 再次选中账号,造成“第一次关闭被重新打开”。
13+
- OpenAI-compatible provider detail 沿用了通用账号详情的双列模块栈和较早的 runtime/evidence split。该页面是密集表单编辑面,双列卡片会制造空白,也会压缩模型行操作区。
14+
15+
## 沉淀模式
16+
17+
- Hash 驱动的 detail/modal 关闭逻辑,必须先同步本地 detail state,再清理 URL hash,不能只依赖异步 `hashchange`
18+
- 账号详情的通用双列模块栈不是绝对规则。对于 provider 配置、模型映射这类密集编辑面板,允许使用 `cardColumns={1}`,把每个模块做成全宽工作表。
19+
- 模型行这类“输入 + 输入 + 行动作”结构要按宽度分阶段响应:中等宽度先让行动作换到下一行且保持横向按钮;足够宽时再回到同一行。
20+
21+
## 本轮改动
22+
23+
- `AccountsFeature`:打开/关闭账号 detail 时同步 `accountDetailIDFromHash`
24+
- `OpenAICompatibleDetailModal`:OpenAI-compatible runtime/evidence split 延后到 `2xl`
25+
- `OpenAICompatibleDetailPanel`:编辑模块改成单列 stack,模型行改成响应式两段布局,删除按钮不再被挤成竖排。
26+
- `gettokens-domain-engineering`:补充 hash detail state 同步和 OpenAI-compatible 详情布局例外规则。
27+
28+
## 验证
29+
30+
- `node --test src/features/accounts/tests/accountDetailLayout.test.mjs`
31+
- `node --test src/features/accounts/tests/openAICompatible.test.mjs`
32+
- `npm run typecheck`
33+
- `npm run test:unit`
34+
35+
## 未纳入
36+
37+
- 未升级 `AGENTS.md`:本轮是账号详情领域内的具体实现边界,不是 repo-wide 流程规则。
38+
- 未新增独立 `space`:这是浏览器评论驱动的小修与会话沉淀,不是多日需求或并行 feature。

docs-linhay/memory/2026-05-26.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
# 2026-05-26
22

3+
## Codex live sessions 心电图式趋势图
4+
- 决策:`#frame=codex&workspace=live-sessions` 的请求耗时趋势图从平滑面积图收敛为更像 ECG 的波形,主 `totalDurationMs` 轨迹改为角点脉冲与轻微发光,不再用大面积填充承载主视觉。
5+
- 边界:保留 timestamp 驱动的 x 轴,所有 timing 轨迹都采用同一套 ECG 波形语言;TTFT / first token 用更细、更低对比的线条区分,live request 保留光圈标记;数据模型不变,只有呈现方式更偏监护波形。
6+
- 验证:`node --test frontend/src/features/codex-live-sessions/model.test.mjs``npm --prefix frontend run typecheck``npm --prefix frontend run build` 通过;浏览器自动化截图这轮被既有 profile 锁住,未能稳妥补出新截图。
7+
38
## Codex 请求模式重新布局
49
- 结论:`#frame=codex&workspace=account-list` 的请求模式区改成了两段式 header,上行只放标题、说明和当前模式,下行把 `顺序 / 均衡` 两个切换按钮铺满整行,空白感明显少了。
510
- 体验:这比把模式按钮挤在右上角更稳,也更适合当前只有两个模式的场景。
611

12+
## Codex 请求模式标题区再收口
13+
- 偏好:用户明确“选中就是当前”后,标题区不再额外显示“当前模式”小字,改成黑底 `Split` 徽标 + `请求模式` 主标题 + 说明按钮 + 同字号 `预览` chip,模式状态完全由右侧选中按钮承担。
14+
- 体验:这样左上角更像工作台身份锁定区,不再用附注式文案解释当前状态,视觉重心也更集中。
15+
- 验证:`node --test frontend/src/features/channel-routing/tests/channelRouting.test.mjs` 通过;验收截图已保存为 `docs-linhay/spaces/20260511-codex-account-list-tab/screenshots/20260526/codex/20260526-codex-account-list-route-mode-header-after-v02.png`
16+
717
## CLIProxyAPI 刷新成功未清理异常态
818
- 结论:`sdk/cliproxy/auth/conductor.go``refreshAuth` 的成功分支只清了 `LastError / NextRefreshAfter / UpdatedAt`,没有把失败后留下的 `StatusError / Unavailable / StatusMessage` 显式回收;因此一次 refresh 失败后,即使后续 refresh 成功,auth 仍可能一直显示“异常”,直到 app 重启把内存态重建。
919
- 证据:失败分支会把 auth 标成 `unauthorized` 并写入运行态;对象存储 / 文件持久化只保存 metadata,不会把这类运行态带到磁盘,所以重启后状态恢复正常。

docs-linhay/memory/2026-05-27.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,36 @@
2929
## Auth-file metadata cache
3030

3131
- 修复方向:桌面客户端普通展示场景不再反复下载同一 auth-file 原文;`ListAuthFiles` 首次 fresh 推断后按 `name + size + modified` 缓存展示元数据。
32+
33+
## Codex live sessions 单指标 ECG 切换
34+
- 决策:`#frame=codex&workspace=live-sessions` 的请求耗时趋势图不再把多个 timing 维度同时画进同一张图里,而是改成“一个指标一条 ECG 线”;最终图表类型定为 `heartbeat strip chart / rolling strip chart`,最新 request 锚在右侧,按稳定时间密度向左回看。
35+
- 实现:`SessionDetail` 维护当前 `selectedTimingMetric``TimingMetrics` 把可绘图项变成可点击按钮并用 `aria-pressed` 标示选中态,`TimingTrendChart` 只按当前 metric 计算 y 轴和单条波形;图表去掉横向滚动,按容器宽度决定可见窗口,宽屏回看更多、窄屏只显示更近样本。
36+
- 补充:`请求时间线` 是扫描区而非完整历史列表,页面内只展示排序后的最近 15 条 request,标题行数按实际可见行数展示。
37+
- 验证:`node --test frontend/src/features/codex-live-sessions/model.test.mjs``npm --prefix frontend run typecheck``npm --prefix frontend run build` 通过;早前 Playwright 复核确认点击 `TTFT 562ms` 后图表切到蓝色单线,点击 `流式` 后切到绿色单线。本轮最终浏览器复核被 Browser URL policy 拦截,未绕过执行。
3238
- 失效边界:上传、删除、启停状态修改成功后按文件名清理缓存;文件大小或修改时间变化会自然触发重新下载与缓存刷新。
3339
- 关键决策:auth-file 仍以文件作为事实源,不迁移到数据库;进程缓存只保存 provider/type/email/plan/priority 等展示元数据,不保存完整凭证内容。
3440
- 验证:新增 sidecar mock 测试覆盖重复列表、元数据仍不完整、fingerprint 变化三类场景,并通过 `go test ./internal/wailsapp`
3541

3642
## Codex live-session controls 评估
3743

3844
- 新建 space:`docs-linhay/spaces/20260527-codex-live-session-controls/`,用于拆解 `live-sessions` 页的账号指定切换与活跃连接终止能力。
39-
- 现状判断:当前 `live-sessions` management API 只有 snapshot/history/clear tracker,没有按 `session_id` 定点终止活跃请求或 websocket 连接的接口;`wsrelay.Manager` 也只有全量 `Stop()`,没有单 session kill 能力。
45+
- 重新评估修正:用户截图中选中的 `ws_sess_7a91` 来自 `localhost:5173` browser preview/cache,页面显示 `VERSION BROWSER``来源 CACHE`,且 `hasWails=false`;dev sidecar `18317` 的真实 live-session snapshot 为 `activeSessions=0`。该行不能作为真实 kill 对象。
46+
- 现状判断:当前 `live-sessions` management API 的 clear tracker 不等于断开连接;按 `session_id` 定点终止活跃请求或 websocket 连接仍需要 sidecar runtime 控制能力。
4047
- 设计结论:`账号指定切换` 更适合落在路由/账号偏好层,只影响后续请求;`kill` 则需要新增 sidecar management API 或 runtime executor 的会话级 cancel/close hook,不能只靠前端补按钮。
41-
- 观察:生产 sidecar `8317` 上当时仍有 8 条 `streaming` live sessions;dev sidecar `18317` 的 live-sessions snapshot 为空。
48+
- 操作边界:正式 App / `8317` sidecar 不属于本需求的止血对象;后续不得对正式环境做 stop、kill、restart 或清理类动作,除非用户明确授权。
49+
50+
## Account detail close 与 OpenAI-compatible 布局修复
51+
52+
- 修复:`#frame=accounts&detail=...` 账号详情关闭时同步清空本地 `accountDetailIDFromHash`,避免旧 hash detail 通过 hydration effect 重新选中账号,导致 `关闭面板` 需要点两次。
53+
- 布局:OpenAI-compatible provider detail 改为单列配置工作表,runtime/evidence split 延后到 `2xl`,模型行在中等宽度下让删除按钮独立横向换行,避免 `MODEL CATALOG` 产生右侧空白或按钮竖排。
54+
- 沉淀:已更新 `.agents/skills/gettokens-domain-engineering/SKILL.md` 的账号详情边界;未升级 `AGENTS.md`,因为这是账号详情领域规则,不是 repo-wide 流程约束。
55+
- 验证:`node --test src/features/accounts/tests/accountDetailLayout.test.mjs``node --test src/features/accounts/tests/openAICompatible.test.mjs``npm run typecheck``npm run test:unit` 均通过。
4256

43-
## 账号启停同步
57+
## 当前 rollout 稳定化计划
4458

45-
- `#frame=accounts``#frame=codex&workspace=account-list` 已统一走 canonical account id 的 `SetAccountDisabled(id, disabled)` 写回与前端同步事件,浏览器 preview 额外把禁用覆盖写入同源 localStorage,避免切换 frame 后状态回跳;同步事件只接受 `auth-file:` / `codex-api-key:` / `openai-compatible:` 三类新 ID,不再保留 bare name 兼容。
59+
- 新建 space:`docs-linhay/spaces/20260527-stabilize-current-rollout/`,用于收敛当前工作区跨账号 UI、账号 disabled 同步、auth-file metadata cache、Codex live-session 图表和文档写回的混合改动。
60+
- 执行决策:采用“先冻结边界,再按交付组验证,最后治理产物与拆提交”的最稳方案;不继续扩大功能面,不实现 live-session kill / 指定会话切号,不 stage / commit,直到分组测试和未跟踪产物归属清楚。
61+
- 计划入口:`docs-linhay/spaces/20260527-stabilize-current-rollout/plans/execution-plan-v01.md`
62+
- 执行进展:已把 `accountDisabledSync.test.mjs` 纳入 `frontend/package.json``test:unit`,并新增 `output/` 忽略规则;A/B/C/D focused tests、`go test ./...``npm --prefix frontend run test:unit``npm --prefix frontend run typecheck``npm --prefix frontend run build``./scripts/wails-cli.sh build` 均通过。
63+
- 提交边界:当前 `master` 已有 5 个本地提交覆盖 live-session runtime optimization、unified compose、account detail layout、disabled sync、update polling;后续继续按 auth-file cache、live-session 单指标 ECG、route mode header、测试入口/治理文档拆提交。
64+
- 账号启停同步:`#frame=accounts``#frame=codex&workspace=account-list` 已统一走 canonical account id 的 `SetAccountDisabled(id, disabled)` 写回与前端同步事件,浏览器 preview 额外把禁用覆盖写入同源 localStorage,避免切换 frame 后状态回跳;同步事件只接受 `auth-file:` / `codex-api-key:` / `openai-compatible:` 三类新 ID,不再保留 bare name 兼容。

0 commit comments

Comments
 (0)