feat(ops): show service version and uptime on the operator overview - #174
Merged
Merged
Conversation
The operator runtime overview had no way to read the deployed build's version,
so confirming which build is live required curling /healthz by hand.
- GET /api/ops/runtime now returns `version` (env!("CARGO_PKG_VERSION"), the
same source /healthz uses) plus uptime_secs / uptime_days / uptime_hours /
uptime_minutes / uptime_secs_rest. Carrying is done in one place, backend
side (split_uptime), instead of in both language packs.
- AppState gains `started_at` (std::time::Instant) to measure uptime on a
monotonic clock.
- The operator overview renders the two new stat cards, matching the prototype
(docs/prototype/aitokenpool-console.html:1386). The version is read from the
response, never hardcoded: the prototype's own "v0.7.20" was a literal that
was already stale the day it was written.
- New bilingual keys ops.stats.version{,.sub}, ops.stats.uptime{,.sub} and
ops.uptime.{days,hours,minutes,seconds}; the i18n_pack gate's maintained
counts move 775 -> 783 keys and 520 -> 531 call sites.
The prototype's third card (错误率) is deliberately not built: the backend has
no 5xx/timeout counter, so it could only be fabricated.
7 tasks done
argszero
added a commit
that referenced
this pull request
Sep 28, 2026
`ui/README.md`'s "设置 / 管理 / 运营布局约定(v1.22)" section still calls the operator overview's key card "上游 key 健康" and lists its three pills as "健康 / N 个异常 / 全部失败". That was true when `7d9b56e` (PR #174) wrote the line; C2158 (#269, `e5ee178`) then renamed the card and rewrote the pills, because the data has no health signal at all — `/api/ops/runtime` only returns `total` / `on` / `off`. #269 updated only the section it added itself further down this same file (`:1080`, which says the opposite), leaving this line behind, and its edit sheet (4 files / 7 edits) never listed it. Correct the wording to what the code ships: the title is `ops.keys.title` ("上游 key 状态") and the pills are `ops.keys.allOn` / `someOff` / `allOff` ("全部启用 / N 个停用 / 全部停用"). No gate: this is prose restating an implementation name, and the repo's standing decision for that axis is to fix the data, not to guard the prose (see PRs #309, #310, #312–#315). Verified on the branch tree: `cargo test` 417 passed / 0 failed (unchanged baseline), `cargo fmt --check` and `cargo clippy --all-targets -D warnings` both clean. The other claims on the same line were re-checked and are still true (`version` ← `env!("CARGO_PKG_VERSION")`, the five `uptime_*` fields, `split_uptime`, `fmtUptime`'s top-two-nonzero units, `ops.uptime.*`, `today_hours` zero-filled 0–23). The one remaining occurrence of the old wording (`:1084`) is the C2158 section quoting it as history and is left untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
运营视图「运行概览」此前完全读不到当前部署的版本号(
grep -rn version ui/为空),确认线上跑的到底是哪个 build 只能手工curl /healthz。本 PR 补上原型docs/prototype/aitokenpool-console.html:1386的服务版本与运行时长两张卡,值全部来自后端真实数据。Related Issue
无关联 issue。本改动来自对原型与实现的功能面差异扫描(
docs/prototype/aitokenpool-console.htmlvsui/):该扫描的结论是运营概览是唯一存在真实功能缺口的视图,其余维度(视图标题 9/9、卡片标题 29/29、列头 38/38、按钮 54/57——其余 3 处是改名)均已对齐。Changes
GET /api/ops/runtime新增version与uptime_secs/uptime_days/uptime_hours/uptime_minutes/uptime_secs_rest;version取自env!("CARGO_PKG_VERSION"),与/healthz(src/routes/mod.rs:121)同源。AppState新增started_at: std::time::Instant(单调时钟,不受系统时间调整影响);进位在后端一处完成(split_uptime),不放到两个语言包里各写一遍。ui/js/app.jsrenderOps)——版本号取自响应,绝不写死。原型那张卡里的v0.7.20是写下当天就已过期的字面量,这正是要避免的做法。ops.stats.version{,.sub}/ops.stats.uptime{,.sub}/ops.uptime.{days,hours,minutes,seconds}(zh/en 同步,键集相等)。ui/README.md运营视图条目更新为四张卡;cache-bust?v=20260911-15→?v=20260911-16(5 处)。config/config.example.toml无变化。刻意不做的部分:原型第三张卡错误率未实现。后端不存在任何 5xx / 超时计数器,实现它只能凭空造数,与本仓「零 mock」约定冲突。等真实埋点落地再补。
Tests
cargo test全部通过 —— 163 passed / 0 failed(原 161 + 新增 2)cargo fmt --check通过cargo clippy --all-targets -- -D warnings0 warning新增测试与证据:
split_uptime进位单测(src/routes/ops.rs,2 个):已知真值表(0 / 59 / 60 / 3599 / 3600 / 86399 / 86400 / 86460 / 「6 天 4 小时」/ 400 天)+ 区间无损归一性(0..100_000每 7 秒)。已用负向对照验证有牙齿:把secs % 60改成secs % 3600⇒ 两个测试各自变红并点名错值((0,0,1,60)、拼不回原值: 63);文件用cp+ md5 逐字节还原(绝不git checkout/stash)。路由测试扩展(
src/routes/mod.rsops_runtime_credits_users):version与/healthz同源、四位分解能拼回uptime_secs、各位已归一、且刚构造的AppState运行时长 < 60s(起点取自构造时而非更早的静态时刻)。A/B 运行时证明(同一生成器取
git show HEAD:ui/js/app.js与工作树):用真实renderOps的#ops-stats表达式 + 真实fmtUptime+ 虚构响应version: "9.9.9"求值 —— BEFORE 6 张卡(无版本/时长卡),AFTER 8 张卡且新卡紧随「运行状态」(与原型顺序一致),渲染出9.9.9(证明值来自响应而非硬编码)、6 天 4 小时;阴性对照:渲染结果里不含v0.7.20。process.env传递却在模块加载后才赋值 ⇒T()拿到空包、全部报!!MISSING。已加阳性对照(断言包解析出 783 键且ops.stats.version == "服务版本")后才采信结果。Checklist
feat/ops-version-uptime-cardsfeat(ops): ...i18n 门禁计数是有意更新的:
src/i18n_pack.rs的阳性对照真值随本次改动从 775→783 键、520→531 调用点(去重 418→426)。这是该门禁设计的维护方式(注释里已写明);它先以 panic 拦下我一次——我最初把调用点增量估成 +6,实际是 +11,是门禁报出的实际值纠正了我。