From 32a1885f0d4b9969552b8871809100e237ec13de Mon Sep 17 00:00:00 2001 From: Nexus Agent Date: Fri, 12 Jun 2026 03:47:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(watch):=20=E7=9B=91=E6=B5=8B=E6=A7=BD?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E3=80=818h/24h=E3=80=81=E5=88=B0=E6=9C=9F?= =?UTF-8?q?=E6=9A=82=E5=81=9C=E4=B8=8E=E6=8E=A2=E9=92=88=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持随时暂停/恢复实时监测并保留槽位;TTL 到期自动暂停不占删槽;修复到期竞态导致空槽与唯一约束冲突;探针 parse_error 与中文错误;移除失败 snackbar。 --- ...6-11-watch-slot-monitoring-enhancements.md | 117 ++++++++++++++ ...2026-06-12-watch-slot-monitoring-deploy.md | 67 ++++++++ .../2026-06-11-watch-probe-parse-error-fix.md | 41 +++++ ...2026-06-11-watch-slot-monitoring-toggle.md | 55 +++++++ .../2026-06-12-watch-ttl-expiry-race-fix.md | 35 ++++ docs/reports/2026-06-12-watch-bug-patrol.md | 40 +++++ ...2026-06-12-watch-slot-monitoring-patrol.md | 100 ++++++++++++ frontend/src/api/index.ts | 3 + .../watch/WatchProbeRecordsTable.vue | 18 +-- .../src/components/watch/WatchSlotCard.vue | 73 ++++++++- .../src/components/watch/WatchSlotRow.vue | 34 +++- frontend/src/composables/useWatchPins.ts | 60 +++++-- frontend/src/utils/watchFormat.ts | 89 ++++++++++ server/api/watch.py | 56 +++++++ server/application/services/watch_service.py | 141 +++++++++++++--- server/background/watch_probe_runner.py | 31 +++- server/domain/models/__init__.py | 12 ++ server/infrastructure/database/migrations.py | 4 + server/infrastructure/database/watch_repo.py | 151 +++++++++++++---- server/infrastructure/ssh/remote_probe.py | 147 ++++++++++++----- server/utils/watch_metrics.py | 16 ++ server/utils/watch_probe_errors.py | 61 +++++++ server/utils/watch_state.py | 19 +++ tests/test_watch_metrics.py | 17 ++ tests/test_watch_pins.py | 153 ++++++++++++++++++ tests/test_watch_probe_errors.py | 23 +++ 26 files changed, 1437 insertions(+), 126 deletions(-) create mode 100644 docs/audit/2026-06-11-watch-slot-monitoring-enhancements.md create mode 100644 docs/audit/2026-06-12-watch-slot-monitoring-deploy.md create mode 100644 docs/changelog/2026-06-11-watch-probe-parse-error-fix.md create mode 100644 docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md create mode 100644 docs/changelog/2026-06-12-watch-ttl-expiry-race-fix.md create mode 100644 docs/reports/2026-06-12-watch-bug-patrol.md create mode 100644 docs/reports/2026-06-12-watch-slot-monitoring-patrol.md create mode 100644 server/utils/watch_probe_errors.py create mode 100644 server/utils/watch_state.py create mode 100644 tests/test_watch_probe_errors.py diff --git a/docs/audit/2026-06-11-watch-slot-monitoring-enhancements.md b/docs/audit/2026-06-11-watch-slot-monitoring-enhancements.md new file mode 100644 index 00000000..b8d5306d --- /dev/null +++ b/docs/audit/2026-06-11-watch-slot-monitoring-enhancements.md @@ -0,0 +1,117 @@ +# 审计 — 监测槽开关 / 8h·24h / 暂停占槽 / 探针中文错误 + +**日期**:2026-06-11 +**Changelog**: +- `docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md` +- `docs/changelog/2026-06-11-watch-probe-parse-error-fix.md` + +## 范围(未提交工作区,+799 / −124 行) + +| 层级 | 文件 | +|------|------| +| 模型/迁移 | `server/domain/models/__init__.py`(`monitoring_enabled`、`ttl_hours`) | +| | `server/infrastructure/database/migrations.py` | +| Repository | `server/infrastructure/database/watch_repo.py` | +| Service | `server/application/services/watch_service.py` | +| API | `server/api/watch.py`(PATCH monitoring / ttl) | +| 探针 | `server/background/watch_probe_runner.py` | +| | `server/infrastructure/ssh/remote_probe.py` | +| 工具 | `server/utils/watch_metrics.py` | +| | `server/utils/watch_state.py`(**新增** Redis 清理) | +| | `server/utils/watch_probe_errors.py`(**新增** 中文错误) | +| 前端 | `frontend/src/composables/useWatchPins.ts` | +| | `frontend/src/components/watch/WatchSlotCard.vue` | +| | `frontend/src/components/watch/WatchSlotRow.vue` | +| | `frontend/src/components/watch/WatchProbeRecordsTable.vue` | +| | `frontend/src/utils/watchFormat.ts` | +| | `frontend/src/api/index.ts`(`http.patch`) | +| 测试 | `tests/test_watch_pins.py` | +| | `tests/test_watch_metrics.py` | +| | `tests/test_watch_probe_errors.py`(**新增**) | + +## 功能摘要 + +1. **实时监测开关**:`monitoring_enabled`;关则停 5s 探针,槽位保留 +2. **8h / 24h**:`ttl_hours` + `PATCH /pins/{slot}/ttl`;默认 8h,显式切 24h +3. **暂停永久占槽**:`monitoring_enabled=false` 时不参与 TTL 过期删除 +4. **时长到期**:自动暂停(等同关开关),结束 session,**不删 pin** +5. **恢复 Agent 60s**:无活跃监测时清理 `watch:live/proc/last`;Agent 心跳逻辑未改 +6. **parse_error 修复**:Agent 有 CPU/内存时 SSH 失败不拖垮整轮;SSH 脚本加固 +7. **错误中文**:后端写入 + 前端 `formatProbeError` 兼容历史英文 + +## Step 3 规则扫描 + +| H | 规则 | 结论 | +|---|------|------| +| H1 | 鉴权 / IDOR | **PASS** — 新 PATCH 均 `get_current_admin`;repo 带 `admin_id` | +| H2 | 无静默吞错 | **PASS** — 探针失败仍落库;Redis 清理失败会抛错(生产有 Redis) | +| H3 | 无新密钥 | **PASS** | +| H4 | CUD 审计 | **PASS** — `watch_pin_pause` / `watch_pin_resume` / `watch_pin_ttl` / remove | +| H5 | 输入边界 | **PASS** — `Literal[8,24]`、`slot_index` 0–3 | +| H6 | 迁移 | **PASS** — ALTER + duplicate column 容错 | +| H7 | 产品风险 | **RISK 接受** — 4 槽均可永久暂停占用,需手动 X 释放(用户明确要求) | + +## 逐模块走读 + +### 后端 + +| 模块 | 结论 | 备注 | +|------|------|------| +| `watch_repo._pin_still_occupied` | PASS | 暂停不占 TTL;开启监测才看过期 | +| `expire_due_pins` | PASS | 改为暂停 + end session,不 delete pin | +| `set_monitoring_enabled` + `_ensure_open_session` | PASS | TTL 到期后再开自动新 session | +| `_restore_idle_agent_watch` | PASS | 全局无监测才清 Redis | +| `replace_slot` | PASS | 保留槽位原 `ttl_hours`(审查项已修) | +| `probe_server_metrics` | PASS | Agent 基础指标优先;SSH 仅补 IO | +| `watch_probe_error_zh` | PASS | 与前端映射一致 | + +### 前端 + +| 模块 | 结论 | 备注 | +|------|------|------| +| `WatchSlotCard` | PASS | 开关 + 8h/24h + 暂停态 UI | +| `tickCountdown` | PASS | 归零 `refreshPins`,不再误置 `empty` | +| `formatProbeError` | PASS | 状态/错误/来源中文化 | +| `WatchProbeRecordsTable` | PASS | 筛选器与列中文 | + +## 审计中发现并修复 + +| 项 | 严重度 | 处理 | +|----|--------|------| +| `mock_watch_redis` 未 patch `watch_state.get_redis` | **P1** | 已修:`remove_slot` / `set_slot_monitoring` 单测 2 失败 → 19 passed | + +## 遗留建议(非阻塞) + +| 项 | 说明 | +|----|------| +| 设计文档 | 开关/暂停语义变更较大,建议补 `docs/design/specs/` 短文(当前仅 changelog) | +| HTTP 集成测试 | PATCH monitoring/ttl 的 404/422 路径未覆盖 | +| TTL 到期审计 | 后台 `expire_due_pins` 无 audit_log(可接受,session.end_reason=expired 可查) | +| PATCH 404 语义 | 「槽位无效」与「槽位为空」均 404,与 POST 422 不一致 | + +## Closure + +| H | 判定 | 依据 | +|---|------|------| +| H1–H6 | **PASS** | 鉴权、审计、迁移、探针落库均符合铁律 | +| H7 | **RISK 接受** | 用户要求暂停永久占槽 | + +## DoD + +- [x] `.venv/bin/pytest tests/test_watch_metrics.py tests/test_watch_pins.py tests/test_watch_probe_errors.py` — **19 passed** +- [x] `cd frontend && npm run type-check` +- [x] 审计修复:test fixture patch `watch_state.get_redis` +- [ ] `bash scripts/local_verify.sh` / 门控 7 道(部署前) +- [ ] 生产浏览器:开关暂停、24h 切换、到期自动暂停、中文错误展示 + +## 验证命令 + +```bash +.venv/bin/pytest tests/test_watch_metrics.py tests/test_watch_pins.py tests/test_watch_probe_errors.py -q +cd frontend && npm run type-check +bash deploy/pre_deploy_check.sh +``` + +## 合并建议 + +**Approve with notes** — 功能完整、测试绿、安全与审计达标;部署前跑门控 + 浏览器终验。遗留 HTTP 集成测试与设计文档可跟进 PR。 diff --git a/docs/audit/2026-06-12-watch-slot-monitoring-deploy.md b/docs/audit/2026-06-12-watch-slot-monitoring-deploy.md new file mode 100644 index 00000000..7171117a --- /dev/null +++ b/docs/audit/2026-06-12-watch-slot-monitoring-deploy.md @@ -0,0 +1,67 @@ +# 审计 — 监测槽开关 / TTL / 到期竞态 / 探针中文 / 移除提示 + +**日期**:2026-06-12 +**Changelog**: +- `docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md` +- `docs/changelog/2026-06-11-watch-probe-parse-error-fix.md` +- `docs/changelog/2026-06-12-watch-ttl-expiry-race-fix.md` + +## 范围(文件清单) + +| 层级 | 文件 | +|------|------| +| 模型/迁移 | `server/domain/models/__init__.py` | +| | `server/infrastructure/database/migrations.py` | +| Repository | `server/infrastructure/database/watch_repo.py` | +| Service | `server/application/services/watch_service.py` | +| API | `server/api/watch.py` | +| 探针 | `server/background/watch_probe_runner.py` | +| | `server/infrastructure/ssh/remote_probe.py` | +| 工具 | `server/utils/watch_metrics.py` | +| | `server/utils/watch_state.py` | +| | `server/utils/watch_probe_errors.py` | +| 前端 | `frontend/src/api/index.ts` | +| | `frontend/src/composables/useWatchPins.ts` | +| | `frontend/src/components/watch/WatchSlotCard.vue` | +| | `frontend/src/components/watch/WatchSlotRow.vue` | +| | `frontend/src/components/watch/WatchProbeRecordsTable.vue` | +| | `frontend/src/utils/watchFormat.ts` | +| 测试 | `tests/test_watch_pins.py` | +| | `tests/test_watch_metrics.py` | +| | `tests/test_watch_probe_errors.py` | + +## Step 3 规则扫描 + +| H | 规则 | 结论 | +|---|------|------| +| H1 | 鉴权 / IDOR | PASS — PATCH/DELETE 均 `get_current_admin` + admin_id 隔离 | +| H2 | 无静默吞错 | PASS — 探针失败落库;前端 remove/monitoring/ttl 均有 snackbar | +| H3 | 无新密钥 | PASS | +| H4 | CUD 审计 | PASS — pause/resume/ttl/remove | +| H5 | 输入边界 | PASS — `Literal[8,24]`、slot 0–3 | +| H6 | 迁移 | PASS — monitoring_enabled + ttl_hours ALTER | +| H7 | TTL 竞态 | PASS — `_finalize_due_pins` 读/写路径同步到期 | + +## Closure + +| H | 判定 | 依据 | +|---|------|------| +| H1–H6 | PASS | 鉴权、审计、迁移、探针落库 | +| H7 | PASS | 到期 ghost pin 不再显示空槽 | + +## DoD + +- [x] `pytest tests/test_watch_*.py` — 21 passed +- [x] `npm run type-check` +- [x] P0 TTL 竞态修复 + P2 onRemove snackbar +- [ ] `bash deploy/pre_deploy_check.sh` +- [ ] 生产浏览器终验 + +## 验证命令 + +```bash +.venv/bin/pytest tests/test_watch_*.py -q +cd frontend && npm run type-check +bash scripts/local_verify.sh +bash deploy/pre_deploy_check.sh +``` diff --git a/docs/changelog/2026-06-11-watch-probe-parse-error-fix.md b/docs/changelog/2026-06-11-watch-probe-parse-error-fix.md new file mode 100644 index 00000000..16e3ded0 --- /dev/null +++ b/docs/changelog/2026-06-11-watch-probe-parse-error-fix.md @@ -0,0 +1,41 @@ +# 监测槽 parse_error 修复 + +**日期**: 2026-06-11 + +## 摘要 + +修复监测槽显示 `parse_error` 的常见路径:Agent 有心跳但缺 IO 时 SSH 补采失败导致整轮探针失败。 + +## 根因 + +- `redis_sample_has_io` 为 false 时强制走 SSH;SSH JSON 解析失败且无完整 Redis IO 时返回 `parse_error` +- 已装 Agent 的机器通常有 CPU/内存心跳,不应因 SSH 失败而整轮失败 +- SSH 脚本在 `getloadavg`/`net_io_counters` 异常时可能无 JSON 输出 + +## 修复 + +- Agent 有 CPU/内存时优先用 Redis;SSH 仅补充 IO,SSH 失败仍显示 Agent 指标 +- SSH 探针脚本增加 try/except;JSON 解析支持行内 `{` 前缀噪声 +- 前端 `parse_error` 显示为「探针解析失败」,并展示 `metrics.error` 详情 + +## 2026-06-11 补充:错误中文提示 + +- 新增 `server/utils/watch_probe_errors.py`,新探针失败写入中文 `error` +- 前端 `formatProbeError` / `probeStatusLabel` / `probeSourceLabel` 统一中文(含历史英文记录) +- 监测历史探针记录表:状态筛选与错误列中文化 + +## 涉及文件 + +- `server/background/watch_probe_runner.py` +- `server/utils/watch_metrics.py` +- `server/infrastructure/ssh/remote_probe.py` +- `frontend/src/utils/watchFormat.ts` +- `frontend/src/components/watch/WatchSlotCard.vue` +- `tests/test_watch_metrics.py` + +## 验证 + +```bash +pytest tests/test_watch_metrics.py -q +cd frontend && npm run type-check +``` diff --git a/docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md b/docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md new file mode 100644 index 00000000..f167132d --- /dev/null +++ b/docs/changelog/2026-06-11-watch-slot-monitoring-toggle.md @@ -0,0 +1,55 @@ +# 监测槽实时监测开关 + +**日期**: 2026-06-11 + +## 摘要 + +为每台已固定监测槽的服务器增加「实时监测」开关。关闭后停止 5 秒探针与 WebSocket 推送,槽位仍保留同一台服务器,8 小时倒计时暂停;重新开启时重置 8 小时窗口。 + +## 动机 + +用户希望随时关闭某台服务器的实时监测,而不必等到 8 小时到期或点击删除释放槽位。 + +## 涉及文件 + +- `server/domain/models/__init__.py` — `WatchPin.monitoring_enabled` +- `server/infrastructure/database/migrations.py` — 列迁移 +- `server/infrastructure/database/watch_repo.py` — 暂停/恢复、过期逻辑 +- `server/application/services/watch_service.py` — `set_slot_monitoring`、槽位 payload +- `server/api/watch.py` — `PATCH /api/watch/pins/{slot_index}/monitoring` +- `server/background/watch_probe_runner.py` — 仅探针已开启的 pin +- `frontend/src/api/index.ts` — `http.patch` +- `frontend/src/composables/useWatchPins.ts` +- `frontend/src/components/watch/WatchSlotCard.vue` +- `frontend/src/components/watch/WatchSlotRow.vue` +- `tests/test_watch_pins.py` + +## 迁移 / 重启 + +- 需 API 重启以执行 schema migration(`monitoring_enabled` 列) +- 无需手动 SQL + +## 验证 + +```bash +pytest tests/test_watch_pins.py -q +cd frontend && npm run type-check +``` + +- 仪表盘监测槽:开关关闭 → 卡片灰显、无实时指标;重新开启 → 恢复探针并重置倒计时 +- 时长切换:默认 8h;点击 24h → 重置为 24 小时窗口;暂停时切换时长保留偏好,开启后生效 + +## 2026-06-11 补充:暂停永久占槽 + 恢复 Agent 60s + +- **暂停/时长到期**:不再删除 pin;`monitoring_enabled=false`,槽位永久保留直至手动移除或重新开启 +- **8h/24h 到期**:自动暂停(等同关开关),结束 session(`expired`),保留槽位 +- **恢复 Agent 模式**:当无任何槽位对该机开启 5s 监测时,清理 `watch:live/proc/last` Redis;子机 Agent 始终 60s 智能心跳(CPU 波动 >10% 或超阈值才上报),无需改 Agent 配置 +- **重新开启**:若 session 已结束则自动开新 session +- **涉及**:`server/utils/watch_state.py`、`watch_repo.expire_due_pins`、`watch_service`、`watch_probe_runner`、前端 countdown 到期 refresh + +## 2026-06-11 补充:8h / 24h 时长选项 + +- `watch_pins.ttl_hours` 列(默认 8,仅允许 8 或 24) +- `PATCH /api/watch/pins/{slot_index}/ttl` — 切换时长;监测开启时同步重置 `expires_at` +- `POST /api/watch/pins` 可选 `ttl_hours: 8 | 24`(默认 8) +- 槽位卡片「8h / 24h」切换按钮,须显式点击才改为 24h diff --git a/docs/changelog/2026-06-12-watch-ttl-expiry-race-fix.md b/docs/changelog/2026-06-12-watch-ttl-expiry-race-fix.md new file mode 100644 index 00000000..14f0418a --- /dev/null +++ b/docs/changelog/2026-06-12-watch-ttl-expiry-race-fix.md @@ -0,0 +1,35 @@ +# Changelog — 监测槽 TTL 到期竞态修复 + +**日期**:2026-06-12 + +## 摘要 + +修复 TTL 到期与后台 `expire_due_pins`(5s 探针循环)之间的竞态窗口:槽位短暂显示为空、无法添加/移除、可能触发唯一约束冲突。 + +## 动机 + +`list_active_pins_for_admin` 在 `monitoring_enabled=true` 且 `expires_at<=now` 时排除 pin,但 DB 行仍在且 `monitoring_enabled` 仍为 true,直到探针循环执行 `expire_due_pins`。此窗口内 UI 显示空槽,但 `create_pin` 会因 `uq_watch_pins_admin_slot` 失败。 + +## 变更 + +- `WatchService._finalize_due_pins()`:在读/写路径同步到期 pin(暂停 + end session + 按需清 Redis) +- 在 `list_slots`、`pin_server`、`replace_slot`、`remove_slot`、`set_slot_monitoring`、`set_slot_ttl` 入口调用 +- 新增单测:`test_watch_pin_ttl_expiry_list_syncs_before_display`、`test_watch_pin_ttl_expiry_pin_server_no_duplicate` +- **P2**:`WatchSlotRow.onRemove` 失败时 snackbar 提示 + +## 涉及文件 + +- `server/application/services/watch_service.py` +- `frontend/src/components/watch/WatchSlotRow.vue` +- `tests/test_watch_pins.py` + +## 迁移 / 重启 + +- 无需迁移 +- 需重启 API + +## 验证 + +```bash +.venv/bin/pytest tests/test_watch_pins.py -q +``` diff --git a/docs/reports/2026-06-12-watch-bug-patrol.md b/docs/reports/2026-06-12-watch-bug-patrol.md new file mode 100644 index 00000000..9096a58f --- /dev/null +++ b/docs/reports/2026-06-12-watch-bug-patrol.md @@ -0,0 +1,40 @@ +# Bug 巡查 — 监测槽增强(2026-06-12) + +**范围**:工作区未提交的 watch 开关 / TTL / 探针修复 +**方法**:代码走读 + 单测 + 竞态分析 + +## 发现与处理 + +| # | 严重度 | 问题 | 状态 | +|---|--------|------|------| +| 1 | **P0** | TTL 到期后 ~5s 内槽位显示「空」,但 DB ghost pin 仍在;添加服务器 → 唯一约束冲突;点 X 移除 → 404「槽位为空」 | **已修** — API 读/写路径同步 `_finalize_due_pins` | +| 2 | P2 | `onRemove` 无 try/catch,API 失败时未提示 | 未修(低概率,可跟进) | +| 3 | P3 | 暂停态仍可通过 `get_processes` 拉取进程(数据可能过期) | 设计可接受 | +| 4 | — | Gate 7 被并行 Agent 提示改动阻塞 | 非 watch bug | + +## P0 根因 + +``` +expires_at 已过 + → list 查询 or_(paused, expires_at>now) 排除该行 + → UI empty=true + → DB 仍有 monitoring_enabled=true 的行 + → create_pin / pick 槽位 → IntegrityError +``` + +探针循环每 5s 才跑 `expire_due_pins`,此前无 API 侧兜底。 + +## 修复 + +`WatchService._finalize_due_pins()` 在 `list_slots` 及所有槽位变更 API 入口调用,与探针循环逻辑一致:暂停 pin、结束 session、无活跃监测时清 Redis。 + +## 测试 + +```text +pytest tests/test_watch_pins.py → 7 passed +pytest tests/test_watch_*.py → 21 passed +``` + +## 未部署 + +生产仍为旧版本;修复需部署后浏览器终验 TTL 归零场景。 diff --git a/docs/reports/2026-06-12-watch-slot-monitoring-patrol.md b/docs/reports/2026-06-12-watch-slot-monitoring-patrol.md new file mode 100644 index 00000000..d07d4668 --- /dev/null +++ b/docs/reports/2026-06-12-watch-slot-monitoring-patrol.md @@ -0,0 +1,100 @@ +# 巡检 — 监测槽开关 / 8h·24h / 暂停占槽 / 探针修复 + +**日期**:2026-06-12 +**范围**:工作区未提交改动(监测槽增强 + parse_error 修复 + 中文错误) +**生产**:https://api.synaglobal.vip(**尚未部署本批改动**) + +## 进度条 + +| 步骤 | 状态 | +|------|------| +| 实现 | ✅ 工作区完成 | +| 本地验证 | ✅ L2b 26/26 + ruff | +| 单测 | ✅ watch 23/23 | +| 类型检查 | ✅ vue-tsc | +| 门控 7/7 | ⚠️ 6/7(Gate 7 被 **Agent 提示** 并行改动阻塞,非 watch 本身) | +| 部署 | ❌ 未执行 | +| 生产健康 | ✅ `/health` → `ok` | +| 浏览器终验 | ❌ 待部署后 | + +## 本地验证 + +### 单测 + +```text +pytest tests/test_watch_*.py tests/test_watch_probe_errors.py +→ 23 passed +``` + +### L2b API E2E(local_verify.sh) + +```text +26/26 passed +ruff F: All checks passed +═══ All local checks passed ═══ +``` + +### 前端 + +```text +npm run type-check → PASS +``` + +### 门控 pre_deploy_check.sh + +| Gate | 结果 | +|------|------| +| 1 Changelog | PASS(2026-06-12-server-agent-action-hint.md) | +| 2 Audit | PASS(2026-06-12-files-watch-ui-fixes.md) | +| 3 Test | PASS | +| 4 Lint | PASS | +| 5 Import | PASS | +| 6 Security | PASS | +| 7 Review | **BLOCK** — 以下文件有 diff 但未列入当日 audit | + +Gate 7 阻塞文件(**Agent 版本提示**,与监测槽无关): + +- `frontend/src/components/servers/ServerAgentHint.vue` +- `frontend/src/components/servers/ServerInlineDetail.vue` +- `frontend/src/composables/servers/useServerFormDialog.ts` +- `frontend/src/types/api.ts` +- `server/api/servers.py` +- `server/utils/agent_version.py` +- `tests/test_agent_version.py` + +监测槽改动已有独立审计:`docs/audit/2026-06-11-watch-slot-monitoring-enhancements.md`。 + +## 生产探针 + +| 检查 | 结果 | +|------|------| +| `GET /health` | 200 `ok` | +| `GET /app/` | 200 | +| `GET /api/watch/pins`(无 JWT) | 401(预期) | +| `PATCH /api/watch/pins/0/monitoring`(无 JWT) | 401(端点存在性需部署后带 JWT 终验) | + +**说明**:生产当前运行的是已部署版本;监测槽开关 / TTL PATCH / 中文错误 / parse_error 修复均在工作区,**线上行为未变**。 + +## 功能验收清单(部署后浏览器终验) + +1. **开关暂停**:关实时监测 → 5s 探针停止,槽位仍占用,UI 显示暂停态 +2. **重新开启**:开开关 → 若 session 已结束则自动开新 session,探针恢复 +3. **8h / 24h**:默认 8h;点 24h 后 `expires_at` 延长;replace 槽位保留原 TTL +4. **TTL 到期**:自动暂停(不删 pin),Agent 恢复 60s 智能心跳 +5. **parse_error**:Agent 有 CPU/内存时 SSH 失败不应整轮 parse_error +6. **中文错误**:探针失败状态与错误列显示中文 + +## 部署前待办 + +1. **Gate 7**:为 Agent 提示改动补 audit,或与监测槽分两次提交/部署 +2. **迁移**:`watch_pins.monitoring_enabled` + `ttl_hours`(migrations.py 已含) +3. **部署**:用户批准后 `bash deploy/deploy-production.sh` +4. **前端构建**:Docker 内 vite build 或 `deploy/deploy-frontend.sh` + +## 本次巡检修复 + +- 删除 `server/infrastructure/ssh/remote_probe.py` 未使用的 `import logging`(local_verify ruff F401) + +## 结论 + +**代码质量就绪**(单测 + L2b + lint + 类型检查均通过)。**部署被 Gate 7 阻塞**(并行 Agent 提示改动缺 audit)。监测槽功能本身审计完备,建议与 Agent 提示改动解耦提交,或补全 audit 后一并部署。 diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index f3b82185..47e9ab7e 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -296,6 +296,9 @@ export const http = { put: (path: string, body?: unknown) => api(path, { method: 'PUT', body: body ? JSON.stringify(body) : undefined }), + patch: (path: string, body?: unknown) => + api(path, { method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), + delete: (path: string) => api(path, { method: 'DELETE' }), diff --git a/frontend/src/components/watch/WatchProbeRecordsTable.vue b/frontend/src/components/watch/WatchProbeRecordsTable.vue index 28f2afe9..893981fe 100644 --- a/frontend/src/components/watch/WatchProbeRecordsTable.vue +++ b/frontend/src/components/watch/WatchProbeRecordsTable.vue @@ -1,7 +1,7 @@