Skip to content

fix(dashboard): surface host activity delivery windows (adopt #6465) - #6495

Merged
huangruiteng merged 6 commits into
mainfrom
codex/adopt-6465-host-activity-windows
Oct 15, 2026
Merged

huangruiteng merged 6 commits into
mainfrom
codex/adopt-6465-host-activity-windows

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Maintainer adoption of #6465

This lands the work authored by @ikunikun1145 in #6465. That pull request could
not be merged: its head branch had drifted into a merge conflict with main,
and the author's fork does not allow maintainer edits, so the branch could not be
updated in place.

The merge with main had exactly one conflict, a single import line in
apps/presentation/dashboard/src/features/personal-workspace/goal-activity.test.mjs:
the pull request added goalHostDeliveryWindows while main added
taskSessionStatus. The resolution keeps both. No other file conflicted and no
behavior was changed by the resolution.

The author's three commits are preserved unchanged on this branch; the only
additional commit is the main merge that resolves the import collision.

Goal and delivered outcome

  • Outcome basis: Dashboard readback slice for #3927; this PR is related to, and does not close, that issue.
  • Goal/source and gap: The status API already attaches a cadence-based delivery_window to each bound host thread. The Dashboard schema was stripping it, so users could not see stale or missing host activity.
  • Observable before to after: Before, the Goal row showed its normal activity state only. After, it retains the per-thread window through parsing and view-model projection, shows a visible stale or missing badge, and keeps host, Agent, and age in the activity detail.
Criterion Disposition Symbol / path Test or command
Preserve existing per-thread window state and age through Dashboard status parsing and projection implemented status.ts; dashboard-page.tsx npm run smoke:status-projection-contract
Make stale and missing host activity visible without changing execution state or claiming prompt receipt implemented goal-activity.ts; goal-sidebar.tsx; goal-activity-view.tsx npm run smoke:goal-activity
Verify that a scheduled task body was delivered and an Agent started out of scope #3927 host integration This PR presents only the existing activity-window evidence.
  • Self-check: Compared the Dashboard projection to the existing backend payload; checked stale, missing, fresh, and no-expectation behavior. No scheduler or host-receipt semantics were changed.

Scope and continuation

Validation

  • Run state: finished
  • Input classes: synthetic
Check kind Result Public-safe evidence / limitation
unit passed npm run smoke:goal-activity — stale/missing selection, fresh retention, and unknown/no-expectation suppression.
integration passed npm run smoke:status-projection-contract — stale state and age survive the status decoder.
static passed npm run build:desktop — TypeScript check and production Vite build passed; Vite reported its existing large-chunk advisory.
merge passed The main merge conflict is a single import line, resolved to keep both symbols; the diff against main is otherwise unchanged from #6465.
  • Coverage and gaps: Parsing, view-model projection, Goal-row visibility, and production compilation are covered. Live Codex App prompt delivery, Agent start, and the full LaunchAgent path were not verified.

Frontend / Visual Evidence

  • UI impact: changed
  • Before: See host-activity-before below (synthetic fixture, desktop).
  • After: See the stale and missing state screenshots below (synthetic fixture, desktop).
  • States and viewports shown: Before, stale, and missing; desktop Goal list.
  • Source data: synthetic
  • Attention review: The compact badge makes a missed or absent activity window visible beside the existing Goal status. Full host/Agent/age details stay in the existing activity text and tooltip; no extra card or interaction was added.
  • Craft review: Reuses the existing amber/red status tokens and typography. The badge adds no animation or raw colors; unknown/no-expectation remains non-alarming.

Type of change

  • Bug fix
  • Test update

Boundary checklist

  • No private state, credentials, raw traces, internal links, or local paths are included.
  • Every commit includes a DCO Signed-off-by trailer.

ikun and others added 4 commits October 14, 2026 13:47
Signed-off-by: ikun <ikunikun1145@gmail.com>
Signed-off-by: ikun <ikunikun1145@gmail.com>
Signed-off-by: ikun <ikunikun1145@gmail.com>
Resolve import-line conflict in goal-activity.test.mjs by keeping both
goalHostDeliveryWindows (PR) and taskSessionStatus (main).

Signed-off-by: huangruiteng <huangrt01@163.com>
docs/development/design.md forbids sub-12px UI copy, and every other badge in
personal-workspace.css uses --text-caption/--leading-caption. The new host
delivery-window badge was the only 10px outlier, so it now uses the existing
tokens.

Signed-off-by: huangruiteng <huangrt01@163.com>
@mergify

mergify Bot commented Oct 15, 2026

Copy link
Copy Markdown

Hi @huangruiteng, the DCO Sign-off check did not pass. Please inspect
its details first: checkout, fetch, timeout or infrastructure errors
need their own recovery, not a rewrite of otherwise signed commits.

If the log confirms a missing Signed-off-by trailer, amend the
affected commit with git commit --amend -s; for multiple commits,
use an interactive rebase against the current base from the correct
base-repository remote and sign off each affected commit. Push the
rewritten PR branch with git push --force-with-lease origin HEAD.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent · gpt-6.1-sol · OpenAI · self_reported · effort_unavailable

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

精确 head:71f5e3b50948cb6f0db56d56aee67c1cfe05582d;base 51832c59a698950c396e293a8165d07e0dfb12e2;完整差异 9 文件 +137/-5(生产 85/-4,测试 52/-1)。

这是对 #6465(作者 @ikunikun1145)的维护者采纳:原分支与 main 冲突,且作者 fork 不允许维护者推送,本地合并只有一处冲突——goal-activity.test.mjs 的 import 行(本 PR 新增 goalHostDeliveryWindows,main 新增 taskSessionStatus),解析为同时保留两者。作者三份提交原样保留,只有合并提交与一处 CSS 修正是新增的。

动机

在个人工作区同时照看多个 Goal 的维护者,需要在原界面判断哪个宿主长时间没有活动。此前 Dashboard 解析会丢弃 delivery_window,用户只能另开诊断才知道宿主是否超时;现在同一条 Goal 行直接显示 stale / missing 徽标与宿主、Agent、小时数详情。可观察结果是既有宿主活动时间窗在原来的 Goal 行上可见,fresh 只增加信息文案,unknown 与 no_expectation 保持不报警。规范来源是既有 HostDeliveryWindow 载荷(loopx/control_plane/agents/host_thread_activity.py,revision 51832c59)与关联 issue #3927。不宣称定时正文已送达或 Agent 已启动,不改调度、doctor 与宿主观察,也不关闭 #3927。 真实宿主送达与 Agent 启动、安装态采用以及 #3927 整体关闭仍未验收。

改动思路

时间窗的事实与判定仍由后台既有 owner 产生(HostDeliveryWindowState 与 HostDeliveryWindowUnknownReason),Dashboard 只做两件事:在状态解码边界保留该字段,再用一个窄投影把它折进既有的活动展示。改动只是在既有后端契约之上增加一个派生的展示投影,宿主时间窗的判定 owner 没有变化。本次边界是展示层读数:只保留并呈现既有宿主时间窗证据,不改变任何调度或执行语义。没有新增第二个活动分类器、没有重算节奏窗口、没有新增持久状态或额外读取;goalHostDeliveryWindows 只筛出 fresh/stale/missing 并按 stale → missing → fresh 排序,unknown 不进入告警集合,因此「无法计算」不会被当成「超时」。

具体改动

  1. src/data/status.ts:在既有 host_thread_activity.threads[] 上保留可选 delivery_window,覆盖后台四态、原因、年龄与窗口参数;state 用 z.enum(...).catch("unknown") 解码,字段缺失或取值意外时降级为 unknown,不会让整份状态解析失败。
  2. src/views/dashboard-page.tsx:把每条线程的 agentId、state、ageHours、reason 传入既有工作区模型,未提供 delivery_window 时保持 null。
  3. src/features/personal-workspace/goal-activity.ts:新增 goalHostDeliveryWindows()(约 :153),从 hostThreadActivity 投影出告警候选;GoalHostThread 只扩展可选字段,旧 payload 仍可读。
  4. goal-activity-view.tsx:useGoalActivity 复用原有运行判定与详情,追加双语宿主/Agent/年龄文案,并择一产出 windowBadge;GoalActivityChip 与 goal-sidebar.tsx 的 GoalRowActivity 共用同一结果,不各自判断。
  5. i18n.tsx:英文与 zh-CN 各补 5 条消息(fresh/stale/missing 详情与两枚短徽标),两套字典键集合保持一致。
  6. personal-workspace.css:长详情截断、徽标不参与收缩,复用既有 amber/red 语义色。本次评审的一处修正:新徽标原为 font-size: 10px; line-height: 1.4,违反 docs/development/design.md「不得引入 sub-12px UI 文案」,也已偏离同文件其余徽标,现改用既有 --text-caption/--leading-caption。
  7. 对照 #3927 与既有 HostDeliveryWindow 载荷(spec_ref:#3927 与 loopx/control_plane/agents/host_thread_activity.py):preserve_backend_window 与 visible_without_execution_claim 为 implemented;actual_host_delivery_receipt 为 deferred,归宿主集成 owner;scheduler_or_doctor_change 为 out_of_scope。
  8. 测试:goal-activity.test.mjs 覆盖 stale/missing 选中、fresh 保留与 unknown/no_expectation 抑制;smoke/status-projection-contract-smoke.ts 证明 state 与 age 能穿过状态解码器。

对主干的风险

最大风险是把时间窗读成「正在运行」或「送达成功」。代码与文档都把它限定为节奏证据:status.ts 就地注明了「不是送达或启动证明」,unknown 不参与告警,徽标只贴在既有活动行上,不新增运行态标记。

其次,本 PR 只在既有 Goal 行上增加了文字与徽标,没有默认开关,因此不存在 default-off 对偶面;也没有新增协议名、权限边界或持久契约,authority_semantics 与词汇归属都是复用既有 owner。非阻断建议(P2):z.enum(...).catch("unknown") 会把后台未来新增的 state(例如某个新诊断态)静默降级为 unknown,表现为「什么都没有」而不是报错;目前与后台枚举逐值一致,建议将来后台扩展词表时同步这里,或让未知取值留下可观察的降级痕迹。

验证覆盖:smoke:goal-activity、smoke:status-projection-contract、build:desktop(tsc --noEmit + 生产构建,仅有既存大 chunk 提示)、check:css-custom-properties(16 份样式表、无未定义引用)均在 71f5e3b5 上通过;loopx canary premerge 为 3 条 direct 全过、8 条 selected 中 7 过 1 败。唯一失败 examples/control_plane/quota-work-lane-policy-smoke.py 与本 diff 无关:它是纯 Python 控制面 smoke,本 PR 未触碰任何 Python 文件;我在不可变的 51832c59 干净检出上复现了同一断言失败(build_work_lane_context_contract 与配额路径的 monitor_due_items 在 content_revision 上不一致),归因为 3f9f5b3cc6(#6475)在 WORK_LANE_TODO_ITEM_FIELDS 加入 content_revision 后两条路径失去对齐,属 pre_existing_unrelated。按 verdict_policy.unrelated_validation_failure,这不阻断本 PR 批准,但作为独立的 merge-readiness hold 记录,不由本 dashboard diff 承担修复。未查询、轮询或等待 CI(wait_for_ci=false);change-quality 在最终 scope 上记录为 pass(cqr_0e1401cdf60efa98c071)。

我的整体评价

未发现阻断本次有界修复的问题。APPROVE,justified_increment。 long_horizon 与 user_experience 均为 improved:后台已经算出的缺失/超时事实不再在界面上被丢弃,且没有为此新增持久状态、额外读取或执行副作用;未来演进检查已做,两处视图共用同一 useGoalActivity 结果,后台枚举仍是唯一词表 owner,后续若要扩展状态只需改解码与文案一处。批准范围限定为这份既有诊断的可见性。真实宿主送达与 Agent 启动、安装态采用以及 #3927 整体关闭仍未验收;公开首屏与合并权限保持原规则。

English verdict: APPROVE - 71f5e3b50948cb6f0db56d56aee67c1cfe05582d preserves the backend's existing host delivery-window evidence through Dashboard decoding and surfaces stale/missing states on the existing Goal row without claiming prompt delivery or Agent start. Repository-native smokes, the production dashboard build, the stylesheet token check and a change-quality pass hold at this head; the single failing canary is a pure-Python work-lane smoke independently reproduced on unchanged 51832c59 and is recorded as a separate merge-readiness hold.

@huangruiteng
huangruiteng merged commit efd372b into main Oct 15, 2026
25 of 28 checks passed
@huangruiteng
huangruiteng deleted the codex/adopt-6465-host-activity-windows branch October 15, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant