harnery 0.30.0 → 0.31.1
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/README.md +4 -4
- package/dist/commander.d.ts +8 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +14 -13
- package/dist/commands/adapter.d.ts +12 -0
- package/dist/commands/adapter.d.ts.map +1 -0
- package/dist/commands/{harness.js → adapter.js} +35 -35
- package/dist/commands/agents.d.ts +3 -2
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +185 -74
- package/dist/commands/artifacts.d.ts +4 -0
- package/dist/commands/artifacts.d.ts.map +1 -0
- package/dist/commands/artifacts.js +143 -0
- package/dist/commands/backup.d.ts +1 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +5 -2
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +310 -7
- package/dist/commands/checkpoint.d.ts +12 -0
- package/dist/commands/checkpoint.d.ts.map +1 -0
- package/dist/commands/checkpoint.js +162 -0
- package/dist/commands/context.d.ts +2 -2
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +3 -151
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +31 -7
- package/dist/commands/deinit.d.ts +2 -2
- package/dist/commands/deinit.js +15 -15
- package/dist/commands/doctor.js +23 -23
- package/dist/commands/governor.d.ts +4 -0
- package/dist/commands/governor.d.ts.map +1 -0
- package/dist/commands/{supervisor.js → governor.js} +133 -108
- package/dist/commands/grep.d.ts +1 -1
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +19 -2
- package/dist/commands/init.d.ts +12 -12
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +44 -30
- package/dist/commands/{session.d.ts → journal.d.ts} +2 -2
- package/dist/commands/journal.d.ts.map +1 -0
- package/dist/commands/{scratch.js → journal.js} +47 -47
- package/dist/commands/policy.js +1 -1
- package/dist/commands/presence.js +2 -2
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.js +3 -3
- package/dist/commands/tunnel.d.ts +16 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +213 -27
- package/dist/commands/web-fetch.js +1 -1
- package/dist/commands/web.d.ts +19 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +51 -0
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +38 -22
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +35 -28
- package/dist/core/{harnesses → adapters}/attest-projection.d.ts +2 -2
- package/dist/core/adapters/attest-projection.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attest.d.ts +16 -16
- package/dist/core/adapters/attest.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attest.js +9 -9
- package/dist/core/{harnesses → adapters}/attestation.d.ts +16 -16
- package/dist/core/adapters/attestation.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attestation.js +20 -20
- package/dist/core/{harnesses → adapters}/bench.d.ts +12 -12
- package/dist/core/adapters/bench.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/bench.js +12 -12
- package/dist/core/adapters/index.d.ts +13 -0
- package/dist/core/adapters/index.d.ts.map +1 -0
- package/dist/core/adapters/index.js +6 -0
- package/dist/core/{harnesses → adapters}/profiles.d.ts +11 -11
- package/dist/core/adapters/profiles.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/profiles.js +11 -11
- package/dist/core/adapters/registry.d.ts +15 -0
- package/dist/core/adapters/registry.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/registry.js +11 -11
- package/dist/core/{harnesses → adapters}/types.d.ts +23 -23
- package/dist/core/adapters/types.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/types.js +1 -1
- package/dist/core/agents/canonical-emit.d.ts +9 -14
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +15 -44
- package/dist/core/agents/cli-emit.js +1 -1
- package/dist/core/agents/cli.js +30 -26
- package/dist/core/agents/codex-replay.d.ts +1 -1
- package/dist/core/agents/codex-replay.js +6 -6
- package/dist/core/agents/coord-bin.d.ts +33 -0
- package/dist/core/agents/coord-bin.d.ts.map +1 -0
- package/dist/core/agents/coord-bin.js +89 -0
- package/dist/core/agents/coord-client.d.ts +78 -8
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +303 -75
- package/dist/core/agents/events/consume.d.ts +1 -1
- package/dist/core/agents/events/emit.d.ts +5 -6
- package/dist/core/agents/events/emit.d.ts.map +1 -1
- package/dist/core/agents/events/emit.js +2 -2
- package/dist/core/agents/paths.d.ts +5 -2
- package/dist/core/agents/paths.d.ts.map +1 -1
- package/dist/core/agents/paths.js +7 -13
- package/dist/core/agents/render/prompt-context.d.ts +21 -9
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +82 -30
- package/dist/core/agents/render/session-context.d.ts +1 -1
- package/dist/core/agents/render/session-context.js +5 -5
- package/dist/core/agents/rules/claim-conflict.d.ts +2 -6
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +1 -1
- package/dist/core/agents/rules/commit-conflict.js +98 -22
- package/dist/core/agents/rules/stop-hook.d.ts +9 -9
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +23 -5
- package/dist/core/agents/rules/verdict.d.ts +14 -0
- package/dist/core/agents/rules/verdict.d.ts.map +1 -0
- package/dist/core/agents/rules/verdict.js +1 -0
- package/dist/core/agents/session-events.js +3 -3
- package/dist/core/agents/state/council.d.ts +1 -1
- package/dist/core/agents/state/council.js +1 -1
- package/dist/core/agents/state/heartbeat-projector.d.ts +3 -2
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +14 -10
- package/dist/core/agents/state/heartbeat-writer.d.ts +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +12 -12
- package/dist/core/agents/state/{scratch.d.ts → journal.d.ts} +7 -7
- package/dist/core/agents/state/{scratch.d.ts.map → journal.d.ts.map} +1 -1
- package/dist/core/agents/state/{scratch.js → journal.js} +12 -12
- package/dist/core/agents/state/pidmap.d.ts +28 -4
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +130 -15
- package/dist/core/agents/state/proc-start.d.ts +95 -0
- package/dist/core/agents/state/proc-start.d.ts.map +1 -0
- package/dist/core/agents/state/proc-start.js +199 -0
- package/dist/core/agents/state/shell-mutation.d.ts +1 -1
- package/dist/core/agents/state/shell-mutation.js +1 -1
- package/dist/core/agents/state/stale-sweep.js +7 -7
- package/dist/core/artifacts/index.d.ts +86 -0
- package/dist/core/artifacts/index.d.ts.map +1 -0
- package/dist/core/artifacts/index.js +421 -0
- package/dist/core/config.d.ts +9 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +26 -2
- package/dist/core/context/index.d.ts +12 -12
- package/dist/core/context/index.js +10 -10
- package/dist/core/governor/adapter-spread.d.ts +52 -0
- package/dist/core/governor/adapter-spread.d.ts.map +1 -0
- package/dist/core/governor/adapter-spread.js +52 -0
- package/dist/core/governor/index.d.ts +7 -0
- package/dist/core/governor/index.d.ts.map +1 -0
- package/dist/core/governor/index.js +6 -0
- package/dist/core/governor/plan-api.d.ts +38 -0
- package/dist/core/governor/plan-api.d.ts.map +1 -0
- package/dist/core/governor/plan-api.js +83 -0
- package/dist/core/governor/plan-read.d.ts +5 -0
- package/dist/core/governor/plan-read.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/plan-read.js +66 -52
- package/dist/core/{supervisor → governor}/plan-types.d.ts +57 -56
- package/dist/core/governor/plan-types.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/plan-types.js +4 -4
- package/dist/core/governor/planning.d.ts +48 -0
- package/dist/core/governor/planning.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/planning.js +125 -94
- package/dist/core/governor/read.d.ts +6 -0
- package/dist/core/governor/read.d.ts.map +1 -0
- package/dist/core/governor/read.js +4 -0
- package/dist/core/governor/runner.d.ts +37 -0
- package/dist/core/governor/runner.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/runner.js +15 -15
- package/dist/core/governor/service-read.d.ts +6 -0
- package/dist/core/governor/service-read.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/service-read.js +12 -12
- package/dist/core/governor/service.d.ts +114 -0
- package/dist/core/governor/service.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/service.js +57 -57
- package/dist/core/governor/state.d.ts +116 -0
- package/dist/core/governor/state.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/state.js +228 -108
- package/dist/core/hooks/adapter/detect.d.ts +9 -0
- package/dist/core/hooks/{harness → adapter}/detect.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/detect.js +8 -8
- package/dist/core/hooks/{harness → adapter}/events.d.ts +15 -14
- package/dist/core/hooks/adapter/events.d.ts.map +1 -0
- package/dist/core/hooks/{harness → adapter}/events.js +5 -5
- package/dist/core/hooks/{harness → adapter}/output.d.ts +20 -14
- package/dist/core/hooks/adapter/output.d.ts.map +1 -0
- package/dist/core/hooks/{harness → adapter}/output.js +30 -22
- package/dist/core/hooks/{harness → adapter}/parse.d.ts +5 -5
- package/dist/core/hooks/{harness → adapter}/parse.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/parse.js +4 -4
- package/dist/core/hooks/{harness → adapter}/wiring.d.ts +15 -15
- package/dist/core/hooks/{harness → adapter}/wiring.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/wiring.js +13 -13
- package/dist/core/hooks/cli.d.ts +3 -3
- package/dist/core/hooks/cli.js +187 -162
- package/dist/core/hooks/effects/image-capture.d.ts +5 -5
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +3 -3
- package/dist/core/hooks/effects/index.d.ts +12 -12
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +19 -19
- package/dist/core/hooks/events/emit.d.ts +2 -2
- package/dist/core/hooks/events/emit.d.ts.map +1 -1
- package/dist/core/hooks/events/emit.js +1 -1
- package/dist/core/hooks/events/rotate.js +1 -1
- package/dist/core/hooks/events/schema.d.ts +13 -5
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/guard-path.d.ts +2 -2
- package/dist/core/hooks/guard-path.js +2 -2
- package/dist/core/hooks/index.d.ts +1 -1
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/resolve/anchor.d.ts +14 -5
- package/dist/core/hooks/resolve/anchor.d.ts.map +1 -1
- package/dist/core/hooks/resolve/anchor.js +64 -7
- package/dist/core/hooks/resolve/coord-root.d.ts +16 -11
- package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
- package/dist/core/hooks/resolve/coord-root.js +18 -43
- package/dist/core/hooks/resolve/intent.js +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +1 -1
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +11 -5
- package/dist/core/{scratch → journal}/index.d.ts +25 -25
- package/dist/core/{scratch → journal}/index.d.ts.map +1 -1
- package/dist/core/{scratch → journal}/index.js +38 -38
- package/dist/core/policy/evaluate.d.ts +1 -1
- package/dist/core/policy/evaluate.d.ts.map +1 -1
- package/dist/core/policy/evaluate.js +7 -7
- package/dist/core/policy/types.d.ts +3 -3
- package/dist/core/policy/types.d.ts.map +1 -1
- package/dist/core/work/state.d.ts +12 -4
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +50 -17
- package/dist/core/workflow/adapters.d.ts +17 -0
- package/dist/core/workflow/adapters.d.ts.map +1 -0
- package/dist/core/workflow/adapters.js +21 -0
- package/dist/core/workflow/approvals.js +6 -6
- package/dist/core/workflow/billing.d.ts +9 -9
- package/dist/core/workflow/billing.js +9 -9
- package/dist/core/workflow/child-env.d.ts +10 -2
- package/dist/core/workflow/child-env.d.ts.map +1 -1
- package/dist/core/workflow/child-env.js +12 -4
- package/dist/core/workflow/engine.d.ts +15 -5
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +138 -83
- package/dist/core/workflow/evidence-preflight.d.ts +24 -0
- package/dist/core/workflow/evidence-preflight.d.ts.map +1 -0
- package/dist/core/workflow/evidence-preflight.js +134 -0
- package/dist/core/workflow/index.d.ts +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/proof.d.ts +11 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +45 -36
- package/dist/core/workflow/run-state.d.ts +1 -1
- package/dist/core/workflow/run-state.js +7 -7
- package/dist/core/workflow/sandbox-projection.d.ts +6 -6
- package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
- package/dist/core/workflow/sandbox-projection.js +11 -11
- package/dist/core/workflow/spawn-claude.d.ts +3 -3
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +9 -6
- package/dist/core/workflow/spawn-codex.d.ts +4 -4
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +9 -6
- package/dist/core/workflow/spawn-cursor.d.ts +4 -4
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +9 -6
- package/dist/core/workflow/spawn-failure.d.ts +1 -1
- package/dist/core/workflow/spawn-failure.js +1 -1
- package/dist/core/workflow/specialists.js +2 -2
- package/dist/core/workflow/{journal.d.ts → transcript.d.ts} +8 -8
- package/dist/core/workflow/transcript.d.ts.map +1 -0
- package/dist/core/workflow/{journal.js → transcript.js} +14 -14
- package/dist/core/workflow/types.d.ts +98 -51
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +11 -1
- package/dist/core/workflow/validate.d.ts +1 -1
- package/dist/core/workflow/validate.js +1 -1
- package/dist/core/workflow/workspaces/cancellation.js +2 -2
- package/dist/core/workflow/workspaces/cleanup.js +2 -2
- package/dist/core/workflow/workspaces/execution.js +6 -6
- package/dist/core/workflow/workspaces/inspect.js +9 -9
- package/dist/core/workflow/workspaces/integration.js +14 -14
- package/dist/core/workflow/workspaces/lifecycle.d.ts +1 -1
- package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/lifecycle.js +9 -9
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +39 -5
- package/dist/core/workflow/workspaces/recovery.js +3 -3
- package/dist/core/workflow/workspaces/state.d.ts +1 -1
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +3 -3
- package/dist/core/workflow/workspaces/types.d.ts +1 -1
- package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
- package/dist/lib/browser/asserts.d.ts +28 -0
- package/dist/lib/browser/asserts.d.ts.map +1 -0
- package/dist/lib/browser/asserts.js +152 -0
- package/dist/lib/browser/client.d.ts +49 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +155 -14
- package/dist/lib/browser/content-checks.d.ts +108 -0
- package/dist/lib/browser/content-checks.d.ts.map +1 -0
- package/dist/lib/browser/content-checks.js +474 -0
- package/dist/lib/browser/critique.d.ts +91 -0
- package/dist/lib/browser/critique.d.ts.map +1 -0
- package/dist/lib/browser/critique.js +167 -0
- package/dist/lib/browser/geometry.d.ts +32 -0
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +244 -1
- package/dist/lib/browser/index.d.ts +4 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -1
- package/dist/lib/claude-desktop.js +4 -1
- package/dist/lib/context/index.js +9 -2
- package/dist/lib/council/index.d.ts +6 -6
- package/dist/lib/council/index.d.ts.map +1 -1
- package/dist/lib/council/index.js +8 -8
- package/dist/lib/identities/assume.d.ts +2 -2
- package/dist/lib/identities/assume.js +7 -7
- package/dist/lib/instructions/apply.d.ts +3 -3
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +75 -27
- package/dist/lib/instructions/host-addendum.d.ts +54 -0
- package/dist/lib/instructions/host-addendum.d.ts.map +1 -0
- package/dist/lib/instructions/host-addendum.js +107 -0
- package/dist/lib/instructions/templates.d.ts +10 -3
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +41 -12
- package/dist/lib/machine.d.ts +2 -2
- package/dist/lib/machine.js +2 -2
- package/package.json +26 -21
- package/schemas/config.schema.json +26 -1
- package/src/commander.ts +22 -13
- package/src/commands/{harness.ts → adapter.ts} +46 -46
- package/src/commands/agents.ts +200 -78
- package/src/commands/artifacts.ts +168 -0
- package/src/commands/backup.ts +47 -33
- package/src/commands/browse.ts +438 -2
- package/src/commands/checkpoint.ts +196 -0
- package/src/commands/context.ts +3 -176
- package/src/commands/decision.ts +41 -7
- package/src/commands/deinit.ts +16 -16
- package/src/commands/doctor.ts +28 -28
- package/src/commands/{supervisor.ts → governor.ts} +184 -154
- package/src/commands/grep.ts +19 -2
- package/src/commands/init.ts +50 -34
- package/src/commands/{scratch.ts → journal.ts} +60 -60
- package/src/commands/policy.ts +1 -1
- package/src/commands/presence.ts +2 -2
- package/src/commands/sync.ts +3 -3
- package/src/commands/tunnel.ts +256 -38
- package/src/commands/web-fetch.ts +1 -1
- package/src/commands/web.ts +56 -1
- package/src/commands/work.ts +50 -35
- package/src/commands/workflow.ts +43 -34
- package/src/core/{harnesses → adapters}/attest-projection.ts +2 -2
- package/src/core/{harnesses → adapters}/attest.ts +27 -27
- package/src/core/{harnesses → adapters}/attestation.ts +41 -41
- package/src/core/{harnesses → adapters}/bench.ts +34 -43
- package/src/core/adapters/index.ts +56 -0
- package/src/core/{harnesses → adapters}/profiles.ts +16 -16
- package/src/core/{harnesses → adapters}/registry.ts +23 -23
- package/src/core/{harnesses → adapters}/types.ts +23 -23
- package/src/core/agents/canonical-emit.ts +16 -43
- package/src/core/agents/cli-emit.ts +1 -1
- package/src/core/agents/cli.ts +30 -28
- package/src/core/agents/codex-replay.ts +6 -6
- package/src/core/agents/coord-bin.ts +92 -0
- package/src/core/agents/coord-client.ts +302 -78
- package/src/core/agents/events/consume.ts +1 -1
- package/src/core/agents/events/emit.ts +7 -6
- package/src/core/agents/paths.ts +7 -11
- package/src/core/agents/render/prompt-context.ts +107 -31
- package/src/core/agents/render/session-context.ts +6 -6
- package/src/core/agents/rules/claim-conflict.ts +4 -7
- package/src/core/agents/rules/commit-conflict.ts +103 -22
- package/src/core/agents/rules/stop-hook.ts +33 -17
- package/src/core/agents/rules/verdict.ts +13 -0
- package/src/core/agents/session-events.ts +4 -4
- package/src/core/agents/state/council.ts +1 -1
- package/src/core/agents/state/heartbeat-projector.ts +16 -12
- package/src/core/agents/state/heartbeat-writer.ts +12 -12
- package/src/core/agents/state/{scratch.ts → journal.ts} +12 -12
- package/src/core/agents/state/pidmap.ts +130 -15
- package/src/core/agents/state/proc-start.ts +208 -0
- package/src/core/agents/state/shell-mutation.ts +1 -1
- package/src/core/agents/state/stale-sweep.ts +7 -7
- package/src/core/artifacts/index.ts +557 -0
- package/src/core/config.ts +30 -2
- package/src/core/context/index.ts +15 -15
- package/src/core/governor/adapter-spread.ts +82 -0
- package/src/core/governor/index.ts +91 -0
- package/src/core/governor/plan-api.ts +115 -0
- package/src/core/{supervisor → governor}/plan-read.ts +112 -97
- package/src/core/{supervisor → governor}/plan-types.ts +59 -56
- package/src/core/{supervisor → governor}/planning.ts +223 -192
- package/src/core/governor/read.ts +59 -0
- package/src/core/{supervisor → governor}/runner.ts +39 -39
- package/src/core/{supervisor → governor}/service-read.ts +22 -22
- package/src/core/{supervisor → governor}/service.ts +117 -119
- package/src/core/{supervisor → governor}/state.ts +325 -167
- package/src/core/hooks/adapter/detect.ts +30 -0
- package/src/core/hooks/{harness → adapter}/events.ts +16 -14
- package/src/core/hooks/{harness → adapter}/output.ts +31 -23
- package/src/core/hooks/{harness → adapter}/parse.ts +5 -5
- package/src/core/hooks/{harness → adapter}/wiring.ts +21 -21
- package/src/core/hooks/cli.ts +197 -173
- package/src/core/hooks/effects/image-capture.ts +6 -6
- package/src/core/hooks/effects/index.ts +19 -19
- package/src/core/hooks/events/emit.ts +3 -3
- package/src/core/hooks/events/rotate.ts +1 -1
- package/src/core/hooks/events/schema.ts +15 -7
- package/src/core/hooks/guard-path.ts +2 -2
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/resolve/anchor.ts +63 -8
- package/src/core/hooks/resolve/coord-root.ts +18 -40
- package/src/core/hooks/resolve/intent.ts +1 -1
- package/src/core/hooks/resolve/owner.ts +11 -5
- package/src/core/{scratch → journal}/index.ts +53 -53
- package/src/core/policy/evaluate.ts +8 -8
- package/src/core/policy/types.ts +3 -3
- package/src/core/work/state.ts +65 -23
- package/src/core/workflow/adapters.ts +33 -0
- package/src/core/workflow/approvals.ts +7 -7
- package/src/core/workflow/billing.ts +12 -12
- package/src/core/workflow/child-env.ts +13 -4
- package/src/core/workflow/engine.ts +155 -90
- package/src/core/workflow/evidence-preflight.ts +165 -0
- package/src/core/workflow/index.ts +3 -3
- package/src/core/workflow/proof.ts +60 -50
- package/src/core/workflow/run-state.ts +7 -7
- package/src/core/workflow/sandbox-projection.ts +16 -16
- package/src/core/workflow/spawn-claude.ts +13 -10
- package/src/core/workflow/spawn-codex.ts +13 -10
- package/src/core/workflow/spawn-cursor.ts +13 -10
- package/src/core/workflow/spawn-failure.ts +1 -1
- package/src/core/workflow/specialists.ts +2 -2
- package/src/core/workflow/{journal.ts → transcript.ts} +16 -16
- package/src/core/workflow/types.ts +108 -51
- package/src/core/workflow/validate.ts +1 -1
- package/src/core/workflow/workspaces/cancellation.ts +2 -2
- package/src/core/workflow/workspaces/cleanup.ts +2 -2
- package/src/core/workflow/workspaces/execution.ts +6 -6
- package/src/core/workflow/workspaces/inspect.ts +14 -11
- package/src/core/workflow/workspaces/integration.ts +18 -14
- package/src/core/workflow/workspaces/lifecycle.ts +10 -10
- package/src/core/workflow/workspaces/local-git.ts +47 -5
- package/src/core/workflow/workspaces/recovery.ts +3 -3
- package/src/core/workflow/workspaces/state.ts +4 -3
- package/src/core/workflow/workspaces/types.ts +1 -1
- package/src/lib/browser/asserts.ts +177 -0
- package/src/lib/browser/client.ts +189 -14
- package/src/lib/browser/content-checks.ts +571 -0
- package/src/lib/browser/critique.ts +231 -0
- package/src/lib/browser/geometry.ts +297 -1
- package/src/lib/browser/index.ts +34 -0
- package/src/lib/claude-desktop.ts +4 -1
- package/src/lib/context/index.ts +11 -1
- package/src/lib/council/index.ts +9 -9
- package/src/lib/identities/assume.ts +7 -7
- package/src/lib/instructions/apply.ts +87 -25
- package/src/lib/instructions/host-addendum.ts +126 -0
- package/src/lib/instructions/templates.ts +44 -15
- package/src/lib/machine.ts +2 -2
- package/dist/commands/harness.d.ts +0 -12
- package/dist/commands/harness.d.ts.map +0 -1
- package/dist/commands/scratch.d.ts +0 -4
- package/dist/commands/scratch.d.ts.map +0 -1
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/session.js +0 -162
- package/dist/commands/supervisor.d.ts +0 -4
- package/dist/commands/supervisor.d.ts.map +0 -1
- package/dist/core/harnesses/attest-projection.d.ts.map +0 -1
- package/dist/core/harnesses/attest.d.ts.map +0 -1
- package/dist/core/harnesses/attestation.d.ts.map +0 -1
- package/dist/core/harnesses/bench.d.ts.map +0 -1
- package/dist/core/harnesses/index.d.ts +0 -13
- package/dist/core/harnesses/index.d.ts.map +0 -1
- package/dist/core/harnesses/index.js +0 -6
- package/dist/core/harnesses/profiles.d.ts.map +0 -1
- package/dist/core/harnesses/registry.d.ts +0 -15
- package/dist/core/harnesses/registry.d.ts.map +0 -1
- package/dist/core/harnesses/types.d.ts.map +0 -1
- package/dist/core/hooks/harness/detect.d.ts +0 -9
- package/dist/core/hooks/harness/events.d.ts.map +0 -1
- package/dist/core/hooks/harness/output.d.ts.map +0 -1
- package/dist/core/supervisor/index.d.ts +0 -7
- package/dist/core/supervisor/index.d.ts.map +0 -1
- package/dist/core/supervisor/index.js +0 -6
- package/dist/core/supervisor/plan-api.d.ts +0 -23
- package/dist/core/supervisor/plan-api.d.ts.map +0 -1
- package/dist/core/supervisor/plan-api.js +0 -50
- package/dist/core/supervisor/plan-read.d.ts +0 -5
- package/dist/core/supervisor/plan-read.d.ts.map +0 -1
- package/dist/core/supervisor/plan-types.d.ts.map +0 -1
- package/dist/core/supervisor/planning.d.ts +0 -33
- package/dist/core/supervisor/planning.d.ts.map +0 -1
- package/dist/core/supervisor/read.d.ts +0 -6
- package/dist/core/supervisor/read.d.ts.map +0 -1
- package/dist/core/supervisor/read.js +0 -4
- package/dist/core/supervisor/runner.d.ts +0 -37
- package/dist/core/supervisor/runner.d.ts.map +0 -1
- package/dist/core/supervisor/service-read.d.ts +0 -6
- package/dist/core/supervisor/service-read.d.ts.map +0 -1
- package/dist/core/supervisor/service.d.ts +0 -114
- package/dist/core/supervisor/service.d.ts.map +0 -1
- package/dist/core/supervisor/state.d.ts +0 -95
- package/dist/core/supervisor/state.d.ts.map +0 -1
- package/dist/core/workflow/harnesses.d.ts +0 -17
- package/dist/core/workflow/harnesses.d.ts.map +0 -1
- package/dist/core/workflow/harnesses.js +0 -21
- package/dist/core/workflow/journal.d.ts.map +0 -1
- package/src/commands/session.ts +0 -187
- package/src/core/harnesses/index.ts +0 -56
- package/src/core/hooks/harness/detect.ts +0 -30
- package/src/core/supervisor/index.ts +0 -89
- package/src/core/supervisor/plan-api.ts +0 -73
- package/src/core/supervisor/read.ts +0 -59
- package/src/core/workflow/harnesses.ts +0 -33
- /package/dist/core/{harnesses → adapters}/attest-projection.js +0 -0
|
@@ -5,9 +5,9 @@ import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
|
5
5
|
import { assertWorkId, readWorkItem } from "../work/read.js";
|
|
6
6
|
import { workflowScriptDigest } from "../workflow/run-state.js";
|
|
7
7
|
import { normalizeWorkflowSpecialists } from "../workflow/specialists.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
export const
|
|
8
|
+
import { readGovernorPlans } from "./plan-read.js";
|
|
9
|
+
import { governorGraphFingerprint, MAX_GOVERNOR_PLAN_REVIEWERS, MAX_GOVERNOR_PLAN_REVISION_ROUNDS, } from "./plan-types.js";
|
|
10
|
+
export const GOVERNOR_INTENT_SCHEMA_VERSION = 1;
|
|
11
11
|
const GOAL_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
|
|
12
12
|
const MAX_TITLE = 200;
|
|
13
13
|
const MAX_OBJECTIVE = 4_000;
|
|
@@ -23,16 +23,16 @@ const FOREIGN_LEASE_STALE_MS = 24 * 60 * 60 * 1_000;
|
|
|
23
23
|
* rather than a policy field to keep the frozen replanning schema unchanged; an
|
|
24
24
|
* environment failure self-bounds at one because it stops immediately. */
|
|
25
25
|
const MAX_UNCHARGED_REPLANS = 3;
|
|
26
|
-
export function
|
|
26
|
+
export function createGovernor(input) {
|
|
27
27
|
const coordRoot = resolve(input.coordRoot);
|
|
28
|
-
const id = input.id ??
|
|
29
|
-
|
|
28
|
+
const id = input.id ?? newGovernorId();
|
|
29
|
+
assertGovernorId(id);
|
|
30
30
|
const mission = input.mission ? normalizeMission(input.mission) : undefined;
|
|
31
31
|
if (mission && !input.replanning) {
|
|
32
|
-
throw new Error("
|
|
32
|
+
throw new Error("governor mission requires a replanning policy");
|
|
33
33
|
}
|
|
34
34
|
if (!input.rootWorkId && !mission) {
|
|
35
|
-
throw new Error("
|
|
35
|
+
throw new Error("governor creation without root work requires a mission and replanning policy");
|
|
36
36
|
}
|
|
37
37
|
if (input.rootWorkId)
|
|
38
38
|
assertWorkId(input.rootWorkId);
|
|
@@ -48,9 +48,9 @@ export function createSupervisor(input) {
|
|
|
48
48
|
throw new Error("objective-first mission max_replans must exceed max_milestones to reserve completion review");
|
|
49
49
|
}
|
|
50
50
|
const intent = {
|
|
51
|
-
schema_version:
|
|
51
|
+
schema_version: GOVERNOR_INTENT_SCHEMA_VERSION,
|
|
52
52
|
id,
|
|
53
|
-
title: bounded(input.title ?? root?.intent.title ?? missionTitle(mission), "
|
|
53
|
+
title: bounded(input.title ?? root?.intent.title ?? missionTitle(mission), "governor title", MAX_TITLE),
|
|
54
54
|
root_work_id: input.rootWorkId ?? missionRootId(id),
|
|
55
55
|
specialists: normalizeWorkflowSpecialists(input.specialists),
|
|
56
56
|
limits,
|
|
@@ -59,39 +59,39 @@ export function createSupervisor(input) {
|
|
|
59
59
|
...(replanning ? { replanning } : {}),
|
|
60
60
|
created_at: new Date().toISOString(),
|
|
61
61
|
};
|
|
62
|
-
const path =
|
|
62
|
+
const path = governorIntentPath(coordRoot, id);
|
|
63
63
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
64
64
|
chmodSync(dirname(path), 0o700);
|
|
65
65
|
writePrivateJson(path, intent);
|
|
66
|
-
return
|
|
66
|
+
return readGovernor(coordRoot, id);
|
|
67
67
|
}
|
|
68
|
-
export function
|
|
69
|
-
return
|
|
68
|
+
export function readGovernor(coordRoot, goalId) {
|
|
69
|
+
return readGovernorInternal(coordRoot, goalId, false);
|
|
70
70
|
}
|
|
71
|
-
/** @internal Runner seam; ignores the lease held by this
|
|
72
|
-
export function
|
|
73
|
-
return
|
|
71
|
+
/** @internal Runner seam; ignores the lease held by this governor process. */
|
|
72
|
+
export function readGovernorIgnoringLease(coordRoot, goalId) {
|
|
73
|
+
return readGovernorInternal(coordRoot, goalId, true);
|
|
74
74
|
}
|
|
75
|
-
export function
|
|
76
|
-
const base = join(resolve(coordRoot), ".harnery", "
|
|
75
|
+
export function listGovernors(coordRoot) {
|
|
76
|
+
const base = join(resolve(coordRoot), ".harnery", "governors");
|
|
77
77
|
if (!existsSync(base))
|
|
78
78
|
return [];
|
|
79
79
|
const records = [];
|
|
80
80
|
for (const name of readdirSync(base)) {
|
|
81
|
-
if (!GOAL_ID.test(name) || !existsSync(
|
|
81
|
+
if (!GOAL_ID.test(name) || !existsSync(governorIntentPath(coordRoot, name)))
|
|
82
82
|
continue;
|
|
83
|
-
records.push(
|
|
83
|
+
records.push(readGovernor(coordRoot, name));
|
|
84
84
|
}
|
|
85
85
|
return records.sort((left, right) => right.intent.created_at.localeCompare(left.intent.created_at));
|
|
86
86
|
}
|
|
87
|
-
export function
|
|
87
|
+
export function collectGovernorWork(coordRoot, rootWorkId) {
|
|
88
88
|
const records = new Map();
|
|
89
89
|
const visiting = new Set();
|
|
90
90
|
const visit = (workId) => {
|
|
91
91
|
if (records.has(workId))
|
|
92
92
|
return;
|
|
93
93
|
if (visiting.has(workId))
|
|
94
|
-
throw new Error(`
|
|
94
|
+
throw new Error(`governor work graph contains a cycle at ${workId}`);
|
|
95
95
|
visiting.add(workId);
|
|
96
96
|
const record = readWorkItem(coordRoot, workId);
|
|
97
97
|
for (const dependency of record.intent.dependencies)
|
|
@@ -102,17 +102,17 @@ export function collectSupervisorWork(coordRoot, rootWorkId) {
|
|
|
102
102
|
visit(rootWorkId);
|
|
103
103
|
return Array.from(records.values());
|
|
104
104
|
}
|
|
105
|
-
export function
|
|
105
|
+
export function assertGovernorId(goalId) {
|
|
106
106
|
if (!GOAL_ID.test(goalId))
|
|
107
|
-
throw new Error(`invalid
|
|
107
|
+
throw new Error(`invalid governor id ${JSON.stringify(goalId)}`);
|
|
108
108
|
}
|
|
109
|
-
export function
|
|
109
|
+
export function newGovernorId() {
|
|
110
110
|
return `goal-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
|
|
111
111
|
}
|
|
112
|
-
/** @internal Runner seam; one exclusive crash-recoverable
|
|
113
|
-
export function
|
|
114
|
-
|
|
115
|
-
const path = join(
|
|
112
|
+
/** @internal Runner seam; one exclusive crash-recoverable governor lease. */
|
|
113
|
+
export function acquireGovernorLease(coordRoot, goalId) {
|
|
114
|
+
readGovernorIntent(coordRoot, goalId);
|
|
115
|
+
const path = join(governorDir(coordRoot, goalId), "lease.json");
|
|
116
116
|
const owner = {
|
|
117
117
|
pid: process.pid,
|
|
118
118
|
host: hostname(),
|
|
@@ -140,11 +140,11 @@ export function acquireSupervisorLease(coordRoot, goalId) {
|
|
|
140
140
|
if (!acquire()) {
|
|
141
141
|
const existing = readLease(path);
|
|
142
142
|
if (existing && leaseIsLive(existing)) {
|
|
143
|
-
throw new Error(`
|
|
143
|
+
throw new Error(`governor ${goalId} is already running under pid ${existing.pid} on ${existing.host}`);
|
|
144
144
|
}
|
|
145
145
|
unlinkSync(path);
|
|
146
146
|
if (!acquire())
|
|
147
|
-
throw new Error(`
|
|
147
|
+
throw new Error(`governor ${goalId} lease raced with another process`);
|
|
148
148
|
}
|
|
149
149
|
return () => {
|
|
150
150
|
try {
|
|
@@ -157,15 +157,15 @@ export function acquireSupervisorLease(coordRoot, goalId) {
|
|
|
157
157
|
}
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
|
-
function
|
|
160
|
+
function readGovernorInternal(coordRootRaw, goalId, ignoreLease) {
|
|
161
161
|
const coordRoot = resolve(coordRootRaw);
|
|
162
|
-
const intent =
|
|
163
|
-
const plans =
|
|
162
|
+
const intent = readGovernorIntent(coordRoot, goalId);
|
|
163
|
+
const plans = readGovernorPlans(coordRoot, intent.id, intent.root_work_id);
|
|
164
164
|
const activeRootExists = workIntentExists(coordRoot, plans.active_root_work_id);
|
|
165
165
|
if (!activeRootExists && (!intent.mission || plans.generation > 0)) {
|
|
166
|
-
throw new Error(`
|
|
166
|
+
throw new Error(`governor ${intent.id} root work is missing`);
|
|
167
167
|
}
|
|
168
|
-
const work = activeRootExists ?
|
|
168
|
+
const work = activeRootExists ? collectGovernorWork(coordRoot, plans.active_root_work_id) : [];
|
|
169
169
|
const governed = collectGovernedWork(coordRoot, intent.root_work_id, plans, work);
|
|
170
170
|
return {
|
|
171
171
|
intent,
|
|
@@ -184,8 +184,13 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
184
184
|
// Replans, like per-item attempts (ADR 0046), are budgeted by the CHARGED
|
|
185
185
|
// count: an uncharged planner failure (environment/upstream) does not spend
|
|
186
186
|
// max_replans. replans_used stays the raw count for display.
|
|
187
|
-
const unchargedReplans = plans.plans.filter((plan) => plan.status === "failed" && (plan.class
|
|
187
|
+
const unchargedReplans = plans.plans.filter((plan) => plan.status === "failed" && isUnchargedPlanClass(plan.class)).length;
|
|
188
188
|
const chargedReplans = plans.plans.length - unchargedReplans;
|
|
189
|
+
// Attribute the consumed replans that did not advance the graph so the
|
|
190
|
+
// projection can distinguish planner no-proposal exhaustion from reviewer
|
|
191
|
+
// rejection through existing plan seams (review receipt presence), rather than
|
|
192
|
+
// reporting both as a single undifferentiated replan exhaustion.
|
|
193
|
+
const replanConsumption = classifyReplanConsumption(plans);
|
|
189
194
|
const readyWork = work
|
|
190
195
|
.filter((record) => record.projection.state === "ready")
|
|
191
196
|
.map((record) => record.intent.id);
|
|
@@ -209,6 +214,15 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
209
214
|
const terminalBlocked = work
|
|
210
215
|
.filter((record) => record.projection.state === "blocked" && record.projection.next_action === "none")
|
|
211
216
|
.map((record) => record.intent.id);
|
|
217
|
+
// Work stopped on a person, kept apart from the rest of terminalBlocked. Every
|
|
218
|
+
// other terminal block is something an agent could in principle clear; this one
|
|
219
|
+
// can only be cleared by a ruling, so it is the thing worth saying out loud.
|
|
220
|
+
const decisionBlocked = work
|
|
221
|
+
.filter((record) => record.projection.blocked_on_decision !== undefined)
|
|
222
|
+
.map((record) => ({
|
|
223
|
+
work_id: record.intent.id,
|
|
224
|
+
decision_id: record.projection.blocked_on_decision || undefined,
|
|
225
|
+
}));
|
|
212
226
|
const attentionWork = unique([
|
|
213
227
|
...pendingApproval,
|
|
214
228
|
...(intent.automation.accept_passing_proof ? [] : reviews),
|
|
@@ -220,6 +234,12 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
220
234
|
const initialRootAccepted = intent.mission !== undefined &&
|
|
221
235
|
governed.some((record) => record.intent.id === intent.root_work_id && record.projection.state === "succeeded");
|
|
222
236
|
const milestonesCompleted = plans.milestones_completed + (initialRootAccepted ? 1 : 0);
|
|
237
|
+
const resumableDispatchable = intent.automation.resume_approved ? resumableWork : [];
|
|
238
|
+
const attemptDispatchable = [
|
|
239
|
+
...readyWork,
|
|
240
|
+
...(intent.automation.retry_blocked ? retryableWork : []),
|
|
241
|
+
];
|
|
242
|
+
const dispatchable = [...resumableDispatchable, ...attemptDispatchable];
|
|
223
243
|
const base = {
|
|
224
244
|
id: intent.id,
|
|
225
245
|
title: intent.title,
|
|
@@ -230,6 +250,7 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
230
250
|
resumable_work: resumableWork,
|
|
231
251
|
retryable_work: retryableWork,
|
|
232
252
|
attention_work: attentionWork,
|
|
253
|
+
decision_blocked_work: decisionBlocked,
|
|
233
254
|
attempts_used: attemptsUsed,
|
|
234
255
|
attempts_remaining: Math.max(0, intent.limits.max_total_attempts - chargedUsed),
|
|
235
256
|
specialists: Object.keys(intent.specialists),
|
|
@@ -240,13 +261,14 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
240
261
|
milestones_remaining: Math.max(0, (intent.mission?.max_milestones ?? 0) - milestonesCompleted),
|
|
241
262
|
pending_plan_id: plans.latest?.status === "proposed" ? plans.latest.request.id : undefined,
|
|
242
263
|
latest_plan_status: plans.latest?.status,
|
|
264
|
+
...(replanConsumption.planner_no_proposal > 0 ? { replan_consumption: replanConsumption } : {}),
|
|
243
265
|
governed_work_ids: governed.map((record) => record.intent.id),
|
|
244
266
|
};
|
|
245
|
-
if (!ignoreLease &&
|
|
267
|
+
if (!ignoreLease && governorLeaseIsLive(coordRoot, intent.id)) {
|
|
246
268
|
return {
|
|
247
269
|
...base,
|
|
248
270
|
state: "running",
|
|
249
|
-
reason: "the foreground
|
|
271
|
+
reason: "the foreground governor holds the goal lease",
|
|
250
272
|
next_action: "wait_for_run",
|
|
251
273
|
};
|
|
252
274
|
}
|
|
@@ -258,6 +280,19 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
258
280
|
next_action: "none",
|
|
259
281
|
};
|
|
260
282
|
}
|
|
283
|
+
// ADR 0050: a mission whose completion was reopened dispatches the reopened work
|
|
284
|
+
// before anything else. Without this the goal falls through to the milestone
|
|
285
|
+
// branch below, which still sees a succeeded root when the reopened item is one
|
|
286
|
+
// of its children, and would spend a replan reassessing a mission whose real
|
|
287
|
+
// remaining work is already sitting in ready_work.
|
|
288
|
+
if (intent.mission && plans.latest?.status === "reopened" && dispatchable.length > 0) {
|
|
289
|
+
return {
|
|
290
|
+
...base,
|
|
291
|
+
state: "ready",
|
|
292
|
+
reason: `mission completion was reopened; ${dispatchable.length} work item${dispatchable.length === 1 ? " is" : "s are"} dispatchable`,
|
|
293
|
+
next_action: "run",
|
|
294
|
+
};
|
|
295
|
+
}
|
|
261
296
|
if (plans.latest?.status === "proposed") {
|
|
262
297
|
return {
|
|
263
298
|
...base,
|
|
@@ -298,6 +333,17 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
298
333
|
next_action: "none",
|
|
299
334
|
};
|
|
300
335
|
}
|
|
336
|
+
if (plans.latest?.status === "failed" && plans.latest.class === "decision") {
|
|
337
|
+
// The planner concluded that a human must rule before this can be planned.
|
|
338
|
+
// Stop and say so. Replanning would re-ask a question the planner already
|
|
339
|
+
// answered correctly, which is how a goal spins without a person noticing.
|
|
340
|
+
return {
|
|
341
|
+
...base,
|
|
342
|
+
state: "blocked",
|
|
343
|
+
reason: `planning is waiting on a human decision: ${plans.latest.reason ?? "the planner did not say which"}`,
|
|
344
|
+
next_action: "none",
|
|
345
|
+
};
|
|
346
|
+
}
|
|
301
347
|
if (plans.latest?.status === "failed" && plans.latest.class === "upstream") {
|
|
302
348
|
// The vendor refused. Uncharged replans do not spend max_replans, so the
|
|
303
349
|
// only brake on an unending outage is this consecutive bound; at the limit
|
|
@@ -305,7 +351,7 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
305
351
|
let trailingUncharged = 0;
|
|
306
352
|
for (let index = plans.plans.length - 1; index >= 0; index--) {
|
|
307
353
|
const plan = plans.plans[index];
|
|
308
|
-
if (plan.status !== "failed" || (plan.class
|
|
354
|
+
if (plan.status !== "failed" || !isUnchargedPlanClass(plan.class)) {
|
|
309
355
|
break;
|
|
310
356
|
}
|
|
311
357
|
trailingUncharged++;
|
|
@@ -322,7 +368,7 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
322
368
|
// dispatchable — the vendor may have recovered. canReplan reads
|
|
323
369
|
// chargedReplans, so these uncharged attempts do not exhaust max_replans.
|
|
324
370
|
}
|
|
325
|
-
const triggerFingerprint =
|
|
371
|
+
const triggerFingerprint = governorGraphFingerprint({
|
|
326
372
|
rootWorkId: plans.active_root_work_id,
|
|
327
373
|
generation: plans.generation,
|
|
328
374
|
work,
|
|
@@ -331,12 +377,15 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
331
377
|
plans.latest.request.prior_root_work_id === plans.active_root_work_id &&
|
|
332
378
|
plans.latest.status === "attention";
|
|
333
379
|
if (latestHandledSameGraph && plans.latest) {
|
|
380
|
+
const canRetry = intent.replanning !== undefined && chargedReplans < intent.replanning.max_replans;
|
|
334
381
|
return {
|
|
335
382
|
...base,
|
|
336
383
|
state: "awaiting_attention",
|
|
337
|
-
reason:
|
|
384
|
+
reason: canRetry
|
|
385
|
+
? (plans.latest.reason ?? `plan ${plans.latest.request.id} requires attention`)
|
|
386
|
+
: exhaustedAttentionReason(plans.latest, replanConsumption),
|
|
338
387
|
attention_plan_id: plans.latest.request.id,
|
|
339
|
-
next_action:
|
|
388
|
+
next_action: canRetry ? "retry_plan" : "none",
|
|
340
389
|
};
|
|
341
390
|
}
|
|
342
391
|
if (!root && intent.mission) {
|
|
@@ -344,7 +393,7 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
344
393
|
return {
|
|
345
394
|
...base,
|
|
346
395
|
state: "budget_exhausted",
|
|
347
|
-
reason: "mission exhausted its planning budget before creating an initial milestone",
|
|
396
|
+
reason: replanBudgetReason("mission exhausted its planning budget before creating an initial milestone", replanConsumption),
|
|
348
397
|
next_action: "none",
|
|
349
398
|
};
|
|
350
399
|
}
|
|
@@ -356,13 +405,13 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
356
405
|
};
|
|
357
406
|
}
|
|
358
407
|
if (!root)
|
|
359
|
-
throw new Error(`
|
|
408
|
+
throw new Error(`governor ${intent.id} root work is missing`);
|
|
360
409
|
if (root.projection.state === "succeeded" && intent.mission) {
|
|
361
410
|
if (!intent.replanning || chargedReplans >= intent.replanning.max_replans) {
|
|
362
411
|
return {
|
|
363
412
|
...base,
|
|
364
413
|
state: "budget_exhausted",
|
|
365
|
-
reason: "mission exhausted its planning budget at a milestone boundary",
|
|
414
|
+
reason: replanBudgetReason("mission exhausted its planning budget at a milestone boundary", replanConsumption),
|
|
366
415
|
next_action: "none",
|
|
367
416
|
};
|
|
368
417
|
}
|
|
@@ -381,12 +430,6 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
381
430
|
next_action: "none",
|
|
382
431
|
};
|
|
383
432
|
}
|
|
384
|
-
const resumableDispatchable = intent.automation.resume_approved ? resumableWork : [];
|
|
385
|
-
const attemptDispatchable = [
|
|
386
|
-
...readyWork,
|
|
387
|
-
...(intent.automation.retry_blocked ? retryableWork : []),
|
|
388
|
-
];
|
|
389
|
-
const dispatchable = [...resumableDispatchable, ...attemptDispatchable];
|
|
390
433
|
if (intent.automation.accept_passing_proof && reviews.length > 0) {
|
|
391
434
|
return {
|
|
392
435
|
...base,
|
|
@@ -479,45 +522,122 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
|
|
|
479
522
|
return {
|
|
480
523
|
...base,
|
|
481
524
|
state: "budget_exhausted",
|
|
482
|
-
reason: `goal exhausted its ${intent.replanning.max_replans} replans`,
|
|
525
|
+
reason: replanBudgetReason(`goal exhausted its ${intent.replanning.max_replans} replans`, replanConsumption),
|
|
483
526
|
next_action: "none",
|
|
484
527
|
};
|
|
485
528
|
}
|
|
486
529
|
return {
|
|
487
530
|
...base,
|
|
488
531
|
state: "blocked",
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
532
|
+
// Lead with the decisions when there are any. "3 work items need
|
|
533
|
+
// intervention" reads as a queue an agent will get to; "waiting on you to
|
|
534
|
+
// rule on X" is the only phrasing that reaches the person who can clear it.
|
|
535
|
+
reason: decisionBlocked.length > 0
|
|
536
|
+
? `${decisionBlocked.length} work item${decisionBlocked.length === 1 ? " is" : "s are"} waiting on a human decision: ${describeDecisionBlocks(decisionBlocked)}`
|
|
537
|
+
: attentionWork.length > 0
|
|
538
|
+
? `${attentionWork.length} work item${attentionWork.length === 1 ? " needs" : "s need"} intervention`
|
|
539
|
+
: "goal graph has no legal progress action",
|
|
492
540
|
next_action: "none",
|
|
493
541
|
};
|
|
494
542
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
543
|
+
/** Bounded, operator-readable list of what is waiting on a ruling. */
|
|
544
|
+
function describeDecisionBlocks(blocks) {
|
|
545
|
+
const shown = blocks
|
|
546
|
+
.slice(0, 3)
|
|
547
|
+
.map((b) => (b.decision_id ? `${b.work_id} (${b.decision_id})` : b.work_id))
|
|
548
|
+
.join(", ");
|
|
549
|
+
return blocks.length > 3 ? `${shown}, +${blocks.length - 3} more` : shown;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Classify each consumed replan that did not advance the graph, using existing
|
|
553
|
+
* plan seams only. A plan carries a review receipt exactly when a proposal was
|
|
554
|
+
* produced and independently reviewed, so its presence separates a reviewer
|
|
555
|
+
* rejection from a planner run that produced no reviewable proposal. Uncharged
|
|
556
|
+
* environment/upstream planner failures (ADR 0046) do not spend the replan
|
|
557
|
+
* budget and are attributed to their outside precondition, not counted here.
|
|
558
|
+
*/
|
|
559
|
+
/** Whether a failed plan told us nothing about the plan, and so must not spend
|
|
560
|
+
* a replan (ADR 0046). All three classes mean "replanning this cannot help":
|
|
561
|
+
* the binary is missing, the vendor is down, or a person has to rule. */
|
|
562
|
+
function isUnchargedPlanClass(value) {
|
|
563
|
+
return value === "environment" || value === "upstream" || value === "decision";
|
|
564
|
+
}
|
|
565
|
+
function classifyReplanConsumption(plans) {
|
|
566
|
+
let reviewerRejection = 0;
|
|
567
|
+
let plannerNoProposal = 0;
|
|
568
|
+
for (const plan of plans.plans) {
|
|
569
|
+
if (plan.status === "failed" && isUnchargedPlanClass(plan.class)) {
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (plan.review && plan.review.status !== "passed") {
|
|
573
|
+
reviewerRejection++;
|
|
574
|
+
}
|
|
575
|
+
else if (!plan.review &&
|
|
576
|
+
(plan.status === "attention" ||
|
|
577
|
+
plan.status === "interrupted" ||
|
|
578
|
+
plan.status === "failed" ||
|
|
579
|
+
plan.status === "retry_requested")) {
|
|
580
|
+
// `retry_requested` is a planner no-proposal attention the operator asked to
|
|
581
|
+
// replan: the original run still produced no reviewable proposal and still
|
|
582
|
+
// spent a charged replan, so it belongs in this bucket even though a later
|
|
583
|
+
// plan superseded it. Omitting it would misattribute a retried no-proposal
|
|
584
|
+
// to nothing and let the reason read as pure review exhaustion.
|
|
585
|
+
plannerNoProposal++;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return { reviewer_rejection: reviewerRejection, planner_no_proposal: plannerNoProposal };
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Reason for a goal held at `awaiting_attention/none` because its latest plan is
|
|
592
|
+
* an unresolved attention and no replan slot remains. The latest plan's own
|
|
593
|
+
* per-plan reason always leads (a reviewed-and-rejected latest reports its
|
|
594
|
+
* review-round exhaustion verbatim), then `replanBudgetReason` names the planner
|
|
595
|
+
* no-proposal share of the consumed budget. This keeps the `projection.reason`
|
|
596
|
+
* field carrying the same truth the operator-visible row does: a goal whose
|
|
597
|
+
* budget was mostly spent by planner no-proposal runs is not attributed wholesale
|
|
598
|
+
* to review just because its final, reviewed plan happened to be rejected.
|
|
599
|
+
*/
|
|
600
|
+
function exhaustedAttentionReason(latest, consumption) {
|
|
601
|
+
const fallback = latest.reason ?? `plan ${latest.request.id} requires attention`;
|
|
602
|
+
return replanBudgetReason(fallback, consumption);
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Append planner no-proposal attribution to a replan-exhaustion reason. Returns
|
|
606
|
+
* the base reason unchanged when no consumed replan was a planner no-proposal
|
|
607
|
+
* outcome, so goals without that history project exactly as before.
|
|
608
|
+
*/
|
|
609
|
+
function replanBudgetReason(base, consumption) {
|
|
610
|
+
if (consumption.planner_no_proposal <= 0)
|
|
611
|
+
return base;
|
|
612
|
+
const count = consumption.planner_no_proposal;
|
|
613
|
+
return `${base}; ${count} replan${count === 1 ? "" : "s"} ended with the planner producing no proposal`;
|
|
614
|
+
}
|
|
615
|
+
function readGovernorIntent(coordRoot, goalId) {
|
|
616
|
+
assertGovernorId(goalId);
|
|
617
|
+
const path = governorIntentPath(coordRoot, goalId);
|
|
498
618
|
if (!existsSync(path))
|
|
499
|
-
throw new Error(`
|
|
619
|
+
throw new Error(`governor ${goalId} does not exist`);
|
|
500
620
|
const size = statSync(path).size;
|
|
501
621
|
if (size <= 0 || size > MAX_INTENT_BYTES) {
|
|
502
|
-
throw new Error(`
|
|
622
|
+
throw new Error(`governor intent has invalid size ${size}`);
|
|
503
623
|
}
|
|
504
624
|
let intent;
|
|
505
625
|
try {
|
|
506
626
|
intent = JSON.parse(readFileSync(path, "utf8"));
|
|
507
627
|
}
|
|
508
628
|
catch (error) {
|
|
509
|
-
throw new Error(`cannot parse
|
|
629
|
+
throw new Error(`cannot parse governor intent ${goalId}: ${error.message}`);
|
|
510
630
|
}
|
|
511
631
|
validateIntent(intent, goalId);
|
|
512
632
|
return intent;
|
|
513
633
|
}
|
|
514
634
|
function validateIntent(intent, goalId) {
|
|
515
|
-
if (intent.schema_version !==
|
|
635
|
+
if (intent.schema_version !== GOVERNOR_INTENT_SCHEMA_VERSION ||
|
|
516
636
|
intent.id !== goalId ||
|
|
517
637
|
!validTimestamp(intent.created_at)) {
|
|
518
|
-
throw new Error(`
|
|
638
|
+
throw new Error(`governor intent ${goalId} has an unsupported or mismatched schema`);
|
|
519
639
|
}
|
|
520
|
-
bounded(intent.title, "
|
|
640
|
+
bounded(intent.title, "governor title", MAX_TITLE);
|
|
521
641
|
assertWorkId(intent.root_work_id);
|
|
522
642
|
if (intent.mission) {
|
|
523
643
|
const normalizedMission = normalizeMission({
|
|
@@ -526,40 +646,40 @@ function validateIntent(intent, goalId) {
|
|
|
526
646
|
maxMilestones: intent.mission.max_milestones,
|
|
527
647
|
});
|
|
528
648
|
if (JSON.stringify(normalizedMission) !== JSON.stringify(intent.mission)) {
|
|
529
|
-
throw new Error(`
|
|
649
|
+
throw new Error(`governor intent ${goalId} mission is not canonical`);
|
|
530
650
|
}
|
|
531
651
|
if (!intent.replanning) {
|
|
532
|
-
throw new Error(`
|
|
652
|
+
throw new Error(`governor intent ${goalId} mission requires replanning`);
|
|
533
653
|
}
|
|
534
654
|
}
|
|
535
655
|
const specialists = normalizeWorkflowSpecialists(intent.specialists);
|
|
536
656
|
if (JSON.stringify(specialists) !== JSON.stringify(intent.specialists)) {
|
|
537
|
-
throw new Error(`
|
|
657
|
+
throw new Error(`governor intent ${goalId} specialists are not canonical`);
|
|
538
658
|
}
|
|
539
659
|
if (JSON.stringify(normalizeLimits(intent.limits)) !== JSON.stringify(intent.limits)) {
|
|
540
|
-
throw new Error(`
|
|
660
|
+
throw new Error(`governor intent ${goalId} limits are not canonical`);
|
|
541
661
|
}
|
|
542
662
|
if (JSON.stringify(normalizeAutomation(intent.automation)) !== JSON.stringify(intent.automation)) {
|
|
543
|
-
throw new Error(`
|
|
663
|
+
throw new Error(`governor intent ${goalId} automation policy is not canonical`);
|
|
544
664
|
}
|
|
545
665
|
if (intent.replanning)
|
|
546
666
|
validateReplanning(intent.replanning, specialists, intent.limits, goalId);
|
|
547
667
|
}
|
|
548
668
|
function normalizeMission(input) {
|
|
549
669
|
if (!Array.isArray(input.acceptance)) {
|
|
550
|
-
throw new Error("
|
|
670
|
+
throw new Error("governor mission acceptance must be an array");
|
|
551
671
|
}
|
|
552
672
|
if (input.acceptance.length < 1 || input.acceptance.length > MAX_ACCEPTANCE) {
|
|
553
|
-
throw new Error(`
|
|
673
|
+
throw new Error(`governor mission acceptance must contain 1 to ${MAX_ACCEPTANCE} criteria`);
|
|
554
674
|
}
|
|
555
|
-
const acceptance = input.acceptance.map((criterion, index) => bounded(criterion, `
|
|
675
|
+
const acceptance = input.acceptance.map((criterion, index) => bounded(criterion, `governor mission acceptance[${index}]`, 500));
|
|
556
676
|
if (new Set(acceptance).size !== acceptance.length) {
|
|
557
|
-
throw new Error("
|
|
677
|
+
throw new Error("governor mission acceptance criteria must be unique");
|
|
558
678
|
}
|
|
559
679
|
return {
|
|
560
|
-
objective: bounded(input.objective, "
|
|
680
|
+
objective: bounded(input.objective, "governor mission objective", MAX_OBJECTIVE),
|
|
561
681
|
acceptance,
|
|
562
|
-
max_milestones: positive(input.maxMilestones ?? 4, "
|
|
682
|
+
max_milestones: positive(input.maxMilestones ?? 4, "governor mission max_milestones", 20),
|
|
563
683
|
};
|
|
564
684
|
}
|
|
565
685
|
function missionTitle(mission) {
|
|
@@ -569,12 +689,12 @@ function missionTitle(mission) {
|
|
|
569
689
|
}
|
|
570
690
|
function normalizeLimits(input) {
|
|
571
691
|
return {
|
|
572
|
-
max_cycles: positive(input?.max_cycles ?? 50, "
|
|
573
|
-
max_runtime_ms: positive(input?.max_runtime_ms ?? 4 * 60 * 60 * 1_000, "
|
|
574
|
-
max_parallel_work: positive(input?.max_parallel_work ?? 1, "
|
|
575
|
-
max_total_attempts: positive(input?.max_total_attempts ?? 100, "
|
|
576
|
-
max_agents_per_work: positive(input?.max_agents_per_work ?? 20, "
|
|
577
|
-
agent_concurrency: positive(input?.agent_concurrency ?? 4, "
|
|
692
|
+
max_cycles: positive(input?.max_cycles ?? 50, "governor max_cycles", 1_000),
|
|
693
|
+
max_runtime_ms: positive(input?.max_runtime_ms ?? 4 * 60 * 60 * 1_000, "governor max_runtime_ms", 7 * 24 * 60 * 60 * 1_000),
|
|
694
|
+
max_parallel_work: positive(input?.max_parallel_work ?? 1, "governor max_parallel_work", 20),
|
|
695
|
+
max_total_attempts: positive(input?.max_total_attempts ?? 100, "governor max_total_attempts", 10_000),
|
|
696
|
+
max_agents_per_work: positive(input?.max_agents_per_work ?? 20, "governor max_agents_per_work", 1_000),
|
|
697
|
+
agent_concurrency: positive(input?.agent_concurrency ?? 4, "governor agent_concurrency", 100),
|
|
578
698
|
};
|
|
579
699
|
}
|
|
580
700
|
function normalizeAutomation(input) {
|
|
@@ -637,8 +757,8 @@ function normalizeReviewPolicy(input, specialists, plannerSpecialist, limits) {
|
|
|
637
757
|
if (!Array.isArray(input.reviewerSpecialists) || input.reviewerSpecialists.length < 1) {
|
|
638
758
|
throw new Error("replanning review requires at least one reviewer specialist");
|
|
639
759
|
}
|
|
640
|
-
if (input.reviewerSpecialists.length >
|
|
641
|
-
throw new Error(`replanning review cannot exceed ${
|
|
760
|
+
if (input.reviewerSpecialists.length > MAX_GOVERNOR_PLAN_REVIEWERS) {
|
|
761
|
+
throw new Error(`replanning review cannot exceed ${MAX_GOVERNOR_PLAN_REVIEWERS} reviewer specialists`);
|
|
642
762
|
}
|
|
643
763
|
const reviewerSpecialists = input.reviewerSpecialists.map((specialist, index) => bounded(specialist, `reviewer specialist[${index}]`, 100));
|
|
644
764
|
if (new Set(reviewerSpecialists).size !== reviewerSpecialists.length) {
|
|
@@ -652,7 +772,7 @@ function normalizeReviewPolicy(input, specialists, plannerSpecialist, limits) {
|
|
|
652
772
|
throw new Error("reviewer specialist cannot be the planner specialist");
|
|
653
773
|
}
|
|
654
774
|
}
|
|
655
|
-
const maxRevisionRounds = nonNegative(input.maxRevisionRounds, "replanning review max_revision_rounds",
|
|
775
|
+
const maxRevisionRounds = nonNegative(input.maxRevisionRounds, "replanning review max_revision_rounds", MAX_GOVERNOR_PLAN_REVISION_ROUNDS);
|
|
656
776
|
const worstCaseAgents = 1 + reviewerSpecialists.length * (maxRevisionRounds + 1) + maxRevisionRounds;
|
|
657
777
|
if (worstCaseAgents > limits.max_agents_per_work) {
|
|
658
778
|
throw new Error(`replanning review worst-case ${worstCaseAgents} agents exceeds max_agents_per_work ${limits.max_agents_per_work}`);
|
|
@@ -664,18 +784,18 @@ function normalizeReviewPolicy(input, specialists, plannerSpecialist, limits) {
|
|
|
664
784
|
}
|
|
665
785
|
function validateReplanning(policy, specialists, limits, goalId) {
|
|
666
786
|
if (!specialists[policy.planner_specialist]) {
|
|
667
|
-
throw new Error(`
|
|
787
|
+
throw new Error(`governor ${goalId} planner specialist is not in the frozen team`);
|
|
668
788
|
}
|
|
669
789
|
boolean(policy.auto_apply, "replanning auto_apply");
|
|
670
790
|
positive(policy.max_replans, "replanning max_replans", 100);
|
|
671
791
|
positive(policy.max_work_items_per_plan, "replanning max_work_items_per_plan", 25);
|
|
672
792
|
positive(policy.max_total_work_items, "replanning max_total_work_items", 100);
|
|
673
793
|
if (policy.max_work_items_per_plan > policy.max_total_work_items) {
|
|
674
|
-
throw new Error(`
|
|
794
|
+
throw new Error(`governor ${goalId} replanning work-item bounds are inconsistent`);
|
|
675
795
|
}
|
|
676
796
|
const entries = Object.entries(policy.templates ?? {});
|
|
677
797
|
if (entries.length < 1 || entries.length > MAX_TEMPLATES) {
|
|
678
|
-
throw new Error(`
|
|
798
|
+
throw new Error(`governor ${goalId} has invalid replanning templates`);
|
|
679
799
|
}
|
|
680
800
|
let rootCapable = false;
|
|
681
801
|
for (const [id, template] of entries) {
|
|
@@ -686,45 +806,45 @@ function validateReplanning(policy, specialists, limits, goalId) {
|
|
|
686
806
|
template.max_attempts < 1 ||
|
|
687
807
|
template.max_attempts > 100 ||
|
|
688
808
|
typeof template.root !== "boolean") {
|
|
689
|
-
throw new Error(`
|
|
809
|
+
throw new Error(`governor ${goalId} replanning template ${id} is invalid`);
|
|
690
810
|
}
|
|
691
811
|
rootCapable ||= template.root;
|
|
692
812
|
}
|
|
693
813
|
if (!rootCapable)
|
|
694
|
-
throw new Error(`
|
|
814
|
+
throw new Error(`governor ${goalId} has no root-capable replanning template`);
|
|
695
815
|
if (policy.review !== undefined) {
|
|
696
816
|
const review = policy.review;
|
|
697
817
|
if (!Array.isArray(review.reviewer_specialists) ||
|
|
698
818
|
review.reviewer_specialists.length < 1 ||
|
|
699
|
-
review.reviewer_specialists.length >
|
|
819
|
+
review.reviewer_specialists.length > MAX_GOVERNOR_PLAN_REVIEWERS ||
|
|
700
820
|
!Number.isSafeInteger(review.max_revision_rounds) ||
|
|
701
821
|
review.max_revision_rounds < 0 ||
|
|
702
|
-
review.max_revision_rounds >
|
|
703
|
-
throw new Error(`
|
|
822
|
+
review.max_revision_rounds > MAX_GOVERNOR_PLAN_REVISION_ROUNDS) {
|
|
823
|
+
throw new Error(`governor ${goalId} replanning review policy is invalid`);
|
|
704
824
|
}
|
|
705
825
|
if (new Set(review.reviewer_specialists).size !== review.reviewer_specialists.length) {
|
|
706
|
-
throw new Error(`
|
|
826
|
+
throw new Error(`governor ${goalId} replanning reviewers are not unique`);
|
|
707
827
|
}
|
|
708
828
|
for (const specialist of review.reviewer_specialists) {
|
|
709
829
|
if (!specialists[specialist]) {
|
|
710
|
-
throw new Error(`
|
|
830
|
+
throw new Error(`governor ${goalId} reviewer specialist is not in the frozen team`);
|
|
711
831
|
}
|
|
712
832
|
if (specialist === policy.planner_specialist) {
|
|
713
|
-
throw new Error(`
|
|
833
|
+
throw new Error(`governor ${goalId} reviewer specialist cannot be planner`);
|
|
714
834
|
}
|
|
715
835
|
}
|
|
716
836
|
const worstCaseAgents = 1 +
|
|
717
837
|
review.reviewer_specialists.length * (review.max_revision_rounds + 1) +
|
|
718
838
|
review.max_revision_rounds;
|
|
719
839
|
if (worstCaseAgents > limits.max_agents_per_work) {
|
|
720
|
-
throw new Error(`
|
|
840
|
+
throw new Error(`governor ${goalId} review policy exceeds the agent budget`);
|
|
721
841
|
}
|
|
722
842
|
}
|
|
723
843
|
}
|
|
724
844
|
function collectGovernedWork(coordRoot, originalRootWorkId, plans, active) {
|
|
725
845
|
const governed = new Map();
|
|
726
846
|
if (workIntentExists(coordRoot, originalRootWorkId)) {
|
|
727
|
-
for (const record of
|
|
847
|
+
for (const record of collectGovernorWork(coordRoot, originalRootWorkId)) {
|
|
728
848
|
governed.set(record.intent.id, record);
|
|
729
849
|
}
|
|
730
850
|
}
|
|
@@ -740,15 +860,15 @@ function workIntentExists(coordRoot, workId) {
|
|
|
740
860
|
function missionRootId(goalId) {
|
|
741
861
|
return `${goalId.slice(0, 87)}-mission-root`;
|
|
742
862
|
}
|
|
743
|
-
function
|
|
744
|
-
|
|
745
|
-
return join(resolve(coordRoot), ".harnery", "
|
|
863
|
+
function governorDir(coordRoot, goalId) {
|
|
864
|
+
assertGovernorId(goalId);
|
|
865
|
+
return join(resolve(coordRoot), ".harnery", "governors", goalId);
|
|
746
866
|
}
|
|
747
|
-
function
|
|
748
|
-
return join(
|
|
867
|
+
function governorIntentPath(coordRoot, goalId) {
|
|
868
|
+
return join(governorDir(coordRoot, goalId), "intent.json");
|
|
749
869
|
}
|
|
750
|
-
function
|
|
751
|
-
const lease = readLease(join(
|
|
870
|
+
function governorLeaseIsLive(coordRoot, goalId) {
|
|
871
|
+
const lease = readLease(join(governorDir(coordRoot, goalId), "lease.json"));
|
|
752
872
|
return lease ? leaseIsLive(lease) : false;
|
|
753
873
|
}
|
|
754
874
|
function readLease(path) {
|
|
@@ -787,7 +907,7 @@ function leaseIsLive(lease) {
|
|
|
787
907
|
function writePrivateJson(path, value) {
|
|
788
908
|
const body = `${JSON.stringify(value, null, 2)}\n`;
|
|
789
909
|
if (Buffer.byteLength(body) > MAX_INTENT_BYTES) {
|
|
790
|
-
throw new Error(`
|
|
910
|
+
throw new Error(`governor intent exceeds ${MAX_INTENT_BYTES} bytes`);
|
|
791
911
|
}
|
|
792
912
|
writeFileSync(path, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
793
913
|
chmodSync(path, 0o600);
|
|
@@ -816,7 +936,7 @@ function nonNegative(value, field, max) {
|
|
|
816
936
|
}
|
|
817
937
|
function boolean(value, field) {
|
|
818
938
|
if (typeof value !== "boolean")
|
|
819
|
-
throw new Error(`
|
|
939
|
+
throw new Error(`governor ${field} must be boolean`);
|
|
820
940
|
return value;
|
|
821
941
|
}
|
|
822
942
|
function validTimestamp(value) {
|