feat: verbose mode for the top summary panels — instance overview (010)#145
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reframe from a separate overview screen to a verbose toggle of the sysstat/pgstat top panels (no duplication antipattern). Full data layout pinned (iostat/nicstat/filesyst + workload/databases/workers/ replication/bgwr-ckpt). R1 + tiering return; size L. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply non-blocking findings: weight the layout() geometry rework as the invasive core (not the printers); clarify guard throttles only non-panel aggregates (system rows stay fresh for consistency); note net-new GUC reads; precise height-guard threshold; explicit integration-test rationale; implementation-sequencing note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verbose-panel mode: 11 tasks across 3 waves + QA. Invasive core = layout() geometry + all-three collection branch; no new view (zero view-count test churn). 10 decisions, full data/test/risk plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Re-decompose into 5 file-disjoint waves (10 tasks): no two parallel tasks touch the same file; hot files sequenced across waves. - Fold architect MAJOR: toggleVerbose skips collectStat Reset (prev.Verbose!=v.Verbose continue branch) — Decision 2 + Task 2. - Security: archiving as own QueryRow (per-row n/a), EvalSymlinks robustness->n/a, no raw error text — Risks + Tasks 5/8. - Decision 9: concrete guard threshold + verboseCollectState sub-struct. - Trim rationale from task descriptions; add dev-security-auditor to the path/symlink task; field-layout note delegates to user-spec. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve last minor: drop duplicate fsstat.go from Task 8 Files-to-read. Wave conflicts + Reset-skip confirmed fixed; tech-spec-validator and architect re-approved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Task 05 depends_on ["04"]->["02","04"] (gates on view.Verbose). - First-tick n/a no longer relies on nil slice (collect* sets prev=curr on mismatch): explicit verboseFirstTick flag in Task 07, consumed by Task 08, grouped into verboseCollectState + cmdline hint in Task 09. - Minor: Task 01 Mbps divisor pointer -> top/stat.go:741; Task 02 continue precedes both Resets; link conventions normalized. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
verboseFirstTick must re-arm on every verbose OFF->ON re-enable (toggleVerbose skips Reset per Decision 2), else a re-enabled session computes deltas vs a stale prev. Task 07 adds prevVerboseActive and sets the flag when verbose runs and was off last tick (no Reset dependency); Task 09 carries both fields into verboseCollectState and re-shows the collecting hint. Minor: corrected connect-or-fail test pattern wording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…amic unit suffix) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split printSysstat/printPgstat into thin *gocui.View wrappers that delegate to writer-based renderSysstat/renderPgstat(w io.Writer, …), mirroring the printDbstat → renderDbstat precedent. Compact output stays byte-identical (golden tests on bytes.Buffer encode this). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend SelectCommonProperties with five new reads (max_worker_processes, max_logical_replication_workers, max_parallel_workers, wal_segment_size as int64 bytes via pg_size_bytes, data_directory) and propagate them into PostgresProperties via the GetPostgresProperties scan in lockstep order. Extend TestGetPostgresProperties to cover the new fields. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All three reviewers (code, security, test) approved round 1 with zero critical/major findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wave 1 (01 formatters, 02 toggle plumbing, 03 printer refactor, 04 GUC reads) implemented, reviewed, committed by teammates. Build + affected test packages green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the data layer for the five verbose pgstat panel rows (workload, databases, workers, replication, bgwr/ckpt): version-aware aggregate queries, flat structs, Go-side rates vs the previous snapshot, and wire collection into Collector.Update gated on view.Verbose. New internal/query/overview.go holds the workload/databases/workers/ replication aggregates; replication lag and slots are recovery-aware templates run through Format/NewOptions. bgwr/ckpt reuses the existing SelectStatBgwriterQuery (PG14-16/17/18 layout) with no new SQL. PgstatOverview + collectOverviewStat (internal/stat/postgres.go) run each privileged/expensive aggregate (database-size sum, archiving backlog) as its OWN QueryRow so a 42501 privilege error or archive_mode=off degrades just that field to n/a via an availability flag, without aborting the sample or surfacing raw PG error text. cache hit ratio is per-interval (Δhit/Δ(hit+read)) with division-by-zero -> n/a; tps = commit+rollback; others is an interval delta. Live-PG tests cover PG 14-18, template recovery substitution, archiving backlog degradation, and the verbose on/off gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code review (critical): split the databases aggregate so the expensive sum(pg_database_size) runs as its OWN QueryRow (OverviewDatabasesSize), matching AC/Decision 6/10. A size failure now degrades only TotalSize/ GrowthPerSec to n/a while count and the per-interval cache-hit ratio stay populated; the previous combined query would have cascaded. Corrected the inline comment that falsely claimed the split already existed. Extracted cacheHitRatio() as a pure helper (deterministic n/a on Δ(hit+read) <= 0, never NaN) and dropped redundant `_ = err` noise. Test review: - query tests now QueryRow().Scan(...) into the exact receivers collectOverviewStat uses, so column-count/type drift fails here, not at runtime; added OverviewDatabasesSize coverage. - replaced tautological tps/others `>= 0` checks with an exact-formula assertion against a synthetic prev (itv=2 makes the /itv division observable; others asserted as a raw interval delta, not /s). - Test_cacheHitRatio table test covers the division-by-zero edge directly; the live cache-hit test now uses a deterministic synthetic prev. - degradation test asserts the archiving-backlog field and that degraded replication rows do not blank count/size/cache. - new Test_OverviewBgwriterColumns verifies the by-name bgwriter columns exist on PG14-18 (the real risk of the scan-by-name approach). - verbose-off test now asserts the compact path (Result/Activity) is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract pure topBandLayout(verbose, maxY) into top/layout.go: compact reproduces today's literals byte-identically; verbose grows sysstat +3, pgstat +5 and pushes cmdline/dbstat down to clear the taller panel; a height-guard falls back to compact on terminals too short to fit the expanded band + cmdline + dbstat header + >=1 data row. layout() in top/ui.go consumes the result instead of hard-coded literals and emits a one-shot cmdline hint when verbose is requested but the guard tripped. Table test in top/layout_test.go covers compact / verbose / height-guard / boundary cases, gocui-free (mirrors the visibleColumns precedent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- name the height-guard's header+data-row reservation (minDbstatRows = 2) so the off-by-one is self-documenting at the comparison site (dev-code-reviewer minor). - repurpose the redundant height-guard test row (was maxY=12, identical to boundary-fallback) to a distinct tiny maxY=5, and add a verbose-zero-maxY case pinning that non-positive maxY degrades to compact (dev-test-reviewer minors: redundant_testing + missing_coverage). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wave 2 (05 aggregate SQL + verbose collection, 06 layout geometry) implemented, reviewed, committed. Full `go test ./...` green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the verbose-mode extended rows for both top panels, gated on the verbose flag, inside the writer cores renderSysstat/renderPgstat (Task 3). sysstat (+3 rows): iostat/nicstat select the max-%util / max-Utilization device among active ones (Completed!=0 / Packets!=0), reusing the struct math from count*Usage verbatim (never recomputed) so the rows match the full B/N panels (Decision 5). nicstat rMbps/wMbps replicate printNetdev's print-time Rbytes/1024/128 conversion. filesyst shows the data_directory filesystem via the new MatchDataDirFs longest-mount-prefix matcher (internal/stat/fsstat.go), resolving the symlink with EvalSymlinks only when local; any match/EvalSymlinks failure -> n/a (no panic, no raw-path logging). mounted truncated to 10. pgstat (+5 rows): workload/databases/workers/replication/bgwr-ckpt from the PgstatOverview aggregate (Task 5), using the Task 1 formatters (Ceil/ReserveWidth/RateUnit-family). Unavailable sources and first-tick deltas render the n/a literal, distinguishable from a real 0. First-tick n/a for the system rows is keyed on the collector's verboseFirstTick flag, propagated into Stat.System.VerboseFirstTick (the collector and renderer share state only via Stat) — NOT on len(slice)==0, since collect* populates a zero-delta slice on the first tick. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply the converging code+test review findings (all minor): - Lock the verbose-row layout with full-line golden assertions (reserve width / field order) for iostat/nicstat/filesyst and all five pgstat rows, replacing the substring Contains assertions — the reserve-digit layout is spec-load-bearing. - Strengthen the *_compactUnchanged tests: instead of comparing verbose=false to itself (tautological), assert that the verbose output's first compact rows are byte-identical to the compact render (verbose only appends, never perturbs). - Replace the coarse global NotContains(n/a) in the pgstat available case with positive per-field golden, pinning the bgwr write/sync ms deltas and the maxwritten delta value. - Document the intentional matchDataDirFs -> MatchDataDirFs rename (exported: called across the package boundary from package top) so the TDD anchor name mismatch is traceable. Security review: 0 findings. Code/test reviews: approved, only minors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verbose row composers (both panels) implemented, reviewed, committed. Note: task 08 added a public System.VerboseFirstTick bridge field on stat.Stat to carry Collector's private first-tick flag to the renderer across the channel (reviewer-confirmed minimal). Full go test ./... green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Group verbose-mode collection state into a verboseCollectState sub-struct on Collector (Decision 9), moving the Task-7 first-tick re-arm flags (verboseFirstTick + prevVerboseActive) into it and updating the System.VerboseFirstTick bridge accordingly, preserving the OFF->ON re-arm semantics (no reliance on c.Reset()). Add a per-source latency guard for the dear no-twin db-size/growth aggregate: when its last query exceeded max(25% of refresh, 500ms floor), skip the next collection and reuse the cached stale value (not n/a). System rows and the cheap aggregates collect every tick (consistency). All behind the single z knob — no new user knob. Auto-resumes when latency recovers. collectOverviewStat gains a skipDatabasesSize parameter so the guard can avoid running the expensive sum(pg_database_size) query (same-package, minimal). Wire the first-tick "collecting..." cmdline hint in top/stat.go off the same flag (via Stat.System.VerboseFirstTick), respecting printCmdline mutual exclusion (one call per path). It clears after the first successful refresh and reappears on every OFF->ON re-enable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code-reviewer critical: the latency guard was a one-way latch — skipSize depended only on dbSizeLastLatency, which is updated only on a real collection, so once a query was slow the source was skipped forever and auto-resume never happened. Add a per-source cadence (dbSizeLastRun) so the dear db-size source is throttled only until the cadence budget (one refresh interval) elapses, then force-collected to re-probe its latency — a genuine throttle that auto-resumes when latency recovers. dbSizeThrottled is now a pure 3-arg decision (threshold, budget, sinceLastRun) including the genuine-first-tick guard. Code-reviewer minor: measure the db-size query latency narrowly inside collectOverviewStat (returned as a second value) instead of around the whole overview collection, so a slow neighbour aggregate cannot trip the guard for the wrong source. Code-reviewer minor: document at the printStat call site that the cmdline is event-driven and the hint self-clears via printCmdline's 2s timer. Test-reviewer minors: add Test_verboseCollectState_firstTickNotThrottled (pure genuine-first-tick guard) and drive auto-resume end-to-end through the real Update path (backdating dbSizeLastRun past the budget) in TestCollector_Update_DbSizeThrottle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both round-2 reviewers approved/passed (0 critical/major). Applied the two optional minors: - code-reviewer: note at the dbSizeThrottled call site that the zero-time first-tick time.Since(...) is deliberately unused (short-circuited by the dbSizeCacheValid guard). - test-reviewer: make the end-to-end auto-resume assertion deterministic by also asserting dbSizeLastRun advanced past the backdated value (proves a real collection ran, independent of host timing); the latency-recovery assertion is kept as a coarse smoke check with a note on its wide headroom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tiering + latency guard + first-tick grouping (verboseCollectState) implemented, reviewed (round-1 critical: one-way-latch guard fixed with dbSizeLastRun cadence), committed. Guard threshold max(refresh/4, 500ms). All 9 implementation tasks done; build + stat/top tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All automated gates green (build, test race+coverage 69.7%, gosec 0 issues, go vet + gofmt clean). 6 automated acceptance criteria PASS; 6 visual TUI criteria deferred to user manual verification. govulncheck flags one stdlib advisory (GO-2026-5037, toolchain go1.25.10 -> CI bump) — not feature code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ty, senders/receivers label Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y static Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lesovsky
pushed a commit
that referenced
this pull request
Jun 25, 2026
…ch debt, metrics, archive Post-merge finalization of the verbose-panel feature (merged via PR #145): - project-knowledge: verbose-mode capability (overview), Verbose Top-Panel Mode architecture subsection, 4 reusable patterns. - features-catalog: [010] entry. - decisions-log: 8 ADRs (mode-not-view, dual-boolean, topBandLayout, all-three branch, verboseCollectState re-arm, .ready backlog, databases split, latency guard). - tech-debt: [010]-[015] (recovery-t substitution, rateField/RateUnit dup, Size-field width, golangci-lint v1/v2, tracked bin/pgcenter, GO-2026-5037). - user-spec Post-implementation section; metrics finalized + copied to docs/metrics/; feature dir archived. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lesovsky
added a commit
that referenced
this pull request
Jun 25, 2026
* feat: verbose mode for the top summary panels — instance overview (010) (#145) Adds a verbose toggle (`v`) for the sysstat/pgstat top panels: sysstat +3 rows (iostat/nicstat/filesyst), pgstat +5 rows (workload/databases/workers/ replication/bgwr-ckpt). A display mode (no new view), reusing the free-form render path, persistent across screens. Includes verbose-gated all-three system collection, verboseCollectState (first-tick n/a + collecting hint + re-arm without Reset, latency guard max(refresh/4,500ms)), new formatters (ceil/reserved-digit/dynamic unit suffix), and panel-consistent aggregates. Full go test ./... green (live PG 14-18), gosec clean. TUI-only (NotRecordable). Decision history under docs/features/010-feat-overview-dashboard/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: finalize 010-feat-overview-dashboard — PK, catalog, ADR log, tech debt, metrics, archive Post-merge finalization of the verbose-panel feature (merged via PR #145): - project-knowledge: verbose-mode capability (overview), Verbose Top-Panel Mode architecture subsection, 4 reusable patterns. - features-catalog: [010] entry. - decisions-log: 8 ADRs (mode-not-view, dual-boolean, topBandLayout, all-three branch, verboseCollectState re-arm, .ready backlog, databases split, latency guard). - tech-debt: [010]-[015] (recovery-t substitution, rateField/RateUnit dup, Size-field width, golangci-lint v1/v2, tracked bin/pgcenter, GO-2026-5037). - user-spec Post-implementation section; metrics finalized + copied to docs/metrics/; feature dir archived. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(lint): rename builtin-shadowing vars to satisfy revive revive redefines-builtin-id flagged local vars `max` (Go 1.21+ builtin) in pretty.RateUnit and top.rateField, and `real` (complex builtin) in an fsstat test. Rename to maxFit / realPath. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Alexey Lesovsky <a.lesovsky@postgrespro.ru>
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.
Что
Добавляет режим verbose для двух верхних сводных панелей
pgcenter top(sysstatслева /pgstatсправа), переключаемый клавишейv. Compact — как сейчас (по 4 строки); verbose разворачивает панели: sysstat +3 строки (iostat / nicstat / filesyst) и pgstat +5 (workload / databases / workers / replication / bgwr-ckpt). Это режим, а не новый экран — переиспользует free-formFprintf-путь рендеринга, persistent между экранами, держит расширенную сводку здоровья над любой таблицей.Зачем
Две верхние панели — это уже мини-обзор инстанса; отдельный экран дублировал бы их (антипаттерн). Реальный пробел — панели по 4 строки и не показывают production-сигналы (насыщение диска/сети/ФС, агрегированную нагрузку, суммарный размер БД + рост + cache hit, насыщение воркеров, репликацию/слоты/архивный бэклог, стоимость чекпоинтов), которые сегодня требуют обхода сайд-панелей и экранов. Дифференциатор vs pg_activity: всё работает по сети через PL/Perl, и сводка едет с DBA по экранам.
Как
top/verbose.go(toggle),top/layout.go(чистаяtopBandLayout+ height-guard),internal/query/overview.go(агрегатные SQL).view.View.Verbose+config.verbose;collectStatReset-skip; verbose-gated all-three system collection (R1) с==nil-guards, не трогая mutual-exclusion сайд-панелей.verboseCollectState: first-tickn/a+ cmdlinecollecting...с ре-армом на OFF→ON (безReset()), latency-guardmax(refresh/4, 500ms)(throttle только дорогих агрегатов без панель-двойника → stale, неn/a).%util/Pused/struct-математики).Тесты / QA
go test ./...зелёный (race+coverage, live PG 14–18, 0 FAIL/0 SKIP).gosec0 issues,go vet/gofmtчисто. golangci-lint — в CI (v1-конфиг).Границы / отложено
NotRecordable).tWAL-шаблоны (standby) — проверены подстановкой, не live (нет standby-кластера, техдолг [006]).Полная история решений — в
docs/features/010-feat-overview-dashboard/.🤖 Generated with Claude Code