harnery 0.29.0 → 0.31.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/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 +61 -60
- 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/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 +193 -23
- 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 +2 -1
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +55 -25
- 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 +28 -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 +4 -4
- package/dist/core/agents/canonical-emit.js +5 -5
- 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-client.d.ts +21 -2
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +122 -27
- 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/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 +71 -51
- package/dist/core/governor/plan-types.d.ts +181 -0
- 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 +143 -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 +290 -116
- 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 +175 -151
- 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 +17 -17
- 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 +3 -3
- package/dist/core/hooks/resolve/coord-root.js +4 -4
- 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/runner.d.ts.map +1 -1
- package/dist/core/work/runner.js +11 -2
- package/dist/core/work/state.d.ts +28 -3
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +148 -16
- 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 +151 -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 +3 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- package/dist/core/workflow/proof.d.ts +28 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +77 -34
- 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 +28 -8
- 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 +26 -8
- 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 +27 -8
- package/dist/core/workflow/spawn-failure.d.ts +15 -1
- package/dist/core/workflow/spawn-failure.d.ts.map +1 -1
- package/dist/core/workflow/spawn-failure.js +35 -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 +119 -46
- 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/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/exec.d.ts +7 -0
- package/dist/lib/exec.d.ts.map +1 -1
- package/dist/lib/exec.js +6 -3
- 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 +71 -64
- 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/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 +237 -34
- package/src/commands/web-fetch.ts +1 -1
- package/src/commands/web.ts +56 -1
- package/src/commands/work.ts +72 -38
- 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 +28 -23
- package/src/core/agents/canonical-emit.ts +6 -6
- 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-client.ts +119 -28
- package/src/core/agents/events/consume.ts +1 -1
- package/src/core/agents/events/emit.ts +7 -6
- 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 +120 -96
- package/src/core/{supervisor → governor}/plan-types.ts +64 -50
- package/src/core/{supervisor → governor}/planning.ts +240 -188
- 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 +389 -174
- 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 +185 -162
- package/src/core/hooks/effects/image-capture.ts +6 -6
- package/src/core/hooks/effects/index.ts +17 -17
- 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 +4 -4
- 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/runner.ts +11 -2
- package/src/core/work/state.ts +185 -21
- 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 +166 -90
- package/src/core/workflow/evidence-preflight.ts +165 -0
- package/src/core/workflow/index.ts +6 -3
- package/src/core/workflow/proof.ts +94 -48
- 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 +34 -12
- package/src/core/workflow/spawn-codex.ts +30 -12
- package/src/core/workflow/spawn-cursor.ts +31 -12
- package/src/core/workflow/spawn-failure.ts +41 -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 +130 -46
- 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/council/index.ts +9 -9
- package/src/lib/exec.ts +13 -3
- 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 +0 -170
- 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
|
@@ -23,27 +23,23 @@ import {
|
|
|
23
23
|
type WorkflowProof,
|
|
24
24
|
workflowScriptDigest,
|
|
25
25
|
} from "../workflow/index.ts";
|
|
26
|
+
import { readGovernorPlan, readGovernorPlanReviewReceipt, readGovernorPlans } from "./plan-read.ts";
|
|
26
27
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
type
|
|
34
|
-
type
|
|
35
|
-
type
|
|
36
|
-
type
|
|
37
|
-
type
|
|
38
|
-
type
|
|
39
|
-
|
|
40
|
-
type SupervisorPlanReviewReviewer,
|
|
41
|
-
type SupervisorPlanReviewRound,
|
|
42
|
-
type SupervisorPlanWorkSpec,
|
|
43
|
-
type SupervisorReplanningPolicy,
|
|
44
|
-
supervisorGraphFingerprint,
|
|
28
|
+
GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
29
|
+
type GovernorPlanEvent,
|
|
30
|
+
type GovernorPlanMilestone,
|
|
31
|
+
type GovernorPlanOutcome,
|
|
32
|
+
type GovernorPlanProposal,
|
|
33
|
+
type GovernorPlanRequest,
|
|
34
|
+
type GovernorPlanReviewFinding,
|
|
35
|
+
type GovernorPlanReviewReceipt,
|
|
36
|
+
type GovernorPlanReviewReviewer,
|
|
37
|
+
type GovernorPlanReviewRound,
|
|
38
|
+
type GovernorPlanWorkSpec,
|
|
39
|
+
type GovernorReplanningPolicy,
|
|
40
|
+
governorGraphFingerprint,
|
|
45
41
|
} from "./plan-types.ts";
|
|
46
|
-
import type {
|
|
42
|
+
import type { GovernorRecord } from "./state.ts";
|
|
47
43
|
|
|
48
44
|
const PLAN_KEY = /^[a-z][a-z0-9-]{0,31}$/;
|
|
49
45
|
const TEMPLATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
@@ -53,26 +49,26 @@ const MAX_REASON = 2_000;
|
|
|
53
49
|
const PROPOSAL_ROOT_RULE =
|
|
54
50
|
"proposal.root names one newly proposed work key using a root-capable template; it does not preserve or repeat active_root, which is context only";
|
|
55
51
|
|
|
56
|
-
export interface
|
|
52
|
+
export interface RunGovernorPlannerInput {
|
|
57
53
|
coordRoot: string;
|
|
58
|
-
record:
|
|
54
|
+
record: GovernorRecord;
|
|
59
55
|
engine: Omit<EngineOpts, "coordRoot" | "runId" | "resumeRunId" | "specialists">;
|
|
60
56
|
actor: string;
|
|
61
57
|
onLog?: (line: string) => void;
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
export async function
|
|
65
|
-
input:
|
|
66
|
-
): Promise<
|
|
60
|
+
export async function runGovernorPlanner(
|
|
61
|
+
input: RunGovernorPlannerInput,
|
|
62
|
+
): Promise<GovernorPlanOutcome> {
|
|
67
63
|
const coordRoot = resolve(input.coordRoot);
|
|
68
64
|
const policy = input.record.intent.replanning;
|
|
69
|
-
if (!policy) throw new Error(`
|
|
70
|
-
const history =
|
|
65
|
+
if (!policy) throw new Error(`governor ${input.record.intent.id} does not allow replanning`);
|
|
66
|
+
const history = readGovernorPlans(
|
|
71
67
|
coordRoot,
|
|
72
68
|
input.record.intent.id,
|
|
73
69
|
input.record.intent.root_work_id,
|
|
74
70
|
);
|
|
75
|
-
const triggerFingerprint =
|
|
71
|
+
const triggerFingerprint = governorGraphFingerprint({
|
|
76
72
|
rootWorkId: input.record.projection.root_work_id,
|
|
77
73
|
generation: input.record.projection.plan_generation,
|
|
78
74
|
work: input.record.work,
|
|
@@ -136,7 +132,7 @@ export async function runSupervisorPlanner(
|
|
|
136
132
|
const reviewInput = resumingReview
|
|
137
133
|
? readBoundedJson<{ candidate: unknown }>(
|
|
138
134
|
reviewInputPath(coordRoot, input.record.intent.id, request.id),
|
|
139
|
-
"
|
|
135
|
+
"governor plan review input",
|
|
140
136
|
)
|
|
141
137
|
: undefined;
|
|
142
138
|
const rawProposal = reviewInput
|
|
@@ -169,9 +165,9 @@ export async function runSupervisorPlanner(
|
|
|
169
165
|
actor: input.actor,
|
|
170
166
|
reason: proposal.rationale,
|
|
171
167
|
});
|
|
172
|
-
return outcome(
|
|
168
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
173
169
|
}
|
|
174
|
-
let receipt:
|
|
170
|
+
let receipt: GovernorPlanReviewReceipt;
|
|
175
171
|
try {
|
|
176
172
|
receipt = await ensurePlanReview({
|
|
177
173
|
coordRoot,
|
|
@@ -196,7 +192,7 @@ export async function runSupervisorPlanner(
|
|
|
196
192
|
MAX_REASON,
|
|
197
193
|
),
|
|
198
194
|
});
|
|
199
|
-
return outcome(
|
|
195
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
200
196
|
}
|
|
201
197
|
return finalizeReviewedProposal({
|
|
202
198
|
coordRoot,
|
|
@@ -210,7 +206,7 @@ export async function runSupervisorPlanner(
|
|
|
210
206
|
writeExclusiveJson(
|
|
211
207
|
planProposalPath(coordRoot, input.record.intent.id, request.id),
|
|
212
208
|
proposal,
|
|
213
|
-
"
|
|
209
|
+
"governor plan proposal",
|
|
214
210
|
);
|
|
215
211
|
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
216
212
|
event: "plan.proposed",
|
|
@@ -224,18 +220,18 @@ export async function runSupervisorPlanner(
|
|
|
224
220
|
actor: input.actor,
|
|
225
221
|
reason: proposal.rationale,
|
|
226
222
|
});
|
|
227
|
-
return outcome(
|
|
223
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
228
224
|
}
|
|
229
225
|
if (policy.auto_apply) {
|
|
230
|
-
return
|
|
226
|
+
return applyGovernorPlanProposal({
|
|
231
227
|
coordRoot,
|
|
232
228
|
record: input.record,
|
|
233
229
|
planId: request.id,
|
|
234
230
|
actor: input.actor,
|
|
235
|
-
reason: "proposal applied by frozen
|
|
231
|
+
reason: "proposal applied by frozen governor replanning policy",
|
|
236
232
|
});
|
|
237
233
|
}
|
|
238
|
-
return outcome(
|
|
234
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
239
235
|
} catch (error) {
|
|
240
236
|
if (proposalWritten) throw error;
|
|
241
237
|
if (error instanceof WorkflowParkedError) {
|
|
@@ -245,29 +241,47 @@ export async function runSupervisorPlanner(
|
|
|
245
241
|
reason: `planning workflow parked for approval ${error.approvalId}`,
|
|
246
242
|
approval_id: error.approvalId,
|
|
247
243
|
});
|
|
248
|
-
return outcome(
|
|
244
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
|
|
249
245
|
}
|
|
246
|
+
// ADR 0046: a planner workflow that never touched the plan (its binary was
|
|
247
|
+
// absent, or the vendor refused) writes a proof carrying run.class. Stamp it
|
|
248
|
+
// on the failure so the projection can stop an environment failure and bound
|
|
249
|
+
// consecutive upstream ones, instead of replanning an unchanged environment
|
|
250
|
+
// to budget exhaustion — the failure mode that burned the measured 19.
|
|
251
|
+
const failureClass = plannerFailureClass(coordRoot, request.workflow_run_id);
|
|
250
252
|
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
251
253
|
event: "plan.failed",
|
|
252
254
|
actor: input.actor,
|
|
253
255
|
reason: bounded((error as Error).message, "plan failure", MAX_REASON),
|
|
256
|
+
...(failureClass ? { class: failureClass } : {}),
|
|
254
257
|
});
|
|
255
258
|
throw error;
|
|
256
259
|
}
|
|
257
260
|
}
|
|
258
261
|
|
|
262
|
+
/** The failure class (ADR 0046) of a planner workflow run, read from its proof.
|
|
263
|
+
* Undefined when no proof was written, the proof is unreadable, or the run was
|
|
264
|
+
* informative about the plan — all of which default to a charged replan. */
|
|
265
|
+
function plannerFailureClass(coordRoot: string, workflowRunId: string): GovernorPlanEvent["class"] {
|
|
266
|
+
try {
|
|
267
|
+
return readWorkflowProof(coordRoot, workflowRunId).run.class;
|
|
268
|
+
} catch {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
259
273
|
async function recoverReviewedPlan(input: {
|
|
260
274
|
coordRoot: string;
|
|
261
|
-
record:
|
|
262
|
-
request:
|
|
263
|
-
history: ReturnType<typeof
|
|
264
|
-
trigger: NonNullable<
|
|
265
|
-
policy:
|
|
275
|
+
record: GovernorRecord;
|
|
276
|
+
request: GovernorPlanRequest;
|
|
277
|
+
history: ReturnType<typeof readGovernorPlans>;
|
|
278
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>;
|
|
279
|
+
policy: GovernorReplanningPolicy;
|
|
266
280
|
actor: string;
|
|
267
|
-
}): Promise<
|
|
281
|
+
}): Promise<GovernorPlanOutcome | undefined> {
|
|
268
282
|
const review = input.policy.review;
|
|
269
283
|
if (!review) return undefined;
|
|
270
|
-
const existing =
|
|
284
|
+
const existing = readGovernorPlanReviewReceipt(
|
|
271
285
|
input.coordRoot,
|
|
272
286
|
input.record.intent.id,
|
|
273
287
|
input.request.id,
|
|
@@ -287,7 +301,7 @@ async function recoverReviewedPlan(input: {
|
|
|
287
301
|
writeExclusiveJson(
|
|
288
302
|
reviewReceiptPath(input.coordRoot, input.record.intent.id, input.request.id),
|
|
289
303
|
receipt,
|
|
290
|
-
"
|
|
304
|
+
"governor plan review receipt",
|
|
291
305
|
);
|
|
292
306
|
}
|
|
293
307
|
return finalizeReviewedProposal({
|
|
@@ -302,17 +316,17 @@ async function recoverReviewedPlan(input: {
|
|
|
302
316
|
|
|
303
317
|
async function ensurePlanReview(input: {
|
|
304
318
|
coordRoot: string;
|
|
305
|
-
record:
|
|
306
|
-
request:
|
|
307
|
-
proposal:
|
|
308
|
-
history: ReturnType<typeof
|
|
309
|
-
trigger: NonNullable<
|
|
310
|
-
policy:
|
|
319
|
+
record: GovernorRecord;
|
|
320
|
+
request: GovernorPlanRequest;
|
|
321
|
+
proposal: GovernorPlanProposal;
|
|
322
|
+
history: ReturnType<typeof readGovernorPlans>;
|
|
323
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>;
|
|
324
|
+
policy: GovernorReplanningPolicy;
|
|
311
325
|
engine: Omit<EngineOpts, "coordRoot" | "runId" | "resumeRunId" | "specialists">;
|
|
312
326
|
actor: string;
|
|
313
327
|
onLog?: (line: string) => void;
|
|
314
|
-
}): Promise<
|
|
315
|
-
const existing =
|
|
328
|
+
}): Promise<GovernorPlanReviewReceipt> {
|
|
329
|
+
const existing = readGovernorPlanReviewReceipt(
|
|
316
330
|
input.coordRoot,
|
|
317
331
|
input.record.intent.id,
|
|
318
332
|
input.request.id,
|
|
@@ -323,7 +337,7 @@ async function ensurePlanReview(input: {
|
|
|
323
337
|
writeExclusiveJson(
|
|
324
338
|
reviewReceiptPath(input.coordRoot, input.record.intent.id, input.request.id),
|
|
325
339
|
reconstructed,
|
|
326
|
-
"
|
|
340
|
+
"governor plan review receipt",
|
|
327
341
|
);
|
|
328
342
|
return reconstructed;
|
|
329
343
|
}
|
|
@@ -331,12 +345,12 @@ async function ensurePlanReview(input: {
|
|
|
331
345
|
writeExclusiveJson(
|
|
332
346
|
reviewInputPath(input.coordRoot, input.record.intent.id, input.request.id),
|
|
333
347
|
{ candidate: input.proposal },
|
|
334
|
-
"
|
|
348
|
+
"governor plan review input",
|
|
335
349
|
);
|
|
336
350
|
writeExclusive(
|
|
337
351
|
reviewScript,
|
|
338
352
|
plannerReviewScript(input.record, input.request.id, input.proposal, input.trigger),
|
|
339
|
-
"
|
|
353
|
+
"governor plan review script",
|
|
340
354
|
);
|
|
341
355
|
const review = input.policy.review!;
|
|
342
356
|
const runId = reviewWorkflowRunId(input.request.id);
|
|
@@ -364,19 +378,19 @@ async function ensurePlanReview(input: {
|
|
|
364
378
|
writeExclusiveJson(
|
|
365
379
|
reviewReceiptPath(input.coordRoot, input.record.intent.id, input.request.id),
|
|
366
380
|
receipt,
|
|
367
|
-
"
|
|
381
|
+
"governor plan review receipt",
|
|
368
382
|
);
|
|
369
383
|
return receipt;
|
|
370
384
|
}
|
|
371
385
|
|
|
372
386
|
function finalizeReviewedProposal(input: {
|
|
373
387
|
coordRoot: string;
|
|
374
|
-
record:
|
|
375
|
-
request:
|
|
376
|
-
receipt:
|
|
377
|
-
policy:
|
|
388
|
+
record: GovernorRecord;
|
|
389
|
+
request: GovernorPlanRequest;
|
|
390
|
+
receipt: GovernorPlanReviewReceipt;
|
|
391
|
+
policy: GovernorReplanningPolicy;
|
|
378
392
|
actor: string;
|
|
379
|
-
}):
|
|
393
|
+
}): GovernorPlanOutcome {
|
|
380
394
|
if (input.receipt.status !== "passed") {
|
|
381
395
|
const event = input.receipt.status === "failed" ? "plan.failed" : "plan.attention";
|
|
382
396
|
appendPlanEventIfMissing(input.coordRoot, input.record.intent.id, input.request.id, event, {
|
|
@@ -384,7 +398,7 @@ function finalizeReviewedProposal(input: {
|
|
|
384
398
|
actor: input.actor,
|
|
385
399
|
reason: reviewStatusReason(input.receipt),
|
|
386
400
|
});
|
|
387
|
-
return outcome(
|
|
401
|
+
return outcome(readGovernorPlan(input.coordRoot, input.record.intent.id, input.request.id));
|
|
388
402
|
}
|
|
389
403
|
// The review authority must become durable before the proposal can become
|
|
390
404
|
// visible. If the process stops after this event, the plan remains
|
|
@@ -404,7 +418,7 @@ function finalizeReviewedProposal(input: {
|
|
|
404
418
|
writeExclusiveJson(
|
|
405
419
|
planProposalPath(input.coordRoot, input.record.intent.id, input.request.id),
|
|
406
420
|
input.receipt.final_candidate,
|
|
407
|
-
"
|
|
421
|
+
"governor plan proposal",
|
|
408
422
|
);
|
|
409
423
|
appendPlanEventIfMissing(
|
|
410
424
|
input.coordRoot,
|
|
@@ -418,18 +432,18 @@ function finalizeReviewedProposal(input: {
|
|
|
418
432
|
},
|
|
419
433
|
);
|
|
420
434
|
if (input.policy.auto_apply) {
|
|
421
|
-
return
|
|
435
|
+
return applyGovernorPlanProposal({
|
|
422
436
|
coordRoot: input.coordRoot,
|
|
423
437
|
record: input.record,
|
|
424
438
|
planId: input.request.id,
|
|
425
439
|
actor: input.actor,
|
|
426
|
-
reason: "proposal applied by frozen
|
|
440
|
+
reason: "proposal applied by frozen governor replanning policy",
|
|
427
441
|
});
|
|
428
442
|
}
|
|
429
|
-
return outcome(
|
|
443
|
+
return outcome(readGovernorPlan(input.coordRoot, input.record.intent.id, input.request.id));
|
|
430
444
|
}
|
|
431
445
|
|
|
432
|
-
function reviewStatusReason(receipt:
|
|
446
|
+
function reviewStatusReason(receipt: GovernorPlanReviewReceipt): string {
|
|
433
447
|
if (receipt.status === "revision_exhausted") {
|
|
434
448
|
return "plan review exhausted its bounded revision rounds";
|
|
435
449
|
}
|
|
@@ -437,47 +451,43 @@ function reviewStatusReason(receipt: SupervisorPlanReviewReceipt): string {
|
|
|
437
451
|
return "plan review requires attention";
|
|
438
452
|
}
|
|
439
453
|
|
|
440
|
-
export function
|
|
454
|
+
export function applyGovernorPlanProposal(input: {
|
|
441
455
|
coordRoot: string;
|
|
442
|
-
record:
|
|
456
|
+
record: GovernorRecord;
|
|
443
457
|
planId: string;
|
|
444
458
|
actor: string;
|
|
445
459
|
reason?: string;
|
|
446
|
-
}):
|
|
460
|
+
}): GovernorPlanOutcome {
|
|
447
461
|
const coordRoot = resolve(input.coordRoot);
|
|
448
462
|
const policy = input.record.intent.replanning;
|
|
449
|
-
if (!policy) throw new Error(`
|
|
450
|
-
const plan =
|
|
463
|
+
if (!policy) throw new Error(`governor ${input.record.intent.id} does not allow replanning`);
|
|
464
|
+
const plan = readGovernorPlan(coordRoot, input.record.intent.id, input.planId);
|
|
451
465
|
if (plan.status === "applied" || plan.status === "completed") return outcome(plan);
|
|
452
466
|
if (
|
|
453
467
|
plan.status !== "proposed" ||
|
|
454
468
|
!plan.proposal ||
|
|
455
469
|
!["apply", "complete"].includes(plan.proposal.decision)
|
|
456
470
|
) {
|
|
457
|
-
throw new Error(`
|
|
471
|
+
throw new Error(`governor plan ${input.planId} cannot be applied from ${plan.status}`);
|
|
458
472
|
}
|
|
459
473
|
if (policy.review) {
|
|
460
|
-
const receipt =
|
|
461
|
-
coordRoot,
|
|
462
|
-
input.record.intent.id,
|
|
463
|
-
input.planId,
|
|
464
|
-
);
|
|
474
|
+
const receipt = readGovernorPlanReviewReceipt(coordRoot, input.record.intent.id, input.planId);
|
|
465
475
|
if (receipt?.status !== "passed") {
|
|
466
|
-
throw new Error(`
|
|
476
|
+
throw new Error(`governor plan ${input.planId} has no passed review receipt`);
|
|
467
477
|
}
|
|
468
478
|
if (candidateDigest(plan.proposal) !== receipt.candidate_sha256) {
|
|
469
|
-
throw new Error(`
|
|
479
|
+
throw new Error(`governor plan ${input.planId} proposal does not match its passed review`);
|
|
470
480
|
}
|
|
471
481
|
if (!plan.events.some((event) => event.event === "plan.reviewed")) {
|
|
472
|
-
throw new Error(`
|
|
482
|
+
throw new Error(`governor plan ${input.planId} has no reviewed authority event`);
|
|
473
483
|
}
|
|
474
484
|
}
|
|
475
485
|
if (plan.request.prior_root_work_id !== input.record.projection.root_work_id) {
|
|
476
486
|
throw new Error(
|
|
477
|
-
`
|
|
487
|
+
`governor plan ${input.planId} targets stale root ${plan.request.prior_root_work_id}`,
|
|
478
488
|
);
|
|
479
489
|
}
|
|
480
|
-
const history =
|
|
490
|
+
const history = readGovernorPlans(
|
|
481
491
|
coordRoot,
|
|
482
492
|
input.record.intent.id,
|
|
483
493
|
input.record.intent.root_work_id,
|
|
@@ -495,7 +505,7 @@ export function applySupervisorPlanProposal(input: {
|
|
|
495
505
|
actor: input.actor,
|
|
496
506
|
reason: input.reason ?? proposal.rationale,
|
|
497
507
|
});
|
|
498
|
-
return outcome(
|
|
508
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, input.planId));
|
|
499
509
|
}
|
|
500
510
|
const ids = new Map<string, string>();
|
|
501
511
|
const created: string[] = [];
|
|
@@ -517,7 +527,7 @@ export function applySupervisorPlanProposal(input: {
|
|
|
517
527
|
max_attempts: template.max_attempts,
|
|
518
528
|
source: {
|
|
519
529
|
kind: "workflow" as const,
|
|
520
|
-
ref: `
|
|
530
|
+
ref: `governor:${input.record.intent.id}/plan:${input.planId}`,
|
|
521
531
|
},
|
|
522
532
|
};
|
|
523
533
|
if (existsSync(join(coordRoot, ".harnery", "work", workId, "intent.json"))) {
|
|
@@ -556,55 +566,91 @@ export function applySupervisorPlanProposal(input: {
|
|
|
556
566
|
appendPlanEvent(coordRoot, input.record.intent.id, input.planId, {
|
|
557
567
|
event: "plan.applied",
|
|
558
568
|
actor: input.actor,
|
|
559
|
-
reason: input.reason ?? "
|
|
569
|
+
reason: input.reason ?? "governor plan explicitly approved",
|
|
560
570
|
root_work_id: rootWorkId,
|
|
561
571
|
work_ids: created,
|
|
562
572
|
});
|
|
563
|
-
return outcome(
|
|
573
|
+
return outcome(readGovernorPlan(coordRoot, input.record.intent.id, input.planId));
|
|
564
574
|
}
|
|
565
575
|
|
|
566
|
-
export function
|
|
576
|
+
export function rejectGovernorPlanProposal(input: {
|
|
567
577
|
coordRoot: string;
|
|
568
578
|
goalId: string;
|
|
569
579
|
planId: string;
|
|
570
580
|
actor: string;
|
|
571
581
|
reason: string;
|
|
572
|
-
}):
|
|
573
|
-
const plan =
|
|
582
|
+
}): GovernorPlanOutcome {
|
|
583
|
+
const plan = readGovernorPlan(input.coordRoot, input.goalId, input.planId);
|
|
574
584
|
if (plan.status === "rejected") return outcome(plan);
|
|
575
585
|
if (plan.status !== "proposed") {
|
|
576
|
-
throw new Error(`
|
|
586
|
+
throw new Error(`governor plan ${input.planId} cannot be rejected from ${plan.status}`);
|
|
577
587
|
}
|
|
578
588
|
appendPlanEvent(input.coordRoot, input.goalId, input.planId, {
|
|
579
589
|
event: "plan.rejected",
|
|
580
590
|
actor: input.actor,
|
|
581
591
|
reason: input.reason,
|
|
582
592
|
});
|
|
583
|
-
return outcome(
|
|
593
|
+
return outcome(readGovernorPlan(input.coordRoot, input.goalId, input.planId));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** ADR 0050: reopen a mission whose completion was already accepted, so an operator
|
|
597
|
+
* finding on work beneath it can be dispatched through the normal governor rather
|
|
598
|
+
* than only by running the work item by hand.
|
|
599
|
+
*
|
|
600
|
+
* The accepted `plan.completed` event is never rewritten. This appends a superseding
|
|
601
|
+
* `plan.reopened` alongside it, which is why the prior completion survives as history
|
|
602
|
+
* and why a reader that cannot understand the new event still sees a completed plan
|
|
603
|
+
* rather than a silently altered one. Refuses when the mission is not complete, so a
|
|
604
|
+
* caller cannot use it to skip the ordinary completion path. */
|
|
605
|
+
export function reopenGovernorMissionPlan(input: {
|
|
606
|
+
coordRoot: string;
|
|
607
|
+
record: GovernorRecord;
|
|
608
|
+
actor: string;
|
|
609
|
+
reason: string;
|
|
610
|
+
}): GovernorPlanOutcome {
|
|
611
|
+
const goalId = input.record.intent.id;
|
|
612
|
+
if (!input.record.intent.mission) {
|
|
613
|
+
throw new Error(`governor ${goalId} is not a mission`);
|
|
614
|
+
}
|
|
615
|
+
const history = readGovernorPlans(input.coordRoot, goalId, input.record.intent.root_work_id);
|
|
616
|
+
const latest = history.latest;
|
|
617
|
+
if (!latest) {
|
|
618
|
+
throw new Error(`governor ${goalId} has no plan to reopen`);
|
|
619
|
+
}
|
|
620
|
+
if (latest.status === "reopened") return outcome(latest);
|
|
621
|
+
if (!history.completed || latest.status !== "completed") {
|
|
622
|
+
throw new Error(`governor ${goalId} mission is not complete, so there is nothing to reopen`);
|
|
623
|
+
}
|
|
624
|
+
appendPlanEvent(input.coordRoot, goalId, latest.request.id, {
|
|
625
|
+
event: "plan.reopened",
|
|
626
|
+
actor: input.actor,
|
|
627
|
+
reason: bounded(input.reason, "mission reopen reason", MAX_REASON),
|
|
628
|
+
});
|
|
629
|
+
return outcome(readGovernorPlan(input.coordRoot, goalId, latest.request.id));
|
|
584
630
|
}
|
|
585
631
|
|
|
586
|
-
export function
|
|
632
|
+
export function retryGovernorPlanProposal(input: {
|
|
587
633
|
coordRoot: string;
|
|
588
|
-
record:
|
|
634
|
+
record: GovernorRecord;
|
|
589
635
|
planId: string;
|
|
590
636
|
actor: string;
|
|
591
637
|
reason: string;
|
|
592
|
-
}):
|
|
638
|
+
}): GovernorPlanOutcome {
|
|
593
639
|
const policy = input.record.intent.replanning;
|
|
594
640
|
if (!policy) {
|
|
595
|
-
throw new Error(`
|
|
641
|
+
throw new Error(`governor ${input.record.intent.id} does not allow replanning`);
|
|
596
642
|
}
|
|
597
643
|
const reason = bounded(input.reason, "plan retry reason", MAX_REASON);
|
|
598
|
-
const history =
|
|
644
|
+
const history = readGovernorPlans(
|
|
599
645
|
input.coordRoot,
|
|
600
646
|
input.record.intent.id,
|
|
601
647
|
input.record.intent.root_work_id,
|
|
602
648
|
);
|
|
603
649
|
const latest = history.latest;
|
|
604
650
|
if (!latest || latest.request.id !== input.planId) {
|
|
605
|
-
throw new Error(`
|
|
651
|
+
throw new Error(`governor plan ${input.planId} is not the latest plan`);
|
|
606
652
|
}
|
|
607
|
-
const triggerFingerprint =
|
|
653
|
+
const triggerFingerprint = governorGraphFingerprint({
|
|
608
654
|
rootWorkId: history.active_root_work_id,
|
|
609
655
|
generation: history.generation,
|
|
610
656
|
work: input.record.work,
|
|
@@ -613,18 +659,18 @@ export function retrySupervisorPlanProposal(input: {
|
|
|
613
659
|
latest.request.trigger_fingerprint !== triggerFingerprint ||
|
|
614
660
|
latest.request.prior_root_work_id !== history.active_root_work_id
|
|
615
661
|
) {
|
|
616
|
-
throw new Error(`
|
|
662
|
+
throw new Error(`governor plan ${input.planId} no longer matches the active graph`);
|
|
617
663
|
}
|
|
618
664
|
if (history.completed) {
|
|
619
|
-
throw new Error(`
|
|
665
|
+
throw new Error(`governor ${input.record.intent.id} mission is already complete`);
|
|
620
666
|
}
|
|
621
667
|
if (latest.status === "retry_requested") return outcome(latest);
|
|
622
668
|
if (latest.status !== "attention") {
|
|
623
|
-
throw new Error(`
|
|
669
|
+
throw new Error(`governor plan ${input.planId} cannot be retried from ${latest.status}`);
|
|
624
670
|
}
|
|
625
671
|
if (history.plans.length >= policy.max_replans) {
|
|
626
672
|
throw new Error(
|
|
627
|
-
`
|
|
673
|
+
`governor ${input.record.intent.id} exhausted its ${policy.max_replans} replans`,
|
|
628
674
|
);
|
|
629
675
|
}
|
|
630
676
|
appendPlanEvent(input.coordRoot, input.record.intent.id, input.planId, {
|
|
@@ -632,24 +678,24 @@ export function retrySupervisorPlanProposal(input: {
|
|
|
632
678
|
actor: input.actor,
|
|
633
679
|
reason,
|
|
634
680
|
});
|
|
635
|
-
return outcome(
|
|
681
|
+
return outcome(readGovernorPlan(input.coordRoot, input.record.intent.id, input.planId));
|
|
636
682
|
}
|
|
637
683
|
|
|
638
684
|
function createPlanRequest(
|
|
639
685
|
coordRoot: string,
|
|
640
|
-
record:
|
|
686
|
+
record: GovernorRecord,
|
|
641
687
|
sequence: number,
|
|
642
688
|
triggerFingerprint: string,
|
|
643
|
-
trigger: NonNullable<
|
|
644
|
-
):
|
|
689
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>,
|
|
690
|
+
): GovernorPlanRequest {
|
|
645
691
|
const policy = record.intent.replanning;
|
|
646
|
-
if (!policy) throw new Error(`
|
|
692
|
+
if (!policy) throw new Error(`governor ${record.intent.id} does not allow replanning`);
|
|
647
693
|
if (sequence > policy.max_replans) {
|
|
648
|
-
throw new Error(`
|
|
694
|
+
throw new Error(`governor ${record.intent.id} exhausted its ${policy.max_replans} replans`);
|
|
649
695
|
}
|
|
650
696
|
const planId = `plan-${String(sequence).padStart(4, "0")}-${randomBytes(4).toString("hex")}`;
|
|
651
|
-
const request:
|
|
652
|
-
schema_version:
|
|
697
|
+
const request: GovernorPlanRequest = {
|
|
698
|
+
schema_version: GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
653
699
|
id: planId,
|
|
654
700
|
goal_id: record.intent.id,
|
|
655
701
|
sequence,
|
|
@@ -663,19 +709,19 @@ function createPlanRequest(
|
|
|
663
709
|
const dir = planDir(coordRoot, record.intent.id, planId);
|
|
664
710
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
665
711
|
chmodSync(dir, 0o700);
|
|
666
|
-
writeExclusiveJson(join(dir, "request.json"), request, "
|
|
667
|
-
writeExclusive(join(dir, "planner.mjs"), script, "
|
|
712
|
+
writeExclusiveJson(join(dir, "request.json"), request, "governor plan request");
|
|
713
|
+
writeExclusive(join(dir, "planner.mjs"), script, "governor planner script");
|
|
668
714
|
return request;
|
|
669
715
|
}
|
|
670
716
|
|
|
671
717
|
function plannerScript(
|
|
672
718
|
coordRoot: string,
|
|
673
|
-
record:
|
|
719
|
+
record: GovernorRecord,
|
|
674
720
|
planId: string,
|
|
675
|
-
trigger: NonNullable<
|
|
721
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>,
|
|
676
722
|
): string {
|
|
677
723
|
const policy = record.intent.replanning;
|
|
678
|
-
if (!policy) throw new Error(`
|
|
724
|
+
if (!policy) throw new Error(`governor ${record.intent.id} does not allow replanning`);
|
|
679
725
|
const prompt = [
|
|
680
726
|
"You are producing one bounded replacement plan or milestone decision for a durable supervised goal.",
|
|
681
727
|
record.intent.mission
|
|
@@ -754,14 +800,14 @@ function plannerScript(
|
|
|
754
800
|
}
|
|
755
801
|
|
|
756
802
|
function plannerReviewScript(
|
|
757
|
-
record:
|
|
803
|
+
record: GovernorRecord,
|
|
758
804
|
planId: string,
|
|
759
|
-
initialCandidate:
|
|
760
|
-
trigger: NonNullable<
|
|
805
|
+
initialCandidate: GovernorPlanProposal,
|
|
806
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>,
|
|
761
807
|
): string {
|
|
762
808
|
const policy = record.intent.replanning;
|
|
763
809
|
const review = policy?.review;
|
|
764
|
-
if (!policy || !review) throw new Error(`
|
|
810
|
+
if (!policy || !review) throw new Error(`governor ${record.intent.id} does not review plans`);
|
|
765
811
|
const proposalSchema = planProposalSchema(record, trigger);
|
|
766
812
|
const reviewerSchema: StageSchema = {
|
|
767
813
|
type: "object",
|
|
@@ -822,7 +868,7 @@ function plannerReviewScript(
|
|
|
822
868
|
" stage('Review round ' + round);",
|
|
823
869
|
" const reviewersOut = await Promise.all(reviewers.map(async (specialist) => {",
|
|
824
870
|
" const prompt = [",
|
|
825
|
-
" 'Review this bounded
|
|
871
|
+
" 'Review this bounded governor plan candidate independently.',",
|
|
826
872
|
" 'Return approve only when the candidate is complete, scoped, and satisfies the goal context.',",
|
|
827
873
|
" 'Return revise for blocking defects. Return attention when human judgment is required.',",
|
|
828
874
|
" 'Apply proposal_root_rule exactly; never require proposal.root to equal active_root.',",
|
|
@@ -842,7 +888,7 @@ function plannerReviewScript(
|
|
|
842
888
|
" if (round > maxRevisionRounds) break;",
|
|
843
889
|
" stage('Revise round ' + round);",
|
|
844
890
|
" const revisionPrompt = [",
|
|
845
|
-
" 'Revise this
|
|
891
|
+
" 'Revise this governor plan candidate. Return a complete replacement candidate, not a patch.',",
|
|
846
892
|
" 'Do not merge reviewer text mechanically; satisfy the blocking findings within the frozen goal and template constraints.',",
|
|
847
893
|
" 'Apply proposal_root_rule exactly; never require proposal.root to equal active_root.',",
|
|
848
894
|
" 'Goal context: ' + JSON.stringify(goalContext),",
|
|
@@ -864,13 +910,13 @@ function plannerReviewScript(
|
|
|
864
910
|
|
|
865
911
|
function normalizeReviewReceipt(input: {
|
|
866
912
|
raw: unknown;
|
|
867
|
-
initialCandidate:
|
|
868
|
-
record:
|
|
869
|
-
request:
|
|
870
|
-
history: ReturnType<typeof
|
|
871
|
-
trigger: NonNullable<
|
|
872
|
-
policy:
|
|
873
|
-
}):
|
|
913
|
+
initialCandidate: GovernorPlanProposal;
|
|
914
|
+
record: GovernorRecord;
|
|
915
|
+
request: GovernorPlanRequest;
|
|
916
|
+
history: ReturnType<typeof readGovernorPlans>;
|
|
917
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>;
|
|
918
|
+
policy: GovernorReplanningPolicy;
|
|
919
|
+
}): GovernorPlanReviewReceipt {
|
|
874
920
|
const review = input.policy.review;
|
|
875
921
|
if (!review) throw new Error("missing review policy");
|
|
876
922
|
if (!input.raw || typeof input.raw !== "object" || Array.isArray(input.raw)) {
|
|
@@ -881,9 +927,9 @@ function normalizeReviewReceipt(input: {
|
|
|
881
927
|
if (raw.rounds.length < 1 || raw.rounds.length > review.max_revision_rounds + 1) {
|
|
882
928
|
throw new Error("review result has an invalid number of rounds");
|
|
883
929
|
}
|
|
884
|
-
const rounds:
|
|
930
|
+
const rounds: GovernorPlanReviewRound[] = [];
|
|
885
931
|
let candidate = input.initialCandidate;
|
|
886
|
-
let status:
|
|
932
|
+
let status: GovernorPlanReviewReceipt["status"] | undefined;
|
|
887
933
|
for (const [index, rawRound] of raw.rounds.entries()) {
|
|
888
934
|
if (!rawRound || typeof rawRound !== "object" || Array.isArray(rawRound)) {
|
|
889
935
|
throw new Error(`review round ${index + 1} must be an object`);
|
|
@@ -894,7 +940,7 @@ function normalizeReviewReceipt(input: {
|
|
|
894
940
|
if (roundNumber !== index + 1) throw new Error(`review round must be ${index + 1}`);
|
|
895
941
|
const reviewers = normalizeReviewers(value.reviewers, review.reviewer_specialists);
|
|
896
942
|
const outcome = aggregateReviewers(reviewers);
|
|
897
|
-
const round:
|
|
943
|
+
const round: GovernorPlanReviewRound = {
|
|
898
944
|
round: roundNumber,
|
|
899
945
|
candidate_sha256: candidateDigest(candidate),
|
|
900
946
|
reviewers,
|
|
@@ -925,7 +971,7 @@ function normalizeReviewReceipt(input: {
|
|
|
925
971
|
}
|
|
926
972
|
status ??= "attention";
|
|
927
973
|
return {
|
|
928
|
-
schema_version:
|
|
974
|
+
schema_version: GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
929
975
|
plan_id: input.request.id,
|
|
930
976
|
status,
|
|
931
977
|
candidate_sha256: candidateDigest(candidate),
|
|
@@ -937,7 +983,7 @@ function normalizeReviewReceipt(input: {
|
|
|
937
983
|
function normalizeReviewers(
|
|
938
984
|
raw: unknown,
|
|
939
985
|
expectedSpecialists: readonly string[],
|
|
940
|
-
):
|
|
986
|
+
): GovernorPlanReviewReviewer[] {
|
|
941
987
|
if (!Array.isArray(raw) || raw.length !== expectedSpecialists.length) {
|
|
942
988
|
throw new Error("reviewer result count does not match the frozen review policy");
|
|
943
989
|
}
|
|
@@ -960,7 +1006,7 @@ function normalizeReviewers(
|
|
|
960
1006
|
});
|
|
961
1007
|
}
|
|
962
1008
|
|
|
963
|
-
function normalizeFindings(raw: unknown, specialist: string):
|
|
1009
|
+
function normalizeFindings(raw: unknown, specialist: string): GovernorPlanReviewFinding[] {
|
|
964
1010
|
if (!Array.isArray(raw) || raw.length > 50) {
|
|
965
1011
|
throw new Error(`review findings from ${specialist} must contain at most 50 items`);
|
|
966
1012
|
}
|
|
@@ -989,8 +1035,8 @@ function findingCode(value: unknown, specialist: string, index: number): string
|
|
|
989
1035
|
}
|
|
990
1036
|
|
|
991
1037
|
function aggregateReviewers(
|
|
992
|
-
reviewers: readonly
|
|
993
|
-
):
|
|
1038
|
+
reviewers: readonly GovernorPlanReviewReviewer[],
|
|
1039
|
+
): GovernorPlanReviewRound["outcome"] {
|
|
994
1040
|
if (reviewers.length < 1) return "failed";
|
|
995
1041
|
if (reviewers.some((reviewer) => reviewer.verdict === "attention")) return "attention";
|
|
996
1042
|
if (
|
|
@@ -1007,12 +1053,12 @@ function aggregateReviewers(
|
|
|
1007
1053
|
|
|
1008
1054
|
function reconstructReviewReceiptFromProof(input: {
|
|
1009
1055
|
coordRoot: string;
|
|
1010
|
-
record:
|
|
1011
|
-
request:
|
|
1012
|
-
history: ReturnType<typeof
|
|
1013
|
-
trigger: NonNullable<
|
|
1014
|
-
policy:
|
|
1015
|
-
}):
|
|
1056
|
+
record: GovernorRecord;
|
|
1057
|
+
request: GovernorPlanRequest;
|
|
1058
|
+
history: ReturnType<typeof readGovernorPlans>;
|
|
1059
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>;
|
|
1060
|
+
policy: GovernorReplanningPolicy;
|
|
1061
|
+
}): GovernorPlanReviewReceipt | undefined {
|
|
1016
1062
|
const runId = reviewWorkflowRunId(input.request.id);
|
|
1017
1063
|
const proofPath = join(input.coordRoot, ".harnery", "workflows", runId, "proof.json");
|
|
1018
1064
|
if (!existsSync(proofPath)) return undefined;
|
|
@@ -1044,19 +1090,19 @@ function recoverReviewWorkflowResult(
|
|
|
1044
1090
|
proof: WorkflowProof,
|
|
1045
1091
|
expectedSpecialists: readonly string[],
|
|
1046
1092
|
): {
|
|
1047
|
-
initialCandidate:
|
|
1093
|
+
initialCandidate: GovernorPlanProposal;
|
|
1048
1094
|
result: { rounds: unknown[] };
|
|
1049
1095
|
} {
|
|
1050
1096
|
const inputPath = reviewInputPath(coordRoot, goalId, planId);
|
|
1051
|
-
const reviewInput = readBoundedJson<{ candidate:
|
|
1097
|
+
const reviewInput = readBoundedJson<{ candidate: GovernorPlanProposal }>(
|
|
1052
1098
|
inputPath,
|
|
1053
|
-
"
|
|
1099
|
+
"governor plan review input",
|
|
1054
1100
|
);
|
|
1055
|
-
const
|
|
1101
|
+
const transcript = readVerifiedWorkflowTranscript(coordRoot, reviewWorkflowRunId(planId), proof);
|
|
1056
1102
|
const starts = new Map<string, { specialist?: string }>();
|
|
1057
1103
|
const byRound = new Map<number, Record<string, unknown>>();
|
|
1058
1104
|
let currentCandidate: unknown = reviewInput.candidate;
|
|
1059
|
-
for (const line of
|
|
1105
|
+
for (const line of transcript.split("\n")) {
|
|
1060
1106
|
if (!line.trim()) continue;
|
|
1061
1107
|
const event = JSON.parse(line) as Record<string, unknown>;
|
|
1062
1108
|
if (event.event === "agent.start" && typeof event.id === "string") {
|
|
@@ -1065,7 +1111,7 @@ function recoverReviewWorkflowResult(
|
|
|
1065
1111
|
});
|
|
1066
1112
|
}
|
|
1067
1113
|
if (event.event !== "agent.end" || event.result_kind !== "json") continue;
|
|
1068
|
-
const round =
|
|
1114
|
+
const round = workflowTranscriptRound(event.stage);
|
|
1069
1115
|
if (!round) continue;
|
|
1070
1116
|
let record = byRound.get(round.round);
|
|
1071
1117
|
if (!record) {
|
|
@@ -1076,7 +1122,7 @@ function recoverReviewWorkflowResult(
|
|
|
1076
1122
|
const specialist =
|
|
1077
1123
|
typeof event.id === "string" ? starts.get(event.id)?.specialist : undefined;
|
|
1078
1124
|
if (!event.result || typeof event.result !== "object" || Array.isArray(event.result)) {
|
|
1079
|
-
throw new Error("
|
|
1125
|
+
throw new Error("governor plan review transcript contains an invalid reviewer result");
|
|
1080
1126
|
}
|
|
1081
1127
|
(record.reviewers as unknown[]).push({
|
|
1082
1128
|
specialist,
|
|
@@ -1108,22 +1154,28 @@ function recoverReviewWorkflowResult(
|
|
|
1108
1154
|
};
|
|
1109
1155
|
}
|
|
1110
1156
|
|
|
1111
|
-
function
|
|
1157
|
+
function readVerifiedWorkflowTranscript(
|
|
1112
1158
|
coordRoot: string,
|
|
1113
1159
|
runId: string,
|
|
1114
1160
|
proof: WorkflowProof,
|
|
1115
1161
|
): string {
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1162
|
+
const transcriptPath = join(
|
|
1163
|
+
coordRoot,
|
|
1164
|
+
".harnery",
|
|
1165
|
+
"workflows",
|
|
1166
|
+
runId,
|
|
1167
|
+
proof.integrity.transcript.path,
|
|
1168
|
+
);
|
|
1169
|
+
const transcript = readFileSync(transcriptPath, "utf8");
|
|
1170
|
+
const bytes = Buffer.byteLength(transcript);
|
|
1171
|
+
if (bytes <= 0 || bytes > MAX_RECORD_BYTES || bytes !== proof.integrity.transcript.bytes) {
|
|
1172
|
+
throw new Error(`governor plan review transcript does not match proof integrity`);
|
|
1121
1173
|
}
|
|
1122
|
-
const sha256 = createHash("sha256").update(
|
|
1123
|
-
if (sha256 !== proof.integrity.
|
|
1124
|
-
throw new Error(`
|
|
1174
|
+
const sha256 = createHash("sha256").update(transcript).digest("hex");
|
|
1175
|
+
if (sha256 !== proof.integrity.transcript.sha256) {
|
|
1176
|
+
throw new Error(`governor plan review transcript does not match proof integrity`);
|
|
1125
1177
|
}
|
|
1126
|
-
return
|
|
1178
|
+
return transcript;
|
|
1127
1179
|
}
|
|
1128
1180
|
|
|
1129
1181
|
function orderRecoveredReviewers(raw: unknown, expectedSpecialists: readonly string[]): unknown[] {
|
|
@@ -1181,7 +1233,7 @@ function aggregateRecoveredReviewers(reviewers: readonly unknown[]): string {
|
|
|
1181
1233
|
|
|
1182
1234
|
function assertResultDigest(raw: unknown, expected: ResultDigest | undefined, runId: string): void {
|
|
1183
1235
|
if (!expected) {
|
|
1184
|
-
throw new Error(`
|
|
1236
|
+
throw new Error(`governor plan review proof ${runId} is missing its result digest`);
|
|
1185
1237
|
}
|
|
1186
1238
|
const actual = digestResult(raw, "json");
|
|
1187
1239
|
if (
|
|
@@ -1189,11 +1241,11 @@ function assertResultDigest(raw: unknown, expected: ResultDigest | undefined, ru
|
|
|
1189
1241
|
actual.sha256 !== expected.sha256 ||
|
|
1190
1242
|
actual.bytes !== expected.bytes
|
|
1191
1243
|
) {
|
|
1192
|
-
throw new Error(`
|
|
1244
|
+
throw new Error(`governor plan review result does not match proof digest`);
|
|
1193
1245
|
}
|
|
1194
1246
|
}
|
|
1195
1247
|
|
|
1196
|
-
function
|
|
1248
|
+
function workflowTranscriptRound(
|
|
1197
1249
|
stage: unknown,
|
|
1198
1250
|
): { kind: "review" | "revision"; round: number } | undefined {
|
|
1199
1251
|
if (typeof stage !== "string") return undefined;
|
|
@@ -1204,13 +1256,13 @@ function workflowJournalRound(
|
|
|
1204
1256
|
return undefined;
|
|
1205
1257
|
}
|
|
1206
1258
|
|
|
1207
|
-
function candidateDigest(candidate:
|
|
1259
|
+
function candidateDigest(candidate: GovernorPlanProposal): string {
|
|
1208
1260
|
return createHash("sha256")
|
|
1209
1261
|
.update(JSON.stringify(canonicalCandidate(candidate)))
|
|
1210
1262
|
.digest("hex");
|
|
1211
1263
|
}
|
|
1212
1264
|
|
|
1213
|
-
function canonicalCandidate(candidate:
|
|
1265
|
+
function canonicalCandidate(candidate: GovernorPlanProposal): unknown {
|
|
1214
1266
|
return {
|
|
1215
1267
|
schema_version: candidate.schema_version,
|
|
1216
1268
|
plan_id: candidate.plan_id,
|
|
@@ -1230,11 +1282,11 @@ function hasReviewRecoveryEvidence(coordRoot: string, goalId: string, planId: st
|
|
|
1230
1282
|
}
|
|
1231
1283
|
|
|
1232
1284
|
function planProposalSchema(
|
|
1233
|
-
record:
|
|
1234
|
-
trigger: NonNullable<
|
|
1285
|
+
record: GovernorRecord,
|
|
1286
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>,
|
|
1235
1287
|
): StageSchema {
|
|
1236
1288
|
const policy = record.intent.replanning;
|
|
1237
|
-
if (!policy) throw new Error(`
|
|
1289
|
+
if (!policy) throw new Error(`governor ${record.intent.id} does not allow replanning`);
|
|
1238
1290
|
const rationale: StageSchema = { type: "string", minLength: 1, maxLength: MAX_REASON };
|
|
1239
1291
|
const workItem: StageSchema = {
|
|
1240
1292
|
type: "object",
|
|
@@ -1324,13 +1376,13 @@ function planProposalSchema(
|
|
|
1324
1376
|
function normalizeProposal(
|
|
1325
1377
|
planId: string,
|
|
1326
1378
|
raw: unknown,
|
|
1327
|
-
record:
|
|
1379
|
+
record: GovernorRecord,
|
|
1328
1380
|
previouslyApplied: number,
|
|
1329
|
-
trigger: NonNullable<
|
|
1381
|
+
trigger: NonNullable<GovernorPlanRequest["trigger"]>,
|
|
1330
1382
|
preservedProposedAt?: string,
|
|
1331
|
-
):
|
|
1383
|
+
): GovernorPlanProposal {
|
|
1332
1384
|
const policy = record.intent.replanning;
|
|
1333
|
-
if (!policy) throw new Error(`
|
|
1385
|
+
if (!policy) throw new Error(`governor ${record.intent.id} does not allow replanning`);
|
|
1334
1386
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1335
1387
|
throw new Error("planner result must be an object");
|
|
1336
1388
|
}
|
|
@@ -1348,7 +1400,7 @@ function normalizeProposal(
|
|
|
1348
1400
|
throw new Error("mission completion may be proposed only at a milestone boundary");
|
|
1349
1401
|
}
|
|
1350
1402
|
return {
|
|
1351
|
-
schema_version:
|
|
1403
|
+
schema_version: GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
1352
1404
|
plan_id: planId,
|
|
1353
1405
|
decision,
|
|
1354
1406
|
rationale,
|
|
@@ -1376,7 +1428,7 @@ function normalizeProposal(
|
|
|
1376
1428
|
}
|
|
1377
1429
|
const active = new Set(record.projection.work_ids);
|
|
1378
1430
|
const seen = new Set<string>();
|
|
1379
|
-
const work = value.work.map((candidate, index):
|
|
1431
|
+
const work = value.work.map((candidate, index): GovernorPlanWorkSpec => {
|
|
1380
1432
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1381
1433
|
throw new Error(`plan work[${index}] must be an object`);
|
|
1382
1434
|
}
|
|
@@ -1442,7 +1494,7 @@ function normalizeProposal(
|
|
|
1442
1494
|
`plan contains work not reachable from root: ${unused.map((item) => item.key).join(", ")}`,
|
|
1443
1495
|
);
|
|
1444
1496
|
return {
|
|
1445
|
-
schema_version:
|
|
1497
|
+
schema_version: GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
1446
1498
|
plan_id: planId,
|
|
1447
1499
|
decision,
|
|
1448
1500
|
rationale,
|
|
@@ -1464,7 +1516,7 @@ function persistedProposalTimestamp(raw: unknown): string {
|
|
|
1464
1516
|
return value;
|
|
1465
1517
|
}
|
|
1466
1518
|
|
|
1467
|
-
function normalizeMilestone(raw: unknown, expectedSequence: number):
|
|
1519
|
+
function normalizeMilestone(raw: unknown, expectedSequence: number): GovernorPlanMilestone {
|
|
1468
1520
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1469
1521
|
throw new Error("mission plan must contain a milestone object");
|
|
1470
1522
|
}
|
|
@@ -1486,7 +1538,7 @@ function normalizeMilestone(raw: unknown, expectedSequence: number): SupervisorP
|
|
|
1486
1538
|
};
|
|
1487
1539
|
}
|
|
1488
1540
|
|
|
1489
|
-
function planTrigger(record:
|
|
1541
|
+
function planTrigger(record: GovernorRecord): NonNullable<GovernorPlanRequest["trigger"]> {
|
|
1490
1542
|
if (
|
|
1491
1543
|
record.intent.mission &&
|
|
1492
1544
|
record.projection.plan_generation === 0 &&
|
|
@@ -1502,13 +1554,13 @@ function appendPlanEvent(
|
|
|
1502
1554
|
coordRootRaw: string,
|
|
1503
1555
|
goalId: string,
|
|
1504
1556
|
planId: string,
|
|
1505
|
-
input: Omit<
|
|
1557
|
+
input: Omit<GovernorPlanEvent, "schema_version" | "plan_id" | "seq" | "ts">,
|
|
1506
1558
|
): void {
|
|
1507
1559
|
const coordRoot = resolve(coordRootRaw);
|
|
1508
1560
|
const path = join(planDir(coordRoot, goalId, planId), "events.jsonl");
|
|
1509
|
-
const current =
|
|
1510
|
-
const event:
|
|
1511
|
-
schema_version:
|
|
1561
|
+
const current = readGovernorPlan(coordRoot, goalId, planId).events;
|
|
1562
|
+
const event: GovernorPlanEvent = {
|
|
1563
|
+
schema_version: GOVERNOR_PLAN_SCHEMA_VERSION,
|
|
1512
1564
|
plan_id: planId,
|
|
1513
1565
|
seq: current.length + 1,
|
|
1514
1566
|
ts: new Date().toISOString(),
|
|
@@ -1519,7 +1571,7 @@ function appendPlanEvent(
|
|
|
1519
1571
|
const line = `${JSON.stringify(event)}\n`;
|
|
1520
1572
|
const existing = existsSync(path) ? statSync(path).size : 0;
|
|
1521
1573
|
if (existing + Buffer.byteLength(line) > MAX_EVENTS_BYTES) {
|
|
1522
|
-
throw new Error("
|
|
1574
|
+
throw new Error("governor plan event log would exceed its byte limit");
|
|
1523
1575
|
}
|
|
1524
1576
|
appendFileSync(path, line, { encoding: "utf8", mode: 0o600 });
|
|
1525
1577
|
chmodSync(path, 0o600);
|
|
@@ -1529,15 +1581,15 @@ function appendPlanEventIfMissing(
|
|
|
1529
1581
|
coordRoot: string,
|
|
1530
1582
|
goalId: string,
|
|
1531
1583
|
planId: string,
|
|
1532
|
-
eventType:
|
|
1533
|
-
input: Omit<
|
|
1584
|
+
eventType: GovernorPlanEvent["event"],
|
|
1585
|
+
input: Omit<GovernorPlanEvent, "schema_version" | "plan_id" | "seq" | "ts">,
|
|
1534
1586
|
): void {
|
|
1535
|
-
const plan =
|
|
1587
|
+
const plan = readGovernorPlan(coordRoot, goalId, planId);
|
|
1536
1588
|
if (plan.events.some((event) => event.event === eventType)) return;
|
|
1537
1589
|
appendPlanEvent(coordRoot, goalId, planId, input);
|
|
1538
1590
|
}
|
|
1539
1591
|
|
|
1540
|
-
function outcome(plan: ReturnType<typeof
|
|
1592
|
+
function outcome(plan: ReturnType<typeof readGovernorPlan>): GovernorPlanOutcome {
|
|
1541
1593
|
return {
|
|
1542
1594
|
plan_id: plan.request.id,
|
|
1543
1595
|
status: plan.status,
|
|
@@ -1578,7 +1630,7 @@ function writeExclusive(path: string, body: string, label: string): void {
|
|
|
1578
1630
|
}
|
|
1579
1631
|
|
|
1580
1632
|
function planDir(coordRoot: string, goalId: string, planId: string): string {
|
|
1581
|
-
return join(coordRoot, ".harnery", "
|
|
1633
|
+
return join(coordRoot, ".harnery", "governors", goalId, "plans", planId);
|
|
1582
1634
|
}
|
|
1583
1635
|
|
|
1584
1636
|
function planScriptPath(coordRoot: string, goalId: string, planId: string): string {
|