Move VoidBot watchdog ownership to Idunn

This commit is contained in:
Meta Vens 2026-06-07 02:43:24 +01:00
commit 96f4875e1a
9 changed files with 55 additions and 37 deletions

View file

@ -586,6 +586,22 @@ function Test-ConfigEnabled {
return $true
}
function Get-IdunnLocalKeepaliveStatus {
$taskName = "Idunn Local Keepalive"
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
$taskEnabled = $null -ne $task -and [bool]$task.Settings.Enabled
$startupPath = Join-Path ([Environment]::GetFolderPath("Startup")) "$taskName.cmd"
$startupInstalled = Test-Path -LiteralPath $startupPath
return [pscustomobject]@{
taskName = $taskName
taskEnabled = $taskEnabled
startupPath = $startupPath
startupInstalled = $startupInstalled
installed = $taskEnabled -or $startupInstalled
}
}
function Invoke-RemotePowerShellJson {
param(
[Parameter(Mandatory = $true)]
@ -1307,22 +1323,38 @@ try {
$watchdogEnabled = [bool]$watchdogTask.Settings.Enabled
$orchestratorTask = Get-ScheduledTask -TaskName "GameCult Local Orchestrator" -ErrorAction SilentlyContinue
$orchestratorEnabled = $null -ne $orchestratorTask -and [bool]$orchestratorTask.Settings.Enabled
$watchdogTaskStatus = if ($watchdogEnabled -or $orchestratorEnabled) { "passed" } else { "failed" }
$idunnKeepalive = Get-IdunnLocalKeepaliveStatus
$watchdogTaskStatus = if ($idunnKeepalive.installed -or $watchdogEnabled) { "passed" } else { "failed" }
$watchdogTaskDetail = if ($watchdogEnabled) {
"Operations watchdog task is installed and enabled."
} elseif ($orchestratorEnabled) {
"Operations watchdog task is disabled because GameCult Local Orchestrator owns the watchdog pulse."
"Legacy operations watchdog task is still installed and enabled."
} elseif ($idunnKeepalive.installed) {
"Operations watchdog task is disabled because Idunn Local Keepalive owns watchdog recovery and escalation."
} else {
"Operations watchdog task is installed but disabled, and GameCult Local Orchestrator is not enabled."
"Operations watchdog task is installed but disabled, and Idunn Local Keepalive is not enabled."
}
Add-Check -Name "scheduled_task.watchdog" -Status $watchdogTaskStatus -Detail $watchdogTaskDetail -Data @{
taskName = $watchdogTaskName
state = [string]$watchdogTask.State
orchestratorTaskName = "GameCult Local Orchestrator"
orchestratorEnabled = $orchestratorEnabled
idunnTaskName = $idunnKeepalive.taskName
idunnTaskEnabled = $idunnKeepalive.taskEnabled
idunnStartupPath = $idunnKeepalive.startupPath
idunnStartupInstalled = $idunnKeepalive.startupInstalled
}
} catch {
Add-Check -Name "scheduled_task.watchdog" -Status "warning" -Detail "Operations watchdog task $watchdogTaskName is not installed yet."
$idunnKeepalive = Get-IdunnLocalKeepaliveStatus
if ($idunnKeepalive.installed) {
Add-Check -Name "scheduled_task.watchdog" -Status "passed" -Detail "VoidBot legacy operations watchdog task is absent because Idunn Local Keepalive owns watchdog recovery and escalation." -Data @{
taskName = $watchdogTaskName
idunnTaskName = $idunnKeepalive.taskName
idunnTaskEnabled = $idunnKeepalive.taskEnabled
idunnStartupPath = $idunnKeepalive.startupPath
idunnStartupInstalled = $idunnKeepalive.startupInstalled
}
} else {
Add-Check -Name "scheduled_task.watchdog" -Status "warning" -Detail "Operations watchdog task $watchdogTaskName is not installed, and Idunn Local Keepalive is not enabled."
}
}
if (-not $offsiteBackupEnabled) {

View file

@ -77,7 +77,7 @@ function buildCatalog() {
witnesses: [
witness("voidbot.discord_archive", ".voidbot/rag/messages.json", "VoidBot raw archive", ["raw archive", "forensics"]),
witness("voidbot.history_vectors", "qdrant://voidbot/history", "Qdrant", ["semantic history vectors"]),
witness("voidbot.operations_health", ".voidbot/status/operations-health.json", "VoidBot watchdog", ["debug status only"]),
witness("voidbot.operations_health", ".voidbot/status/operations-health.json", "VoidBot operations probe", ["debug status only", "lifecycle owned by Idunn"]),
],
commands: [
command("archive.search_history", "read-only", "Search archived Discord history through native CultMesh/CultNet service commands; MCP is external-agent compatibility."),

View file

@ -68,21 +68,13 @@ if ($intervalMinutesValue -lt 15) {
throw "VOIDBOT_HEALTHCHECK_INTERVAL_MINUTES must be at least 15."
}
if (-not ($config.ContainsKey("DISCORD_BOT_TOKEN")) -or [string]::IsNullOrWhiteSpace($config["DISCORD_BOT_TOKEN"])) {
throw "DISCORD_BOT_TOKEN must be configured in .env before installing the watchdog task."
}
if (-not ($config.ContainsKey("DISCORD_OWNER_ID")) -or [string]::IsNullOrWhiteSpace($config["DISCORD_OWNER_ID"])) {
throw "DISCORD_OWNER_ID must be configured in .env before installing the watchdog task."
}
$startAt = (Get-Date).AddMinutes(5)
# Use WSH as a GUI host so the interactive task can stay hidden without flashing a console.
$action = New-ScheduledTaskAction -Execute "wscript.exe" -Argument "//B //nologo `"$hiddenLauncher`" -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$checkScript`" -NotifyOwner -FailOnIssues"
$action = New-ScheduledTaskAction -Execute "wscript.exe" -Argument "//B //nologo `"$hiddenLauncher`" -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$checkScript`" -FailOnIssues"
$trigger = New-ScheduledTaskTrigger -Once -At $startAt -RepetitionInterval (New-TimeSpan -Minutes $intervalMinutesValue) -RepetitionDuration (New-TimeSpan -Days 3650)
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Minutes 15)
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited
$description = "Runs the VoidBot operations watchdog on a repeating interval and DMs the owner when the stack or backup path drifts into the swamp."
$description = "Runs the legacy VoidBot operations probe. Idunn owns watchdog recovery and operator escalation."
Register-ScheduledTask -TaskName $taskNameValue -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Description $description -Force | Out-Null
@ -92,6 +84,7 @@ Write-Host "Task runs as: $($env:USERDOMAIN)\$($env:USERNAME)"
Write-Host "Logon mode: Interactive"
Write-Host "Launcher: wscript.exe hidden PowerShell shim"
Write-Host "Execution time limit: 15 minutes"
Write-Host "Operator escalation: owned by Idunn Local Keepalive, not this legacy probe task"
if ($RunNow) {
Start-ScheduledTask -TaskName $taskNameValue

View file

@ -319,15 +319,6 @@ try {
Cwd = $repoRoot
Executable = $powershell
Arguments = @("-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", (Join-Path $PSScriptRoot "run-void-moderator-rumination.ps1"))
},
[pscustomobject]@{
Id = "voidbot-operations-watchdog"
Label = "VoidBot operations watchdog"
IntervalMinutes = Get-ConfigInt -Config $config -Name "VOIDBOT_HEALTHCHECK_INTERVAL_MINUTES" -Default 60 -Minimum 15
TimeoutMinutes = 5
Cwd = $repoRoot
Executable = $powershell
Arguments = @("-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", (Join-Path $PSScriptRoot "check-voidbot-operations.ps1"), "-NotifyOwner", "-FailOnIssues")
}
)