-
Notifications
You must be signed in to change notification settings - Fork 2
Architecture Decisions
AceGuru-mjh edited this page Oct 1, 2026
·
4 revisions
📑 本页目录
本项目用交付报告 + ADR 记录"为什么这样决定"。本页汇总跨任务的关键决策。 原文:
docs/T76_ADR.md、docs/T81_ARCHITECTURE_ASSESSMENT.md、docs/T82_FINAL_REPORT.md、docs/terminal/TERMUX_CAPABILITY_MATRIX.md§15。
| # | 决策 | 理由 / 否决项 |
|---|---|---|
| D-1 | 文件式 JSON + 原子 rename 存储 | checkpoint 频率远超 SharedPreferences 的 O(n) 模型;否决 SharedPreferences(非原子)、Room(第二数据库)、DataStore(收益有限) |
| D-2 |
TaskRuntime 作为叠加层(组合而非替换 AgentEngine 绑定) |
审计修正:VM 有 15 处 (agentEngine as? ApexAgentEngine) cast,替换绑定会让全部 cast 静默失效;最终改经 AgentTaskStatusController 转发(3 处一行改动) |
| D-3 | 恢复触发 = ViewModel init 时确定性发现 | 可测、零后台依赖;不复活 platform:persistence 死代码;WorkManager expedited 恢复列为 v1.1 可选 |
| D-4 | taskId 一等公民 + v1 单活跃执行 | 存储 schema 不含单任务假设;不为 T76 先造第二套 Session 系统 |
| 附加 | 悬空 toolCall 合成 ToolResult(R-5) |
否则重启后 OpenAI 兼容 API 返回 400,整条历史不可用 |
| # | 决策 | 内容 |
|---|---|---|
| D-1 | Native 并发 | IO 方法改"锁内拷贝 shared_ptr → 锁外执行",mutex_ 只保护 map 结构 → 从全局串行变 per-session 串行 |
| D-2 | Job 终止语义 | 统一走 TimeoutController 三级(SIGTERM → grace → SIGKILL);信号目标从"整个 session 进程组"收窄为前台进程组(tcgetpgrp)+ shell 组,shell 优先保留;exitCode/signal 如实上报(不再编 130/0) |
| D-3 | Job 完成检测 |
InputWaitingDetector 补齐真实 PS1 正则并与 PromptDetector 对齐;JobManager 合成退出仅在 native exit code 不可得时使用 |
| D-4 | 事件系统收敛 |
TerminalEventLogImpl 加 per-session 上限(默认 500);SessionManagerImpl.close 调 eventLog.drop + eventBus.drop;bus subscribe 改"先建 live channel 再查历史" |
| D-5 | 持久化真原子 | tmp 写 + fsync + rename(与 T76 同模式);RuntimeRecoveryService.recover 完整实现;恢复的 session 一律 EXITED/BROKEN,不伪造 RUNNING;isPidAlive 改 /proc/<pid> 存在性检查(不再 fork kill -0) |
| D-6 | LinuxExecutionContext |
统一构造点(rootfs + workspace + home + env + arch + proot + cwd)供所有 Linux 侧组件复用;env 基线单一来源 |
| D-7 | Capability 真接线 | 基于 ProotExecutor 的轻量真实探测(which X / X --version,带超时 + 缓存)→ 产出 EnvironmentSnapshot
|
| 附加 | Shutdown 设计 |
TerminalRuntime.shutdown() 幂等(AtomicBoolean):停新请求 → cancel 全部 job → 停 pump → close session → scope.cancel → nativeCloseAll 兜底 |
三套"规格先行、实现未接线"的平行层(observation v2、process2、reliability/RecoveryCoordinator) 与两套仅测试引用的状态机一律不删除;接线优先于新写。
| # | 决策 | 内容 |
|---|---|---|
| 1 | 状态派生而非复制 |
derivePhase(hasRootfs, rootfsState, bootstrapState) 纯函数(11 组合矩阵测试),底层单一事实源不动 |
| 2 | 函数端口而非接口 | bootstrap / probe / repair 以 suspend (…) -> … 注入(T81 禁令:不建第二套类抽象) |
| 3 | 超时 = IN_PROGRESS | 与 install 工具同语义:断点续传 + stageEvidence 续跑,进度永不丢失 |
| 4 | probe 失败不否定 READY | 环境可用性与诊断快照分离 |
| 5 | RECOVERING 是过程态 |
refreshState 一律派生事实终态,不残留 |
| 6 | 细粒度工具全保留 |
ensure 是聚合入口,不是替代 |
| 判决 | 原则 |
|---|---|
| 死层(~5000 行 PR#55–#67 平行层)不接线、不删除 | 能力由生产路径实现(exit code → JobManager;fs → GuestFilesystem) |
| P60 api 层是唯一例外 | 以 TerminalSdk 适配器落地(文档已宣称冻结契约,不能让文档与现实割裂) |
| 每命令 PID 身份 | marker 携带 jobId(shell 级关联);/proc 级 PID 追踪仍属 process2 死层(已记录) |
| keep-alive / reattach | 设计记录(TerminalSupervisorService 草案)不实现 —— 无法在本环境验证进程死亡矩阵,拒绝发布未验证的生命周期服务 |
- 会话跨 App 死亡保活(需 supervisor service + 进程死亡矩阵);
- guest 内 sshd(暴露面,需安全评审);
- X11 / VNC GUI(独立产品面);
- 内置 rootfs(原为 APK 体积产品决策 —— T83 已落地);
- ARM32(无 Ubuntu armhf base 镜像);
- 鼠标上报(需先有 UI 手势层);
- 物理 Gradle 模块拆分(尚无第二消费方)。
Important
以审计文为准,而不是 README:
- 实际注册工具 ≈80 个(73 无条件 + 7 GitHub 条件;browser 15、terminal v2 16、terminal legacy 4、cs-mem 3)——
既不是 README 的 35,也不是
ToolModule注释的 53; - 行数门禁 main ≤1200 / test ≤1600;写 T76 时
ApexAgentEngine已 1057 行、AgentChatViewModel已 1123 行 → 几乎不能再往这两个文件加代码。
| 盲区 | 现状 |
|---|---|
:core:llm-adapter:test(69 用例) |
不在 CI |
:app:test(37 用例) |
不在 CI;app 模块无 androidTest |
:app:compileDebugKotlin |
continue-on-error |
| gradle wrapper | 仓库无 wrapper,CI 现场生成 8.10 |
| lint | CI 无 lintDebug 任务(审计建议补充) |
| 括号平衡检查 | 按原始字符计数 → 产生 \x28 类绕行写法(见 流水线输出 UI) |
- 任务运行时 · 终端 API 契约 · SDK 边界
- Ubuntu 生命周期 · 深度文档索引
-
MCP 生态总览
新 - (沙箱 MCP · 官方 Hub · 逆向 Host · 门控语义)
- 终端运行时
- 终端 API 契约
- SDK 边界
- Termux 能力矩阵
- Ubuntu rootfs 供给
- Ubuntu 生命周期
- PRoot 二进制溯源
- VT100/ANSI 模拟器
- 终端性能
- 终端迁移
- 原生层 C++/JNI