-
Notifications
You must be signed in to change notification settings - Fork 34
调研核心大包与高耦合结构拆分方案 #713
Copy link
Copy link
Closed
Labels
area:daemonDaemon server, admin API, and runtime controlDaemon server, admin API, and runtime controlarea:feishuFeishu/Lark integration, gateway, projector, or previewFeishu/Lark integration, gateway, projector, or previewarea:runtimeRuntime manager, process lifecycle, and persisted stateRuntime manager, process lifecycle, and persisted statemaintainabilityRefactors, code structure, and long-term maintainability workRefactors, code structure, and long-term maintainability workstatus:needs-planTechnical investigation is sufficient, but the staged plan is not yet execution-readyTechnical investigation is sufficient, but the staged plan is not yet execution-ready
Description
Metadata
Metadata
Assignees
Labels
area:daemonDaemon server, admin API, and runtime controlDaemon server, admin API, and runtime controlarea:feishuFeishu/Lark integration, gateway, projector, or previewFeishu/Lark integration, gateway, projector, or previewarea:runtimeRuntime manager, process lifecycle, and persisted stateRuntime manager, process lifecycle, and persisted statemaintainabilityRefactors, code structure, and long-term maintainability workRefactors, code structure, and long-term maintainability workstatus:needs-planTechnical investigation is sufficient, but the staged plan is not yet execution-readyTechnical investigation is sufficient, but the staged plan is not yet execution-ready
背景
近期多次修复 race、SSOT、fallback、性能和重复实现问题时,反复命中同一类结构性风险:少数核心包承担了过多职责,导致局部修改需要同时理解多条状态机、多个 runtime、Feishu 投影规则和持久化同步边界。
本 issue 用于对当前代码的“大包 / 高耦合 / 改动半径过大”问题做深度调研,并形成可以拆成执行单元的计划。当前不直接要求一次性重构。
初步证据
包规模:
核心包 receiver 方法数量:
前三个风险包生产 Go 代码合计约 69k 行,测试约 80k 行。多个单文件接近或超过 800-950 行,例如:
internal/core/orchestrator/service.gointernal/core/orchestrator/service_request.gointernal/core/orchestrator/service_target_picker.gointernal/app/daemon/app_ingress.gointernal/app/daemon/app_surface_resume_state.gointernal/adapter/feishu/app_autoconfig.gointernal/adapter/feishu/projector.go范围
本母 issue 只负责结构调研、风险分层和拆分计划,不直接承载全部重构实现。调研范围限定为:
非目标
相关文档
docs/general/remote-surface-state-machine.mddocs/general/feishu-card-ui-state-machine.mddocs/general/feishu-menu-card-usage-guidelines.mddocs/general/feishu-card-content-context-guidelines.mddocs/general/issue-orchestration-workflow.md涉及文件
优先调研这些文件/区域:
internal/app/daemon/app.gointernal/app/daemon/app_ingress.gointernal/app/daemon/app_surface_resume_state.gointernal/app/daemon/app_vscode_migration.gointernal/app/daemon/app_headless*.gointernal/app/daemon/app_cron*.gointernal/app/daemon/app_feishu_permissions.gointernal/core/orchestrator/service.gointernal/core/orchestrator/service_runtime_clusters.gointernal/core/orchestrator/service_queue*.gointernal/core/orchestrator/service_target_picker*.gointernal/core/orchestrator/service_request*.gointernal/core/orchestrator/service_routing_*.gointernal/adapter/feishu/projector.gointernal/adapter/feishu/gateway*.gointernal/adapter/feishu/app_autoconfig.gointernal/adapter/feishu/connection_status.gointernal/adapter/feishu/drive_file_comments.gointernal/adapter/feishu/im_*.go当前观察
internal/app/daemonApp现在是运行时总线,集中持有 relay/API/pprof server、Feishu gateway/projector、orchestrator service、headless runtime、surface resume runtime、cron runtime、upgrade runtime、turn patch runtime、external access、admin state、多个 mutex 与多类 async callback。风险:
具体热点:
maybeRecoverVSCodeSurfacesLocked/maybePromptDetachedVSCodeSurfacesLocked/maybeRecoverHeadlessSurfacesLocked在onHello、onEvents、onDisconnect、onTick等入口重复手写组合。syncSurfaceResumeStateLocked、syncClaudeWorkspaceProfileStateLocked、syncWorkspaceSurfaceContextFilesLocked分散在 command/action/hello/event/disconnect 分支中,缺少统一 “state changed -> persistence sync” runner。internal/core/orchestratorService是状态机 SSOT,但已经同时承载 route/claim、queue/dispatch、request gate、picker、model catalog、progress、review、autocontinue、surface UI runtime、cooldown 等子状态机。风险:
state.Root和 service runtime map,边界主要靠约定。service_*文件,测试也逐渐偏大集成 fixture。具体热点:
service_runtime_clusters.go已经把turns/pickers/catalog/progress聚成 runtime cluster,但调用端仍大量直接访问s.turns、s.pickers、s.catalog、s.progress。execprogress子包是正向例子:纯算法/数据变换先抽出包,保留状态 owner 在Service。internal/adapter/feishu同一个包内混合:gateway transport、callback parsing、IM/Drive API helper、Projector、app autoconfig、connection status、card rendering helper。
风险:
projectEventBase是大型 payload switch,新 payload 容易误漏 reply lane、inline update、temporary header、card envelope 等跨切面规则。LiveGateway同时持有 Lark client、broker、message/reaction tracking、大量 test hook function,transport 与 API helper 耦合明显。具体热点:
PlanAppAutoConfig/ApplyAppAutoConfig/PublishAppAutoConfig与LiveGateway共用LiveGatewayConfig、Lark client 和 broker,但产品生命周期完全不同。GetLongConnectionStatus/GetBotInfo是 setup/admin 检测能力,不应强依赖 runtime gateway 包内细节。feishuapi或feishuclient层,gateway runtime 只编排。深度调研结论
值得优先做
daemon 串行 recovery pipeline 收口。
这是最高优先级,因为它直接降低 race、漏同步和“一个入口修了另一个入口没修”的风险。目标不是拆包,而是先把重复的 recovery/sync 编排变成单一 helper/runner。
daemon runtime controller 边界收口。
将 surface resume、VS Code compatibility、managed headless、Feishu permission refresh 这类有 in-flight/backoff/follow-up 的 runtime state 分别收敛为小 controller 或至少统一的 locked method contract。目标是明确 background goroutine 只产出结果,业务推进必须回串行入口。
Feishu app autoconfig / setup API helper 从 runtime gateway 主包中分离。
这类改动主要是包边界和 API facade 调整,行为风险相对可控;同时能降低 websetup/onboarding 后续迭代的影响面。
Projector payload projection registry / helper 收口。
不建议马上拆整个 projector 包;先把
projectEventBase的重复 Operation 构造、reply lane、temporary header、inline update 统一 helper 化或 registry 化,保证新增 payload 不会漏跨切面规则。orchestrator 内部 runtime facade。
不建议第一批做大拆包。优先在同包内把
turns/pickers/catalog/progress/claims的直接 map 访问减少为 facade 方法,并补 contract tests。等调用点变少后再考虑包级拆分。暂不建议先做
internal/core/orchestrator拆成多个 Go package:当前共享state.Root、route/claim/queue/request/progress 横向调用太多,直接拆会产生 import cycle 或大量临时 adapter。orchestrator.Service加全局锁:这会掩盖 daemon 串行边界问题,不解决 owner 不清晰。推荐拆分结构
本 issue 应作为母 issue,拆出以下子 issue;推荐顺序如下。
子 issue A:收口 daemon VS Code/headless recovery 串行 pipeline
目标:把
onHello、onEvents、onDisconnect、onTick中重复的 VS Code compatibility follow-up、VS Code prompt/recovery、headless recovery、surface resume sync 编排收成统一 locked runner。非目标:不改变 recovery 策略,不改用户提示文案,不移动 orchestrator ownership。
验收:
go test ./internal/app/daemon -run 'VSCode|SurfaceResume|Headless' -count=1通过。优先级:P1。
子 issue B:收口 daemon 持锁外调用 / async result contract
目标:盘点 daemon 内所有
a.mu.Unlock()后执行 I/O 或启动 goroutine 的路径,建立统一 contract:background 只能产出 result/cache/follow-up;业务状态推进必须由 daemon serial runner 消费。非目标:不重写全部 goroutine;先覆盖风险最高的 Feishu permission refresh、upgrade check、admin async UI follow-up、cron writeback、VS Code migration/apply。
验收:
优先级:P1,建议在 A 后做。
子 issue C:拆出 Feishu setup/autoconfig client facade
目标:把 app autoconfig、connection status、bot info、permission/scope 检测相关 API facade 从 runtime gateway 关注点中分离,服务 websetup/onboarding 后续迭代。
非目标:不改 websetup UI,不改配置流程语义,不改 LiveGateway runtime 行为。
验收:
LiveGatewayruntime message/reaction tracking。go test ./internal/adapter/feishu ./internal/app/daemon -run 'Feishu|Onboarding|Setup|AutoConfig|Connection' -count=1通过。优先级:P2。
子 issue D:Projector cross-cutting operation builder 收口
目标:降低
projectEventBaseswitch 中重复 Operation 构造和跨切面处理遗漏风险,统一 reply lane、temporary session header、inline update、card envelope、theme fallback 的 builder。非目标:不改变卡片视觉,不重做 projector 架构。
验收:
优先级:P2/P3,建议在 C 后做。
子 issue E:orchestrator runtime facade 与 contract tests
目标:在同包内逐步收口
s.turns、s.pickers、s.catalog、s.progress、claim map 的直接访问,形成 facade 方法和局部 contract tests,为未来包拆分做准备。非目标:不跨包拆
orchestrator,不改变状态机语义。验收:
pickers或progress,减少直接 map 访问。优先级:P3;收益大但风险和工作量也最大,应在 A/B 降低 daemon 边界风险后推进。
拆分结构
本 issue 是母 issue,不直接编码。拆分为五个候选子 issue:
第一批只建议创建 A/B。C/D/E 等 A/B 边界稳定后再创建,避免母 issue 一次性制造过多待办。
当前执行点
深度调研已完成,当前母 issue 处于
status:needs-plan。下一步是创建子 issue A/B,并把链接和状态回卷到总调度表;随后从子 issue A 进入prepare。恢复步骤
总调度表和执行快照。推荐拆分结构创建。总调度表。prepare。status:implementable-now且 lint 通过后才开始编码。推荐顺序
A/B 是 correctness 风险优先;C/D 是影响面收敛;E 是长期结构治理。
可并行组
当前风险
目标
完成标准
建议范围
执行决策
实现参考
优先从子 issue A 开始,因为它最直接降低 race 和漏同步风险。实现时应保持行为不变,先抽 runner/helper,再通过现有 VS Code/SurfaceResume/Headless 测试证明等价。
检查参考
调研命令:
go list -f '{{.ImportPath}} {{len .GoFiles}} {{len .TestGoFiles}}' ./...find internal/core/orchestrator internal/app/daemon internal/adapter/feishu -maxdepth 1 -name '*.go' -not -name '*_test.go' -print0 | xargs -0 wc -l | sort -nrrg -n '^func \(' internal/core/orchestrator internal/app/daemon internal/adapter/feishu --glob '*.go' --glob '!*_test.go'rg -n 'maybeRecoverVSCodeSurfacesLocked|maybePromptDetachedVSCodeSurfacesLocked|maybeRecoverHeadlessSurfacesLocked|syncSurfaceResumeState|syncWorkspaceSurfaceContextFilesLocked|syncClaudeWorkspaceProfileStateLocked|consumeVSCodeCompatibilityFollowupLocked' internal/app/daemon --glob '*.go' --glob '!*_test.go'若后续进入实现子 issue,按触及逻辑分别触发 remote/Feishu UI state-machine guardrail。
收尾参考
docs/general/或相关 skill/AGENTS guardrail。A/B 后重新评估
重新评估结论:实际情况没有偏离原计划,A/B 完成后 C 仍是下一优先级。
证据:
connection_status.go、scopes.go、app_autoconfig*.go仍在internal/adapter/feishu主包内,并共用LiveGatewayConfig/FeishuCallBroker/ Lark client,但这些路径不依赖 runtime gateway 的 message/reaction tracking、inbound routing 或 projector 状态。feishu.PlanAppAutoConfig/ApplyAppAutoConfig/PublishAppAutoConfig/GetLongConnectionStatus/GetBotInfo,适合先收口为 setup client/facade 语义。执行结果:已创建子 issue
#716,作为 C 的执行单元。A/B/C 后重新评估
重新评估结论:实际技术顺序没有偏离原计划;只有旧执行快照文字曾停在 #716 close-out,需要修正。C 完成后未发现必须先处理的 setup-client follow-up,D 仍是下一执行单元。
证据:
feishu.SetupClient与 daemon 单一 setup facade 已落地,feishuRuntime.setup和分散 setup hook 已由结构测试防回归。projectEventBase与相邻 projector 文件仍存在多处手写Operation{...}、cardEnvelopeV2、rawCardDocument(...)、send/update 判定、reply lane 与 temporary session header 组合。执行结果:已创建子 issue
#717,作为 D 的执行单元。D 后重新评估
重新评估结论:E 不适合直接创建一个大范围
orchestrator runtime facade执行单元。当前s.turns/s.progress/s.pickers/s.catalogdirect access 仍横跨多条状态机,若一次推进会把 queue、snapshot、compact、request cleanup、picker owner-flow 混成一个验证面。第一执行切片选择 remote turn binding facade:
pendingRemote/activeRemote已经有一半逻辑集中在service_queue_binding.go,比progress或compact更容易形成稳定执行闭包。pendingSteers、compactTurns、progress暂不混入,后续按验证面另拆。执行结果:已创建子 issue
#718,作为 E 的第一执行单元。E1 后重新评估
重新评估结论:E 的下一切片选择
compactTurns,不选择progress或pendingSteers。证据:
compactTurnsdirect access 主要集中在 compact lifecycle 与少量 command binding,状态 owner 边界更清晰。progress横跨 final text、plan snapshot、MCP progress、request cleanup 和 queue,验证面更大。pendingSteers分布在 reply auto-steer 与 snapshot runtime,和用户追加输入/steer 恢复语义更近,适合 compact 后再单独切。执行结果:已创建子 issue
#719,作为 E 的第二执行单元。E3 后重新评估
重新评估结论:
progress不适合作为一个整体执行单元,下一步应拆成更小的 progress 子切片;第一片选择pendingTurnText/pendingPlanProposal。证据:
progress当前同时覆盖 final text、plan proposal、plan snapshot、MCP tool progress、file change summary、turn diff snapshot 和 compact gating,直接开大单会把多套生命周期和验证面混在一起。pendingTurnText与pendingPlanProposal同属 completed text item 暂存,direct access 集中在 queue completion、turn completed、cleanup 和 proposal presentation,能形成稳定执行闭包。执行结果:已创建子 issue
#721,作为 E 的第四执行单元。E4 后重新评估
重新评估结论:#721 完成后,
progress剩余 map 仍不应开大单;下一片选择turnPlanSnapshots。证据:
turnPlanSnapshotsdirect access 集中在 plan update upsert/dedup 和 turn cleanup,验证面小于 MCP tool progress。turnFileChanges/turnDiffSnapshots已有较多 runtime method,是否还需要结构测试收口应后续再评估。执行结果:已创建子 issue
#722,作为 E 的第五执行单元。E5 后重新评估
重新评估结论:#722 完成后,下一片选择
mcpToolCallProgress。证据:
mcpToolCallProgressdirect access 集中在 upsert/dedup 与 cleanup,能形成稳定执行闭包。turnFileChanges/turnDiffSnapshots仍留待后续单独评估。执行结果:已创建子 issue
#723,作为 E 的第六执行单元。总调度表
11c13f61runSurfaceRecoveryPipelineLocked;入口不再手写 VS Code/headless recovery 组合;G7 文档已同步a75fca62328f93fafeishu.SetupClient与 daemon 单一 setup facadebf282ad2newEventCardOperation,收口普通 card Operation 构造;Snapshot reply-lane 漂移已由回归测试锁住76d8d90f5658199dserviceTurnRuntime,只切 compact lifecycle,不混入 pendingSteers/progress8575f9e9serviceTurnRuntime,只切 pendingSteers,不混入 progress4e10614cprogress不开大单,先切 pendingTurnText/pendingPlanProposale25a9d80progress,只切 turnPlanSnapshots186cf634progress,只切 mcpToolCallProgressbb7de26ec7e626c6itemBuffers25705de47b83af68执行快照
7b83af68;所有已创建子 issue 均已关闭并回卷;本 issue 已达到当前结构治理阶段收口点低优先级待办
子 issue 回卷
子 issue
#714已完成并关闭,结果回卷如下:runSurfaceRecoveryPipelineLocked;onHello、onEvents、onDisconnect、onTick与 stamped/mode vscode后续恢复不再各自手写 recovery 组合。consumeVSCodeCompatibilityFollowupLocked只消费 async follow-up 标记,不再直接运行 prompt/recovery primitives;实际 prompt/recovery 统一由 surface recovery pipeline 执行。go test ./internal/app/daemon -count=1、go test ./...、文件长度与 diff check 均通过。docs/general/remote-surface-state-machine.md的G7 VSCodeCompatibilityBlocked已同步统一 pipeline 边界。11c13f61。status:implementable-now,下一步推进 daemon async result contract。子 issue
#715已完成并关闭,结果回卷如下:daemonAsyncResult;实际 UI/service mutation 由 daemon 串行入口或 queued drain 在a.mu下消费。go test ./...、文件长度与 diff check 均通过。a75fca62。子 issue
#716已完成并关闭,结果回卷如下:feishu.SetupClientConfig/feishu.SetupClient/NewSetupClient,把 setup/admin API helper 从 runtimeLiveGateway语义中分离。GetBotInfo、GetLongConnectionStatus、ListAppScopes、PlanAppAutoConfig、ApplyAppAutoConfig、PublishAppAutoConfig都已有SetupClientmethod;旧 exported functions 保留薄桥接以兼容现有调用面。daemonFeishuSetupFacade,收敛 plan/apply/publish/long-connection/describe-app 调用;移除feishuRuntime.setup、旧feishuSetupClientruntime field 和多个分散包级 hook。LiveGateway.Start/Applyruntime 行为,也未触碰 projector/card payload。go test ./...、文件长度与 diff check 均通过。328f93fa。子 issue
#717已完成实现与 verifier,结果回卷如下:newEventCardOperation/eventCardOperationSpec,统一普通 card operation 的基础字段、send/update 判定、reply lane、temporary session header、card envelope 与 raw card document 构造。projectEventBase中 Snapshot / Notice / PlanUpdate / Selection / Page / Request / PathPicker / TargetPicker 普通 card payload,以及projectExecCommandProgress、projectThreadHistory的同类 send/update path。ApplyReplyLane显式 opt-in,保留 Snapshot 状态卡顶层发送语义;新增TestProjectSnapshotIgnoresExplicitReplyLane防止统一 builder 再次引入行为漂移。go test ./...、Feishu guardrail 聚焦包测试、文件长度与 diff check 均通过。bf282ad2。子 issue
#718已完成实现与 verifier,结果回卷如下:serviceTurnRuntimepending/active remote binding facade,并新增 Service 级语义 helper,收口 queue/dispatch/snapshot 相关 remote binding 查询和写入。service_dispatch_core.go、service_queue.go、service_autowhip.go、service_autocontinue.go、service_compact.go、service_snapshot_query.go、service_snapshot_binding.go、service_snapshot_runtime.go、service_reply_auto_steer.go。TestRemoteTurnBindingMapsStayBehindFacade,禁止非 owner/facade 文件直接访问s.turns.pendingRemote/s.turns.activeRemote。pendingSteers、compactTurns、progress、picker/catalog runtime 未混入本切片。go test ./...、文件长度与 diff check 均通过。76d8d90f。pendingSteers/compactTurns/progressfacade。子 issue
#719已完成实现与 verifier,结果回卷如下:compactTurns的直接访问。TestCompactTurnBindingMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.turns.compactTurns。service_compact.go继续作为 compact lifecycle owner/facade;pendingSteers、pending/active remote binding、progress runtime 未混入本切片。/compactbusy 判断、owner card lifecycle、dispatch failure restore、command rejected restore、problem handling、completion notice 或 queue dispatch 状态迁移,不需要更新 canonical doc。go test ./...、文件长度与 diff check 均通过。5658199d。pendingSteers或progressfacade。子 issue #720 已完成并关闭,结果回卷如下:
pendingSteers的 bind/get/delete/iterate、command binding、instance/surface pending 判断和 restore key 查询。/steerall/ surface action、command ack/reject、dispatch failure restore、snapshot restore、surface/instance pending query。TestPendingSteerBindingMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.turns.pendingSteers;测试断言也改走 facade helper。progress、pending/active remote binding、compactTurns、picker/catalog runtime 未混入本切片。turn.steerack/restore、disconnect restore、command matrix 或用户可见语义,不需要更新 canonical doc。go test ./...、文件长度与 diff check 均通过。8575f9e9。progressfacade。子 issue #721 已完成并关闭,结果回卷如下:
pendingTurnText/pendingPlanProposal的 store/get/take/delete/cleanup。TestProgressPendingTextMapsStayBehindFacade,禁止非 owner/facade 文件直接访问.progress.pendingTurnText/.progress.pendingPlanProposal。turnPlanSnapshots、mcpToolCallProgress、turnFileChanges、turnDiffSnapshots、exec progress card、MCP progress 和 compact gating 未混入本切片。go test ./...、文件长度与 diff check 均通过。4e10614c。progressmap。子 issue #722 已完成并关闭,结果回卷如下:
turnPlanSnapshots的 upsert/dedup 与 cleanup。TestProgressPlanSnapshotMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.progress.turnPlanSnapshots。mcpToolCallProgress、turnFileChanges、turnDiffSnapshots、completed plan proposal handoff 未混入本切片。go test ./...、文件长度与 diff check 均通过。e25a9d80。progressmap。子 issue
#723已完成并关闭,结果回卷如下:mcpToolCallProgress的 duplicate check、store 和 cleanup。TestProgressMCPToolCallProgressMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.progress.mcpToolCallProgress。turnFileChanges/turnDiffSnapshots未混入本切片。go test ./...、文件长度与 diff check 均通过。186cf634。progress剩余turnFileChanges/turnDiffSnapshots是否需要继续结构测试 facade。子 issue
#724已完成并关闭,结果回卷如下:turnFileChanges/turnDiffSnapshots补齐结构测试,并将 owner 文件重命名为service_progress_file_change.go/service_progress_turn_diff.go。TestProgressFileChangeMapStaysBehindFacade与TestProgressTurnDiffMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.turnFileChanges/.turnDiffSnapshots。go test ./...、文件长度与 diff check 均通过。bb7de26e。子 issue
#725已完成并关闭,结果回卷如下:itemBuffers的 get/delete/cleanup,并移除底层 map 参数 helper。TestItemBufferMapStaysBehindFacade,禁止非 owner/facade 文件直接访问.itemBuffers。go test ./...、文件长度与 diff check 均通过。c7e626c6。子 issue
#726已完成并关闭,结果回卷如下:workspaceClaims/instanceClaims/threadClaims的非 owner direct access。TestRouteClaimMapsStayBehindFacade,禁止非 owner/facade 文件直接访问.workspaceClaims/.instanceClaims/.threadClaims。go test ./...、文件长度与 diff check 均通过。25705de4。子 issue
#727已完成并关闭,结果回卷如下:serviceCatalogRuntime.hasPersistedThreads(),收口非 owner 文件对 catalog 内部字段的可用性判断。TestCatalogRuntimeFieldsStayBehindFacade,禁止非 owner 文件直接访问.catalog.persistedThreads*/.catalog.persistedWorkspaces。go test ./...、文件长度与 diff check 均通过。7b83af68。E 阶段收口复核
#727 关闭后重新扫描 runtime direct access,结论如下:
progress已按子切片完成 pending text/proposal、plan snapshot、MCP progress、file change、turn diff 的 owner/facade 或结构测试收口。itemBuffers已完成底层 map 外传收口。pickers剩余访问主要是next*Token/ consumer/filter lookup/register 等 runtime method 调用,不是内部 map direct access;当前不建议为“调用 runtime method”继续拆机械子单。surfaceUIRuntimedirect access 集中在service_ui_runtime.goowner 文件;当前不建议只为已在 owner 内的 map 访问继续开子单。当前判断:#713 的本轮结构治理已达到可收口状态。后续若继续做更大拆包,应另开新母 issue 重新调研,而不是在本母 issue 内无限延伸。