Web system administration and monitoring module for ShariX Open and ShariX Platform: component health, logs, backups, module configuration and support requests.

Веб-модуль системного администрирования и мониторинга ShariX Open и ShariX Platform: состояние компонентов, логи, резервные копии, подключение модулей и заявки в техподдержку.

ShariX Developer daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
bin 2d2639a272 S92.6: converge dependency constraints and installation identity 2 weeks ago
handlers 7ef5503697 Stage 16.6 repository update monitoring 1 month ago
integration f652cc7ac2 new scenarios 2 months ago
license_corpus a03a2a5e35 stage 16.1 1 month ago
locale daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
management e87a12eb7c S92.7: update rich-text installation diagnostics 2 weeks ago
migrations 5aedf40510 stage 16.2 1 month ago
services daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
templates 0ceb8404af S92.9 mandatory first-party Blockly canonical source 2 weeks ago
tests dd13bf19d1 S92.10 rebaseline appointments Blockly generator provenance 2 weeks ago
.gitignore e296137469 Snapshot before Django 5.2 upgrade: backup/django-4.2-final 1 month ago
CODING_POLICY.md daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
LICENSE a03a2a5e35 stage 16.1 1 month ago
README.md daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
RELEASE_POLICY.md ab0b233b96 Stage 19.6 release policy and system release projection 1 month ago
__init__.py 1bc3b20994 fix structure 4 months ago
admin.py 1bc3b20994 fix structure 4 months ago
apps.py 7ef5503697 Stage 16.6 repository update monitoring 1 month ago
check_stage15_9.py 4dec9c2b8e Stage 15.9: unify module metadata and source compliance 1 month ago
check_stage16_1.py a03a2a5e35 stage 16.1 1 month ago
forms.py 74a0132c41 stab 2 4 weeks ago
handler_contributions.py 7ef5503697 Stage 16.6 repository update monitoring 1 month ago
models.py 5aedf40510 stage 16.2 1 month ago
page_help.py daf3b03d43 Distinguish recovered systemd restart history from current handler failure 1 hour ago
platform_module.py b8bc5a1748 platform role activation 2 months ago
requirements.txt 1678b0937f initial commit 4 months ago
sharix_access.py 9365d3766a S92.8: add functional handler health evidence 2 weeks ago
sharix_health.py eeab5c47c0 stage 3 module diagnostics 1 month ago
sharix_management.py fcb2bf5aa7 module installation improved 2 months ago
sharix_menu.py b8bc5a1748 platform role activation 2 months ago
sharix_pages.py 92911db2fe Stage 10.4-10.6 onboarding and navigation completion 1 month ago
urls.py 9365d3766a S92.8: add functional handler health evidence 2 weeks ago
views.py 9365d3766a S92.8: add functional handler health evidence 2 weeks ago

README.md

sharix_sysadmin

Подключаемый модуль ShariX для платформы и сервиса: веб-интерфейс системного администрирования для Django admin/staff, METASERVICE-TECHSUPPORT и PLATFORM-TECHSUPPORT.

Что входит

Для системных администраторов

  • единая панель мониторинга компонентов: slapd, ejabberd, postgresql, подключение Django к БД, SMTP/mail-сервер из .env, процессы обработчиков webservice_running/platform_running;
  • показатели нагрузки: load average, RAM, диск проекта;
  • централизованный просмотр логов: journalctl, systemd unit, файлы из logs/, /var/log/sharix, /var/log/messages, /var/log/syslog;
  • фильтры логов по уровню, строке поиска и временному интервалу;
  • создание бэкапа PostgreSQL через pg_dump -Fc в папку backups/;
  • редактирование bin/install.cfg с синтаксической проверкой и сравнением с bin/install.cfg.example;
  • подключение новых модулей через обычный bin/install.cfg, INSTALLED_APPS_LOCAL и универсальный installer;
  • системные операции с явным подтверждением: завершение VSCode/code-server процессов, перезагрузка машины, перезапуск Django systemd unit;
  • журнал действий администраторов.

Для пользователей

  • страница «Заявка в техподдержку»; сообщение превращается в Ticket в модуле tickets, если модель tickets доступна.

Подключение

  1. Скопировать папку sharix_sysadmin в корень платформы или сервиса.
  2. Добавить sharix_sysadmin в INSTALLED_APPS_LOCAL в .env.
  3. Добавить URL в core/urls.py:

    if sv.is_local_app_enabled("sharix_sysadmin"):
    localized_urlpatterns.append(
        path(
            f"{sv.SHARIX_ADMIN_PATH}sysadmin/",
            include("sharix_sysadmin.urls", namespace="sharix_sysadmin"),
            name="sharix_sysadmin",
        )
    )
    
  4. Для платформы добавить пункты меню в sharix_admin/context_processors.py:

    is_sysadmin = (
        user.is_staff
        or user.is_superuser
        or "PLATFORM-TECHSUPPORT" in user_groups
        or "METASERVICE-TECHSUPPORT" in user_groups
    )
    
    if sv.is_local_app_enabled("sharix_sysadmin"):
        _add_menu_item(
            items,
            "Заявка в техподдержку",
            url_name="sharix_sysadmin:support_request",
            icon="sharix_admin/img/menu/tickets.svg",
            active_pages=["sysadmin_support_request"],
        )
        if is_sysadmin:
            _add_menu_item(
                items,
                "Системная панель",
                url_name="sharix_sysadmin:dashboard",
                icon="sharix_admin/img/menu/settings.svg",
                active_pages=[
                    "sysadmin_dashboard",
                    "sysadmin_logs",
                    "sysadmin_backup",
                    "sysadmin_install_cfg",
                    "sysadmin_modules",
                    "sysadmin_actions",
                    "sysadmin_audit",
                ],
            )
    
  5. Для сервиса ShariX Open добавить в sharix_admin/lib/menu.py:

    if sv.is_local_app_enabled("sharix_sysadmin"):
    _append_once(MENU_GLOBAL, "sysadmin_support_request")
    _append_once(MENU_GLOBAL_CUSTOMIZABLE, "sysadmin_support_request")
    MENU_SCHEME_LIST_OPEN["sysadmin_support_request"] = [
        "sharix_sysadmin",
        "tickets",
        "Заявка в техподдержку",
    ]
    
    _append_once(STAFF_METASERVICE_MENU_GLOBAL, "sysadmin_dashboard")
    _append_once(STAFF_METASERVICE_MENU_CUSTOMIZABLE, "sysadmin_dashboard")
    MENU_SCHEME_LIST_OPEN["sysadmin_dashboard"] = [
        "sharix_sysadmin",
        "hdd-network",
        "Системная панель",
    ]
    

И в sharix_admin/lib/access_matrix.py:

VIEW_ACCESS_RULES.update({
    "sysadmin_support_request": {"auth": True},
    "sysadmin_dashboard": {"roles": ("METASERVICE-TECHSUPPORT",)},
})
  1. Применить миграции:

    python manage.py makemigrations sharix_sysadmin
    python manage.py migrate sharix_sysadmin
    

Права на системные команды

Модуль вызывает systemctl, journalctl, pg_dump, pkill. В зависимости от того, от какого пользователя запущен Django, могут потребоваться sudo/systemd-права. Для production лучше выдавать точечные sudoers-правила только на разрешённые команды.

ALT Linux P10

Модуль ориентирован на systemd-окружение ALT Linux P10. Для PostgreSQL проверяются типовые unit names postgresql, postgresql-15, postgresql-14, postgresql-13; подключение к БД дополнительно проверяется через Django connection.

Module installation contract

bin/install.cfg.example is the tracked catalogue of repository/branch keys. The root installer copies missing keys into the installation-local bin/install.cfg before repository processing; existing local values are never overwritten.

Public ShariX_Open/sharix-open-* modules may be selected from the public catalogue. Private modules are intentionally absent from that catalogue and are installed by an explicit repository URL. Both variants are stored in the same install.cfg and INSTALLED_APPS_LOCAL model.

The same configuration lifecycle is available non-interactively through Django:

./venv/bin/python manage.py sysadmin_module add sharix_onboarding
./bin/install.sh

sysadmin_module add and Системная панель -> Модули use the same lifecycle service. For an enabled module, initial add invokes the root-owned targeted materializer for that module; broad assembly installation/update remains owned by the root installer. For a private repository pass --repo-url explicitly; enable, disable, remove, materialize and status use the same service layer as the web UI.

Git credentials, when required by the root repository policy, are process-local only (SHARIX_GIT_USERNAME plus SHARIX_GIT_TOKEN/SHARIX_GIT_PASSWORD) and are never stored by Sysadmin. An interactive sysadmin_module add may ask for these one-shot credentials at the management-command boundary; JSON/non-interactive execution must provide them through the environment. If initial materialization fails, Sysadmin restores .env and bin/install.cfg to their exact pre-add contents so a missing checkout cannot remain in INSTALLED_APPS_LOCAL; any source files created before a later failure are left in place for inspection/retry.

The installer must not create Django migrations. If model state differs from the canonical migration files, installation stops and the migration must be created and committed in the repository that owns the model.

Module health contract

Stage 3 adds derived module health without an InstalledModule database table. services.module_health combines source presence, assembly configuration, per-module enable flags, Django runtime state and optional <app>.sharix_health probes. Structural health is side-effect free; external connectivity is checked only with check_sharix_modules --live.

Canonical derived states are absent, disabled, not_configured, not_authorized, ready, degraded and error. A missing optional capability must not break core. A broken enabled integration is recorded as error rather than silently presented as absent.

Canonical module metadata projection

Stage 15.7.2 keeps descriptive/source metadata in services.module_metadata and combines it with the existing install.cfg and module-health lifecycle through services.modules_catalog.canonical_module_metadata(). Consumers such as Onboarding must use this projection instead of maintaining their own module catalogue.

Repository visibility (ShariX_Open/... public vs ShariX/... private), runtime availability and software-license identity are separate facts. License identity comes only from the explicit Stage 16.1 repository binding plus the actual canonical LICENSE bytes/hash (or, for an unregistered materialized source, from an exact corpus-byte match). Namespace visibility never invents a license. Onboarding and other consumers must use the same Sysadmin metadata projection rather than maintaining their own license catalogue.

Canonical module licenses (Stage 16.1)

Sysadmin owns one tracked license corpus for GPL-3.0-only, AGPL-3.0-only and sharix-proprietary-v1. Every registered managed module repository is explicitly bound to a license_id, canonical license_file, SHA-256 and presentation mode. The repository LICENSE is authoritative evidence: if its bytes do not match the registered hash, Sysadmin reports an inconsistent identity instead of substituting a short notice or inferring a license from the repository namespace.

The Web module-install flow always opens a separate server-side license step before changing install.cfg. GPL/AGPL use an informational view with a Continue action and no synthetic acceptance checkbox. sharix-proprietary-v1 additionally requires explicit acceptance of the exact displayed license_id and SHA-256. Pending state stores a sanitized canonical repository URL and license snapshot; credentials and license bodies are never written to the session or audit log. If an already materialized proprietary checkout has a missing or different LICENSE, a new Web configuration fails closed.

Repository access entitlement remains independent from software-license presentation. A private ShariX/... repository can require Platform/Gogs access even though its license identity is determined only by explicit canonical metadata and verified license bytes. License acceptance never expands rights granted by a separate agreement and never creates repository entitlement.

Platform entitlement for private modules (Stage 11.2)

On a Service assembly, accepting the proprietary license is necessary but no longer sufficient to configure a private ShariX/... repository. Sysadmin asks the registered Platform for the current entitlement and fails closed unless the module status is active. The same check is used by the web UI and manage.py sysadmin_module add through the existing module_lifecycle service.

The Modules page can submit an entitlement request to Platform. It displays the Platform state independently from local source/configuration state: not_requested, requested, awaiting_gogs_account, active, revoked or error. Public ShariX_Open/... modules are unaffected if Platform is unreachable. The Service never receives or stores the Platform Gogs admin token.

Platform assemblies skip this Service-side entitlement gate: Platform is the owner of the private repository access policy and must not call its own Service API.

Owner-service Git fallback

A single owner-service exception exists for installations whose canonical METASERVICE_INN is 7801685119. If a private https://git.sharix-app.org/ShariX/... module does not have an active Platform entitlement, the interactive manage.py sysadmin_module add command may verify direct repository read access instead of fabricating an entitlement. The command asks for a Gogs login and password/access token, runs one git ls-remote check for the exact repository and branch through an ephemeral GIT_ASKPASS helper, and only then changes install.cfg/.env.

The fallback does not write or change Platform entitlement state. Git credentials are not stored in Django, .env, install.cfg, the Sysadmin audit payload or command arguments. They live only in the process environment used for the one verification command. Non-interactive automation may supply temporary SHARIX_GIT_USERNAME plus SHARIX_GIT_TOKEN or SHARIX_GIT_PASSWORD; --json never opens an interactive password prompt. Because credentials are deliberately not retained, a subsequent ./bin/install.sh clone/update may request them again. All other Service INNs remain fail-closed behind the normal Platform entitlement.

Unified module/version status (Stage 11.3)

services.repository_status is the common read-only Git inspector for the Open AGPL root and independent private module checkouts. It never crosses repository ownership and never stores credentials. The Open root may refresh its public origin and reports the existing AGPL publication proof. Private repositories use local/cached Git metadata only; Platform compares the reported installed commit with the current Gogs branch using its own service token.

The Modules page and manage.py report_module_statuses send the versioned Stage-11 report to Platform. Stage 16.7 extends that same channel to schema v2: all managed-source components are projected from the existing Stage-16.4/16.6 owners with license identity, deployment/canonical-upstream refs, running commit/tree, publication evidence and update/divergence states. Building the report does not create a second Service inventory and does not perform hidden Git network I/O. The explicit Modules-page send action may first refresh anonymous public repository evidence; automatic commercial delivery only reuses the last safe local snapshot. Git credentials, Platform API keys, offline grants and signing material are never report fields.

Contextual help contribution

The module owns operation-aware help for the module-management page through sharix_sysadmin.page_help:PAGE_HELP_CONTRIBUTIONS. Open and Platform resolve this contribution dynamically when the module is installed. Stable operation/empty-state IDs are used for coverage; user-facing text is translated in this module's ru/en catalogs. Help visibility does not grant lifecycle permissions.

Stage 15.9 canonical module metadata and source state

The Modules page consumes one Sysadmin-owned metadata projection for module identity, configured repository, repository visibility, actual software-license identity, source availability, runtime health and Stage-11 Git/version evidence. Onboarding uses the same projection and must not maintain a second license/repository catalogue.

Repository visibility and installation access remain separate from software license. In particular sharix_translations is identified as GPL-3.0-only only when its canonical root LICENSE matches the registered corpus hash, while sharix_russian_post is identified as sharix-proprietary-v1 only through its explicit repository binding and matching canonical root LICENSE. A private namespace alone is never used to invent a license name.

For configured modules the repository hyperlink is the repository recorded in the active installation configuration. The local checkout remote is inspected separately; a mismatch is shown explicitly instead of silently replacing the configured URL. Version and dirty state come from the existing Stage-11 repository inspector. Private checkouts never perform an authenticated background fetch merely to render the page.

Stage 16.4 source provenance

Sysadmin owns source/provenance inspection and verification metadata; the public HTTP page itself belongs to webapp-base at /source/. Canonical upstream is the normal AGPL source, but a divergent running tree is never represented by an unrelated upstream link. A matching public fork/ref can be verified and recorded in conf-real/source-provenance.json with:

python manage.py source_publication status
python manage.py source_publication set-override COMPONENT https://public.example/repo.git REF
python manage.py source_publication clear-override COMPONENT
python manage.py source_publication switch-source COMPONENT https://public.example/repo.git BRANCH

set-override and switch-source require anonymous public HTTPS Git access and prove source-tree equivalence before mutation. The override file never stores credentials and is not a replacement for bin/install.cfg; repository movement remains owned by bin/repositories.sh.

Platform-only Service Projects capability

Sysadmin recognizes sharix_service_projects / sharix-service-projects as a canonical private module with sharix-proprietary-v1 license identity. The repository may be advertised by Platform bin/install.cfg.example, but normal Open assemblies do not expose it as an install candidate unless their own install configuration contains SHARIX_SERVICE_PROJECTS. Platform capability resolution treats the canonical repository as Platform-owned and does not call the Service entitlement endpoint.

Proprietary capability resolution

Private-module installation/repository authorization is centralized in services/proprietary_capabilities.py. UI and lifecycle code use the same resolver; signed offline evidence is accepted only during Platform unavailability, reachable online non-active state remains authoritative, and the owner-Service Git fallback remains an explicit narrow exception. The resolver does not mutate installation configuration or business data when authorization is denied.

Repository update monitoring

services.repository_updates provides the Stage 16.6 update view for all repositories listed by the existing managed-source/install configuration. It does not replace bin/install.cfg, bin/repositories.sh or Stage 16.4 source-publication evidence.

Each row keeps two independent remote targets:

  • configured deployment URL/ref;
  • canonical upstream URL/ref from tracked bin/install.cfg.example.

The resulting state for each target is one of CURRENT, UPDATE_AVAILABLE, LOCAL_AHEAD, DIVERGED, SOURCE_UNAVAILABLE, PRIVATE_AUTH_REQUIRED or UNKNOWN. Local commit/tree/dirty state and Stage 16.4 publication evidence are shown alongside them.

The Modules page itself does not perform Git network I/O to calculate update state. Use the explicit refresh public Git status action, or the optional repository_update_watch handler. The watcher is a normal handler contribution, is disabled by default and performs anonymous public Git checks only.

CLI equivalents:

./venv/bin/python manage.py repository_updates
./venv/bin/python manage.py repository_updates --refresh-public
./venv/bin/python manage.py repository_updates --json

A private repository that cannot be checked anonymously remains PRIVATE_AUTH_REQUIRED. An administrator may run an explicit one-shot refresh:

./venv/bin/python manage.py repository_updates \
  --refresh-private SHARIX_APPOINTMENTS \
  --username <gogs-login>

The command requests the password/access token with getpass; the secret is not accepted as a command-line argument and is not persisted. Web Sysadmin uses the same process-local GIT_ASKPASS boundary. Safe results are stored in conf-real/repository-update-status.json; changing the local commit/tree or configured repository/ref invalidates stale remote evidence automatically.

Stabilization 0.9.1 baseline audit

Before changing configuration/admin/first-run/runtime behaviour for the 0.9.1 stabilization track, run the read-only S.1 audit from the assembly root:

./venv/bin/python sharix_sysadmin/bin/audit_stabilization_0_9_1_baseline.py \
  --format markdown \
  --output /tmp/stabilization-0.9.1-s1.md

The same command is used on Open and Platform. It records exact local Git commit/branch/tag facts for the root and materialized child repositories, the existing Stage-19 release/update files, current configuration owners, the current admin/first-run/profile/module boundaries and a key-only configuration classification for S.2. It never emits .env values or credentials.

The audit distinguishes four configuration classes instead of treating every .env.example assignment as a Web setting:

  • ordinary application/operator settings that may remain in the administrative allowlist;
  • environment-profile-managed values that must be edited atomically as one profile;
  • module-lifecycle-only values such as INSTALLED_APPS_LOCAL;
  • file-only installation/runtime values such as SYSTEMD_SERVICE_NAME.

A source bundle can establish a historical code baseline, but S.1 factual installation evidence must be produced on the actual target installation so its current SHA/tag/branch/config-symlink facts are not guessed.

Stabilization 0.9.1 S.2

bin/check_stabilization_0_9_1_config.py --project-root <assembly-root> is the DB-independent configuration convergence guard. First-run edits Service identity and the same atomic Testing/Production profile used by the post-first-run administrative surface; it does not own a second configuration store.

Stabilization 0.9.1 S.7 example configuration

services.config.read_install_cfg_values() returns only active installation-local assignments. read_install_cfg_example_values() also understands commented # KEY=... declarations so proprietary optional repositories remain discoverable without becoming enabled. Reconciliation preserves that comment state and must never auto-activate such modules.

Release 0.9.2 factual baseline audit

R92.0 reuses the Sysadmin/source-lifecycle ownership established by the 0.9.1 baseline audit. Run the read-only 0.9.2 audit from each factual 0.9.1 assembly root before product changes:

./venv/bin/python sharix_sysadmin/bin/audit_release_0_9_2_baseline.py \
  --format markdown \
  --strict \
  --output /tmp/release-0.9.2-baseline.md

Add --with-runtime on a running installation when local systemd/module-health evidence is required. Runtime mode does not pass --live to module providers and therefore does not intentionally perform external connectivity checks.

The report records only non-secret facts:

  • exact local Git SHA/branch/tag/dirty/upstream state for the root and managed materialized repositories;
  • local release metadata and the latest successful updater summary, when such evidence exists;
  • the installation-local configured/enabled module profile and each module's source SHA;
  • existing Page Registry/module contribution anchors used by Platform menus;
  • the source owners that later 0.9.2 passes must reuse for profile/sync, client-order composition, documents, Metaservices, support and Service Projects;
  • a bounded source collision search for an existing generic short-link/QR capability and for persisted Service Projects graph-layout state.

The audit never treats another release-builder/rehearsal host as the source of truth for an installation's optional-module profile. Missing or untagged historical release evidence is reported as observed and is never fabricated. Credentials from Git URLs are stripped before report output; .env secret values are not emitted.

R92.5 support navigation

support/request/ remains available to an authenticated user when the module is available, but its upper tab navigation is permission-aware. Each administrative tab is emitted only when the same authorization predicate used by the destination view accepts the current user; the destination view remains the authoritative backend guard. Ordinary support users therefore do not receive links to logs, handlers, backup, module, operations or audit pages they cannot open.

R92.8 shared short links

sharix_shortlinks is a public GPLv3 optional shared module discovered through the canonical SHARIX_SHORTLINKS install.cfg key. Sysadmin owns installation/source/license metadata only; redirect, QR and aggregate analytics remain module-owned.

Read-only installation diagnostics

python manage.py installation_diagnostics inventories local/cached source evidence, requirements declarations, env-key ownership/read-sites, CKEditor/rich-field uses and handler Blockly/provenance state. Use --section <name> to narrow the report and --json for machine-readable output.

The command does not refresh Git remotes, read deployment secret values, mutate configuration/business rows or start handlers. Dirty-path classes are diagnostic annotations only; they do not change source/publication compliance state.

S92.6 dependency convergence evidence

python sharix_sysadmin/bin/s92_6_dependency_evidence.py --root . --assembly open|platform validates the assembly constraints, runs pip check and writes credential-blind dependency evidence. The shared validator also ensures constrained versions satisfy every direct declaration found in the assembled source tree and keeps pycares as an assembly-owned transitive resolver constraint.

S92.8 handler functional health

The handlers page exposes canonical functional states DISABLED, STOPPED, STARTING, HEALTHY, DEGRADED and FAILED. Classification combines local runtime configuration, systemd state/restart count and the current handler runtime-health evidence. XMPP handlers additionally receive one bounded DNS/TCP probe of their configured endpoint; non-XMPP handlers do not gain an arbitrary network dependency.

Activate all disabled is an enable-only administration operation. It changes eligible disabled entries to runtime mode handler and runs systemctl enable, but never starts or restarts a process. Start/restart remains a separate explicit operation.

S92.10 branch-schema and handler-health recovery

OPERATIONAL_BRANCH remains the canonical branch selector. Commented repository-specific # *_BRANCH=... examples in bin/install.cfg.example are not missing installation-local keys; active overrides are still tracked. This is narrower than the ordinary optional repository-key rule: commented repository URL declarations keep their existing schema/discovery semantics.

Handler health keeps runtime evidence and XMPP session evidence separate from systemd active. The live S92.8/S92.10 diagnostics distinguish an unreachable/unconfigured XMPP endpoint from a reachable DNS/TCP endpoint whose handler did not establish an authenticated session, without printing credential values. Systemd namespace repair is an explicit root-installer action, not a Sysadmin render-time side effect.

Recovered systemd restart history

NRestarts is a cumulative systemd counter, not a count for the last heartbeat interval. It stays visible in the existing handlers table and is never reset by Sysadmin. The restart_loop_evidence threshold remains 3; recovery is a separate, conservative classifier branch, not a raised threshold.

After at least 600 seconds (10 minutes) in the same error-free process, previous systemd restarts alone need not force DEGRADED. The classifier requires all of the following in addition to the usual fresh-heartbeat/bootstrap checks:

  • systemd says active/running, and its nonzero MainPID matches the health JSON;
  • ExecMainStartTimestampMonotonic proves at least 600 seconds of process age;
  • JSON started_at agrees with that process age within the existing 120-second heartbeat freshness limit; both clocks show at least 600 seconds;
  • the current process reports exactly zero internal restarts, no error code and no recorded error timestamp, and a success timestamp within this process;
  • an XMPP-required handler has an authenticated session at least 600 seconds old, no disconnect after that session started, and passes any supplied endpoint smoke result. last_success_at may mean authenticated XMPP connection; it is not proof of completed domain/report work.

The returned state is then HEALTHY with reason functional_evidence_current_with_restart_history and the untouched count in historical_systemd_restarts. The table continues to show the real NRestarts. A new process restarts the recovery interval automatically. Missing/invalid monotonic time or ambiguous process evidence keeps the old conservative result; there is no fallback to PID-only health. Current-process internal restart/error history is intentionally not aged out by this change.

Inspection never calls reset-failed, restarts a process, removes a health file, creates a DB/table, or writes a diagnostic checkpoint. Old restart causes still require their own historical journal investigation. The normal classifier is pure Python and can be exercised without Django or a test database:

python3 -m unittest sharix_sysadmin.tests.test_handler_health -v

Publish this shared repository on Open first; other installations receive it through repositories.sh pull --shared --repo sharix_sysadmin. Fresh CLI checks load the new classifier immediately, without restarting any handler. A normal web-worker reload/restart is needed only to update an already running Sysadmin web process. No migration, runtime schema change or collectstatic is required; compile the changed module RU/EN catalogs before publication.