21 KiB
Operational Recovery Audit
Date: 2026-07-01
Scope: repository-first audit of the current AWatch-rus / DetMir operational recovery capability. This document describes only mechanisms already present in the repository. It does not define new backup or recovery mechanisms.
Evidence Sources
The audit reviewed these repository sources:
docs/BACKUP_AND_RECOVERY_RU.mddocs/RETENTION_POLICY_RU.mddocs/OPERATIONS_RUNBOOK_RU.mddocs/OPERATIONS_VALIDATION_RUNBOOK_RU.mddocs/DETMIR_RESTORE_BASELINE_2026-06-29_RU.mdscripts/prod_backup_restore.shadk-rust/crates/prod-backup-restore/src/main.rsansible/deploy_aw_server.ymlansible/deploy_aw_windows.ymlansible/post_validate_aw_windows.ymlaw-server/*.service,aw-server/*.timer,aw-server/*.pathwindows/ActivityWatch.Windows.Common.psm1windows/hardening-recovery.ps1windows/rebuild-worktime-tasks.ps1windows/fix-session-watchers.ps1windows/cleanup-disc-sessions.ps1clickhouse-1c/docker-compose.ymlclickhouse-workforce/docker-compose.ymlgrafana-1c/docker-compose.ymldocs/registry/GITEA_BACKUP_AND_RESTORE_RUNBOOK_RU.mddocs/registry/registry-evidence-manifest.json
Current Recovery Procedure Actually Supported
Server-side service recovery
The repository supports service restart and health validation through systemd, Ansible deployment, and smoke checks:
activitywatch-server.servicerestarts on failure and runs with the configured AW server env file. Evidence:aw-server/activitywatch-server.service.ansible/deploy_aw_server.ymlinstalls and restartsactivitywatch-server.service, then waits for/api/0/info. Evidence:ansible/deploy_aw_server.yml:2365-2375.- The generic operations runbook requires checking
/healthz,/readyz,/metrics, service status, journal, and smoke scripts after recovery. Evidence:docs/OPERATIONS_RUNBOOK_RU.md:59-71. - The production validation runbook defines the DetMir smoke sequence through
check-aw-data.sh,check-aw-full.sh, and local contour smoke. Evidence:docs/OPERATIONS_VALIDATION_RUNBOOK_RU.md.
ActivityWatch SQLite maintenance and recovery support
The repository supports guarded maintenance and limited DB merge/migration flows, not a complete automated restore:
- Weekly guarded SQLite maintenance is installed as
aw-db-maintenance.service/aw-db-maintenance.timer. Evidence:aw-server/aw-db-maintenance.service,aw-server/aw-db-maintenance.timer. - Optional SQLite vacuum is defined as
aw-db-vacuum.service/aw-db-vacuum.timer. It is opt-in in Ansible throughaw_db_vacuum_timer_enabled. Evidence:aw-server/aw-db-vacuum.service,aw-server/aw-db-vacuum.timer,ansible/deploy_aw_server.yml:613-649. - Legacy root DB merge is implemented in
ansible/deploy_aw_server.ymlwhenaw_legacy_db_merge_enabledis true. It stops the service, backs up target and legacy DB files, merges them withmerge-aw-server-dbs, installs the merged DB, restarts the service, and waits for API readiness. Evidence:ansible/deploy_aw_server.yml:2248-2375. - A separate Rust
prod-backup-restorebinary exists only as a plan/checker. It explicitly rejects--apply. Evidence:adk-rust/crates/prod-backup-restore/src/main.rs:100-105.
Windows collector recovery
The Windows side has the strongest implemented recovery automation:
- Deployment writes
deployment-config.json, launcher scripts, andrecovery-loop.ps1. Evidence:windows/deploy-domain-users.ps1,windows/hardening-recovery.ps1. Write-ActivityWatchRecoveryScriptgenerates a script that importsActivityWatch.Windows.Common.psm1and callsInvoke-ActivityWatchRecoveryLoop. Evidence:windows/ActivityWatch.Windows.Common.psm1:1576-1597.Register-ActivityWatchRecoveryTaskcreates the scheduled taskActivityWatch Recovery, using an interactive user when possible and SYSTEM fallback otherwise. Evidence:windows/ActivityWatch.Windows.Common.psm1:2447-2488.Invoke-ActivityWatchRecoveryLoopis an actual loop: it uses a lock file, cleans non-live session processes, starts the worktime session collector when allowed, starts configured live user launch tasks, and uses console fallback. Evidence:windows/ActivityWatch.Windows.Common.psm1:2114-2168.Start-ActivityWatchTasksstarts launch tasks for live users and starts the recovery task. Evidence:windows/ActivityWatch.Windows.Common.psm1:2656-2672.rebuild-worktime-tasks.ps1,fix-session-watchers.ps1, andcleanup-disc-sessions.ps1provide manual repair paths for task/script regeneration, stale recovery loop restart, and disconnected-session cleanup.
Hayabusa intake recovery
The repository supports event-driven reprocessing of uploaded Hayabusa packages:
aw-hayabusa-drop.pathwatches/opt/activitywatch/aw-rus-ops/dropfor zip packages and triggersaw-hayabusa-drop.service. Evidence:aw-server/aw-hayabusa-drop.path.aw-hayabusa-drop.serviceruns/usr/local/bin/aw-hayabusa-autoprocess. Evidence:aw-server/aw-hayabusa-drop.service.ansible/deploy_aw_server.ymlcreates Hayabusa directories, installs pinned Hayabusa, installs Rust helpers, creates the drop zone, enablesaw-hayabusa-drop.path, and runsaw-hayabusa doctor. Evidence:ansible/deploy_aw_server.yml:2780-3070.
Readiness evidence recovery support
The repository supports periodic readiness bundle generation:
detmir-readiness.servicewrites readiness output to/var/lib/activitywatch/health/readiness-bundle. Evidence:aw-server/detmir-readiness.service.detmir-readiness.timerruns daily with persistent timer behavior. Evidence:aw-server/detmir-readiness.timer.
Current Backup Procedure Actually Supported
ActivityWatch server local backup artifacts
Implemented:
ansible/deploy_aw_server.ymlcreates/var/lib/activitywatch/backupsand/var/lib/activitywatch/backups/db. Evidence:ansible/deploy_aw_server.yml:80-128,ansible/deploy_aw_server.yml:2263-2269.- Before legacy DB merge, Ansible copies the target DB and legacy root DB into
timestamped files under
{{ aw_server_data_dir }}/backups/db. Evidence:ansible/deploy_aw_server.yml:2274-2294. - Before applying server-side settings/views/classes, Ansible copies current
payloads to timestamped JSON backups under
{{ aw_server_data_dir }}/backups. Evidence:ansible/deploy_aw_server.yml:2406-2420. aw-prune-local-state.timerprunes old local backups using configured retention and keep-last values. Evidence:ansible/deploy_aw_server.yml:236-281,docs/RETENTION_POLICY_RU.md:70-71.
Not currently implemented:
- A general scheduled full backup of the active ActivityWatch SQLite DB.
- A repository-defined off-host backup copy for AW DB, configs, Grafana, ClickHouse, DLP evidence, Hayabusa archives, or Windows collector state.
Windows package rollback backup
Implemented:
Install-ActivityWatchPackagebacks up the existing install root intoinstall-<timestamp>before replacing it, keeps only the latest two install backups, checks free space, and cleans temporary extraction directories. Evidence:windows/ActivityWatch.Windows.Common.psm1:80-95,windows/ActivityWatch.Windows.Common.psm1:148-245.hardening-recovery.ps1can runInstall-ActivityWatchPackagewhen-RepairPackageis supplied. Evidence:windows/hardening-recovery.ps1.
Not currently implemented:
- Automatic restore from the saved Windows
install-*backup directory. - Backup of
C:\ProgramData\AWatch-rusas a whole before repair.
Gitea registry backup
Implemented as registry-readiness support, not DetMir runtime recovery:
- Registry docs define Gitea backup path, script, systemd service/timer,
gitea dumpZIP format, SHA256 checksum, daily schedule, and 14-day retention. Evidence:docs/registry/GITEA_BACKUP_AND_RESTORE_RUNBOOK_RU.md:7-23,docs/registry/registry-evidence-manifest.json:26-39.
Not currently implemented:
- Tested Gitea restore. The manifest explicitly says
restore_tested=falseandproduction_ready=false. Evidence:docs/registry/registry-evidence-manifest.json:37-39.
Current Restore Procedure
ActivityWatch DB merge/restore-like flow
Supported:
- Enable
aw_legacy_db_merge_enabled. - Deploy server playbook.
- Playbook checks legacy root DB and target DB.
- Playbook stops
activitywatch-server.service. - Playbook backs up target and legacy DB files.
- Playbook runs
/usr/local/bin/merge-aw-server-dbs. - Playbook installs the merged DB as active target DB.
- Playbook restarts
activitywatch-server.service. - Playbook waits for
/api/0/info.
Evidence: ansible/deploy_aw_server.yml:2248-2375.
Not currently implemented:
- A generic "restore selected backup file to active AW DB" command.
- A tested end-to-end AW DB restore runbook.
- Automated checksum verification for AW DB backup files.
- Automated rollback from a failed DB merge to the backup file.
prod-backup-restore plan-only flow
Supported:
scripts/prod_backup_restore.shlocates the Rust planner binary or exits with build instructions. Evidence:scripts/prod_backup_restore.sh:14-29.- The Rust planner reads
private-config/runtime.envif available, checks required env vars, checkssshpass,ansible-playbook, inventory, andmerge-aw-server-dbs. Evidence:adk-rust/crates/prod-backup-restore/src/main.rs:111-131,adk-rust/crates/prod-backup-restore/src/main.rs:175-209. - The planner prints planned commands including remote backup directory
creation, DB copies, service stop, merge, install, and Ansible validation.
Evidence:
adk-rust/crates/prod-backup-restore/src/main.rs:211-280.
Not currently implemented:
- Execution of the planned restore.
--applyfails by design. Evidence:adk-rust/crates/prod-backup-restore/src/main.rs:100-105.
Windows collector recovery
Supported:
- Run
ActivityWatch Recoveryscheduled task or let it run on its configured trigger. - Recovery loop enforces a single lock.
- Recovery loop stops collectors/watchers in non-live sessions.
- Recovery loop starts the global worktime collector when allowed.
- Recovery loop starts configured live-user launch tasks.
- Recovery loop attempts console fallback when no configured live task starts.
Evidence: windows/ActivityWatch.Windows.Common.psm1:2114-2168,
windows/ActivityWatch.Windows.Common.psm1:2447-2488,
windows/ActivityWatch.Windows.Common.psm1:2656-2672.
Not currently implemented:
- Automatic reconstruction of lost Windows state from an external backup.
- Automatic restore of Windows collector queues after corruption or deletion.
Gitea restore
Supported:
- Manual outline exists: prepare isolated test server, install same Gitea
version, stop Gitea, verify checksum, unpack dump, restore app/data/repos/db
according to Gitea official procedure, fix ownership, start Gitea, run
gitea doctor check, regenerate hooks if needed, and run post-restore checks. Evidence:docs/registry/GITEA_BACKUP_AND_RESTORE_RUNBOOK_RU.md:42-90.
Not currently implemented:
- Tested Gitea restore. Evidence:
docs/registry/GITEA_BACKUP_AND_RESTORE_RUNBOOK_RU.md:92-100.
Components That Cannot Yet Be Restored Automatically
The following are confirmed by repository inspection:
| Component | Current state | Evidence |
|---|---|---|
| ActivityWatch active SQLite DB | Backups exist around merge/settings operations, but generic restore is Not currently implemented. | ansible/deploy_aw_server.yml:2274-2294, adk-rust/crates/prod-backup-restore/src/main.rs:100-105 |
| ClickHouse 1C data | Docker volume exists; no backup/restore automation found. Not currently implemented. | clickhouse-1c/docker-compose.yml:13-19 |
| ClickHouse Workforce data | Docker volume exists; no backup/restore automation found. Not currently implemented. | clickhouse-workforce/docker-compose.yml:11-17 |
| Grafana data volume | Docker volume exists; no repo cleanup and no restore automation. Not currently implemented. | grafana-1c/docker-compose.yml:67-79, docs/RETENTION_POLICY_RU.md:99 |
| Prometheus TSDB | Retention configured, backup/restore not documented. Not currently implemented. | grafana-1c/docker-compose.yml:40-49 |
| DLP policy/case/warehouse DBs | Retention doc says no automatic deletion; backup/restore not implemented. Not currently implemented. | docs/RETENTION_POLICY_RU.md:43-47, docs/RETENTION_POLICY_RU.md:87-90 |
| DLP evidence and compliance reports | Cleanup disabled; restore depends on customer backup if manually deleted. Not currently implemented. | docs/RETENTION_POLICY_RU.md:221-223 |
| Hayabusa reports/archive | Processing is automated; restore of archive/reports is not automated. Not currently implemented. | docs/RETENTION_POLICY_RU.md:48, docs/RETENTION_POLICY_RU.md:91 |
| Windows collector state and queues | Recovery restarts collectors; external backup/restore of state is not implemented. | docs/RETENTION_POLICY_RU.md:40, docs/RETENTION_POLICY_RU.md:85 |
| Diagnostic bundles and release evidence | No automatic backup/restore found. Not currently implemented. | docs/RETENTION_POLICY_RU.md:100-101 |
Components Requiring Manual Intervention
- AW DB merge/recovery: operator must enable
aw_legacy_db_merge_enabled, run Ansible, review backup files, and verify API. Evidence:ansible/deploy_aw_server.yml:2248-2375. prod-backup-restore: operator can only review a plan; execution is manual because--applyis disabled. Evidence:adk-rust/crates/prod-backup-restore/src/main.rs:100-105.- Windows collector recovery after severe state loss: operator must use
hardening-recovery.ps1,rebuild-worktime-tasks.ps1,fix-session-watchers.ps1, or redeploy. Evidence:windows/*.ps1. - Hayabusa stuck path/service: operator may need to reset failed units, repair
drop-zone permissions, and rerun processing. Evidence:
aw-server/aw-hayabusa-drop.path,aw-server/aw-hayabusa-drop.service. - Gitea restore: manual isolated test restore is required; tested restore is
not yet recorded. Evidence:
docs/registry/GITEA_BACKUP_AND_RESTORE_RUNBOOK_RU.md:42-100. - ClickHouse/Grafana/Prometheus/DLP data restore: Not currently implemented.
Missing Documentation
Critical and high-confidence gaps only:
- Exact AW DB restore runbook from
/var/lib/activitywatch/backups/dbto the active DB path. Not currently implemented. - Post-restore verification checklist for AW DB backup restore, including checksum, ownership, service restart, bucket freshness, and worktime report checks. Not currently implemented.
- Backup inventory mapping each persistent component to an actual backup owner,
schedule, storage location, retention, and restore command. Partially covered
by
docs/BACKUP_AND_RECOVERY_RU.mdanddocs/RETENTION_POLICY_RU.md, but operational restore ownership is Not currently implemented. - ClickHouse 1C and ClickHouse Workforce backup/restore runbooks. Not currently implemented.
- Grafana volume restore runbook. Not currently implemented.
- DLP evidence/case/policy restore runbook. Not currently implemented.
- Windows
C:\ProgramData\AWatch-russtate backup/restore runbook. Not currently implemented. - Gitea restore evidence result. The runbook exists, but restore test is marked
false. Evidence:
docs/registry/registry-evidence-manifest.json:37-39.
Missing Automation
- Automated AW DB restore from a selected backup file. Not currently implemented.
- Automated AW DB backup with checksum on a schedule independent of merge operations. Not currently implemented.
- Off-host/offline copy for AW DB, ClickHouse volumes, Grafana data, DLP evidence, Hayabusa archives, Windows state, and release evidence. Not currently implemented.
- ClickHouse backup and restore automation. Not currently implemented.
- Grafana data volume backup and restore automation. Not currently implemented.
- DLP evidence/case/policy backup and restore automation. Not currently implemented.
- Windows state backup and restore automation. Not currently implemented.
- Automated restore drill evidence generation. Not currently implemented.
Operational Risks
| Risk | Severity | Evidence | Impact |
|---|---|---|---|
| Restore is partially plan-only for AW DB | Critical | prod-backup-restore rejects --apply |
Operator can plan but cannot run a deterministic automated restore through this tool |
| AW DB backups are created around specific operations, not as a general scheduled full backup | Critical | ansible/deploy_aw_server.yml:2274-2294 |
A recent recovery point may be unavailable if no merge/settings operation occurred |
| ClickHouse data has no repo-defined restore path | Critical | ClickHouse Docker volumes only | Loss/corruption of 1C or workforce ClickHouse data requires ad hoc operator recovery |
| DLP/Hayabusa evidence has no automated restore | High | docs/RETENTION_POLICY_RU.md:87-91, docs/RETENTION_POLICY_RU.md:221-223 |
Forensic/case continuity depends on external/customer backup |
| Grafana data volume has no repo-defined backup/restore | High | grafana-1c/docker-compose.yml:67-79 |
Dashboard DB/users/session state may require manual reconstruction even though provisioned dashboards exist |
| Gitea restore is documented but untested | High | restore_tested=false |
Source-control recovery confidence remains limited |
| Windows recovery restarts collectors but does not restore deleted state | Medium | Windows recovery loop evidence | Collector state/queues/logs can be lost if state root is deleted |
| Generic backup document is intentionally high-level | Medium | docs/BACKUP_AND_RECOVERY_RU.md:5-6 |
Operators need component-specific procedures during incidents |
| Hayabusa path recovery depends on service/path health and permissions | Medium | aw-hayabusa-drop.path, aw-hayabusa-drop.service |
Drop backlog or permission drift can stall forensic intake |
| Recovery smoke is documented but not tied to a single recovery command | Low | docs/OPERATIONS_RUNBOOK_RU.md, docs/OPERATIONS_VALIDATION_RUNBOOK_RU.md |
Operator can validate, but command sequencing remains manual |
Recovery Confidence Score
Overall score: 48 / 100
Justification:
- Windows collector process recovery is mature: scheduled task, lock, live session handling, cleanup of non-live sessions, and task restart are implemented.
- Server service recovery and smoke validation are present.
- Local maintenance and retention are present.
- AW DB merge has safety backups and API validation, but generic restore is not implemented.
prod-backup-restoreis explicitly plan-only.- ClickHouse, Grafana, Prometheus, DLP evidence/cases, Hayabusa archive, Windows state, diagnostic bundles, and release evidence do not have automated restore procedures in the repository.
- Gitea backup is documented with checksum and timer metadata, but restore is marked untested.
Prioritized Confirmed Gaps
Critical
-
Generic AW DB restore from backup is Not currently implemented. Evidence: backup files are created by Ansible, but
prod-backup-restorerefuses--apply. -
Scheduled full AW DB backup independent of merge/settings changes is Not currently implemented. Evidence: backups are tied to merge/settings operations and pruning exists, but no scheduled full DB backup unit is present.
-
ClickHouse 1C and Workforce backup/restore are Not currently implemented. Evidence: both stacks persist to Docker volumes; no backup/restore runbook or automation is present.
High
-
DLP evidence/case/policy restore is Not currently implemented. Evidence: retention policy explicitly leaves DLP evidence/cases without automatic cleanup and says recovery depends on customer backup after manual deletion.
-
Hayabusa reports/archive restore is Not currently implemented. Evidence: intake processing is automated, but archive/report restore is not.
-
Grafana data volume backup/restore is Not currently implemented. Evidence: Grafana uses
grafana-data; no repo restore procedure exists. -
Gitea restore test is Not currently implemented. Evidence: registry manifest has
restore_tested=false.
Medium
-
Windows state root backup/restore is Not currently implemented. Evidence: Windows recovery restarts collectors and repairs tasks, but does not restore
C:\ProgramData\AWatch-rusfrom backup. -
Component-specific recovery ownership matrix is Not currently implemented. Evidence: generic backup doc says component list must be refined by release profile and customer infrastructure.
-
Restore drill evidence generation is Not currently implemented. Evidence: validation commands exist, but no restore-drill artifact workflow is present.
Low
-
Prometheus TSDB restore is Not currently implemented. Evidence: compose config bounds retention, but no backup/restore procedure is present.
-
Diagnostic bundle and release evidence restore is Not currently implemented. Evidence: retention policy intentionally avoids pruning, but does not define backup or restore automation.
Release-Relevant Conclusion
The repository currently supports operational restart, Windows collector self-healing, local maintenance, retention, readiness evidence, and limited backup-before-mutation behavior.
It does not yet support deterministic full production recovery for all persisted state. The most important gap is not service restart; it is data restore: ActivityWatch DB, ClickHouse volumes, Grafana state, DLP/Hayabusa evidence, and Windows state are not covered by a tested automated restore process in the repository.