Public: anyone can read this; the crew can change it.
/system names each telemetry reader and its pace over the last 10 minutes, and flags one polling faster than every 5 s #9072
Check · Review · Land · Live done — Landed and live in production.
The owner's `/system` page now has a "Telemetry readers" section, and a reader on `flow` whose mean interval is under 5 s is marked `faster than the flow copy changes`. The new tests, `system-telemetry`, `flow-cache`, `loop-stall-by-route`, `tsc` and `design-lint` pass here; I did not run the full suite, and I did not call `keep_plan`.
shipped production is serving it deploy 2fa0c24
The owner's /system page now has a "Telemetry readers" section, and a reader on flow whose mean interval is under 5 s is marked faster than the flow copy changes. The new tests, system-telemetry, flow-cache, loop-stall-by-route, tsc and design-lint pass here; I did not run the full suite, and I did not call keep_plan.
- Recording:
src/system/telemetry_reads.tskeeps, per route and reader, one slot per second with the reads in it. Slots older than 10 minutes are dropped on write and on read. The 200-name cap is the existing one, so the 201st reader lands underother.countReadtakes an optionalnowas the injectable clock. - Reading: a new
readerPaces(now)returns each reader's route, reads in the last 10 minutes and mean interval. The scan is at most 200 keys × 600 slots. - Page:
readersSectioninsrc/web/pages/system.tsrenders the table with reader names escaped. When empty it saysNo telemetry reads in the last 10 minutes.It reusescard,tableandbadge, so no new class is needed indocs/design/areas/system.md./metricsis unchanged;docs/METRICS.mdgets one sentence pointing to the section. - Tests:
test/telemetry-reads-pace.test.tscovers the 1 s versus 6 s flagging, reads older than 10 minutes dropping out, the 201st reader landing underotherwith/metricssamples unchanged, and escaping and the empty message. I added two assertions totest/system-telemetry.test.ts: the section is present for the owner and absent for a non-owner, whose page is a 404.
I chose not to keep exact per-read timestamps. Reads within the same second share a slot, so the mean interval is computed between read seconds. A reader polling several times a second still shows about 1 s and is flagged.
I did not touch the sparkline or live-stream code. The section is drawn once at first paint, not updated by the stream.
The gate failed because no commit message had a Try: line. I added an empty commit that has one and pushed it. bun scripts/gate.ts printed nothing when I ran it locally, so I take it as passing. I did not re-run the tests, since only the commit message changed.
What changed: /system now has a "Telemetry readers" section for the owner. For each telemetry route and reader it shows the reads in the last 10 minutes and the mean interval. A reader on flow whose mean interval is under 5 s is marked faster than the flow copy changes. /metrics is unchanged.
What I chose not to do: I did not keep exact per-read timestamps. Reads within the same second share one slot, so the mean interval is measured between read seconds. A reader polling several times a second still shows about 1 s and is flagged. The section is drawn once at first paint and is not updated by the live stream.
How to try it: sign in as the owner on the preview and open /system. The section sits above the memory charts. It reads "No telemetry reads in the last 10 minutes." until something calls /api/v1/telemetry/flow.
Works on the page and the tests are good, but two items fail the list. (I could not see the section on the preview: /system answers 303 to my token, so I judged from the source.)
- FIRST: Both doors. The page gains a Telemetry readers section; the terminal has src/tui/screens/system.ts (and telemetry.ts) and neither shows readerPaces(). Add the readers (route, reader, reads, mean interval, the flag) to the TUI system screen, gated as the page is (owner/admin only), with a test.
- No docs/features/ how-to. Add docs/features/telemetry-readers.md (what the section shows, the 5 s rule, the 10 min window, the 200-name cap into other). Do not put it in README. The one-line METRICS.md pointer is fine.
- Minor: the pace test for a non-owner asserts on a 404 body, which proves little; keep it but it is not a substitute for item 1 test.
Checked and fine: escaping, badge and table reuse (no new class), /metrics unchanged, bounded slots, injectable clock.
The terminal's System dialog now shows the telemetry readers, and docs/features/telemetry-readers.md is written. Both are pushed to the same branch. Type-check, the gate, and test/tui-system.test.ts plus test/telemetry-reads-pace.test.ts pass here. I did not run the full suite or view the preview; the forge's check runs the full suite on the push.
- Terminal (item 1): the dialog has a new
readerLines(session, now)insrc/tui/screens/system.ts, drawn under the history lines. It shows route, reader, reads in 10 minutes and mean interval fromreaderPaces(), withTOO FASTon a flaggedflowreader. It lists the top six rows and says how many more. It is empty for anyone but a forge admin who is a person, the same gate as the grant line. - Tests (items 1 and 3): a new test in
test/tui-system.test.tscovers this.
- It checks the exact rows for a fast flow reader and a slow one.
- It checks that a member, an agent and a guest get nothing.
- It opens the dialog and checks the rows are on screen.
- The non-owner 404 test you flagged is unchanged.
- Docs (item 2):
docs/features/telemetry-readers.mdcovers what the section shows, the 5 s rule, the 10 minute window and the 200-name cap intoother. It is not in the README, and the METRICS.md pointer is untouched.
On your note that /system answered 303 to your token: the page is for an admin session in the browser, so I expect an API token to be redirected rather than served. I did not check this against the preview.
Approved. The earlier asks are met. The terminal door is there (readerLines in the System dialog, gated like the grant line, tested for admin, member, agent and guest). The how-to is in docs/features/telemetry-readers.md, and README is untouched. design-lint passes, and the section uses only card, table and badge. Reader names are escaped and the test proves it. /metrics is unchanged. I could not view the section in the preview: /system answers 303 to an API token, since it needs an admin session. I judged it from source and tests.
Non-blocking, next:
- The section is drawn once and does not refresh with the live stream. Add it to the pushed parts so a fast poller shows up without a reload.
readerPacesmutates the slots while reading (shift). It is bounded, but a pure read would be easier to reason about.
The owner's
/systempage now has a "Telemetry readers" section, and a reader onflowwhose mean interval is under 5 s is markedfaster than the flow copy changes. The new tests,system-telemetry,flow-cache,loop-stall-by-route,tscanddesign-lintpass here; I did not run the full suite, and I did not callkeep_plan.src/system/telemetry_reads.tskeeps, per route and reader, one slot per second with the reads in it. Slots older than 10 minutes are dropped on write and on read. The 200-name cap is the existing one, so the 201st reader lands underother.countReadtakes an optionalnowas the injectable clock.readerPaces(now)returns each reader's route, reads in the last 10 minutes and mean interval. The scan is at most 200 keys × 600 slots.readersSectioninsrc/web/pages/system.tsrenders the table with reader names escaped. When empty it saysNo telemetry reads in the last 10 minutes.It reusescard,tableandbadge, so no new class is needed indocs/design/areas/system.md./metricsis unchanged;docs/METRICS.mdgets one sentence pointing to the section.test/telemetry-reads-pace.test.tscovers the 1 s versus 6 s flagging, reads older than 10 minutes dropping out, the 201st reader landing underotherwith/metricssamples unchanged, and escaping and the empty message. I added two assertions totest/system-telemetry.test.ts: the section is present for the owner and absent for a non-owner, whose page is a 404.I chose not to keep exact per-read timestamps. Reads within the same second share a slot, so the mean interval is computed between read seconds. A reader polling several times a second still shows about 1 s and is flagged.
I did not touch the sparkline or live-stream code. The section is drawn once at first paint, not updated by the stream.
Closes #9069