| 2026-10-10 |

feat: метрики — дайджест бакета при разряжении (крайности и простои не теряются)
...
Прореживание оставляло одну реальную точку на бакет, поэтому всплеск CPU под
98% две минуты или падение, пришедшееся ровно на удалённую точку, исчезали с
графика навсегда. Теперь вместе с выжившей точкой пишется дайджест интервала
в metrics.agg_json: n/exp (пришло замеров против ожидаемых — n < exp значит
простой), min/max по cpu/ram/swap/load/сеть и по каждому маунту диска.
Пишется только там, где бакет реально схлопывается (n > 1), поэтому сырые
сутки остаются сырыми, а повторный прогон ничего не перезаписывает.
- metrics_retention: _Bucket копит крайности; границы бакета для DELETE
собираются через datetime (корректный перенос через час/сутки), удаление —
по индексу, без списка id в памяти.
- схема + ALTER: metrics.agg_json.
- API /servers/{id}/metrics и MCP server_history отдают точку с полем agg;
прореживание внутри тула сливает дайджесты выкинутых точек, а не
выбрасывает их вместе с крайностями.
Eugene Sukhodolskiy
committed
7 hours ago
|

perf: метрики — тяжёлые JSON в server_state, разряжение истории по возрасту
...
Строка метрик худеет с ~5 КБ JSON до ~0.1 КБ: net_json (сырые счётчики),
docker_json, processes_json и extra нужны только от ПОСЛЕДНЕГО пакета, в
истории они были мёртвым грузом (~89% объёма). Теперь они живут в одной
строке server_state на сервер:
- ingest читает предыдущий пакет из server_state (fallback на последнюю
строку метрик — плавный апгрейд на живом деплое), пишет состояние UPSERT;
- GET /servers/{id} берёт процессы/docker/extra из состояния через
LEFT JOIN — контракт API для фронта не менялся;
- в history остаются числа и disks_json (нужны графикам на всю глубину).
Разряжение (app/metrics_retention.py) по возрасту точки: 0–24 ч — всё,
24 ч–3 сут — 1/мин, 3–7 сут — 1/5 мин, 7–365 сут — 1/час, старше года —
удаление. В бакете остаётся реальная последняя точка (бакеты считаются
срезом строки ISO-8601, без парсинга дат). Петля — при старте и каждые
15 минут, затем PRAGMA incremental_vacuum.
Чтобы удалённое возвращалось файлу: auto_vacuum=INCREMENTAL, а на БД,
созданных до этого — разовый VACUUM при старте панели.
Eugene Sukhodolskiy
committed
7 hours ago
|
| 2026-10-05 |
feat: MCP — тулы управления: создание и удаление серверов и сервисов
...
Пишущие тулы переиспользуют роут-функции (server_create возвращает ghm_-
ключ один раз; удаление каскадно чистит метрики/пробы). Запись для всех
валидных ключей — модель панели «любая сессия = админ»; rate-limit 20/10мин
in-memory, ошибки как данные {"error","detail"}. AGENT_INSTRUCTIONS: секция
«Управление (запись)», удаление — только по явной просьбе человека.
Eugene Sukhodolskiy
committed
5 days ago
|
| 2026-10-04 |
feat: персональные MCP-ключи (канон handbook mcp.md)
...
- таблица mcp_tokens: sha256-хэш (unique) + хвост-хинт, снейпшот roles
владельца на момент выпуска; миграции users.system_role/users.blocked
- выдача только из cookie-сессии: GET/POST /me/mcp_tokens (plaintext
ровно один раз, ≥10 активных → 409), ревок вместо архива; админ-роуты
для всех ключей; rate-limit на выдачу (5 за 10 мин)
- гард /mcp — require_mcp: Bearer mcp_* | статический GHARD_ADMIN_TOKEN |
cookie; отозванный/заблокированный — тот же 401 (причина не раскрывается)
- вебхуки user.blocked/deleted/archived → users.blocked=1 + ревок ключей
владельца; разблокировка — при следующем успешном логине; SSO-логаут
ключи не трогает
Eugene Sukhodolskiy
committed
6 days ago
|
feat: MCP — инструкции агенту как prompt agent_guide + тулы сервисов и журнала
...
Инструкции ИИ-агенту раздаются и при initialize (instructions), и как
MCP-prompt agent_guide (паттерн reference-реализации gnexus-creds):
назначение, карта инструментов по типам вопросов, словарь статусов
(online/offline, up/degraded/down + mode не падение) и событий,
правила (read-only, id из overview, история 7 дней).
Новые тулов: services_overview (health-чеки: state/latency/self-report),
service_incidents (моменты недоступности), events_recent (журнал с
фильтром по severity); panel_overview дополнен строкой по сервисам.
Заодно починен мост /mcp: FastAPI валидировал голый ASGI-объект как
endpoint — считывал scope/receive/send query-параметрами и отвечал 422
на любой запрос; теперь реальный endpoint, вручную докручивающий
ASGI-диалог (stateless + json_response — ответ всегда один JSON).
Eugene Sukhodolskiy
committed
6 days ago
|
| 2026-09-11 |
feat: network storage section — panel probes mounted shares itself
...
Backend: shares + share_samples tables, background probe loop
(os.statvfs every GHARD_SHARE_INTERVAL, 7-day retention, ok=0 when
the mount is unreachable), CRUD + samples API, instant first sample
on create/update, shares in MCP panel_overview.
Frontend: /storage page — share cards with status badge/progress/
used-free-total, 24h fill chart, add/delete via modal + confirm.
ChartLine shows a visible point while there are fewer than 3 samples.
README: CIFS/NFS mount + fstab examples, GHARD_SHARE_INTERVAL row.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
29 days ago
|
| 2026-09-10 |
feat: MCP server at /mcp — AI agents read server state from the panel
...
Streamable HTTP, stateless, JSON responses (proxy-friendly). Tools:
panel_overview (fleet summary), server_details (full current state),
server_history (downsampled metrics history). ASGI endpoint registered
directly on FastAPI routes (Mount misses exact /mcp) and the MCP session
manager runs in the app lifespan. mcp SDK pinned >=1.10,<2. README:
tool table, claude mcp add example, token caveat.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 10 Sep
|