harnery 0.38.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +32 -8
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +97 -6
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +239 -33
- package/dist/commands/browse.d.ts +8 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +466 -231
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +6 -3
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +20 -4
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +26 -3
- package/dist/commands/qa-status.d.ts.map +1 -1
- package/dist/commands/qa-status.js +7 -2
- package/dist/commands/resources.d.ts.map +1 -1
- package/dist/commands/resources.js +23 -3
- package/dist/commands/review-pack.d.ts.map +1 -1
- package/dist/commands/review-pack.js +98 -23
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +2 -2
- package/dist/core/adapters/profiles.d.ts +1 -1
- package/dist/core/agents/canonical-emit.d.ts +3 -2
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -0
- package/dist/core/agents/cli.js +13 -6
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +5 -3
- package/dist/core/agents/live-lifecycle-v3.d.ts +2 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.d.ts +7 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +63 -8
- package/dist/core/agents/session-finalizer-v3.d.ts +2 -2
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts +3 -3
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +2 -1
- package/dist/core/agents/state/names.d.ts +35 -2
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +80 -5
- package/dist/core/agents/state/stale-sweep.d.ts +2 -1
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -6
- package/dist/core/agents/turn-elapsed.d.ts +51 -0
- package/dist/core/agents/turn-elapsed.d.ts.map +1 -0
- package/dist/core/agents/turn-elapsed.js +91 -0
- package/dist/core/artifacts/activity.d.ts +14 -0
- package/dist/core/artifacts/activity.d.ts.map +1 -0
- package/dist/core/artifacts/activity.js +52 -0
- package/dist/core/artifacts/delivery-card.d.ts +39 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -0
- package/dist/core/artifacts/delivery-card.js +282 -0
- package/dist/core/artifacts/index.d.ts +42 -7
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +288 -76
- package/dist/core/artifacts/mutation-lock.d.ts +2 -0
- package/dist/core/artifacts/mutation-lock.d.ts.map +1 -0
- package/dist/core/artifacts/mutation-lock.js +91 -0
- package/dist/core/backup/host-snapshot.d.ts +18 -0
- package/dist/core/backup/host-snapshot.d.ts.map +1 -0
- package/dist/core/backup/host-snapshot.js +64 -0
- package/dist/core/config.d.ts +20 -5
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +44 -10
- package/dist/core/diagnostics/advice.d.ts +38 -3
- package/dist/core/diagnostics/advice.d.ts.map +1 -1
- package/dist/core/diagnostics/advice.js +103 -99
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +111 -47
- package/dist/core/diagnostics/comparison.d.ts.map +1 -1
- package/dist/core/diagnostics/comparison.js +3 -2
- package/dist/core/diagnostics/contract.d.ts +15 -31
- package/dist/core/diagnostics/contract.d.ts.map +1 -1
- package/dist/core/diagnostics/contract.js +2 -5
- package/dist/core/diagnostics/index.d.ts +2 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -1
- package/dist/core/diagnostics/index.js +2 -0
- package/dist/core/diagnostics/pressure-contract.d.ts +260 -0
- package/dist/core/diagnostics/pressure-contract.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure-contract.js +70 -0
- package/dist/core/diagnostics/pressure.d.ts +25 -0
- package/dist/core/diagnostics/pressure.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure.js +1138 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -1
- package/dist/core/diagnostics/replay.js +90 -10
- package/dist/core/events/v3/adapter-id.d.ts +6 -0
- package/dist/core/events/v3/adapter-id.d.ts.map +1 -0
- package/dist/core/events/v3/adapter-id.js +7 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -1
- package/dist/core/events/v3/archive-retention.js +3 -2
- package/dist/core/events/v3/bootstrap.d.ts +41 -4
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +120 -17
- package/dist/core/events/v3/capabilities.d.ts +16 -9
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +37 -2
- package/dist/core/events/v3/capability-drift.d.ts +2 -2
- package/dist/core/events/v3/capability-drift.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.d.ts +48 -5
- package/dist/core/events/v3/control-witness.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.js +91 -36
- package/dist/core/events/v3/control.d.ts.map +1 -1
- package/dist/core/events/v3/control.js +22 -2
- package/dist/core/events/v3/index.d.ts +2 -1
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +2 -1
- package/dist/core/events/v3/live-feed.d.ts +7 -1
- package/dist/core/events/v3/live-feed.d.ts.map +1 -1
- package/dist/core/events/v3/live-feed.js +21 -3
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +10 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +2 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +2 -1
- package/dist/core/events/v3/producers/hook-base.d.ts +2 -2
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +15 -5
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook.js +17 -4
- package/dist/core/events/v3/producers/intake.d.ts +4 -4
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +3 -2
- package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -1
- package/dist/core/events/v3/producers/producer-state-observer.js +2 -1
- package/dist/core/events/v3/producers/recorder.d.ts +16 -5
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +31 -9
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +10 -13
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +3 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +2 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/turn-telemetry.d.ts +2 -2
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.d.ts +16 -14
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +36 -38
- package/dist/core/hooks/backup-schedule.d.ts +34 -0
- package/dist/core/hooks/backup-schedule.d.ts.map +1 -0
- package/dist/core/hooks/backup-schedule.js +114 -0
- package/dist/core/hooks/cli.js +61 -18
- package/dist/core/hooks/codex-wsl-bridge.d.ts +2 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -1
- package/dist/core/hooks/codex-wsl-bridge.js +18 -4
- package/dist/core/hooks/index.d.ts +1 -0
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/hooks/prompt-context/contract.d.ts +61 -0
- package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/contract.js +102 -0
- package/dist/core/hooks/prompt-context/index.d.ts +5 -0
- package/dist/core/hooks/prompt-context/index.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/index.js +2 -0
- package/dist/core/hooks/prompt-context/runner.d.ts +24 -0
- package/dist/core/hooks/prompt-context/runner.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/runner.js +249 -0
- package/dist/core/qa-artifacts.d.ts +3 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -1
- package/dist/core/qa-artifacts.js +25 -3
- package/dist/core/resources/contract.d.ts +69 -3
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/contract.js +1 -1
- package/dist/core/resources/index.d.ts +1 -0
- package/dist/core/resources/index.d.ts.map +1 -1
- package/dist/core/resources/index.js +1 -0
- package/dist/core/resources/native.d.ts +36 -0
- package/dist/core/resources/native.d.ts.map +1 -0
- package/dist/core/resources/native.js +418 -0
- package/dist/core/resources/sampler.d.ts +2 -0
- package/dist/core/resources/sampler.d.ts.map +1 -1
- package/dist/core/resources/sampler.js +31 -1
- package/dist/core/resources/status.d.ts +61 -0
- package/dist/core/resources/status.d.ts.map +1 -0
- package/dist/core/resources/status.js +536 -0
- package/dist/core/resources/system.d.ts +27 -0
- package/dist/core/resources/system.d.ts.map +1 -0
- package/dist/core/resources/system.js +439 -0
- package/dist/core/semantic/contract.d.ts +13 -13
- package/dist/core/semantic/service.d.ts +2 -0
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +27 -4
- package/dist/core/storage/builtins.js +41 -0
- package/dist/core/supervisor/contract.d.ts +41 -3
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/contract.js +3 -2
- package/dist/core/supervisor/findings.d.ts +3 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +88 -0
- package/dist/core/supervisor/history.d.ts.map +1 -1
- package/dist/core/supervisor/history.js +14 -0
- package/dist/core/supervisor/ledger-state.d.ts +55 -0
- package/dist/core/supervisor/ledger-state.d.ts.map +1 -0
- package/dist/core/supervisor/ledger-state.js +0 -0
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +120 -7
- package/dist/core/supervisor/storage.d.ts +3 -1
- package/dist/core/supervisor/storage.d.ts.map +1 -1
- package/dist/core/supervisor/storage.js +4 -0
- package/dist/core/workflow/admission.d.ts +3 -0
- package/dist/core/workflow/admission.d.ts.map +1 -1
- package/dist/core/workflow/admission.js +28 -16
- package/dist/core/workflow/engine.js +2 -2
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +6 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +4 -3
- package/dist/lib/browser/capture-fidelity.d.ts +7 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -1
- package/dist/lib/browser/capture-fidelity.js +17 -0
- package/dist/lib/browser/client.d.ts +9 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +85 -37
- package/dist/lib/browser/index.d.ts +3 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -1
- package/dist/lib/browser/page-review-budget.d.ts +13 -0
- package/dist/lib/browser/page-review-budget.d.ts.map +1 -0
- package/dist/lib/browser/page-review-budget.js +251 -0
- package/dist/lib/browser/page-review-contracts.d.ts +127 -0
- package/dist/lib/browser/page-review-contracts.d.ts.map +1 -0
- package/dist/lib/browser/page-review-contracts.js +5 -0
- package/dist/lib/browser/page-review-evidence.d.ts +48 -0
- package/dist/lib/browser/page-review-evidence.d.ts.map +1 -0
- package/dist/lib/browser/page-review-evidence.js +340 -0
- package/dist/lib/browser/page-review-judge.d.ts +1 -1
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +46 -38
- package/dist/lib/browser/page-review-pack.d.ts +44 -22
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
- package/dist/lib/browser/page-review-pack.js +116 -36
- package/dist/lib/browser/page-review-source.d.ts +12 -0
- package/dist/lib/browser/page-review-source.d.ts.map +1 -0
- package/dist/lib/browser/page-review-source.js +22 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +35 -9
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +48 -14
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +215 -68
- package/dist/lib/browser/qa-snapshot.d.ts +6 -0
- package/dist/lib/browser/qa-snapshot.d.ts.map +1 -1
- package/dist/lib/browser/qa-snapshot.js +259 -48
- package/dist/lib/browser/review-capture-transaction.d.ts +13 -0
- package/dist/lib/browser/review-capture-transaction.d.ts.map +1 -0
- package/dist/lib/browser/review-capture-transaction.js +79 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.js +4 -2
- package/dist/lib/browser/thumbnail-association.d.ts +34 -0
- package/dist/lib/browser/thumbnail-association.d.ts.map +1 -0
- package/dist/lib/browser/thumbnail-association.js +158 -0
- package/dist/lib/browser/tiling.d.ts +30 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +38 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
- package/dist/lib/docs-metadata-managed.js +4 -1
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +7 -1
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +1 -0
- package/dist/lib/local-file-url.d.ts +12 -0
- package/dist/lib/local-file-url.d.ts.map +1 -1
- package/dist/lib/local-file-url.js +16 -2
- package/dist/lib/tunnel/state.d.ts +19 -4
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +53 -13
- package/package.json +7 -4
- package/schemas/config.schema.json +69 -2
- package/src/commands/agents.ts +42 -9
- package/src/commands/artifacts.ts +130 -6
- package/src/commands/backup.ts +287 -34
- package/src/commands/browse.ts +564 -267
- package/src/commands/diagnostics.ts +6 -3
- package/src/commands/ledger-v3.ts +20 -3
- package/src/commands/qa-run.ts +37 -3
- package/src/commands/qa-status.ts +11 -2
- package/src/commands/resources.ts +23 -3
- package/src/commands/review-pack.ts +165 -62
- package/src/commands/tunnel.ts +2 -1
- package/src/core/agents/canonical-emit.ts +4 -2
- package/src/core/agents/cli.ts +14 -6
- package/src/core/agents/live-authority-v3.ts +7 -3
- package/src/core/agents/live-lifecycle-v3.ts +2 -2
- package/src/core/agents/render/prompt-context.ts +68 -14
- package/src/core/agents/session-finalizer-v3.ts +2 -2
- package/src/core/agents/state/live-coordination-view.ts +4 -4
- package/src/core/agents/state/names.ts +92 -7
- package/src/core/agents/state/stale-sweep.ts +22 -8
- package/src/core/agents/turn-elapsed.ts +135 -0
- package/src/core/artifacts/activity.ts +71 -0
- package/src/core/artifacts/delivery-card.ts +375 -0
- package/src/core/artifacts/index.ts +385 -91
- package/src/core/artifacts/mutation-lock.ts +106 -0
- package/src/core/backup/host-snapshot.ts +76 -0
- package/src/core/config.ts +66 -13
- package/src/core/diagnostics/advice.ts +148 -120
- package/src/core/diagnostics/bundle.ts +138 -52
- package/src/core/diagnostics/comparison.ts +6 -2
- package/src/core/diagnostics/contract.ts +39 -42
- package/src/core/diagnostics/index.ts +2 -0
- package/src/core/diagnostics/pressure-contract.ts +294 -0
- package/src/core/diagnostics/pressure.ts +1361 -0
- package/src/core/diagnostics/replay.ts +116 -11
- package/src/core/events/v3/adapter-id.ts +12 -0
- package/src/core/events/v3/archive-retention.ts +3 -6
- package/src/core/events/v3/bootstrap.ts +163 -16
- package/src/core/events/v3/capabilities.ts +75 -25
- package/src/core/events/v3/capability-drift.ts +2 -2
- package/src/core/events/v3/control-witness.ts +172 -41
- package/src/core/events/v3/control.ts +34 -2
- package/src/core/events/v3/index.ts +3 -0
- package/src/core/events/v3/live-feed.ts +23 -5
- package/src/core/events/v3/live-routing.ts +14 -2
- package/src/core/events/v3/producers/command-recorder.ts +4 -4
- package/src/core/events/v3/producers/coordination-recorder.ts +4 -4
- package/src/core/events/v3/producers/hook-base.ts +21 -16
- package/src/core/events/v3/producers/hook.ts +21 -4
- package/src/core/events/v3/producers/intake.ts +6 -6
- package/src/core/events/v3/producers/producer-state-observer.ts +2 -1
- package/src/core/events/v3/producers/recorder.ts +50 -21
- package/src/core/events/v3/reader.ts +14 -13
- package/src/core/events/v3/runtime-build.ts +3 -2
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +3 -3
- package/src/core/events/v3/turn-telemetry.ts +4 -4
- package/src/core/hooks/adapter/output.ts +50 -36
- package/src/core/hooks/backup-schedule.ts +147 -0
- package/src/core/hooks/cli.ts +65 -14
- package/src/core/hooks/codex-wsl-bridge.ts +21 -5
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/prompt-context/contract.ts +177 -0
- package/src/core/hooks/prompt-context/index.ts +22 -0
- package/src/core/hooks/prompt-context/runner.ts +303 -0
- package/src/core/qa-artifacts.ts +29 -3
- package/src/core/resources/contract.ts +76 -3
- package/src/core/resources/index.ts +1 -0
- package/src/core/resources/native.ts +481 -0
- package/src/core/resources/sampler.ts +46 -1
- package/src/core/resources/status.ts +717 -0
- package/src/core/resources/system.ts +530 -0
- package/src/core/semantic/service.ts +37 -3
- package/src/core/storage/builtins.ts +41 -0
- package/src/core/supervisor/contract.ts +45 -3
- package/src/core/supervisor/findings.ts +159 -0
- package/src/core/supervisor/history.ts +15 -0
- package/src/core/supervisor/ledger-state.ts +0 -0
- package/src/core/supervisor/service.ts +133 -5
- package/src/core/supervisor/storage.ts +7 -0
- package/src/core/workflow/admission.ts +33 -17
- package/src/core/workflow/engine.ts +2 -2
- package/src/core/workflow/live-session-v3.ts +6 -8
- package/src/core/workflow/proof.ts +4 -3
- package/src/lib/browser/capture-fidelity.ts +23 -0
- package/src/lib/browser/client.ts +96 -44
- package/src/lib/browser/index.ts +15 -1
- package/src/lib/browser/page-review-budget.ts +309 -0
- package/src/lib/browser/page-review-contracts.ts +129 -0
- package/src/lib/browser/page-review-evidence.ts +465 -0
- package/src/lib/browser/page-review-judge.ts +56 -40
- package/src/lib/browser/page-review-pack.ts +181 -43
- package/src/lib/browser/page-review-source.ts +30 -0
- package/src/lib/browser/qa-run-contracts.ts +62 -18
- package/src/lib/browser/qa-run.ts +259 -71
- package/src/lib/browser/qa-snapshot.ts +289 -48
- package/src/lib/browser/review-capture-transaction.ts +106 -0
- package/src/lib/browser/standalone-html.ts +4 -2
- package/src/lib/browser/thumbnail-association.ts +190 -0
- package/src/lib/browser/tiling.ts +63 -0
- package/src/lib/docs-metadata-managed.ts +4 -1
- package/src/lib/identities/assume.ts +12 -4
- package/src/lib/instructions/templates.ts +1 -0
- package/src/lib/local-file-url.ts +17 -2
- package/src/lib/tunnel/state.ts +70 -13
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PressureAssessment,
|
|
3
|
+
PressureHysteresisState,
|
|
4
|
+
} from "../diagnostics/pressure-contract.ts";
|
|
1
5
|
import type { ResourceProcessGroup } from "../resources/contract.ts";
|
|
2
6
|
import type { HarneryLogRecordV1 } from "../storage/jsonl.ts";
|
|
3
7
|
|
|
4
8
|
export const SUPERVISOR_STATUS_SCHEMA_VERSION = 1 as const;
|
|
5
9
|
export const SUPERVISOR_SNAPSHOT_SCHEMA_VERSION = 2 as const;
|
|
6
|
-
export const SUPERVISOR_HISTORY_SCHEMA_VERSION =
|
|
7
|
-
export const SUPERVISOR_FINDING_SCHEMA_VERSION =
|
|
10
|
+
export const SUPERVISOR_HISTORY_SCHEMA_VERSION = 2 as const;
|
|
11
|
+
export const SUPERVISOR_FINDING_SCHEMA_VERSION = 3 as const;
|
|
12
|
+
export const SUPERVISOR_PRESSURE_SCHEMA_VERSION = 1 as const;
|
|
8
13
|
export const SUPERVISOR_ACTIVITY_SCHEMA_VERSION = 1 as const;
|
|
9
14
|
export const SUPERVISOR_TIMELINE_SCHEMA_VERSION = 2 as const;
|
|
10
15
|
export const SUPERVISOR_EXPLANATION_SCHEMA_VERSION = 1 as const;
|
|
@@ -108,7 +113,18 @@ export interface SupervisorHistoryPoint {
|
|
|
108
113
|
memory_percent: number | null;
|
|
109
114
|
memory_used_bytes: number | null;
|
|
110
115
|
swap_used_bytes: number | null;
|
|
111
|
-
process_count: number;
|
|
116
|
+
process_count: number | null;
|
|
117
|
+
load_average_1?: number | null;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* The contention readings the pressure trend follows. Null when the platform
|
|
121
|
+
* does not expose a dimension, never zero, so a gap cannot read as calm.
|
|
122
|
+
*/
|
|
123
|
+
pressure: {
|
|
124
|
+
memory_full_avg10: number | null;
|
|
125
|
+
io_full_avg10: number | null;
|
|
126
|
+
cpu_some_avg60: number | null;
|
|
127
|
+
swap_out_bytes_per_second: number | null;
|
|
112
128
|
};
|
|
113
129
|
groups: readonly ResourceProcessGroup[];
|
|
114
130
|
}
|
|
@@ -129,6 +145,16 @@ export type SupervisorCapabilityState =
|
|
|
129
145
|
| "malformed"
|
|
130
146
|
| "redacted";
|
|
131
147
|
export type SupervisorFindingSeverity = "info" | "warning" | "critical";
|
|
148
|
+
/**
|
|
149
|
+
* Why a finding exists, and therefore what it may influence.
|
|
150
|
+
*
|
|
151
|
+
* `contention` findings report that a shared resource is actually contended,
|
|
152
|
+
* and are the only class the pressure assessment may read as machine state.
|
|
153
|
+
* `attribution` findings name who holds a resource; they are always carried as
|
|
154
|
+
* contributors and never set state. `diagnostic` findings report that an
|
|
155
|
+
* observation path itself is degraded.
|
|
156
|
+
*/
|
|
157
|
+
export type SupervisorFindingClass = "contention" | "attribution" | "diagnostic";
|
|
132
158
|
export type SupervisorFindingState = "opened" | "resolved";
|
|
133
159
|
|
|
134
160
|
export interface SupervisorCapability {
|
|
@@ -179,6 +205,7 @@ export interface SupervisorFinding {
|
|
|
179
205
|
fingerprint: string;
|
|
180
206
|
source_kind: string;
|
|
181
207
|
finding_kind: string;
|
|
208
|
+
finding_class: SupervisorFindingClass;
|
|
182
209
|
severity: SupervisorFindingSeverity;
|
|
183
210
|
state: SupervisorFindingState;
|
|
184
211
|
scope_kind: string;
|
|
@@ -217,6 +244,21 @@ export interface SupervisorActivitySnapshot {
|
|
|
217
244
|
capability: SupervisorCapability;
|
|
218
245
|
}
|
|
219
246
|
|
|
247
|
+
/**
|
|
248
|
+
* The pressure assessment the observer published on its last cycle, with the
|
|
249
|
+
* hysteresis state that produced it. The observer is the only writer, because
|
|
250
|
+
* it is the only reader that sees consecutive samples; every other surface
|
|
251
|
+
* reads this record so all of them report the same assessment.
|
|
252
|
+
*/
|
|
253
|
+
export interface SupervisorPressureRecord {
|
|
254
|
+
schema_version: typeof SUPERVISOR_PRESSURE_SCHEMA_VERSION;
|
|
255
|
+
published_at: string;
|
|
256
|
+
/** Identity of the observer run, so a restart resets carried-forward streaks. */
|
|
257
|
+
observer_generation: string;
|
|
258
|
+
assessment: PressureAssessment;
|
|
259
|
+
prior_hysteresis: PressureHysteresisState | null;
|
|
260
|
+
}
|
|
261
|
+
|
|
220
262
|
export interface SupervisorFindings {
|
|
221
263
|
schema_version: typeof SUPERVISOR_FINDING_SCHEMA_VERSION;
|
|
222
264
|
max_findings: number;
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type SupervisorCapability,
|
|
16
16
|
type SupervisorFinding,
|
|
17
17
|
type SupervisorFindingAttribution,
|
|
18
|
+
type SupervisorFindingClass,
|
|
18
19
|
type SupervisorFindingEvidence,
|
|
19
20
|
type SupervisorFindingSeverity,
|
|
20
21
|
type SupervisorFindings,
|
|
@@ -25,6 +26,10 @@ import {
|
|
|
25
26
|
} from "./contract.ts";
|
|
26
27
|
import type { SupervisorHookHealth } from "./hook-health.ts";
|
|
27
28
|
import { evaluateHookHealthAlerts } from "./hook-health-alerts.ts";
|
|
29
|
+
import {
|
|
30
|
+
type LedgerControlStateFindingInputV1,
|
|
31
|
+
ledgerControlStateFindingCandidateV1,
|
|
32
|
+
} from "./ledger-state.ts";
|
|
28
33
|
|
|
29
34
|
const GIB = 1_024 * 1_024 * 1_024;
|
|
30
35
|
const MIB = 1_024 * 1_024;
|
|
@@ -42,6 +47,7 @@ const MEMORY_GROWTH_WINDOW_MS = 5 * 60_000;
|
|
|
42
47
|
interface Candidate {
|
|
43
48
|
source_kind: string;
|
|
44
49
|
finding_kind: string;
|
|
50
|
+
finding_class: SupervisorFindingClass;
|
|
45
51
|
severity: SupervisorFindingSeverity;
|
|
46
52
|
scope_kind: string;
|
|
47
53
|
scope_id: string;
|
|
@@ -63,6 +69,8 @@ export interface SupervisorFindingEvaluationInput {
|
|
|
63
69
|
hookHealth?: SupervisorHookHealth;
|
|
64
70
|
coordination?: CoordinationHealthSnapshot;
|
|
65
71
|
activity?: SupervisorActivitySnapshot;
|
|
72
|
+
/** Event ledger control drift, when the caller observed the control state. */
|
|
73
|
+
ledgerControlState?: LedgerControlStateFindingInputV1;
|
|
66
74
|
now?: Date;
|
|
67
75
|
}
|
|
68
76
|
|
|
@@ -110,6 +118,7 @@ export function updateSupervisorFindings(
|
|
|
110
118
|
fingerprint,
|
|
111
119
|
source_kind: candidate.source_kind,
|
|
112
120
|
finding_kind: candidate.finding_kind,
|
|
121
|
+
finding_class: candidate.finding_class,
|
|
113
122
|
severity: candidate.severity,
|
|
114
123
|
state: "opened",
|
|
115
124
|
scope_kind: candidate.scope_kind,
|
|
@@ -158,6 +167,7 @@ function evaluateCandidates(input: {
|
|
|
158
167
|
hookHealth?: SupervisorHookHealth;
|
|
159
168
|
coordination?: CoordinationHealthSnapshot;
|
|
160
169
|
activity?: SupervisorActivitySnapshot;
|
|
170
|
+
ledgerControlState?: LedgerControlStateFindingInputV1;
|
|
161
171
|
}): Candidate[] {
|
|
162
172
|
const out: Candidate[] = [];
|
|
163
173
|
const resourceCapability: SupervisorCapability = {
|
|
@@ -213,6 +223,131 @@ function evaluateCandidates(input: {
|
|
|
213
223
|
swapPercent!,
|
|
214
224
|
"percent",
|
|
215
225
|
);
|
|
226
|
+
for (const disk of input.resource.disks ?? []) {
|
|
227
|
+
if (disk.state !== "supported" || disk.available_bytes === null || disk.used_percent === null)
|
|
228
|
+
continue;
|
|
229
|
+
if (disk.used_percent < 90 && disk.available_bytes >= 5 * GIB) continue;
|
|
230
|
+
out.push(
|
|
231
|
+
candidate(
|
|
232
|
+
"machine.disk-space",
|
|
233
|
+
disk.used_percent >= 97 || disk.available_bytes < GIB ? "critical" : "warning",
|
|
234
|
+
"filesystem",
|
|
235
|
+
disk.path,
|
|
236
|
+
`Filesystem ${disk.path} has ${round1(disk.available_bytes / GIB)} GiB available (${disk.used_percent}% used).`,
|
|
237
|
+
source,
|
|
238
|
+
disk.used_percent,
|
|
239
|
+
"percent",
|
|
240
|
+
[resourceCapability],
|
|
241
|
+
),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
const pressure = input.resource.pressure;
|
|
245
|
+
if (pressure?.state === "supported" || pressure?.state === "partial") {
|
|
246
|
+
for (const [kind, full] of [
|
|
247
|
+
["memory", pressure.memory_full],
|
|
248
|
+
["io", pressure.io_full],
|
|
249
|
+
] as const) {
|
|
250
|
+
if (!full || (full.avg10 < 50 && !(full.avg10 >= 20 && full.avg10 > full.avg60))) continue;
|
|
251
|
+
const direction =
|
|
252
|
+
full.avg10 > full.avg60 ? "rising" : full.avg10 < full.avg60 ? "falling" : "steady";
|
|
253
|
+
addMachine(
|
|
254
|
+
`machine.${kind}-full-stall`,
|
|
255
|
+
full.avg10 >= 50 ? "critical" : "warning",
|
|
256
|
+
`All non-idle tasks stalled on ${kind} for ${full.avg10}% of the recent 10-second window (${direction}; 60s ${full.avg60}%, 300s ${full.avg300}%).`,
|
|
257
|
+
full.avg10,
|
|
258
|
+
"percent",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
for (const [kind, value, threshold] of [
|
|
262
|
+
["cpu", pressure.cpu, 20],
|
|
263
|
+
["memory", pressure.memory, 5],
|
|
264
|
+
["io", pressure.io, 10],
|
|
265
|
+
] as const) {
|
|
266
|
+
if (!value || value.avg60 < threshold) continue;
|
|
267
|
+
addMachine(
|
|
268
|
+
`machine.${kind}-stall`,
|
|
269
|
+
value.avg60 >= threshold * 2 ? "critical" : "warning",
|
|
270
|
+
`At least one task stalled on ${kind} for ${value.avg60}% of the last minute.`,
|
|
271
|
+
value.avg60,
|
|
272
|
+
"percent",
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const oom = input.resource.oom;
|
|
277
|
+
if (
|
|
278
|
+
oom?.state === "supported" &&
|
|
279
|
+
oom.last_kill_age_ms !== null &&
|
|
280
|
+
oom.last_kill_age_ms <= 60_000 &&
|
|
281
|
+
oom.total_kills !== null
|
|
282
|
+
) {
|
|
283
|
+
addMachine(
|
|
284
|
+
"machine.oom-kill",
|
|
285
|
+
"critical",
|
|
286
|
+
`Kernel OOM kills increased ${Math.round(oom.last_kill_age_ms / 1000)}s ago; ${oom.total_kills} kills reported in total. Work may have been lost.`,
|
|
287
|
+
oom.total_kills,
|
|
288
|
+
"count",
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
const host = input.resource.host;
|
|
292
|
+
const hostAge = host
|
|
293
|
+
? Date.parse(input.resource.sampled_at) +
|
|
294
|
+
input.resource.sample_duration_ms -
|
|
295
|
+
Date.parse(host.sampled_at)
|
|
296
|
+
: NaN;
|
|
297
|
+
if (
|
|
298
|
+
host?.machine &&
|
|
299
|
+
(host.state === "supported" || host.state === "partial") &&
|
|
300
|
+
hostAge >= 0 &&
|
|
301
|
+
hostAge <= 30_000
|
|
302
|
+
) {
|
|
303
|
+
const hostSource = stableSource(
|
|
304
|
+
"resource.windows-host",
|
|
305
|
+
"windows-host",
|
|
306
|
+
host.sampled_at,
|
|
307
|
+
host.state,
|
|
308
|
+
);
|
|
309
|
+
for (const [kind, value, threshold, severity] of [
|
|
310
|
+
["cpu", host.machine.cpu_percent, MACHINE_CPU_THRESHOLD, "warning"],
|
|
311
|
+
["memory", host.machine.memory_percent, MACHINE_MEMORY_THRESHOLD, "critical"],
|
|
312
|
+
] as const) {
|
|
313
|
+
if (value === null || value < threshold) continue;
|
|
314
|
+
out.push(
|
|
315
|
+
candidate(
|
|
316
|
+
`machine.host-${kind}-pressure`,
|
|
317
|
+
severity,
|
|
318
|
+
"machine",
|
|
319
|
+
"windows-host",
|
|
320
|
+
`Windows host ${kind} is ${value}%.`,
|
|
321
|
+
hostSource,
|
|
322
|
+
value,
|
|
323
|
+
"percent",
|
|
324
|
+
[{ source_kind: "resource.windows-host", state: host.state }],
|
|
325
|
+
),
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
for (const disk of host.disks) {
|
|
329
|
+
if (
|
|
330
|
+
disk.state !== "supported" ||
|
|
331
|
+
disk.available_bytes === null ||
|
|
332
|
+
disk.used_percent === null ||
|
|
333
|
+
(disk.used_percent < 90 && disk.available_bytes >= 5 * GIB)
|
|
334
|
+
)
|
|
335
|
+
continue;
|
|
336
|
+
out.push(
|
|
337
|
+
candidate(
|
|
338
|
+
"machine.host-disk-space",
|
|
339
|
+
disk.used_percent >= 97 || disk.available_bytes < GIB ? "critical" : "warning",
|
|
340
|
+
"filesystem",
|
|
341
|
+
`windows-host:${disk.path}`,
|
|
342
|
+
`Windows filesystem ${disk.path} has ${round1(disk.available_bytes / GIB)} GiB available (${disk.used_percent}% used).`,
|
|
343
|
+
hostSource,
|
|
344
|
+
disk.used_percent,
|
|
345
|
+
"percent",
|
|
346
|
+
[{ source_kind: "resource.windows-host", state: host.state }],
|
|
347
|
+
),
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
216
351
|
if (input.resource.collector_cpu_ms >= COLLECTOR_CPU_THRESHOLD_MS)
|
|
217
352
|
out.push(
|
|
218
353
|
candidate(
|
|
@@ -431,6 +566,10 @@ function evaluateCandidates(input: {
|
|
|
431
566
|
);
|
|
432
567
|
}
|
|
433
568
|
}
|
|
569
|
+
if (input.ledgerControlState) {
|
|
570
|
+
const ledger = ledgerControlStateFindingCandidateV1(input.ledgerControlState);
|
|
571
|
+
if (ledger) out.push(ledger);
|
|
572
|
+
}
|
|
434
573
|
return out;
|
|
435
574
|
}
|
|
436
575
|
|
|
@@ -642,6 +781,7 @@ function candidate(
|
|
|
642
781
|
return {
|
|
643
782
|
source_kind: source.source_kind,
|
|
644
783
|
finding_kind: findingKind,
|
|
784
|
+
finding_class: classifyFinding(findingKind),
|
|
645
785
|
severity,
|
|
646
786
|
scope_kind: scopeKind,
|
|
647
787
|
scope_id: scopeId,
|
|
@@ -654,6 +794,25 @@ function candidate(
|
|
|
654
794
|
};
|
|
655
795
|
}
|
|
656
796
|
|
|
797
|
+
/**
|
|
798
|
+
* Which question a finding answers. Contention findings report a machine
|
|
799
|
+
* resource the kernel says is exhausted or stalling. Attribution findings name
|
|
800
|
+
* who is consuming a resource, which is useful for an operator but is never
|
|
801
|
+
* evidence that the machine is under contention. Diagnostic findings report
|
|
802
|
+
* that the observation path itself is degraded. Anything unrecognized is
|
|
803
|
+
* diagnostic, because only contention may ever bear machine state.
|
|
804
|
+
*/
|
|
805
|
+
function classifyFinding(findingKind: string): SupervisorFindingClass {
|
|
806
|
+
if (findingKind.startsWith("machine.")) return "contention";
|
|
807
|
+
if (
|
|
808
|
+
findingKind === "resource.memory-growth" ||
|
|
809
|
+
["process.", "group.", "hook.", "service."].some((prefix) => findingKind.startsWith(prefix))
|
|
810
|
+
) {
|
|
811
|
+
return "attribution";
|
|
812
|
+
}
|
|
813
|
+
return "diagnostic";
|
|
814
|
+
}
|
|
815
|
+
|
|
657
816
|
function resourceSource(
|
|
658
817
|
resource: ResourceSnapshot,
|
|
659
818
|
capability: SupervisorSourceReference["capability"],
|
|
@@ -38,7 +38,9 @@ export function updateSupervisorHistory(
|
|
|
38
38
|
memory_used_bytes: resource.machine.memory_used_bytes,
|
|
39
39
|
swap_used_bytes: resource.machine.swap_used_bytes,
|
|
40
40
|
process_count: resource.machine.process_count,
|
|
41
|
+
load_average_1: resource.machine.load_average?.[0] ?? null,
|
|
41
42
|
},
|
|
43
|
+
pressure: pressurePoint(resource),
|
|
42
44
|
groups: resource.groups.map((group) => ({ ...group, root_pids: [...group.root_pids] })),
|
|
43
45
|
};
|
|
44
46
|
return {
|
|
@@ -52,6 +54,19 @@ export function updateSupervisorHistory(
|
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
function pressurePoint(resource: ResourceSnapshot): SupervisorHistoryPoint["pressure"] {
|
|
58
|
+
const pressure = resource.pressure;
|
|
59
|
+
const usable = pressure?.state === "supported" || pressure?.state === "partial";
|
|
60
|
+
const vmstat = resource.vmstat;
|
|
61
|
+
const vmstatUsable = vmstat?.state === "supported" || vmstat?.state === "partial";
|
|
62
|
+
return {
|
|
63
|
+
memory_full_avg10: usable ? (pressure.memory_full?.avg10 ?? null) : null,
|
|
64
|
+
io_full_avg10: usable ? (pressure.io_full?.avg10 ?? null) : null,
|
|
65
|
+
cpu_some_avg60: usable ? (pressure.cpu?.avg60 ?? null) : null,
|
|
66
|
+
swap_out_bytes_per_second: vmstatUsable ? vmstat.swap_out_bytes_per_second : null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
function validHistory(value: SupervisorHistory | undefined): value is SupervisorHistory {
|
|
56
71
|
return (
|
|
57
72
|
value?.schema_version === SUPERVISOR_HISTORY_SCHEMA_VERSION &&
|
|
Binary file
|
|
@@ -14,8 +14,13 @@ import {
|
|
|
14
14
|
import { hostname } from "node:os";
|
|
15
15
|
import { resolve } from "node:path";
|
|
16
16
|
import { performance } from "node:perf_hooks";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
17
18
|
import { collectCoordinationHealthSnapshot } from "../agents/health.ts";
|
|
18
19
|
import { checkPidToken, processStartToken } from "../agents/state/proc-start.ts";
|
|
20
|
+
import { pressureHistoryFromSupervisor } from "../diagnostics/advice.ts";
|
|
21
|
+
import { assessPressure } from "../diagnostics/pressure.ts";
|
|
22
|
+
import { readEventV3ControlState } from "../events/v3/control.ts";
|
|
23
|
+
import { janitorLiveDisplayV3 } from "../events/v3/live-feed.ts";
|
|
19
24
|
import type { ResourceSamplerState } from "../resources/contract.ts";
|
|
20
25
|
import { sampleResources } from "../resources/sampler.ts";
|
|
21
26
|
import { requestResourceServiceStop } from "../resources/service.ts";
|
|
@@ -25,8 +30,11 @@ import { writePrivateJsonAtomic } from "../storage/atomic-json.ts";
|
|
|
25
30
|
import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.ts";
|
|
26
31
|
import { collectSupervisorActivitySnapshot } from "./activity.ts";
|
|
27
32
|
import {
|
|
33
|
+
SUPERVISOR_PRESSURE_SCHEMA_VERSION,
|
|
28
34
|
SUPERVISOR_SNAPSHOT_SCHEMA_VERSION,
|
|
29
35
|
SUPERVISOR_STATUS_SCHEMA_VERSION,
|
|
36
|
+
type SupervisorCapability,
|
|
37
|
+
type SupervisorPressureRecord,
|
|
30
38
|
type SupervisorServiceStatusRecord,
|
|
31
39
|
type SupervisorSnapshot,
|
|
32
40
|
type SupervisorStatus,
|
|
@@ -37,10 +45,19 @@ import { updateSupervisorHistory } from "./history.ts";
|
|
|
37
45
|
import { projectHookHealth } from "./hook-health.ts";
|
|
38
46
|
import { writeSupervisorHookHealth } from "./hook-health-storage.ts";
|
|
39
47
|
import { collectHookHealth } from "./hooks.ts";
|
|
48
|
+
import type {
|
|
49
|
+
LedgerControlStateFindingInputV1,
|
|
50
|
+
LedgerControlStateObservationV1,
|
|
51
|
+
} from "./ledger-state.ts";
|
|
40
52
|
import { SupervisorLogCollector } from "./log-feed.ts";
|
|
41
53
|
import { collectServiceHealth } from "./services.ts";
|
|
42
54
|
import { readSupervisorStatus } from "./status.ts";
|
|
43
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
readSupervisorFindings,
|
|
57
|
+
readSupervisorHistory,
|
|
58
|
+
readSupervisorPressure,
|
|
59
|
+
supervisorPaths,
|
|
60
|
+
} from "./storage.ts";
|
|
44
61
|
import { buildSupervisorTimeline } from "./timeline.ts";
|
|
45
62
|
|
|
46
63
|
export const SUPERVISOR_DEFAULT_INTERVAL_MS = 2_000;
|
|
@@ -49,6 +66,7 @@ const SUPERVISOR_MIN_INTERVAL_MS = 500;
|
|
|
49
66
|
const SUPERVISOR_MAX_INTERVAL_MS = 60_000;
|
|
50
67
|
const SUPERVISOR_MIN_IDLE_EXIT_MS = 5_000;
|
|
51
68
|
const SUPERVISOR_MAX_IDLE_EXIT_MS = 24 * 60 * 60_000;
|
|
69
|
+
const LIVE_DISPLAY_SWEEP_INTERVAL_MS = 5 * 60_000;
|
|
52
70
|
|
|
53
71
|
interface SupervisorLease {
|
|
54
72
|
pid: number;
|
|
@@ -87,12 +105,15 @@ export async function spawnSupervisor(
|
|
|
87
105
|
const paths = supervisorPaths(coordRoot);
|
|
88
106
|
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
89
107
|
rmSync(paths.stop, { force: true });
|
|
90
|
-
const
|
|
91
|
-
|
|
108
|
+
const cliPath = fileURLToPath(
|
|
109
|
+
new URL(import.meta.url.endsWith(".ts") ? "../../cli.ts" : "../../cli.js", import.meta.url),
|
|
110
|
+
);
|
|
111
|
+
if (!existsSync(cliPath)) throw new Error(`cannot find harn entrypoint at ${cliPath}`);
|
|
92
112
|
let spawnError: Error | undefined;
|
|
93
113
|
const child = spawn(
|
|
94
|
-
|
|
114
|
+
process.execPath,
|
|
95
115
|
[
|
|
116
|
+
cliPath,
|
|
96
117
|
"supervisor",
|
|
97
118
|
"daemon",
|
|
98
119
|
"--root",
|
|
@@ -106,6 +127,7 @@ export async function spawnSupervisor(
|
|
|
106
127
|
{
|
|
107
128
|
cwd: coordRoot,
|
|
108
129
|
detached: true,
|
|
130
|
+
windowsHide: true,
|
|
109
131
|
stdio: ["ignore", "ignore", "ignore"],
|
|
110
132
|
env: {
|
|
111
133
|
...process.env,
|
|
@@ -153,7 +175,7 @@ export function requestSupervisorStop(coordRootRaw: string): SupervisorStatus {
|
|
|
153
175
|
requested_at: new Date().toISOString(),
|
|
154
176
|
requested_by_pid: process.pid,
|
|
155
177
|
});
|
|
156
|
-
if (status.running && status.record?.host === hostname()) {
|
|
178
|
+
if (status.running && status.record?.host === hostname() && process.platform !== "win32") {
|
|
157
179
|
try {
|
|
158
180
|
process.kill(status.record.pid, "SIGTERM");
|
|
159
181
|
} catch {
|
|
@@ -196,7 +218,22 @@ export async function runSupervisor(
|
|
|
196
218
|
let history = readSupervisorHistory(coordRoot);
|
|
197
219
|
let findings = readSupervisorFindings(coordRoot);
|
|
198
220
|
let coordination = collectCoordinationHealthSnapshot(coordRoot, now());
|
|
221
|
+
// The observer is the only reader that sees consecutive samples, so it is the
|
|
222
|
+
// only writer of the pressure assessment. Trend needs recent samples and a
|
|
223
|
+
// restart deliberately starts with none, which reports an unknown trend
|
|
224
|
+
// rather than a guessed one.
|
|
225
|
+
// The control state is now a cheap witnessed read in both states, so the
|
|
226
|
+
// observer can watch it every cycle. A single non-active sample is a normal
|
|
227
|
+
// boundary between two appends; the finding needs two, so keep a short run.
|
|
228
|
+
const ledgerObservations: LedgerControlStateObservationV1[] = [];
|
|
229
|
+
const priorPressure = readSupervisorPressure(coordRoot);
|
|
230
|
+
let pressureHysteresis = priorPressure?.assessment.hysteresis ?? null;
|
|
231
|
+
const observerGeneration = `${process.pid}:${startedAt}`;
|
|
199
232
|
const logs = new SupervisorLogCollector(coordRoot);
|
|
233
|
+
// Live-display rows expire within the hour, but nothing else deletes their
|
|
234
|
+
// generation files. Left alone the directory grows without bound and every
|
|
235
|
+
// dashboard read pays for the residue, so the supervisor sweeps it.
|
|
236
|
+
let lastLiveDisplaySweepMs = 0;
|
|
200
237
|
const writeStatus = () => {
|
|
201
238
|
status.heartbeat_at = now().toISOString();
|
|
202
239
|
writePrivateJsonAtomic(paths.service, status);
|
|
@@ -221,8 +258,18 @@ export async function runSupervisor(
|
|
|
221
258
|
const cycleStarted = performance.now();
|
|
222
259
|
try {
|
|
223
260
|
const cycleNow = now();
|
|
261
|
+
if (cycleNow.getTime() - lastLiveDisplaySweepMs >= LIVE_DISPLAY_SWEEP_INTERVAL_MS) {
|
|
262
|
+
lastLiveDisplaySweepMs = cycleNow.getTime();
|
|
263
|
+
try {
|
|
264
|
+
const swept = janitorLiveDisplayV3(coordRoot, now);
|
|
265
|
+
if (swept.removed > 0) log(coordRoot, "supervisor.live_display_swept", { ...swept });
|
|
266
|
+
} catch (error) {
|
|
267
|
+
log(coordRoot, "supervisor.live_display_sweep_error", {}, error);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
224
270
|
const serviceHealth = collectServiceHealth(coordRoot, status);
|
|
225
271
|
const resource = sampleResources(coordRoot, previousResource, {
|
|
272
|
+
backgroundHost: true,
|
|
226
273
|
services: [
|
|
227
274
|
{ pid: process.pid, id: "supervisor" },
|
|
228
275
|
...serviceHealth.consumers.map((consumer) => ({
|
|
@@ -246,6 +293,14 @@ export async function runSupervisor(
|
|
|
246
293
|
if (historyResult.changed)
|
|
247
294
|
coordination = collectCoordinationHealthSnapshot(coordRoot, cycleNow);
|
|
248
295
|
writePrivateJsonAtomic(paths.coordination_health, coordination);
|
|
296
|
+
const ledgerControl = observeLedgerControlState(coordRoot, cycleNow);
|
|
297
|
+
const ledgerControlState: LedgerControlStateFindingInputV1 = {
|
|
298
|
+
current: ledgerControl.observation,
|
|
299
|
+
previous: [...ledgerObservations].reverse(),
|
|
300
|
+
capability: ledgerControl.capability,
|
|
301
|
+
};
|
|
302
|
+
ledgerObservations.push(ledgerControl.observation);
|
|
303
|
+
if (ledgerObservations.length > LEDGER_OBSERVATION_LIMIT) ledgerObservations.shift();
|
|
249
304
|
const priorActiveFindingIds = new Set(findings?.active.map((finding) => finding.id) ?? []);
|
|
250
305
|
const priorTransitionKeys = new Set(
|
|
251
306
|
findings?.transitions.map((finding) => `${finding.id}:${finding.state}`) ?? [],
|
|
@@ -260,9 +315,43 @@ export async function runSupervisor(
|
|
|
260
315
|
hookHealth,
|
|
261
316
|
coordination,
|
|
262
317
|
activity,
|
|
318
|
+
ledgerControlState,
|
|
263
319
|
now: cycleNow,
|
|
264
320
|
});
|
|
265
321
|
writePrivateJsonAtomic(paths.findings, findings);
|
|
322
|
+
const assessment = assessPressure({
|
|
323
|
+
snapshot: resource.snapshot,
|
|
324
|
+
history: pressureHistoryFromSupervisor(history.points),
|
|
325
|
+
findings: findings.active,
|
|
326
|
+
findings_capability: { source_kind: "supervisor-findings", state: "supported" },
|
|
327
|
+
prior: pressureHysteresis,
|
|
328
|
+
observer_generation: observerGeneration,
|
|
329
|
+
// Read the clock after sampling. `cycleNow` predates the snapshot, so
|
|
330
|
+
// using it here dates the sample in the future and publishes a
|
|
331
|
+
// negative age that the status reader rejects as malformed.
|
|
332
|
+
now_ms: now().getTime(),
|
|
333
|
+
});
|
|
334
|
+
writePrivateJsonAtomic(paths.pressure, {
|
|
335
|
+
schema_version: SUPERVISOR_PRESSURE_SCHEMA_VERSION,
|
|
336
|
+
published_at: cycleNow.toISOString(),
|
|
337
|
+
observer_generation: observerGeneration,
|
|
338
|
+
assessment,
|
|
339
|
+
prior_hysteresis: pressureHysteresis,
|
|
340
|
+
} satisfies SupervisorPressureRecord);
|
|
341
|
+
const priorPressureState = pressureHysteresis?.state ?? null;
|
|
342
|
+
if (assessment.state !== priorPressureState) {
|
|
343
|
+
// The sample log carries only cycle timings, so without this record
|
|
344
|
+
// a past elevated episode cannot be explained after it clears.
|
|
345
|
+
log(coordRoot, "supervisor.pressure_transition", {
|
|
346
|
+
from_state: priorPressureState ?? "none",
|
|
347
|
+
to_state: assessment.state,
|
|
348
|
+
scope: assessment.scope,
|
|
349
|
+
limiting_resource: assessment.limiting_resource,
|
|
350
|
+
recommended_action: assessment.recommended_action,
|
|
351
|
+
reasons: assessment.reasons.map((reason) => `${reason.code}: ${reason.summary}`),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
pressureHysteresis = assessment.hysteresis;
|
|
266
355
|
mkdirSync(paths.timelines, { recursive: true, mode: 0o700 });
|
|
267
356
|
mkdirSync(paths.explanations, { recursive: true, mode: 0o700 });
|
|
268
357
|
const projectionUpdates = [
|
|
@@ -365,6 +454,45 @@ export async function runSupervisor(
|
|
|
365
454
|
return status;
|
|
366
455
|
}
|
|
367
456
|
|
|
457
|
+
const LEDGER_OBSERVATION_LIMIT = 8;
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Read the control state without letting a broken ledger break observation.
|
|
461
|
+
* A failed read is reported as an unsupported capability with an `invalid`
|
|
462
|
+
* state, never as a healthy `active`.
|
|
463
|
+
*/
|
|
464
|
+
function observeLedgerControlState(
|
|
465
|
+
coordRoot: string,
|
|
466
|
+
now: Date,
|
|
467
|
+
): { observation: LedgerControlStateObservationV1; capability: SupervisorCapability } {
|
|
468
|
+
const observedAt = now.toISOString();
|
|
469
|
+
try {
|
|
470
|
+
const control = readEventV3ControlState(coordRoot);
|
|
471
|
+
return {
|
|
472
|
+
observation: {
|
|
473
|
+
state: control.state,
|
|
474
|
+
...("reason" in control && control.reason ? { reason: control.reason } : {}),
|
|
475
|
+
observed_at: observedAt,
|
|
476
|
+
},
|
|
477
|
+
capability: { source_kind: "event-ledger.control-state", state: "supported" },
|
|
478
|
+
};
|
|
479
|
+
} catch (error) {
|
|
480
|
+
return {
|
|
481
|
+
observation: {
|
|
482
|
+
state: "invalid",
|
|
483
|
+
reason: "control_state_unreadable",
|
|
484
|
+
observed_at: observedAt,
|
|
485
|
+
},
|
|
486
|
+
capability: {
|
|
487
|
+
source_kind: "event-ledger.control-state",
|
|
488
|
+
state: "error",
|
|
489
|
+
reason_code: "control-state-unreadable",
|
|
490
|
+
detail: error instanceof Error ? error.message.slice(0, 200) : "unknown error",
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
368
496
|
function acquireLease(coordRoot: string, now: Date): SupervisorLease {
|
|
369
497
|
const paths = supervisorPaths(coordRoot);
|
|
370
498
|
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
SupervisorFindings,
|
|
9
9
|
SupervisorHistory,
|
|
10
10
|
SupervisorLogFeed,
|
|
11
|
+
SupervisorPressureRecord,
|
|
11
12
|
SupervisorServiceStatusRecord,
|
|
12
13
|
SupervisorSnapshot,
|
|
13
14
|
SupervisorTimeline,
|
|
@@ -22,6 +23,7 @@ export interface SupervisorPaths {
|
|
|
22
23
|
history: string;
|
|
23
24
|
activity: string;
|
|
24
25
|
findings: string;
|
|
26
|
+
pressure: string;
|
|
25
27
|
timelines: string;
|
|
26
28
|
explanations: string;
|
|
27
29
|
coordination_health: string;
|
|
@@ -40,6 +42,7 @@ export function supervisorPaths(coordRootRaw: string): SupervisorPaths {
|
|
|
40
42
|
history: join(root, "history.json"),
|
|
41
43
|
activity: join(root, "activity.json"),
|
|
42
44
|
findings: join(root, "findings.json"),
|
|
45
|
+
pressure: join(root, "pressure.json"),
|
|
43
46
|
timelines: join(root, "timelines"),
|
|
44
47
|
explanations: join(root, "explanations"),
|
|
45
48
|
coordination_health: join(root, "coordination-health.json"),
|
|
@@ -74,6 +77,10 @@ export function readSupervisorFindings(coordRoot: string): SupervisorFindings |
|
|
|
74
77
|
return readJson<SupervisorFindings>(supervisorPaths(coordRoot).findings);
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
export function readSupervisorPressure(coordRoot: string): SupervisorPressureRecord | undefined {
|
|
81
|
+
return readJson<SupervisorPressureRecord>(supervisorPaths(coordRoot).pressure);
|
|
82
|
+
}
|
|
83
|
+
|
|
77
84
|
export function readSupervisorTimeline(
|
|
78
85
|
coordRoot: string,
|
|
79
86
|
findingId: string,
|