提交 37c508e0 authored 作者: 陈泽健's avatar 陈泽健

docs(handoff): 新增问题排查助手与服务监测模块会话交接文档

- trouble_handoff.md:问题排查助手模块交接(离线 Q&A 模式 + 容器化落地,含关键设计决策/坑点/隔离边界/T6-T7 待办)
- Docs/需求文档/服务监测/monitor_handoff.md:服务监测模块交接
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 c552a6b3
# HANDOFF — 服务监测模块(Service Monitor)会话交接
> 最后更新:2026-07-16 14:20 | 分支:troubleshoot-ai-assistant | 提交:`c552a6b3`
> 状态:**代码全部完成,218 测试全绿,已提交 git,** ⏳ **待部署到 5.60**
---
## 1. 模块概览
| 项目 | 描述 |
|------|------|
| **模块 ID** | `service-monitor` |
| **首页 URL** | `/service-monitor` |
| **API 前缀** | `/api/service-monitor/*` |
| **目录** | `skill/code/web/service_monitor/`(自包含子包) |
| **设计思想** | 与「问题排查助手」**完全物理隔离**,不共用 `routes/`/`services/`/`utils/`/`config.json`/`container.py`,仅通过 `server.py` 一行注册 Blueprint 接入平台 |
| **本期范围** | 核心子集:system(01/02/03/04) + Docker-basic + MySQL-basic + Redis-basic |
| **执行模式** | 本机(subprocess 调 bash)+ 远程(paramiko SSH) |
| **报告套件** | 快速巡检(5 模块) / 全量巡检(7 模块) |
---
## 2. 完成的功能
### 2.1 监测目标管理
- ✅ 内置本地目标(不可删)
- ✅ 远程目标 CRUD(SSH 地址/端口/用户名/密码,密码 Fernet 加密存储)
- ✅ 连通性测试(保存前测试 SSH 是否可达)
- ✅ 目标级配置覆盖(容器名模式、凭据、阈值)
### 2.2 巡检执行
- ✅ 快速巡检(`quick`):01/02/03/04 + Docker-basic
- ✅ 全量巡检(`full`):再加 MySQL-basic + Redis-basic
- ✅ 本机执行:直接 subprocess bash
- ✅ 远程执行:paramiko SFTP 上传模块 → SSH 执行
- ✅ SSE 实时推送进度(模块逐项亮起,进度条,汇总)
- ✅ 可取消(Event 标志位)
- ✅ 配置按目标渲染(容器名覆盖 + 凭据注入 + 阈值覆盖)
### 2.3 巡检报告
- ✅ 报告存储:`service_monitor/data/reports/{id}.json`
- ✅ 汇总卡片(总项数 / 正常 / 警告 / 严重)
- ✅ 异常项置顶显示(红/黄色标识 + 模块来源)
- ✅ 分模块折叠明细
- ✅ 导出 Markdown
- ✅ 导出 JSON
- ✅ 报告列表(按时间倒序,支持按目标过滤)
- ✅ 报告历史默认保留 14 天(可配置,`cleanup_expired()`
### 2.4 角色权限
- ✅ 管理员:目标 CRUD / 触发巡检 / 取消 / 删除报告 / 导出 / 修复预留
- ✅ 普通用户:仅查看(目标列表只读、报告详情、导出),操作按钮隐藏
### 2.5 修复预留
- ✅ 报告中异常项旁的「修复」按钮调用 `/api/service-monitor/fix`,返回「修复能力开发中」
---
## 3. 架构与目录结构
```
skill/code/web/service_monitor/ # ★ 自包含子包
├── __init__.py # from .routes import bp
├── routes.py # 4 页面 + 12 API 路由
├── services/ # 业务层(均用相对导入)
│ ├── __init__.py
│ ├── target_service.py # 目标 CRUD + 解密凭据 + 执行器工厂
│ ├── runner_service.py # 巡检编排(SSE 事件生成器)+ 取消
│ └── report_service.py # 报告 CURD + 过期清理 + MD/JSON 导出
├── utils/ # 工具层(均用相对导入)
│ ├── __init__.py
│ ├── paths.py # 私有路径常量(MODULE_DIR/ASSETS_DIR/DATA_DIR/…)
│ ├── crypto.py # Fernet 加密/解密(MONITOR_ENC_KEY → SECRET_KEY → 兜底)
│ ├── check_modules.py # 模块清单 + get_suite() + render_config()(shlex.quote)
│ ├── parser.py # KEY:VALUE 解析(过滤脏行 + 状态判定优先 *_LEVEL)
│ ├── thresholds.py # 阈值表 + judge_status()(数值比较,分级严重/警告)
│ ├── display_names.py # KEY → 中文显示名映射
│ └── executor.py # BaseExecutor / LocalExecutor / SSHExecutor(paramiko)
├── assets/ # bash 检测模块(静态资源)
│ ├── config.sh.template # 模板(容器名模式 + 凭据占位符 + 阈值默认值)
│ ├── common.sh # 通用函数库(log_info/output_result/resolve_container 等)
│ ├── system/
│ │ ├── 01_system_basic.sh # 系统基础信息
│ │ ├── 02_cpu_check.sh # CPU 检测
│ │ ├── 03_memory_check.sh # 内存检测
│ │ └── 04_disk_check.sh # 磁盘检测
│ └── service/
│ ├── 20_docker_basic.sh # Docker 基础
│ ├── 22_mysql_basic.sh # MySQL 基础
│ └── 24_redis_basic.sh # Redis 基础
├── data/ # 运行时数据(.gitignore 忽略,不提交)
│ ├── .gitkeep
│ ├── targets.json # 监测目标列表(密码加密存储)
│ └── reports/ # 巡检报告 JSON 归档
└── tests/ # 模块私有测试(conftest 独立,tmp 隔离数据)
├── __init__.py & conftest.py
├── test_parser.py # 7 用例
├── test_crypto.py # 5 用例
├── test_check_modules.py # 7 用例
├── test_target_service.py # 8 用例
├── test_routes_sm.py # 18 用例(含 routing permission)
└── test_report_service.py # 6 用例
skill/code/web/templates/service_monitor/ # 模板(独立目录,不与 index.html 冲突)
├── index.html # 主页:目标卡片网格 + 报告列表
├── targets.html # 目标管理:表格 + 弹窗 CRUD + 连通性测试
├── run.html # 巡检执行:进度条 + SSE 模块清单
└── report.html # 报告详情:汇总 + 异常置顶 + 折叠明细 + 导出 + 修复
```
---
## 4. 路由与 API 清单
### 页面路由
| 方法 | 路径 | 权限 | 功能 |
|------|------|------|------|
| GET | `/service-monitor` | 登录 | 监测主页 |
| GET | `/service-monitor/targets` | 管理员 | 目标管理页 |
| GET | `/service-monitor/run/<target_id>` | 管理员 | 巡检执行页 |
| GET | `/service-monitor/report/<report_id>` | 登录 | 报告详情页 |
### API
| 方法 | 路径 | 权限 | 功能 |
|------|------|------|------|
| GET | `/api/service-monitor/targets` | 登录 | 目标列表 |
| POST | `/api/service-monitor/targets` | 管理员 | 新增目标 |
| PUT | `/api/service-monitor/targets/<tid>` | 管理员 | 更新目标 |
| DELETE | `/api/service-monitor/targets/<tid>` | 管理员 | 删除目标 |
| POST | `/api/service-monitor/targets/test` | 管理员 | 连通性测试 |
| GET | `/api/service-monitor/run/stream` | 管理员 | SSE 巡检流 |
| POST | `/api/service-monitor/run/<run_id>/cancel` | 管理员 | 取消巡检 |
| GET | `/api/service-monitor/reports` | 登录 | 报告列表 |
| GET | `/api/service-monitor/reports/<rid>` | 登录 | 报告详情 |
| DELETE | `/api/service-monitor/reports/<rid>` | 管理员 | 删除报告 |
| GET | `/api/service-monitor/reports/<rid>/export` | 登录 | 导出 MD/JSON |
| POST | `/api/service-monitor/fix` | 管理员 | 修复预留 |
---
## 5. 关键设计决策
| 决策 | 选择 | 原因 |
|------|------|------|
| 代码隔离 | 自包含子包 `service_monitor/` | 不与问题排查助手代码纠缠,删除模块只需删一个目录 |
| 执行器 | LocalExecutor(subprocess) / SSHExecutor(paramiko) | paramiko 纯 Python,无外部二进制依赖 |
| 凭据存储 | Fernet 加密 | SSH 密码禁止明文落盘 |
| 密钥来源 | MONITOR_ENC_KEY > 派生自 SECRET_KEY > 兜底 | 灵活,生产推荐独立设置 |
| 容器名匹配 | 模糊匹配(`grep -iE`) | 不同服务器容器名不一致 |
| config 渲染 | shlex.quote 防注入 | 密码含特殊字符时不破坏 shell 语法 |
| 状态判定 | 优先模块自带 *_LEVEL | 模块内判定最准确,阈值表为兜底 |
| 进度反馈 | SSE(text/event-stream) | 已有 SSE 经验,无需 WebSocket |
| 数据存储 | JSON 文件 | 与项目现有风格一致(users.json),避免 SQLite 依赖 |
| 报告保留 | 14 天可配置 | 通过 cleanup_expired() 定时或手动清理 |
---
## 6. 关键执行链路(本地巡检)
```
用户点「快速巡检」
→ GET /service-monitor/run/local?suite=quick
→ 页面加载空白进度模板 + JS 开 EventSource
→ GET /api/service-monitor/run/stream?target_id=local&suite=quick
→ runner_service.run_inspection("local", "quick"):
1. target_service.get_target("local") → 取本地目标
2. check_modules.get_suite("quick") → 5 个模块列表
3. render_config(target) → 渲染 config.sh 文本
4. LocalExecutor.setup() → mktemp + 复制 assets
5. for 每个模块:
executor.run_module(module, config) → bash -c 'cd <wd> && …/module.sh'
parser.parse_module_output(raw) → KEY:VALUE → CheckItem[]
yield SSE event("module_done", ...)
6. report_service.save(...) → 报告落盘
7. yield SSE event("finished", report_id)
→ 前端 progress 模块亮起 → 1.5s 自动跳 `/service-monitor/report/<id>`
```
---
## 7. 踩过的坑 & 注意事项
### 🚨 坑 1:模块头部 LIB_DIR 写死覆盖
- **现象**:原脚本 `LIB_DIR="/tmp/check_modules"` 位于模块头部,`source common.sh` 之前,改为 `${LIB_DIR:-/tmp/check_modules}` 才能让 executor 传入的工作目录生效
- **涉及**:7 个 .sh 文件均已改
### 🚨 坑 2:common.sh 加载路径
- `common.sh``source $LIB_DIR/lib/config.sh`,所以 executor 必须把 assets 布置为 `<workdir>/lib/{config.sh, common.sh, system/, service/}` 结构,不能平铺
### 🚨 坑 3:config 模板凭据占位符不加引号
- 模板写 `MYSQL_PASSWORD=__MYSQL_PASSWORD__`(无引号),渲染时 `shlex.quote` 自动按需加单引号。若模板自带 `"__var__"` 会导致 `shlex.quote("'value'")` 产生错误嵌套
### 🚨 坑 4:测试 fixture 不要共用一个 client 实例
- Flask test_client 的 session 是绑在 client 对象上的,`user``admin` 如果用同一个 `client` 注入不同 session,会互相覆盖。必须各自 `app.test_client()` 独立实例
### 🚨 坑 5:Docker basic 的逐容器精确匹配
- `20_docker_basic.sh``check_container_status``grep -q "^${name}$"` 精确匹配。如果是 config 里是模式(如 `mysql`),跑在容器名 `umysql` 的服务器上匹配不到。**本期可接受**(Docker basic 还有 service 状态/资源/日志等通用项),后续若需逐容器检测,应改精确匹配为 `resolve_container` 函数
### 🚨 坑 6:旧占位文件冲突(已解决)
- 平台化创建的 `routes/service_monitor.py``templates/service_monitor.html` 与新子包 bp 端点名冲突。已删除
### ⚠️ 注意 7:部署前服务器需装依赖
- `cryptography` 可能需 libffi-dev 等 C 扩展;`paramiko` 服务器已有(deploy 脚本用了),但需确认版本兼容
### ⚠️ 注意 8:运行时 data 自动创建
- `service_monitor/utils/paths.ensure_dirs()` 在首次访问时自动 `mkdir -p data/``data/reports/`,无需手动创建
---
## 8. 当前待办:部署到 5.60
```
# 1. 服务器安装依赖(cryptography 确保装好)
ssh ubains@192.168.5.60 "pip install paramiko cryptography"
# 2. 上传代码(用 ! 前缀在会话内执行)
! cd deploy && SSH_PASSWORD='***' python upload_to_server.py
# 3. 验证部署
cd deploy && python verify_deployment.py
# 4. 手动验证
# 浏览器访问 http://192.168.5.60:8088/service-monitor
# 管理员账号登录 → 看到本机目标卡片 → 点快速巡检
# → SSE 进度条走完 → 自动跳报告 → 看异常项 + 导出 MD
```
### 部署涉及文件清单
上传脚本已增量修改,**新增 `RECURSIVE_DIRS_TO_UPLOAD`** 递归上传 service_monitor 子包(排除 tests/data/__pycache__):
```
# 自动上传(含递归):
service_monitor/ → /opt/troubleshoot/web/service_monitor/
templates/service_monitor/ → /opt/troubleshoot/web/templates/service_monitor/
# 修改的全局文件自动覆盖:
server.py → 已从 service_monitor import(占位时改好)
.gitignore → 本地不影响
CLAUDE.md → 本地不影响
```
---
## 9. 备忘:模块健康检查
部署后通过以下几点确认模块正常工作:
1. **Blueprint 注册成功**:访问 `/service-monitor` 返回 200(非 404)
2. **目标自动创建**:能列出本机目标(`/api/service-monitor/targets` 返回含 `local` 项)
3. **本地巡检全链路**:SSE 流走完,报告落盘
4. **权限隔离**:普通用户看不到操作按钮,API 返回 403
5. **修复预留**:管理员点修复按钮弹出「开发中」
6. **导出**:MD/JSON 下载正常
---
## 10. 相关文档
| 文件 | 说明 |
|------|------|
| `Docs/需求文档/服务监测/PRD_需求文档_服务监测模块.md` | 需求定义(已确认 Q1-Q10) |
| `Docs/需求文档/服务监测/PRD_计划执行_服务监测模块.md` | 实现计划(7 阶段,已全部完成) |
| `Docs/需求文档/服务监测/HANDOFF.md` | 本文件,服务监测会话交接 |
| `临时目录/服务器监测/` | 参考脚本(bash 模块 + 架构 v4.0) |
# 问题排查助手模块 — 会话交接文档(trouble_handoff)
> 模块:问题排查助手(troubleshoot) | 分支:troubleshoot-ai-assistant
> 交接日期:2026-07-17 | 上次会话末态 commit:`b94d0230`(离线方案落地)
> 范围说明:本文档**仅覆盖问题排查助手模块**。service_monitor / service_manage 模块的进展见各自交接文档。命名 `trouble_handoff.md` 以区分模块。
---
## 1. 模块定位
问题排查助手是运行维护平台的三个模块之一,其余两个为服务管理、服务监测。
- **核心功能**:用户输入问题描述 → TF-IDF 搜索知识库(357 条历史案例)→ 调 Claude API 生成只读排查步骤与根因分析
- **本次交付**:在 `OFFLINE_MODE=true` 时跳过 Claude API,直接返回 TF-IDF 匹配结果(离线 Q&A 模式)+ Docker 容器化部署能力
- **运行环境**:Flask 进程,与 service_monitor / service_manage 同进程共 Blueprint(见 §6 隔离边界)
---
## 2. 本期完成事项(b94d0230 提交内容)
### 2.1 离线 Q&A 模式
| 文件 | 变更 | 说明 |
|------|------|------|
| `skill/code/web/utils/offline_config.py` | 新增 | `is_offline_mode()``OFFLINE_MODE` env,进程级缓存;`reset_for_test()` 测试重置 |
| `skill/code/web/services/ai_service.py` | 修改 | 新增 `build_offline_response(matched_cases)`,兼容两种输入格式(原始 record / 已格式化 dict) |
| `skill/code/web/routes/troubleshoot.py` | 修改 | 4 处离线分支:`/api/troubleshoot``/api/analyze``/api/analyze/stream``/api/health` |
**关键设计决策**(务必记住,避免下次返工):
1. **离线搜索用 TF-IDF,不用向量搜索**——向量预计算要联网调 `/v1/embeddings` API 扣费,离线环境做不了。TF-IDF 纯本地零费用。
2. **流式接口 `/api/analyze/stream` 保留 SSE 协议**——离线模式单帧推送完整结果后 `close`,前端解析逻辑无需改动。
3. **离线跳过缓存读写**——离线 <1s 响应,`cache_manager` 空跑无意义,离线分支直接 return 不走 cache。
4. **`OFFLINE_MODE` 走环境变量**(与 SECRET_KEY 一致),不从 config.json 读。启动时读一次,改了要重启容器。
5. **`build_offline_response` 接收「已格式化 dict 列表」**——troubleshoot 路由先调 `format_matched_cases()` 再传入;analyze 路由入参已是格式化格式,直接传入。两路由复用同一函数,不各自重写。
### 2.2 容器化部署
| 文件 | 说明 |
|------|------|
| `Dockerfile` | python:3.10-slim,WORKDIR `/app/web`,gunicorn `-w 4` 加载 `server:app` |
| `docker-compose.yml` | restart always,records/users/config 只读挂载,logs 持久化 |
| `.dockerignore` | **排除 `搜索向量.json`**(强制容器走 TF-IDF,避免 SearchEngine 静默走向量模式)+ 排除测试/缓存/临时 |
| `requirements.txt`(仓库根) | 镜像依赖,含 cryptography/paramiko(见 §6) |
| `.env.example` | 补 `OFFLINE_MODE=true` 说明 |
### 2.3 文档
| 文件 | 说明 |
|------|------|
| `Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手.md` | PRD v2.2(含 §4.6 同进程依赖耦合说明) |
| `Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手_计划执行.md` | 执行计划,T1-T8 任务表 |
### 2.4 测试
- 新增 `skill/code/tests/test_offline_mode.py`**22 用例全绿**
- 覆盖:offline_config 解析(11 参数化用例)/ build_offline_response(4 用例)/ 路由离线分支(含 SSE)/ 在线模式回归
- 全量回归 **218 用例全绿**(问题排查助手 167 + service_monitor 51)
---
## 3. 当前状态快照
### 3.1 代码层
- `server.py:107` 已有模块级 `app = create_app()` → gunicorn `server:app` 可直接加载,无需改
- 三个被测模块(`search_engine.py` / `safety_filter.py` / `cache_manager.py`)公开接口**未动**
- 离线改造**未碰** `service_manage.py` / `service_monitor.py`(隔离红线遵守)
### 3.2 测试基线
```
cd skill/code && python -m pytest -v
# 期望:218 passed
# 离线专项:python -m pytest tests/test_offline_mode.py -v → 22 passed
```
### 3.3 Git 状态
- 分支 `troubleshoot-ai-assistant`
- 最近提交:
- `b94d0230` feat(offline): 问题排查助手离线 Q&A 模式和容器化部署 ← **本模块本次交付**
- `c552a6b3` feat(service-monitor): 落地服务监测模块(service_monitor 组,非本模块)
- 工作区:本次交接时干净
---
## 4. 待办 / 下一步
| # | 事项 | 优先级 | 说明 |
|---|------|--------|------|
| 1 | **本地容器构建验证(T6)** | 中 | 需要 Docker 环境。`docker build -t troubleshoot:offline .` → run → 验 `/api/health` 返回 `offline_mode:true``search.mode:tfidf` |
| 2 | **部署到 5.60(T7)** | 中 | 5.60 已装 Docker,但当前会话网络不可达。`docker save | gzip` → scp → `docker load``docker compose up -d` |
| 3 | **前端适配 `offline:true`** | 低 | 后端已就绪,前端 index.html 需读 `offline:true` 显示「当前为离线模式」横幅;`analysis:null` 显示「无 AI 分析」提示。本期后端就绪即可,前端另行处理 |
| 4 | **gunicorn WORKDIR 实测** | 中 | Dockerfile WORKDIR 设为 `/app/web` 是推算值,T6 构建后看 `docker run` 启动日志确认能加载 `server` 模块 |
| 5 | **requirements 版本在 5.60 实测** | 低 | 现版本 `cryptography==46.0.7` / `paramiko==4.0.0` 以本地实测为准,5.60 构建时若解析失败再调 |
---
## 5. 关键坑点(踩过,不要再踩)
1. **向量文件静默降级**`搜索向量.json` 存在时 SearchEngine 会静默走 vector 模式,与「离线用 TF-IDF」矛盾。离线镜像**必须排除该文件**(.dockerignore 已处理)。部署后务必查 `/api/health``search.mode` 确认是 `tfidf`。详见 CLAUDE.md 避坑第 7 条。
2. **同进程依赖连累**:service_monitor 的 `utils/crypto.py` 模块级 `from cryptography.fernet import Fernet`,在 `create_app()` 阶段执行。镜像若缺 cryptography,**问题排查助手也起不来**。故 requirements 必须含 cryptography/paramiko(已补,见 §6)。
3. **analyze 与 troubleshoot 的 matched_cases 格式不同**:analyze 收前端传来的已格式化 dict(含 rank/score/project/title/file/phenomenon,**无 solution**);troubleshoot 是 engine.search() 原始结构(含 record,有 solution)。`build_offline_response` 已兼容两者,但改这个函数时要注意两条路径都测。
4. **`/api/analyze/stream` 是 GET 不是 POST**:参数走 URL query string。PRD 早期误写成 POST `/api/analyze_stream`,实际路由是 GET `/api/analyze/stream`。改路由时别改错。
5. **gunicorn 找模块靠 WORKDIR**`server:app` 要求 gunicorn 进程 CWD 在含 `server.py` 的目录(`/app/web`)。WORKDIR 设错会报 `Failed to find application object 'app'`
6. **offline_config 是进程级缓存**:改 `OFFLINE_MODE` env 后,已运行的进程不会感知,必须重启。测试时用 `reset_for_test()` 刷新。
---
## 6. 模块隔离边界(与 service_monitor 的关系)
**部署层隔离,非进程隔离**——这是最重要的架构事实。
- **代码层**:问题排查助手(`routes/troubleshoot.py` + `services/ai_service.py` + `utils/offline_config.py`)与 service_monitor 子包**无任何相互 import**。删掉 service_monitor,离线测试 22 用例不受影响(已验证)。
- **运行时**:同处一个 Flask 进程(`server.py::create_app()` 一次性注册全部 Blueprint)。邻居模块导入失败会连累整个进程启动。
- **依赖**:service_monitor 的 cryptography(模块级)/ paramiko(延迟)依赖必须随镜像一起提供,已补入仓库根 `requirements.txt`
- **PRD §4.6** 如实记录了这个设计妥协:部署层隔离 ≠ 进程隔离。
**隔离红线**(下次改离线功能时仍要遵守):
1. 改动范围仅限 `routes/troubleshoot.py``services/ai_service.py``utils/offline_config.py`
2. `OFFLINE_MODE` 只作用于问题排查助手路由,不影响 service_manage / service_monitor
3. 共享 `utils/*` / `auth.py` / `platform.py` 改动须对三模块无差别兼容
4. **禁止改** `service_manage.py` / `service_monitor.py`
---
## 7. 关键文件速查
```
问题排查助手代码:
skill/code/web/utils/offline_config.py # 离线开关
skill/code/web/services/ai_service.py # build_offline_response()
skill/code/web/routes/troubleshoot.py # 4 处离线分支
skill/code/tests/test_offline_mode.py # 22 用例
容器化:
Dockerfile / docker-compose.yml / requirements.txt / .dockerignore (仓库根)
文档:
Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手.md # PRD v2.2
Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手_计划执行.md # 执行计划
```
---
## 8. 环境变量清单(问题排查助手相关)
| 变量 | 用途 | 默认 |
|------|------|------|
| `OFFLINE_MODE` | 离线开关(true/1/yes → 离线) | 未设=在线 |
| `SECRET_KEY` | Flask session 密钥 | 未设则随机生成(生产必须设) |
| `CLAUDE_API_BASE` | Claude API 地址(在线模式用) | — |
| `CLAUDE_API_KEY` | Claude API key(在线模式用) | — |
| `FLASK_DEBUG` | 调试模式(1=开) | 1 |
---
## 9. 上次会话遗留的待确认项
- **无未决问题**。离线方案所有设计决策已在 PRD v2.2 闭合,代码已提交 b94d0230,测试全绿。
- 唯一悬而未决的是 **T6/T7 的部署验证**——等 Docker 环境就绪即可执行,不阻塞代码层。
---
> 本文档由问题排查助手模块开发者视角输出,便于下次会话追溯。service_monitor 模块的进展不在此列。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论