Skip to content

build: bound retained chat assets - #4233

Merged
huangruiteng merged 3 commits into
loopx-project:mainfrom
Duang777:codex/prune-stale-chat-assets
Sep 12, 2026
Merged

huangruiteng merged 3 commits into
loopx-project:mainfrom
Duang777:codex/prune-stale-chat-assets

Conversation

@Duang777

@Duang777 Duang777 commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • bound packaged chat asset retention to the current and one prior generation, preserving open pages across rolling upgrades without unbounded growth
  • add a small retention manifest and prune 109 stale generated assets (about 83.0 MB)
  • extend the existing dashboard PWA smoke to reject invalid manifests and orphaned assets

Validation

  • npm --prefix apps/presentation/dashboard run build:chat
  • repeated build:chat with an identical resulting diff
  • python3 examples/dashboard-pwa-bundle-smoke.py
  • npm --prefix apps/presentation/dashboard run smoke:personal-workspace-packaged
  • git diff --check
  • loopx canary premerge --from-git-diff --tier standard (passed; public/private scan clean)

No local validation failures, skips, or manual holds. The current first-screen sources and bundle hashes are unchanged relative to the latest main baseline.

Future-facing pass

Applied the bounded retention rule at the existing Vite build owner. Broader bundle splitting is deferred until bundle measurements show a concrete need.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Request changes conclusion

审阅绑定 exact head:e0c6916702e59e68cf1d8963da721a6b590743fb。结论:REQUEST_CHANGES。

动机

当前 vite.chat.config.ts 使用 emptyOutDir=false 保护旧页面引用,但副作用是每次 chat bundle hash 变化都会把旧 JS/CSS 留在仓库和 wheel 里。这个 PR 用“当前 generation + 一个上一代 generation”的 manifest 管理生命周期,并删除一百多个陈旧资产,问题真实、方案方向也合理。

改动思路

新的 Vite plugin 在 build 开始时读取旧 index 和 asset-retention.json,在 writeBundle 时把本次 bundle 作为 generation 0,最多再保留一个覆盖旧 index 的 generation,然后删除其它 loopx/web/chat/assets/*。现有 dashboard-pwa-bundle-smoke.py 同时检查 index 引用、manifest generation 与实际文件集合。

这套 owner 放置正确:生成/清理仍由 chat build 负责,manifest 是 derived projection,Python smoke 是 integration consistency guard。问题不在 plugin 主算法,而在这批跟旧 base 绑定的 generated deletions已经落后于当前 main。

具体改动

103 个文件、+101/-8339:一个 Vite config、一个 Python smoke、一个 20 行 retention manifest,以及约一百个生成资产删除。精确 head 上实际执行 npm ... build:chat 成功,TypeScript check 与 Vite build 通过;生成结果与 commit 完全一致,剩 13 个 assets、一个 generation;PWA smoke、Ruff、git diff --check 均通过。远端 23 个 checks 也全部成功或按预期 skip。

关键代码讲解

  • vite.chat.config.ts:12-60 选择 current/previous generation,并在 53–55 行删除不在 retention set 的文件。
  • asset-retention.json 当前 generation 记录的是 index-CB5NhzNw.js / index-dKo36DAJ.css。
  • dashboard-pwa-bundle-smoke.py:56-74 正确要求当前 index refs 属于 generation 0、retained set 等于磁盘文件并且全部存在。

对主干的风险

有一个可直接复现的 P1 blocker:

  1. 这个 behind head 与当前 main 可以无冲突合并,但合并结果会删除当前页面正在引用的 CSS。 当前 origin/main@49cee5b30fef9f5bacddb548dc37809d7aa71be3 的 /chat/index.html 引用 index-DNTHj6za.js 和 index-Yu1zpL1O.css。本 PR 基于旧 base,把 index-Yu1zpL1O.css 列为 stale 并删除,同时写入旧的 CB5/dKo manifest;它没有改 index,因此 Git 三方合并保留 main 的 DNTH/Yu1 index、应用 CSS 删除和旧 manifest,而且报告 mergeable。

我用真实 git merge-tree --write-tree 生成当前 main + PR head 的结果,再把该 tree 导出并执行 PR 自己新增的 smoke:它稳定失败,报当前 index 引用集合 {DNTH JS, Yu1 CSS} 不属于 generation 0;tree 中 Yu1 CSS 也确实不存在。也就是说 exact-head 所有绿灯没有覆盖最终集成树,直接合并会让 packaged /chat 首屏缺样式。

最小修复:rebase 到最新 main,重新执行 build:chat,把 index、manifest、保留资产和删除集合当成一个原子生成物提交;然后在新 exact head/merge result 上跑同一 smoke。长期 guard 应让 CI 对 proposed merge commit/tree 跑这个 smoke,不能只验证 stale head。

我的整体评价

我支持两代 retention,也认为 plugin + derived manifest + existing smoke 是够小、够可维护的方案;不需要另起 cleanup CLI 或服务端 cache 框架。但 generated asset PR 的停止条件必须是“最新集成树自洽”,不是“旧 exact head 自洽”。请完成 rebase/regenerate 后再复审。

Future-facing pass:本轮最值得补的是 final-merge-tree consistency gate;更长的 stale-tab window、service worker/CDN 策略没有当前证据,不应顺手扩大。

English verdict: REQUEST_CHANGES on exact head e0c6916702e59e68cf1d8963da721a6b590743fb. The two-generation Vite retention design and exact-head build are sound, but this behind branch's generated deletion set is stale against origin/main@49cee5b30fef9f5bacddb548dc37809d7aa71be3. A real conflict-free merge tree keeps main's DNTH/Yu1 index, deletes index-Yu1zpL1O.css, and keeps the old CB5/dKo manifest; the PR's own PWA smoke then fails. Rebase, regenerate the entire chat bundle atomically, and run the same smoke on the final exact head/merge result.

@Duang777
Duang777 force-pushed the codex/prune-stale-chat-assets branch 4 times, most recently from b5c5635 to 7b689bd Compare September 11, 2026 14:50
@Duang777

Duang777 commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor Author

@huangruiteng @maxliux5 Current exact head 387cbfe is synchronized with main 3aa05cc. The stale generated-asset blocker is fixed: the chat bundle was rebuilt from the current main inputs, retention now keeps the current and previous complete generations, and missing generations are excluded. Local build, PWA bundle smoke, full browser smoke, mypy, Ruff, and diff checks passed. Current GitHub checks are all green, including Frontstage, desktop artifacts, merge-gate, Stage2C, and four pytest shards. Please re-review this exact head and clear the stale CHANGES_REQUESTED state if no new finding remains.

huangruiteng pushed a commit that referenced this pull request Sep 11, 2026
`python -m mypy` fails on current main with seven `no-any-return` errors in
`loopx/control_plane/todos/decision_scope.py`. The module's private
`_evaluate` helper validates one typed effect-runtime result and returns
`Any`, but every public wrapper declares a concrete `dict`, `bool`, or list
return type, so strict mode rejects each call site.

Annotate the seven call sites with `cast(...)` to the return type they
already promise. This is a type-level annotation only: no runtime branch,
value, or call sequence changes, and `_evaluate` keeps its single validated
boundary.

The same fix is currently carried inside #4233, which is blocked on chat
asset retention changes. Every pull request inherits this failure through
the required `Type-check kernel contracts` step and the `merge-gate`, so it
is extracted here as a standalone repair.

Validation:
- `python -m mypy` -> Success: no issues found in 22 source files
- `python -m pytest tests/control_plane/test_todo_decision_scope_consistency.py
  tests/control_plane/test_todo_decision_scope_lifecycle.py
  tests/control_plane/test_todo_decision_scope_cli_validation.py
  tests/control_plane/test_user_gate_lane_progress.py
  tests/control_plane/test_scoped_gate_successor_tool_behavior.py` -> 56 passed
- `python examples/control_plane/bounded-context-namespace-smoke.py` -> ok

Signed-off-by: song <liusongstep@gmail.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Request changes conclusion

审阅绑定 exact head:387cbfeabea1ccd79abd87257fadb320a7adcd36。结论:REQUEST_CHANGES。

[P1] 请先 rebase 最新 main,保留主干的两个 superseding shared files,并从最终 source 原子重建 chat bundle。 当前 GitHub mergeStateStatus=DIRTY;git merge-tree --write-tree origin/main@84334f794126735a83a6cfb77882dd58ca8066d9 <head> 在 examples/personal-workspace-browser-smoke.mjs 与 loopx/control_plane/todos/decision_scope.py 冲突。PR 侧是旧单体 browser smoke 和 cast-only decision-scope 适配,而主干已经分别完成模块化拆分及 typed projection schema/shape hardening。不能通过选 PR 一侧来解冲突;rebase 后应保留主干版本,再执行 build:chat、提交最终 index/manifest/assets 原子结果并重跑 smokes。

动机

旧 vite.chat.config.ts 为保护滚动升级中的 stale page 使用 emptyOutDir=false,但从不删除历史 hash 资产。baseline 因此积累到 117 个 asset、约 80.23 MB,并会随每次 hash 变化继续增长。直接切 emptyOutDir=true 又会让仍引用上一代 index 的页面白屏。本 PR 把停止条件明确为“当前完整 generation + 一个上一代完整 generation”,在保留一轮滚动兼容的同时,把仓库、wheel 和构建产物增长约束为常量。

改动思路

生命周期 owner 放在现有 Vite chat build:plugin 在配置阶段读取旧 index 与旧 manifest,在 writeBundle 阶段把本次 Rollup bundle 作为 generation 0,选择一个文件完整、非冗余的 previous generation,删除其余 assets/*,再写回 derived asset-retention.json。路径被约束为单层 assets/[A-Za-z0-9._-]+,缺文件的 generation 不会被误认为完整,manifest malformed 会 fail closed。

现有 dashboard-pwa-bundle-smoke.py 被扩展为独立 readback:要求 1–2 generations、当前 index refs 属于 generation 0、manifest union 与磁盘文件集合完全一致且全部存在。相比一次性删文件或另做 cleanup CLI,这个方案复用了正确的 build owner,也把未来每次生成纳入同一规则。

具体改动

exact-head diff 为 108 文件、+138/-8609:65 行 Vite lifecycle plugin、23 行 smoke、35 行生成 manifest、103 个旧 hash 资产删除,以及两个已被 main supersede 的 integration carryover。资产从 117 个/80,233,332 bytes 降至 14 个/2,254,886 bytes;当前 generation 是 index-Dk5Y5CRw.js + index-DYYo3B8I.css 与共享 fonts,上一代保留 index-B88OPx8f.js。

关键代码讲解

  • retainedChatAssets(apps/presentation/dashboard/vite.chat.config.ts:12):验证旧 manifest,计算 current/prior generations,跳过缺文件或冗余 generation,最多保留两个集合。
  • writeBundle(同文件 35–60):只在 build-time 操作已解析的 chat assets 目录,删除不在 retained set 的文件并写 derived manifest;运行时 serving 不写盘。
  • assert_bounded_chat_assets(examples/dashboard-pwa-bundle-smoke.py:56):从 index、manifest、disk 三个独立视角校验同一 bundle contract。
  • loopx_chat_asset_retention_v1:是 build 输出投影,不是需要人工同步的第二份意图状态。

对主干的风险

我在 exact head 上执行了两次完整 npm run build:chat,两次均通过且 loopx/web/chat 保持 clean;PWA bundle smoke 通过;使用独立端口的 packaged Personal Workspace browser smoke 通过;Ruff、focused mypy 与 git diff --check 通过。临时副本上的 orphan asset 与 invalid schema mutation 都被新增 smoke 拒绝。远端 28 个 checks 全部成功或按预期 skip,说明上一轮“旧 base 会删除当前 index CSS”的 blocker 已在这个 head 相对 3aa05cc 修好。

但 exact-head green 不等于当前 final tree green。latest main 已在两个共享文件上前进,GitHub 和真实 merge-tree 都判定冲突;若选错冲突侧,会回退广泛的 Dashboard acceptance 和 control-plane validation。即使当前 main 的 chat index refs 仍与本 head 相同,rebase 后仍应从最终 source 重跑 build,避免让 generated manifest/deletion set 脱离最终树。

我的整体评价

两代 retention 的产品取舍、owner 放置、manifest 约束与独立 smoke 都合理;大部分 8,609 行删除是必要的历史生成物清理,不应因为 diff 大就否定。也没有证据需要顺手引入 CDN/service-worker 窗口或 bundle-splitting 框架。当前唯一 blocker 是 final integration freshness:请 rebase、保留 main 的模块化 smoke 与 typed decision-scope boundary、原子重建产物并让新 exact head checks 通过,再复审。

Future-facing pass:最有价值的 companion change 是让 CI 始终验证 proposed final tree 的 bundle consistency;更长 retention window 在没有真实 stale-tab 证据前应继续 defer。

English verdict: REQUEST_CHANGES on exact head 387cbfeabea1ccd79abd87257fadb320a7adcd36. The two-generation retention design is sound: assets drop from 117/80.23 MB to 14/2.25 MB, two deterministic builds stay clean, PWA and packaged-browser checks pass, negative mutations reject, and all 28 remote checks are green. But latest main now conflicts in two unrelated shared files; rebase while keeping main's modular browser and typed decision-scope implementations, regenerate the final chat bundle atomically, and rerun the final-tree checks.

@Duang777
Duang777 force-pushed the codex/prune-stale-chat-assets branch 2 times, most recently from b0b0180 to e61bcc1 Compare September 12, 2026 05:28
@Duang777

Copy link
Copy Markdown
Contributor Author

Updated exact head: e61bcc13727855521d511e4c52c7678f707fa44b.

Resolved the original merge conflicts by retaining the superseding main implementations in examples/personal-workspace-browser-smoke.mjs and loopx/control_plane/todos/decision_scope.py. Rebuilt the chat bundle twice from the final source; retained generations are current index-Bb6tQe9a.js / index-C-0JyRzm.css and previous index-BHRJcYkB.js / index-CAld8Q9B.css.

While syncing current main, the Windows lifecycle check exposed a main regression: Python on Windows has no external IANA timezone database, so validating the built-in UTC periodic-report default raised ZoneInfoNotFoundError and made quota should-run fail closed. The fix handles canonical UTC without an external tzdata package while preserving strict ZoneInfo validation for all other names; a regression test simulates the missing database.

Validation recorded on the final head:

  • focused periodic-report/chat configuration: 44 passed; scoped Ruff passed
  • new main frontier tests: 13 Python + 8 TypeScript passed
  • packaged browser, PWA, action-review, attention-details, mypy, TypeScript typecheck, and scoped gates passed during the final-source rebuild cycle
  • GitHub exact-head checks: all successful, including Windows PowerShell, dashboard acceptance, four test shards, Stage2C e2e/installed/mutants/correctness, pytest, and required merge-gate

The branch is clean, contains current main 18fda32fd, and GitHub reports MERGEABLE. Requesting a fresh independent review of this exact head; no merge performed.

@Duang777

Copy link
Copy Markdown
Contributor Author

@huangruiteng GitHub did not allow this fork contributor to add you through reviewRequests; please re-review exact head e61bcc13727855521d511e4c52c7678f707fa44b when available. All exact-head checks are green, and the preceding comment records the conflict resolution and validation.

@Duang777

Duang777 commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor Author

@huangruiteng Updated exact head 06699be onto current main 787e8dd. The superseding main versions of both shared conflict files were retained, then the chat bundle was rebuilt twice from the final source and remained clean; the PWA bundle smoke passed. Fresh exact-head CI is running; please re-review this head after it completes.

@Duang777

Copy link
Copy Markdown
Contributor Author

Exact head d7d97c35e56a908783854c03cbcf5546d1d51b3d is now rebuilt cleanly from main@787e8dd83: 3 DCO commits and only chat asset retention files. Local repeated build, PWA smoke, packaged browser smoke, diff checks, and standard canary pass. The current windows-powershell failure is inherited from the same failure on main and is isolated in #4281; this PR will be refreshed after #4281 lands, without reintroducing unrelated runtime code.

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@huangruiteng
huangruiteng force-pushed the codex/prune-stale-chat-assets branch from d7d97c3 to 66d274c Compare September 12, 2026 11:02

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

评审对象:#4233,最终 exact head 66d274c62155ca6c8566a67e37baa784c9ee89ce,base b9e8c74d4f852a1444c44cca7ac108911407c531。

Findings

没有新的 correctness blocker。此前发现的 stale generated deletion 与落后 main 问题已通过 rebase 和最终 source 重建处理;没有把 #4281 的无关 Windows runtime 修复混入本 PR。

动机

vite.chat.config.ts 使用 emptyOutDir=false 保护滚动升级中的旧页面,但旧 hash 资产会持续累积。这个 PR 将 chat bundle 约束为当前 generation 加一个完整 previous generation,避免仓库、wheel 和构建产物无界增长。

改动思路

由现有 Vite chat build 负责读取旧 index/retention manifest、选择完整 generation、写入新的 derived manifest 并删除其余 assets;没有新增 cleanup CLI、daemon 或运行时 provider。现有 dashboard-pwa-bundle-smoke.py 负责从 index、manifest、磁盘三方校验一致性。

具体改动

  • vite.chat.config.ts 增加 bounded two-generation retention plugin,并对 malformed/missing generation fail closed。
  • 新增 loopx_chat_asset_retention_v1 manifest,记录当前和上一代完整资产集合。
  • 清理历史 hash 资产,保留当前 bundle 与一个滚动升级窗口。
  • 扩展 PWA smoke,要求 index 引用、manifest union 和实际磁盘文件集合完全一致。
  • rebase 到 main@b9e8c74d4 后,从最终 source 重新构建两次,生成树保持 clean。

对主干的风险

主要风险是生成文件与 build plugin 脱节;本轮在 rebase 后运行 npm run build:chat,两次结果均与 commit 一致,随后 PWA bundle smoke、Ruff、mypy、Python compile 和 diff check 全部通过。远端 exact-head required checks 已全部通过:Windows PowerShell、Dashboard、四个 Python shards、Stage2C e2e/installed/mutants/correctness、pytest、merge-gate、Node compatibility、静态检查、Frontstage、desktop artifacts、DCO 和 dependency review 均为成功;Sonar non-blocking 检查也已成功。

我的整体评价

方案把资产生命周期放在正确的 build owner,manifest 是可验证的 derived projection,保留窗口有明确上限,且没有扩大到 CDN、service worker 或运行时缓存框架。此前评审指出的 final-tree freshness 已修复,exact-head required CI 已全绿,建议合并。

English verdict: APPROVE — exact head 66d274c62155ca6c8566a67e37baa784c9ee89ce; the stale generated-asset blocker is resolved by rebasing onto current main and atomically rebuilding the bounded chat bundle, with local and exact-head required checks green.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

评审对象:#4233,最终 exact head 66d274c62155ca6c8566a67e37baa784c9ee89ce,base b9e8c74d4f852a1444c44cca7ac108911407c531。

Findings

没有新的 correctness blocker。此前发现的 stale generated deletion 与落后 main 问题已通过 rebase 和最终 source 重建处理;没有把 #4281 的无关 Windows runtime 修复混入本 PR。

动机

vite.chat.config.ts 使用 emptyOutDir=false 保护滚动升级中的旧页面,但旧 hash 资产会持续累积。这个 PR 将 chat bundle 约束为当前 generation 加一个完整 previous generation,避免仓库、wheel 和构建产物无界增长。

改动思路

由现有 Vite chat build 负责读取旧 index/retention manifest、选择完整 generation、写入新的 derived manifest 并删除其余 assets;没有新增 cleanup CLI、daemon 或运行时 provider。现有 dashboard-pwa-bundle-smoke.py 负责从 index、manifest、磁盘三方校验一致性。

具体改动

  • vite.chat.config.ts 增加 bounded two-generation retention plugin,并对 malformed/missing generation fail closed。
  • 新增 loopx_chat_asset_retention_v1 manifest,记录当前和上一代完整资产集合。
  • 清理历史 hash 资产,保留当前 bundle 与一个滚动升级窗口。
  • 扩展 PWA smoke,要求 index 引用、manifest union 和实际磁盘文件集合完全一致。
  • rebase 到 main@b9e8c74d4 后,从最终 source 重新构建两次,生成树保持 clean。

对主干的风险

主要风险是生成文件与 build plugin 脱节;本轮在 rebase 后运行 npm run build:chat,两次结果均与 commit 一致,随后 PWA bundle smoke、Ruff、mypy、Python compile 和 diff check 全部通过。远端 exact-head required checks 已全部通过:Windows PowerShell、Dashboard、四个 Python shards、Stage2C e2e/installed/mutants/correctness、pytest、merge-gate、Node compatibility、静态检查、Frontstage、desktop artifacts、DCO 和 dependency review 均为成功;Sonar non-blocking 检查也已成功。

我的整体评价

方案把资产生命周期放在正确的 build owner,manifest 是可验证的 derived projection,保留窗口有明确上限,且没有扩大到 CDN、service worker 或运行时缓存框架。此前评审指出的 final-tree freshness 已修复,exact-head required CI 已全绿,建议合并。

English verdict: APPROVE — exact head 66d274c62155ca6c8566a67e37baa784c9ee89ce; the stale generated-asset blocker is resolved by rebasing onto current main and atomically rebuilding the bounded chat bundle, with local and exact-head required checks green.

@huangruiteng
huangruiteng merged commit f88aae3 into loopx-project:main Sep 12, 2026
47 of 50 checks passed
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.

2 participants