Skip to content

feat(architecture): [EPIC-INT-01C] 斩断直连实现纯净架构,引入网关无感自动拉起与高可用加固#391

Merged
phantom5099 merged 13 commits into1024XEngineer:mainfrom
pionxe:main
Apr 22, 2026
Merged

feat(architecture): [EPIC-INT-01C] 斩断直连实现纯净架构,引入网关无感自动拉起与高可用加固#391
phantom5099 merged 13 commits into1024XEngineer:mainfrom
pionxe:main

Conversation

@pionxe
Copy link
Copy Markdown
Collaborator

@pionxe pionxe commented Apr 21, 2026

🎯 目标 (Motivation & Context)

本 PR 是 [EPIC-INT-01] 全链路贯通 的终极收官交付。 此前,TUI 客户端在物理代码上依然强依赖着 internal/runtime,且微服务化导致用户必须手动开启两个终端,体验极速下降。 本 PR 一次性解决了架构纯洁度、开箱即用体验、系统长期稳定性三大核心痛点,让 NeoCode 彻底脱胎换骨为一个“内里是分布式微服务,外表是极简 CLI”的现代化应用。
Closes #362

✨ 主要变更 (Key Changes)

🧱 1. 物理级隔离 (Domain Decoupling & Guardrails)

  • 依赖倒置:抽离 TUI 专属的 Runtime Contract 与事件 DTO,将 core/appstate/messages 与底层业务引擎彻底剥离。
  • 装配与防腐:通过 runtime_contract_adapter 进行组装,并强制网关服务端注入 local 模式,破解“网关连网关”的自举死锁。
  • 架构守卫测试:新增全局物理依赖扫描,若未来有人试图在 TUI 中越界 import internal/runtime,CI 将直接红灯阻断。

🪄 2. 开箱即用 (Seamless Auto-Spawn)

  • 全局默认 Gateway:移除所有模式分叉开关。
  • 无感拉起机制:TUI 启动时自动探测 IPC 管道。若不通,则获取自身执行路径,在后台静默拉起 gateway 守护进程,并在 3 秒内进行高频轮询等待 Ready,用户全程只需输入一次 neocode

🛡️ 3. 生产级维稳 (SRE & Stability Hardening)

  • 消灭僵尸进程:严控 Auto-Spawn 子进程生命周期,当 TUI 触发 Close() 时,精准下发 Process.Kill() 信号并异步回收,绝不遗留进程霸占底层端口。
  • 保护崩溃现场 (Log Rotation):对 gateway_auto.log 实施滚动备份机制(存留上一份 .bak),每次启动执行截断,防止长期运行撑爆磁盘,同时保留异常堆栈。
  • 消除日志风暴 (Ping Muting):在网关日志层拦截 gateway.ping,将其静音,大幅提升核心排障日志的信噪比。

🐛 4. 附带缺陷修复 (Bug Fixes)

  • 修复 CurrentWorkdir 丢失导致的分支异常。
  • 修复 Transcript 历史重建中 Tool 调用未打断 Assistant 折叠的问题。

✅ 验收标准 (Acceptance Criteria)

  • 架构纯度:源码层面已验证 internal/tui 彻底干净,守卫测试通过。
  • 一键启动体验:运行 go run ./cmd/neocode 直接进入界面,无明显卡顿,背后的网关已自动就绪。
  • 资源防泄漏Ctrl+C 关闭 TUI,系统任务管理器中无残留的 neocode gateway 进程,随时可再次顺利拉起。
  • 日志健康度:挂机长耗时任务,日志文件被妥善轮转且未被 Ping 报文刷屏。
  • 全量回归go test ./... 所有单元测试(含新增的并发状态与生命周期测试)全量绿灯通过。

pionxe added 3 commits April 21, 2026 18:13
作为网关下沉战役的最终决战,本提交彻底移除了客户端 (TUI) 对底层业务引擎 (Runtime) 的物理代码依赖,全面贯彻整洁架构 (Clean Architecture) 与依赖倒置原则。

核心演进:
1. 确立独立契约:在 TUI 服务层定义专属 Runtime Contract 与强类型事件 DTO,TUI 核心逻辑全面倒置依赖该契约。
2. 架构防腐层:在 App 装配层引入 runtime_contract_adapter,将本地 Runtime 映射为 TUI Contract,将耦合脏活隔离在主业务逻辑之外。
3. 路由大一统:默认启动路径全局切换为 Gateway 模式。同时为网关服务端进程保留显式 local 注入,彻底规避 Gateway -> Gateway 的无限自举死锁回环。
4. 架构物理守卫:新增依赖扫描测试 (Builder Test),强制断言 TUI 业务代码中不再包含任何 `internal/runtime` 的 import,用代码捍卫架构红线。

附带修复 (UI 边缘场景):
- 修复 `CurrentWorkdir` 初始化分支逻辑异常问题。
- 修复对话历史 (Transcript) 重建时,Tool 边界未正确打断 Assistant 气泡折叠的渲染错位问题。
在引入 Gateway 自动拉起 (Auto-Spawn) 机制后,补齐生产环境必需的系统资源管理与日志治理能力,彻底消除端口死锁与磁盘膨胀风险。

核心改动:
1. 进程同生共死 (Lifecycle Binding):在 GatewayRPCClient 中跟踪 spawnedCmd,在 TUI 触发 Close() 时显式发送 Process.Kill() 并异步 Wait() 回收资源,根除子进程沦为僵尸进程并持续霸占 Named Pipe/端口的问题。
2. 保护崩溃现场 (Log Rotation):在重定向子进程输出前,将现存的 gateway_auto.log 滚动备份为 .bak 文件,并以 O_TRUNC 截断模式开启新日志。确保既不无限膨胀,又完整保留上一次的崩溃现场供排障分析。
3. 消除日志风暴 (Ping Muting):在网关服务端的结构化日志拦截器中,对 method == "gateway.ping" 的高频保活心跳进行 INFO 级别静音(不影响指标采集),大幅提升核心业务日志的信噪比。
fennoai[bot]

This comment was marked as outdated.

本次提交修复了代码审查指出的 3 项高优先级缺陷,解决了导致 CI 崩溃的致命错误,并进一步加固了网关下沉架构的自愈能力与可观测性。

核心改动:
1. 修复 CI 崩溃与文档同步:彻底移除 `root.go` 中重复注册的 `runtime-mode` flag,消除 `panic: flag redefined` 错误。同步刷新 README 与配置文件文档,明确“默认 Gateway + 探测失败自动拉起”的最新架构行为。
2. 完善 Auto-Spawn 持续自愈:修复网关崩溃后只能拉起一次的缺陷。监听子进程的 `Wait()` 退出事件,并在连接强制重置或拉起失败时,准确复位 `autoSpawnAttempt` 标志位,确保客户端拥有长期的无感恢复能力。
3. 保护故障现场观测:优化 `gateway.ping` 的日志静音策略。仅对成功响应(status == ok)的心跳进行静默处理,强制保留失败心跳的错误日志,避免掩盖网络抖动、进程阻塞或鉴权异常等真实故障。
4. 补齐容错与生命周期测试:新增网关断连复位测试、失败心跳穿透静音测试,全量 CI 与覆盖率恢复 100% 绿灯。
@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 21, 2026

@xgopilot 请你帮我解决CI构建错误的问题!

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 21, 2026

已处理并修复本次 CI 构建失败。

处理结果

  • 根因:internal/tui/services/gateway_rpc_client_additional_test.go 中用例 TestGatewayRPCClientCloseStopsSpawnedGatewayProcess 将“进程被 Kill 后退出”错误断言为 ProcessState.Exited() == true。在 Linux 下被信号终止时该值通常为 false,导致 CI 稳定失败。
  • 修复:将断言改为检查 spawnedCmd.ProcessState != nil(表示进程已被 Wait 回收),与真实进程生命周期语义一致。
  • 变更提交:3d1417b(已推送到当前 PR 头分支 pionxe:main)。

验证

  • go test ./internal/tui/services -run TestGatewayRPCClientCloseStopsSpawnedGatewayProcess -count=5 通过
  • go test ./... 全量通过

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 21, 2026

@xgopilot 请你将codecov/patch 覆盖率提升至百分之九十五以上!

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 21, 2026

处理结果

已完成一轮定向补测并推送到当前 PR 分支,目标是提升 codecov/patch 覆盖率到 95%+。

提交:c6f26bc(已 push 到 pionxe:main

本次改动

  • 新增 [internal/app/runtime_contract_adapter_test.go] 的完整契约适配测试(转发、映射、事件桥接、错误分支、日志持久化分支)。
  • 扩展 [internal/tui/services/gateway_rpc_client_additional_test.go],覆盖自动拉起、就绪探测、日志输出/轮转异常、进程生命周期等关键分支。
  • 补充小缺口测试:
    • [internal/tui/services/services_test.go](RunSystemToolCmd
    • [internal/tui/tui_test.go](NewWithMemo 转发)
    • [internal/app/bootstrap_test.go](NewProgram 非法 runtime mode 路径)
    • [internal/cli/root_test.go](--runtime-mode local
    • [internal/tui/core/app/todo_test.go](parseTodoEventPayload(nil)
    • [internal/tui/core/app/update_test.go](RuntimeMsg 非 RuntimeEvent 分支)
    • [internal/tui/services/remote_runtime_adapter_additional_test.go](compact payload decode error)

验证

  • go test ./internal/app ./internal/cli ./internal/tui/core/app ./internal/tui/services ./internal/tui -count=1 通过
  • go test ./... -covermode=atomic -coverprofile=/tmp/cover.out 通过
  • 基于 origin/main...HEAD 的本地 diff 覆盖率估算约为 96.52%(Go 变更行口径)

说明:最终以 Codecov 在线计算结果为准;若仍有偏差,我会继续按 Codecov 缺口清单补齐。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)

Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 21, 2026

/review

fennoai[bot]

This comment was marked as outdated.

@fennoai fennoai Bot mentioned this pull request Apr 21, 2026
@phantom5099
Copy link
Copy Markdown
Collaborator

@xgopilot 批判性review整个PR,分析所有潜在风险点,找出所有漏洞,不许输出正向表扬

@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot 我们来详细探讨你指出的四个问题的解决方法。

  1. 关于“默认网关模式下,首次启动会在 Auto-Spawn 之前因缺失 token 直接失败”问题,进行一个时序重排【先静默探测,然后分支判断(管道存在与不存在的处理),之后再读取 Token,最后进行鉴权连接】,这样能不能解决这个问题?请你说明优缺点,并给出你推荐的方案。
  2. 关于“关闭任意一个 TUI 实例会杀死它拉起的共享网关,影响其它仍在线会话”问题,我的方案是废弃客户端 Kill,然后由网关内部维护一个“当前活跃连接数”,当活跃连接数降为 0 时,网关启动一个倒计时(比如 30 秒)。如果 30 秒内没有新的客户端连进来,网关自己执行优雅退出。这样能不能解决这个问题?请你说明优缺点,并给出你推荐的方案。
  3. 关于“gateway 模式下仍完整构建本地 runtime/tool manager,导致双运行时并存”,我的方案是重构bootstrap.go,将其拆分为BuildGatewayServer()和BuildTUIClient()。这样能不能解决这个问题?请你说明优缺点,并给出你推荐的方案。
  4. 关于“Auto-Spawn 日志文件打开流程缺失防链接保护,存在可控路径截断风险”问题,我的方案是安全文件操作(Lstat 校验 + 原子替换)。这样能不能解决这个问题?请你说明优缺点,并给出你推荐的方案。

@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot 我觉得你提出的方案不错,并且也给出了执行顺序(先解决“gateway 模式下仍完整构建本地 runtime/tool manager,导致双运行时并存”,再解决“默认网关模式下,首次启动会在 Auto-Spawn 之前因缺失 token 直接失败”,再解决“关闭任意一个 TUI 实例会杀死它拉起的共享网关,影响其它仍在线会话”,最后解决“Auto-Spawn 日志文件打开流程缺失防链接保护,存在可控路径截断风险”),现请你按照你的方案进行修改!

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

已按你确认的顺序完成四项修改,并推送到当前 PR 分支 pionxe:main

变更摘要

  1. 架构隔离(先修 feat: init neo-code base framework with ModelScope integration #3
  • 在 [internal/app/bootstrap.go] 中将 TUI 启动装配拆分为按模式构建:
    • gateway 模式仅构建配置与 provider 选择,不再构建本地 runtime/tool/session 栈。
    • local 模式继续走 BuildRuntime
  • 新增/调整测试覆盖该分支行为:[internal/app/bootstrap_test.go]
  1. 首次启动 token 时序问题(再修 Issue #1 项目初始化与基础交互界面 Project Initialization & Basic Interactive Interface #1
  • 在 [internal/tui/services/gateway_rpc_client.go] 将 token 读取从构造阶段改为 Authenticate 阶段:
    • ensureConnected(可触发 auto-spawn)
    • 再延迟加载 token,并对文件落盘竞态做短重试
    • 最后执行 gateway.authenticate
  • 补充测试覆盖“auto-spawn 后再加载 token”路径:[internal/tui/services/gateway_rpc_client_additional_test.go]
  1. 多实例误杀共享网关(再修 Issue #2 接入大模型 #2
  • 客户端 Close() 不再 Kill auto-spawn 网关进程,避免一个 TUI 退出影响其它会话。
  • 同时增加网关服务端空闲自退机制:
    • IPC 活跃连接数为 0 时启动 30 秒倒计时
    • 倒计时内若有新连接则取消退出
    • 超时后由网关自身触发关闭
  • 相关代码:
    • [internal/gateway/server.go](连接数变化回调)
    • [internal/cli/gateway_commands.go](idle shutdown controller)
    • [internal/cli/gateway_commands_idle_test.go]
    • [internal/gateway/server_additional_test.go]
  1. Auto-Spawn 日志路径安全(最后修 项目初步结构 #4
  • 在 [internal/tui/services/gateway_rpc_client.go] 增加日志文件安全打开流程:
    • 目录/文件 Lstat 校验(拒绝 symlink)
    • Unix 下硬链接风险检测
    • 临时文件 + 原子替换写入
    • 轮转 .bak 同步执行安全校验
  • 新增平台实现:
    • [internal/tui/services/gateway_rpc_client_hardlink_unix.go]
    • [internal/tui/services/gateway_rpc_client_hardlink_windows.go]
  • 补充安全相关测试分支:[internal/tui/services/gateway_rpc_client_additional_test.go]

验证

  • 已执行:go test ./...
  • 结果:全部通过

提交

  • 已推送 commit:17acaea

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot
我发现问题:

  1. 我这个PR是为了彻底断开TUI与Runtime的直连,为什么还区分gateway与local模式?请你彻底删除直连部分!
  2. 关于“gateway 模式下仍完整构建本地 runtime/tool manager,导致双运行时并存”问题,请你按照你的推荐方案解决:
    • BuildGatewayServerDeps(ctx, opts):只给 neocode gateway 使用,构建 runtime/tool/session。
    • BuildTUIClientDeps(ctx, opts):只给 TUI 使用,不构建本地 runtime/tool manager,只构建 config/provider selection + remote adapter。
    • BuildSharedConfigDeps 抽公共配置加载,避免两套实现漂移。

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

完成情况

已按你的要求完成“彻底去直连 + 双装配拆分”并已推送到当前 PR 分支 pionxe/main

变更摘要

  1. 装配入口重构(internal/app/bootstrap.go
  • 新增 BuildSharedConfigDeps(ctx, opts):统一配置加载与 provider selection。
  • 新增 BuildGatewayServerDeps(ctx, opts):仅给 neocode gateway 构建 runtime/tool/session 全栈。
  • 新增 BuildTUIClientDeps(ctx, opts):仅给 TUI 构建 config/provider selection,不构建本地 runtime/tool manager。
  • NewProgram 改为固定走 remote runtime adapter,不再按 local/gateway 分叉。
  1. 删除 TUI 直连实现
  • 删除 internal/app/runtime_contract_adapter.go
  • 删除 internal/app/runtime_contract_adapter_test.go
  1. CLI 去模式化
  • 移除 --runtime-mode 参数与校验逻辑(internal/cli/root.gointernal/cli/root_test.go)。
  • gateway runtime bridge 改为使用 BuildGatewayServerDepsinternal/cli/gateway_runtime_bridge.go)。
  1. 文档同步
  • 更新 README.mddocs/guides/configuration.md,移除 runtime-mode local/gateway 说明,改为统一 Gateway 自动拉起语义。
  1. 测试
  • 已修正相关单测并通过全量回归:go test ./...

提交

  • 8d5dfcf refactor(app): remove tui-runtime direct mode and split bootstrap deps

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot
关于“默认网关模式下,首次启动会在 Auto-Spawn 之前因缺失 token 直接失败”问题,你似乎并没有按照你给出的方案修改!

  • ensureConnected 先完成“连通/auto-spawn/ready”等待。
  • 成功连通后再 LoadTokenFromFile,并做短重试(例如 100ms * 10)等 token 落盘。
  • 再执行 gateway.authenticate。
  • 仅在“确实不可达”时触发 auto-spawn,避免覆盖用户已运行实例。
    请你审查!如果不是,请你按该方案进行修改!

@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot 请你帮我解决冲突!

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

处理完成

已完成冲突解决并推送到当前 PR 头分支 pionxe:main

本次关键结果:

  • 已将 origin/main 两轮合并进当前分支,并手工消解冲突:
    • internal/tui/core/app/update.go
    • internal/tui/services/remote_runtime_adapter.go
    • internal/tui/services/remote_runtime_adapter_test.go
  • 同步修复合并后契约与测试适配,确保 internal/tui 不直连 internal/runtime 的守卫测试继续通过。
  • 已执行并通过全量回归:go test ./...
  • 已确认 PR 状态:mergeStateStatus=CLEANmergeable=MERGEABLE

已推送提交:

  • 4473628(首轮冲突修复)
  • a69dc32(合并 main 并处理冲突)
  • 43cc39b(同步最新 main 并处理剩余冲突)

View job run

xgopilot and others added 3 commits April 22, 2026 03:59
…r and events

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
…ct boundaries

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099
Copy link
Copy Markdown
Collaborator

/review

Copy link
Copy Markdown

@fennoai fennoai Bot left a comment

Choose a reason for hiding this comment

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

完成四轮审查(代码质量、性能、安全、文档)后,保留了 2 个需要处理的问题,均会影响运行时行为稳定性。其余改动未发现需要阻断的风险。

_ = logSink.Close()
}()

cmd := exec.Command(executablePath, "gateway")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

defaultAutoSpawnGateway 启动子进程时固定使用 neocode gateway,但没有把 listenAddress 透传为 --listen。这会导致非默认监听地址场景下自动拉起后的网关仍监听默认地址,客户端继续拨号自定义地址并最终失败。建议把 listenAddress(以及对应 token-file 配置)显式透传到子进程参数。

Authenticator: authManager,
ACL: acl,
Metrics: metrics,
ConnectionCountChanged: func(active int) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

空闲退出控制器当前只观察 IPC 连接数(ConnectionCountChanged 来自 IPC server)。当网关仅有 HTTP/WS/SSE 活跃连接而 IPC 为 0 时,30 秒后仍会触发 cancelRuntime 并退出,可能中断有效会话。建议改为聚合 IPC+HTTP 活跃连接,或在存在网络活连接时抑制 idle shutdown。

@phantom5099
Copy link
Copy Markdown
Collaborator

@xgopilot 解决冲突,按照斩断直连的方案,并提交PR到fork仓库

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

处理结果

已按“斩断直连”方案完成冲突处理,并将结果推送到当前 PR 头分支 pionxe:main

关键处理

  • 保持 TUI 侧仅依赖 internal/tui/services 运行时契约,未引入 internal/runtime/* 直连依赖。
  • 调整 update_runtime_events_test.go 以对齐当前事件语义(phase 与 stop reason 行为),确保冲突后测试语义一致。

验证

  • 已执行:go test ./...
  • 结果:通过
  • PR 当前状态:mergeable = MERGEABLE(已可合并)

未做事项:未新建额外 PR(本次按要求直接更新了现有 PR 分支)。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)

Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
@phantom5099
Copy link
Copy Markdown
Collaborator

/code 解决编译错误

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

处理结果

当前 PR 分支未复现编译错误,已完成以下验证:

  • go build ./...:通过
  • go test ./... -count=1:通过
  • 跨平台编译检查:
    • GOOS=linux GOARCH=amd64 go build ./...:通过
    • GOOS=darwin GOARCH=amd64 go build ./...:通过
    • GOOS=windows GOARCH=amd64 go build ./...:通过

说明

本次未检测到可修复的编译失败点,因此没有产生代码改动、提交或推送。

请补充当前 CI 的具体报错日志(失败 job 链接、报错文件与行号、Go 版本/OS),我会按日志精确修复。

View job run

@phantom5099
Copy link
Copy Markdown
Collaborator

@xgopilot 1、解释编译报错原因:gateway-relay: 2026/04/22 05:25:42 connection cid-write-err write failed: io: read/write on closed pipe
--- FAIL: TestNetworkServerCloseInterruptsStreams (0.01s)
network_server_test.go:786: expected websocket receive to fail after server close
gateway-relay: 2026/04/22 05:25:44 connection cid_1776835542_26 queue is full, dropping slow connection
FAIL
2、当前项目在TUI接入了新的状态变更,是否会影响到当前PR的完整度
不许写代码,只允许你回答问题

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

结论

你贴出来的不是“编译报错”,是测试失败go test 阶段)。

  1. 失败日志原因(对应你的问题 1)
  • gateway-relay: ... cid-write-err write failed: io: read/write on closed pipe 来自故障注入测试:internal/gateway/coverage_boost_test.go:282-294,该用例故意让 Write 返回 io.ErrClosedPipe 覆盖错误分支,所以这条日志本身是“测试过程噪音”,不是编译问题。
  • 真正导致 FAIL 的断言是:internal/gateway/network_server_test.go:786TestNetworkServerCloseInterruptsStreams 期望 server.Close() 后 WS 立刻读失败。
  • 该断言有时会被时序击穿:测试默认心跳是 100msinternal/gateway/network_server_test.go:1077-1079),在关闭窗口内 WS 可能先读到一个已入队帧(如 heartbeat),导致 Receive 返回 nil,从而触发 expected websocket receive to fail after server close
  • 你日志里的 queue is full, dropping slow connection 更像失败后的连带现象(连接未及时结束,心跳持续灌入队列后被慢连接剔除),不是首个根因。
  1. TUI 新状态变更是否影响当前 PR 完整度(对应你的问题 2)
  • 不会直接破坏这次 PR 的主目标完整度(“斩断 TUI 对 runtime 直连”):
    • internal/tui/core/app/update.go 已移除对 internal/runtime 的直接依赖;
    • 契约收敛到 internal/tui/services/runtime_contract.go
    • 守卫测试 internal/tui/bootstrap/builder_test.go:398-426 在扫描 internal/tui 非测试文件,阻止再引入 neo-code/internal/runtime
  • 但有两个残余风险需要你关注(属于稳定性层面,不是架构目标失效):
    • RuntimeMsg.Event 改成 anyinternal/tui/state/messages.go:6-9),update.go 中通过类型断言过滤;若上游发错事件类型会被静默忽略。
    • stop_reason_decided 的 UI 映射语义变更后更依赖字符串约定,若后端 reason 新增/漂移,前端状态文案可能退化到通用错误分支。

我这次没有做的事

  • 没有改代码(按你的要求仅回答问题)。

View job run

@pionxe
Copy link
Copy Markdown
Collaborator Author

pionxe commented Apr 22, 2026

@xgopilot 请你帮我解决CI构建失败的问题!

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 22, 2026

修复结果

已修复本次 build-test 失败并推送到当前 PR 分支 pionxe:main

  • 根因:internal/gateway/network_server_test.goTestNetworkServerCloseInterruptsStreams 对 WebSocket 关闭时序做了“立即失败”断言,在 CI 环境下存在抖动导致偶发失败(你这次失败即发生在该用例)。
  • 修复:将断言改为“在短时间窗口内最终失败”(循环设置短读超时并重试接收),避免把正常关闭传播延迟误判为失败。

提交:9bc0579

验证

  • go test ./internal/gateway -run TestNetworkServerCloseInterruptsStreams -count=200 -covermode=atomic
  • go test ./... -covermode=atomic -coverprofile=/tmp/coverage.out
  • 额外执行 3 轮 go test ./... -covermode=atomic 均通过 ✅

未做事项:未改动业务实现逻辑,仅修复不稳定测试断言。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099 phantom5099 merged commit 1289071 into 1024XEngineer:main Apr 22, 2026
2 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.

[EPIC-INT-01C] 阶段 3:彻底斩断直连与依赖清理 (Client Migration - Phase 2)

3 participants