agentic-orchestrator 0.1.28 → 0.2.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/.claude/settings.local.json +46 -1
- package/.cortexrc +28 -0
- package/.github/agents/copilot-instructions.md +29 -0
- package/.github/copilot-instructions.md +93 -0
- package/.vscode/settings.json +13 -0
- package/.vscode/tms.code-snippets +223 -0
- package/AGENTS.md +72 -1
- package/Agentic-Orchestrator.iml +12 -11
- package/CLAUDE.md +72 -1
- package/CONSTITUTION.md +504 -0
- package/FUTURE-ENHANCEMENTS.md +85 -0
- package/NEXT-TASKS.md +25 -0
- package/PROMPTS.md +161 -0
- package/README.md +126 -29
- package/agentic/orchestrator/agents.yaml +4 -3
- package/agentic/orchestrator/defaults/policy.defaults.yaml +39 -3
- package/agentic/orchestrator/gates.yaml +15 -3
- package/agentic/orchestrator/policy.yaml +47 -3
- package/agentic/orchestrator/prompts/builder.system.md +69 -20
- package/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
- package/agentic/orchestrator/prompts/planner.system.md +113 -40
- package/agentic/orchestrator/prompts/qa.system.md +73 -18
- package/agentic/orchestrator/prompts/reconciler.system.md +119 -0
- package/agentic/orchestrator/schemas/agents.schema.json +89 -1
- package/agentic/orchestrator/schemas/execution-control.schema.json +242 -0
- package/agentic/orchestrator/schemas/index.schema.json +234 -0
- package/agentic/orchestrator/schemas/intake.review.schema.json +82 -0
- package/agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json +75 -0
- package/agentic/orchestrator/schemas/plan.schema.json +44 -0
- package/agentic/orchestrator/schemas/policy.schema.json +238 -9
- package/agentic/orchestrator/schemas/policy.user.schema.json +129 -1
- package/agentic/orchestrator/schemas/spec.manifest.bootstrap.schema.json +101 -0
- package/agentic/orchestrator/schemas/spec.manifest.verified.schema.json +80 -0
- package/agentic/orchestrator/schemas/state.schema.json +298 -3
- package/agentic/orchestrator/tools/catalog.json +145 -15
- package/agentic/orchestrator/tools/schemas/input/doctor.run.input.schema.json +18 -0
- package/agentic/orchestrator/tools/schemas/input/evidence.latest.input.schema.json +4 -0
- package/agentic/orchestrator/tools/schemas/input/evidence.verify_chain.input.schema.json +13 -0
- package/agentic/orchestrator/tools/schemas/input/feature.intake_submit.input.schema.json +11 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_answer.input.schema.json +15 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_create.input.schema.json +21 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_list.input.schema.json +13 -0
- package/agentic/orchestrator/tools/schemas/input/feature.ready_to_merge.input.schema.json +5 -0
- package/agentic/orchestrator/tools/schemas/input/feature.send_message.input.schema.json +1 -1
- package/agentic/orchestrator/tools/schemas/input/replay.timeline_get.input.schema.json +32 -0
- package/agentic/orchestrator/tools/schemas/input/repo.conflict_abort.input.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/input/repo.conflict_files.input.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/input/repo.reconcile_mainline.input.schema.json +37 -0
- package/agentic/orchestrator/tools/schemas/input/repo.resolve_conflict.input.schema.json +40 -0
- package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_list.input.schema.json +7 -0
- package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_submit.input.schema.json +25 -0
- package/agentic/orchestrator/tools/schemas/output/doctor.run.output.schema.json +34 -0
- package/agentic/orchestrator/tools/schemas/output/evidence.verify_chain.output.schema.json +23 -0
- package/agentic/orchestrator/tools/schemas/output/feature.get_context.output.schema.json +62 -2
- package/agentic/orchestrator/tools/schemas/output/feature.intake_submit.output.schema.json +24 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_answer.output.schema.json +21 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_create.output.schema.json +12 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_list.output.schema.json +14 -0
- package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +31 -0
- package/agentic/orchestrator/tools/schemas/output/feature.send_message.output.schema.json +8 -18
- package/agentic/orchestrator/tools/schemas/output/replay.timeline_get.output.schema.json +64 -0
- package/agentic/orchestrator/tools/schemas/output/repo.conflict_abort.output.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/output/repo.conflict_files.output.schema.json +22 -0
- package/agentic/orchestrator/tools/schemas/output/repo.reconcile_mainline.output.schema.json +61 -0
- package/agentic/orchestrator/tools/schemas/output/repo.resolve_conflict.output.schema.json +19 -0
- package/agentic/orchestrator/tools/schemas/output/report.dashboard.output.schema.json +26 -0
- package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_list.output.schema.json +17 -0
- package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_submit.output.schema.json +24 -0
- package/agentic/orchestrator/tools.md +13 -0
- package/apps/control-plane/scripts/validate-mcp-contracts.ts +1 -1
- package/apps/control-plane/src/application/kernel-tool-wiring.ts +140 -2
- package/apps/control-plane/src/application/services/activity-monitor-service.ts +44 -1
- package/apps/control-plane/src/application/services/bootstrap-manifest-generator-service.ts +251 -0
- package/apps/control-plane/src/application/services/checkpoint-service.ts +87 -27
- package/apps/control-plane/src/application/services/collision-override-service.ts +906 -0
- package/apps/control-plane/src/application/services/collision-queue-service.ts +129 -38
- package/apps/control-plane/src/application/services/cost-tracking-service.ts +94 -0
- package/apps/control-plane/src/application/services/execution-control-service.ts +599 -0
- package/apps/control-plane/src/application/services/feature-deletion-service.ts +37 -1
- package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +182 -4
- package/apps/control-plane/src/application/services/feature-send-message-service.ts +17 -8
- package/apps/control-plane/src/application/services/feature-state-service.ts +191 -6
- package/apps/control-plane/src/application/services/gate-service.ts +121 -2
- package/apps/control-plane/src/application/services/git-reconciliation-service.ts +1591 -0
- package/apps/control-plane/src/application/services/intake-service.ts +1468 -0
- package/apps/control-plane/src/application/services/merge-service.ts +308 -17
- package/apps/control-plane/src/application/services/notifier-service.ts +3 -1
- package/apps/control-plane/src/application/services/performance-analytics-service.ts +75 -0
- package/apps/control-plane/src/application/services/plan-service.ts +336 -20
- package/apps/control-plane/src/application/services/question-service.ts +693 -0
- package/apps/control-plane/src/application/services/reactions-service.ts +73 -17
- package/apps/control-plane/src/application/services/replay-timeline-service.ts +295 -0
- package/apps/control-plane/src/application/services/reporting-service.ts +194 -10
- package/apps/control-plane/src/application/services/run-lease-service.ts +121 -5
- package/apps/control-plane/src/application/services/worktree-watchdog-service.ts +95 -8
- package/apps/control-plane/src/application/tools/tool-metadata.ts +7 -0
- package/apps/control-plane/src/application/usage-types.ts +138 -0
- package/apps/control-plane/src/cli/add-command-handler.ts +162 -0
- package/apps/control-plane/src/cli/answer-command-handler.ts +113 -0
- package/apps/control-plane/src/cli/attach-command-handler.ts +12 -3
- package/apps/control-plane/src/cli/cli-argument-parser.ts +133 -11
- package/apps/control-plane/src/cli/collision-command-handler.ts +113 -0
- package/apps/control-plane/src/cli/command-catalog.ts +479 -0
- package/apps/control-plane/src/cli/complete-command-handler.ts +23 -0
- package/apps/control-plane/src/cli/completion-command-handler.ts +25 -0
- package/apps/control-plane/src/cli/completion-resolver.ts +319 -0
- package/apps/control-plane/src/cli/completion-shell-renderer.ts +58 -0
- package/apps/control-plane/src/cli/dashboard-command-handler.ts +110 -1
- package/apps/control-plane/src/cli/dashboard-runtime-runner.ts +1036 -0
- package/apps/control-plane/src/cli/dashboard-runtime.ts +31 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +17 -185
- package/apps/control-plane/src/cli/init-command-handler.ts +51 -6
- package/apps/control-plane/src/cli/merge-command-handler.ts +200 -0
- package/apps/control-plane/src/cli/questions-command-handler.ts +70 -0
- package/apps/control-plane/src/cli/replay-command-handler.ts +98 -0
- package/apps/control-plane/src/cli/resume-command-handler.ts +231 -16
- package/apps/control-plane/src/cli/retry-command-handler.ts +229 -17
- package/apps/control-plane/src/cli/retry-resume-decision.ts +75 -0
- package/apps/control-plane/src/cli/rollback-command-handler.ts +4 -2
- package/apps/control-plane/src/cli/run-command-handler.ts +35 -1
- package/apps/control-plane/src/cli/spec-ingestion-service.ts +45 -55
- package/apps/control-plane/src/cli/spec-preparation.ts +114 -0
- package/apps/control-plane/src/cli/spec-utils.ts +90 -11
- package/apps/control-plane/src/cli/status-command-handler.ts +122 -0
- package/apps/control-plane/src/cli/types.ts +41 -3
- package/apps/control-plane/src/core/collisions.ts +150 -31
- package/apps/control-plane/src/core/constants.ts +18 -1
- package/apps/control-plane/src/core/error-codes.ts +39 -0
- package/apps/control-plane/src/core/execution-control.ts +56 -0
- package/apps/control-plane/src/core/feature-resume-phase.ts +118 -0
- package/apps/control-plane/src/core/gate-freshness.ts +359 -0
- package/apps/control-plane/src/core/gate-log-extractor.ts +97 -0
- package/apps/control-plane/src/core/gates.ts +90 -1
- package/apps/control-plane/src/core/intake-artifacts.ts +295 -0
- package/apps/control-plane/src/core/kernel-types.ts +11 -0
- package/apps/control-plane/src/core/kernel.ts +604 -16
- package/apps/control-plane/src/core/mainline-conflict.ts +22 -0
- package/apps/control-plane/src/core/merge-repair.ts +149 -0
- package/apps/control-plane/src/core/path-layout.ts +46 -2
- package/apps/control-plane/src/core/path-rules.ts +11 -3
- package/apps/control-plane/src/core/plan-submit-recovery.ts +130 -0
- package/apps/control-plane/src/core/questions.ts +49 -0
- package/apps/control-plane/src/core/runtime-sessions.ts +4 -0
- package/apps/control-plane/src/core/schemas.ts +40 -1
- package/apps/control-plane/src/core/tool-caller.ts +25 -1
- package/apps/control-plane/src/core/utils/index-normalizer.ts +25 -4
- package/apps/control-plane/src/core/worktree-diff.ts +66 -0
- package/apps/control-plane/src/index.ts +29 -1
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +300 -6
- package/apps/control-plane/src/mcp/kernel-tool-executor.ts +17 -0
- package/apps/control-plane/src/mcp/tool-runtime.ts +63 -4
- package/apps/control-plane/src/providers/api-worker-provider.ts +62 -15
- package/apps/control-plane/src/providers/cli-worker-provider.ts +1037 -61
- package/apps/control-plane/src/providers/output-parsers/generic-output-parser.ts +99 -1
- package/apps/control-plane/src/providers/output-parsers/types.ts +2 -0
- package/apps/control-plane/src/providers/provider-defaults.ts +116 -7
- package/apps/control-plane/src/providers/providers.ts +225 -21
- package/apps/control-plane/src/providers/worker-provider-factory.ts +26 -2
- package/apps/control-plane/src/supervisor/artifact-stager.ts +52 -0
- package/apps/control-plane/src/supervisor/build-wave-executor.ts +477 -166
- package/apps/control-plane/src/supervisor/execution-enrollment-service.ts +408 -0
- package/apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts +117 -0
- package/apps/control-plane/src/supervisor/organizer-sidecar-service.ts +394 -0
- package/apps/control-plane/src/supervisor/plan-conformance-scorer.ts +2 -5
- package/apps/control-plane/src/supervisor/planner-phase.ts +85 -0
- package/apps/control-plane/src/supervisor/planning-wave-executor.ts +993 -64
- package/apps/control-plane/src/supervisor/prompt-bundle-loader.ts +20 -1
- package/apps/control-plane/src/supervisor/qa-wave-executor.ts +384 -177
- package/apps/control-plane/src/supervisor/run-coordinator.ts +723 -20
- package/apps/control-plane/src/supervisor/runtime.ts +485 -9
- package/apps/control-plane/src/supervisor/session-orchestrator.ts +220 -1
- package/apps/control-plane/src/supervisor/types.ts +152 -1
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +1030 -92
- package/apps/control-plane/test/activity-monitor.spec.ts +76 -0
- package/apps/control-plane/test/add-command-handler.spec.ts +189 -0
- package/apps/control-plane/test/application/services/feature-state-service.spec.ts +208 -0
- package/apps/control-plane/test/artifact-stager.spec.ts +93 -0
- package/apps/control-plane/test/batch-operations.spec.ts +58 -0
- package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +50 -2
- package/apps/control-plane/test/bootstrap-manifest-generator-service.spec.ts +99 -0
- package/apps/control-plane/test/bootstrap.spec.ts +177 -4
- package/apps/control-plane/test/checkpoint-service.spec.ts +977 -29
- package/apps/control-plane/test/cli-argument-parser.spec.ts +119 -0
- package/apps/control-plane/test/cli-helpers.spec.ts +1202 -12
- package/apps/control-plane/test/cli.unit.spec.ts +797 -16
- package/apps/control-plane/test/collision-command-handler.spec.ts +182 -0
- package/apps/control-plane/test/collision-override-service.spec.ts +878 -0
- package/apps/control-plane/test/collision-queue.spec.ts +430 -2
- package/apps/control-plane/test/collisions.spec.ts +209 -1
- package/apps/control-plane/test/core-utils.spec.ts +61 -0
- package/apps/control-plane/test/cost-tracking.spec.ts +224 -0
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +185 -5
- package/apps/control-plane/test/dashboard-client.spec.ts +948 -0
- package/apps/control-plane/test/dashboard-command.spec.ts +138 -6
- package/apps/control-plane/test/dashboard-runtime-runner.spec.ts +1550 -0
- package/apps/control-plane/test/dashboard-runtime.spec.ts +138 -0
- package/apps/control-plane/test/dashboard-ui-utils.spec.ts +56 -12
- package/apps/control-plane/test/dependency-scheduler.spec.ts +7 -1
- package/apps/control-plane/test/env-file.spec.ts +76 -0
- package/apps/control-plane/test/execution-control-service.spec.ts +535 -0
- package/apps/control-plane/test/execution-enrollment-service.spec.ts +648 -0
- package/apps/control-plane/test/feature-lifecycle.spec.ts +126 -0
- package/apps/control-plane/test/feature-resume-phase.spec.ts +164 -0
- package/apps/control-plane/test/feature-send-message-service.spec.ts +161 -0
- package/apps/control-plane/test/feature-state-service.spec.ts +295 -0
- package/apps/control-plane/test/fs.spec.ts +80 -0
- package/apps/control-plane/test/gate-freshness.spec.ts +590 -0
- package/apps/control-plane/test/gate-log-extractor.spec.ts +170 -0
- package/apps/control-plane/test/gates.spec.ts +108 -0
- package/apps/control-plane/test/git-reconciliation-service.spec.ts +2307 -0
- package/apps/control-plane/test/helpers.ts +65 -0
- package/apps/control-plane/test/incremental-gates.spec.ts +271 -0
- package/apps/control-plane/test/index-normalizer.spec.ts +98 -0
- package/apps/control-plane/test/init-wizard.spec.ts +17 -0
- package/apps/control-plane/test/intake-artifacts.spec.ts +203 -0
- package/apps/control-plane/test/intake-service.spec.ts +3176 -0
- package/apps/control-plane/test/kernel-collision-replay.spec.ts +3 -2
- package/apps/control-plane/test/kernel-tool-executor.spec.ts +77 -0
- package/apps/control-plane/test/kernel-tool-wiring.spec.ts +279 -0
- package/apps/control-plane/test/kernel.branches.spec.ts +15 -2
- package/apps/control-plane/test/kernel.coverage.spec.ts +7 -3
- package/apps/control-plane/test/kernel.coverage2.spec.ts +731 -2
- package/apps/control-plane/test/kernel.spec.ts +464 -2
- package/apps/control-plane/test/mainline-conflict.spec.ts +66 -0
- package/apps/control-plane/test/mcp-helpers.spec.ts +79 -0
- package/apps/control-plane/test/mcp.spec.ts +177 -13
- package/apps/control-plane/test/merge-command-handler.spec.ts +531 -0
- package/apps/control-plane/test/merge-service.spec.ts +570 -4
- package/apps/control-plane/test/notifier-service.spec.ts +26 -0
- package/apps/control-plane/test/organizer-enrollment-scheduler.spec.ts +340 -0
- package/apps/control-plane/test/organizer-ordering-artifact.spec.ts +95 -0
- package/apps/control-plane/test/organizer-sidecar-service.spec.ts +468 -0
- package/apps/control-plane/test/output-loop-detector.spec.ts +6 -0
- package/apps/control-plane/test/path-layout.spec.ts +70 -0
- package/apps/control-plane/test/performance-analytics.spec.ts +124 -0
- package/apps/control-plane/test/plan-conformance-scorer.spec.ts +53 -0
- package/apps/control-plane/test/plan-service.spec.ts +686 -4
- package/apps/control-plane/test/planning-wave-executor.spec.ts +3272 -86
- package/apps/control-plane/test/policy-loader-service.spec.ts +5 -0
- package/apps/control-plane/test/prompt-overlay.spec.ts +65 -0
- package/apps/control-plane/test/provider-command-runner-epipe.spec.ts +64 -0
- package/apps/control-plane/test/providers/api-worker-provider.spec.ts +129 -0
- package/apps/control-plane/test/providers/cli-worker-provider.spec.ts +148 -0
- package/apps/control-plane/test/providers/usage-types.spec.ts +98 -0
- package/apps/control-plane/test/providers.spec.ts +293 -16
- package/apps/control-plane/test/question-command-handlers.spec.ts +156 -0
- package/apps/control-plane/test/question-service.spec.ts +1119 -0
- package/apps/control-plane/test/reactions.spec.ts +114 -0
- package/apps/control-plane/test/replay-command-handler.spec.ts +144 -0
- package/apps/control-plane/test/replay-timeline-service.spec.ts +459 -0
- package/apps/control-plane/test/response.spec.ts +31 -0
- package/apps/control-plane/test/resume-command.spec.ts +757 -9
- package/apps/control-plane/test/retry-resume-decision.spec.ts +133 -0
- package/apps/control-plane/test/rollback-command-handler.spec.ts +334 -0
- package/apps/control-plane/test/rollback-command.spec.ts +120 -0
- package/apps/control-plane/test/run-coordinator.spec.ts +3062 -404
- package/apps/control-plane/test/schemas/state.schema.spec.ts +71 -0
- package/apps/control-plane/test/service-retry-paths.spec.ts +112 -0
- package/apps/control-plane/test/services.spec.ts +472 -2
- package/apps/control-plane/test/session-management.spec.ts +346 -1
- package/apps/control-plane/test/spec-ingestion.spec.ts +102 -28
- package/apps/control-plane/test/spec-preparation.spec.ts +182 -0
- package/apps/control-plane/test/supervisor-collaborators.spec.ts +191 -3
- package/apps/control-plane/test/supervisor.calltool.spec.ts +198 -0
- package/apps/control-plane/test/supervisor.spec.ts +95 -16
- package/apps/control-plane/test/supervisor.unit.spec.ts +385 -18
- package/apps/control-plane/test/tool-runtime.spec.ts +122 -0
- package/apps/control-plane/test/worker-decision-loop.spec.ts +3479 -476
- package/apps/control-plane/test/worker-execution-policy.spec.ts +1416 -6
- package/apps/control-plane/test/worker-provider-adapters.spec.ts +1894 -37
- package/apps/control-plane/test/worker-provider-factory.spec.ts +81 -0
- package/apps/control-plane/test/worktree-watchdog-service.spec.ts +125 -0
- package/apps/control-plane/vitest.config.ts +5 -0
- package/config/agentic/orchestrator/agents.yaml +22 -1
- package/config/agentic/orchestrator/gates.yaml +24 -7
- package/config/agentic/orchestrator/policy.yaml +23 -1
- package/config/agentic/orchestrator/prompts/builder.system.md +69 -20
- package/config/agentic/orchestrator/prompts/organizer.system.md +85 -0
- package/config/agentic/orchestrator/prompts/overrides/builder.claude.md +28 -0
- package/config/agentic/orchestrator/prompts/overrides/builder.codex.md +28 -0
- package/config/agentic/orchestrator/prompts/overrides/planner.claude.md +20 -0
- package/config/agentic/orchestrator/prompts/overrides/planner.codex.md +20 -0
- package/config/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
- package/config/agentic/orchestrator/prompts/planner.system.md +113 -40
- package/config/agentic/orchestrator/prompts/qa.system.md +75 -18
- package/config/agentic/orchestrator/prompts/reconciler.system.md +119 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.d.ts +26 -2
- package/dist/apps/control-plane/application/kernel-tool-wiring.js +40 -2
- package/dist/apps/control-plane/application/kernel-tool-wiring.js.map +1 -1
- package/dist/apps/control-plane/application/services/activity-monitor-service.js +37 -1
- package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.d.ts +4 -0
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js +188 -0
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.d.ts +5 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js +69 -24
- package/dist/apps/control-plane/application/services/checkpoint-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/collision-override-service.d.ts +139 -0
- package/dist/apps/control-plane/application/services/collision-override-service.js +568 -0
- package/dist/apps/control-plane/application/services/collision-override-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/collision-queue-service.d.ts +15 -0
- package/dist/apps/control-plane/application/services/collision-queue-service.js +92 -33
- package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/cost-tracking-service.d.ts +11 -0
- package/dist/apps/control-plane/application/services/cost-tracking-service.js +75 -0
- package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/execution-control-service.d.ts +75 -0
- package/dist/apps/control-plane/application/services/execution-control-service.js +421 -0
- package/dist/apps/control-plane/application/services/execution-control-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/feature-deletion-service.d.ts +1 -0
- package/dist/apps/control-plane/application/services/feature-deletion-service.js +23 -1
- package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.d.ts +24 -1
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +132 -3
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-send-message-service.js +16 -8
- package/dist/apps/control-plane/application/services/feature-send-message-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-state-service.d.ts +36 -0
- package/dist/apps/control-plane/application/services/feature-state-service.js +163 -6
- package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/gate-service.d.ts +2 -1
- package/dist/apps/control-plane/application/services/gate-service.js +95 -5
- package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/git-reconciliation-service.d.ts +92 -0
- package/dist/apps/control-plane/application/services/git-reconciliation-service.js +1097 -0
- package/dist/apps/control-plane/application/services/git-reconciliation-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/intake-service.d.ts +63 -0
- package/dist/apps/control-plane/application/services/intake-service.js +1050 -0
- package/dist/apps/control-plane/application/services/intake-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/merge-service.d.ts +5 -1
- package/dist/apps/control-plane/application/services/merge-service.js +233 -18
- package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/notifier-service.d.ts +1 -1
- package/dist/apps/control-plane/application/services/notifier-service.js +1 -0
- package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/performance-analytics-service.d.ts +11 -0
- package/dist/apps/control-plane/application/services/performance-analytics-service.js +59 -0
- package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/plan-service.d.ts +5 -0
- package/dist/apps/control-plane/application/services/plan-service.js +254 -15
- package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/question-service.d.ts +72 -0
- package/dist/apps/control-plane/application/services/question-service.js +507 -0
- package/dist/apps/control-plane/application/services/question-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/reactions-service.d.ts +2 -0
- package/dist/apps/control-plane/application/services/reactions-service.js +60 -17
- package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/replay-timeline-service.d.ts +39 -0
- package/dist/apps/control-plane/application/services/replay-timeline-service.js +205 -0
- package/dist/apps/control-plane/application/services/replay-timeline-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/reporting-service.d.ts +59 -0
- package/dist/apps/control-plane/application/services/reporting-service.js +121 -9
- package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/run-lease-service.d.ts +20 -0
- package/dist/apps/control-plane/application/services/run-lease-service.js +81 -4
- package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.d.ts +10 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js +65 -8
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js.map +1 -1
- package/dist/apps/control-plane/application/tools/tool-metadata.js +7 -0
- package/dist/apps/control-plane/application/tools/tool-metadata.js.map +1 -1
- package/dist/apps/control-plane/application/usage-types.d.ts +65 -0
- package/dist/apps/control-plane/application/usage-types.js +75 -0
- package/dist/apps/control-plane/application/usage-types.js.map +1 -0
- package/dist/apps/control-plane/cli/add-command-handler.d.ts +18 -0
- package/dist/apps/control-plane/cli/add-command-handler.js +110 -0
- package/dist/apps/control-plane/cli/add-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/answer-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/answer-command-handler.js +96 -0
- package/dist/apps/control-plane/cli/answer-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/attach-command-handler.js +8 -3
- package/dist/apps/control-plane/cli/attach-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/cli-argument-parser.js +131 -11
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/collision-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/collision-command-handler.js +90 -0
- package/dist/apps/control-plane/cli/collision-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/command-catalog.d.ts +21 -0
- package/dist/apps/control-plane/cli/command-catalog.js +416 -0
- package/dist/apps/control-plane/cli/command-catalog.js.map +1 -0
- package/dist/apps/control-plane/cli/complete-command-handler.d.ts +15 -0
- package/dist/apps/control-plane/cli/complete-command-handler.js +26 -0
- package/dist/apps/control-plane/cli/complete-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/completion-command-handler.js +20 -0
- package/dist/apps/control-plane/cli/completion-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-resolver.d.ts +1 -0
- package/dist/apps/control-plane/cli/completion-resolver.js +250 -0
- package/dist/apps/control-plane/cli/completion-resolver.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.d.ts +3 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.js +53 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.js.map +1 -0
- package/dist/apps/control-plane/cli/dashboard-command-handler.d.ts +1 -0
- package/dist/apps/control-plane/cli/dashboard-command-handler.js +83 -1
- package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.d.ts +81 -0
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.js +724 -0
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.js.map +1 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.d.ts +1 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.js +26 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.js.map +1 -0
- package/dist/apps/control-plane/cli/help-command-handler.js +13 -172
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +51 -6
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/merge-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/merge-command-handler.js +139 -0
- package/dist/apps/control-plane/cli/merge-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/questions-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/questions-command-handler.js +59 -0
- package/dist/apps/control-plane/cli/questions-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/replay-command-handler.d.ts +15 -0
- package/dist/apps/control-plane/cli/replay-command-handler.js +55 -0
- package/dist/apps/control-plane/cli/replay-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/resume-command-handler.d.ts +2 -0
- package/dist/apps/control-plane/cli/resume-command-handler.js +180 -17
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-command-handler.js +202 -16
- package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-resume-decision.d.ts +26 -0
- package/dist/apps/control-plane/cli/retry-resume-decision.js +61 -0
- package/dist/apps/control-plane/cli/retry-resume-decision.js.map +1 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js +3 -2
- package/dist/apps/control-plane/cli/rollback-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/run-command-handler.js +26 -2
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-ingestion-service.d.ts +2 -0
- package/dist/apps/control-plane/cli/spec-ingestion-service.js +37 -48
- package/dist/apps/control-plane/cli/spec-ingestion-service.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-preparation.d.ts +14 -0
- package/dist/apps/control-plane/cli/spec-preparation.js +81 -0
- package/dist/apps/control-plane/cli/spec-preparation.js.map +1 -0
- package/dist/apps/control-plane/cli/spec-utils.d.ts +4 -0
- package/dist/apps/control-plane/cli/spec-utils.js +70 -11
- package/dist/apps/control-plane/cli/spec-utils.js.map +1 -1
- package/dist/apps/control-plane/cli/status-command-handler.js +69 -0
- package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +41 -4
- package/dist/apps/control-plane/cli/types.js +9 -1
- package/dist/apps/control-plane/cli/types.js.map +1 -1
- package/dist/apps/control-plane/core/collisions.d.ts +37 -19
- package/dist/apps/control-plane/core/collisions.js +87 -12
- package/dist/apps/control-plane/core/collisions.js.map +1 -1
- package/dist/apps/control-plane/core/constants.d.ts +17 -1
- package/dist/apps/control-plane/core/constants.js +18 -1
- package/dist/apps/control-plane/core/constants.js.map +1 -1
- package/dist/apps/control-plane/core/error-codes.d.ts +39 -0
- package/dist/apps/control-plane/core/error-codes.js +39 -0
- package/dist/apps/control-plane/core/error-codes.js.map +1 -1
- package/dist/apps/control-plane/core/execution-control.d.ts +45 -0
- package/dist/apps/control-plane/core/execution-control.js +2 -0
- package/dist/apps/control-plane/core/execution-control.js.map +1 -0
- package/dist/apps/control-plane/core/feature-resume-phase.d.ts +3 -0
- package/dist/apps/control-plane/core/feature-resume-phase.js +88 -0
- package/dist/apps/control-plane/core/feature-resume-phase.js.map +1 -0
- package/dist/apps/control-plane/core/gate-freshness.d.ts +48 -0
- package/dist/apps/control-plane/core/gate-freshness.js +267 -0
- package/dist/apps/control-plane/core/gate-freshness.js.map +1 -0
- package/dist/apps/control-plane/core/gate-log-extractor.d.ts +22 -0
- package/dist/apps/control-plane/core/gate-log-extractor.js +66 -0
- package/dist/apps/control-plane/core/gate-log-extractor.js.map +1 -0
- package/dist/apps/control-plane/core/gates.d.ts +11 -2
- package/dist/apps/control-plane/core/gates.js +67 -3
- package/dist/apps/control-plane/core/gates.js.map +1 -1
- package/dist/apps/control-plane/core/intake-artifacts.d.ts +109 -0
- package/dist/apps/control-plane/core/intake-artifacts.js +143 -0
- package/dist/apps/control-plane/core/intake-artifacts.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-types.d.ts +8 -0
- package/dist/apps/control-plane/core/kernel.d.ts +256 -8
- package/dist/apps/control-plane/core/kernel.js +400 -14
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/mainline-conflict.d.ts +7 -0
- package/dist/apps/control-plane/core/mainline-conflict.js +20 -0
- package/dist/apps/control-plane/core/mainline-conflict.js.map +1 -0
- package/dist/apps/control-plane/core/merge-repair.d.ts +35 -0
- package/dist/apps/control-plane/core/merge-repair.js +99 -0
- package/dist/apps/control-plane/core/merge-repair.js.map +1 -0
- package/dist/apps/control-plane/core/path-layout.d.ts +10 -0
- package/dist/apps/control-plane/core/path-layout.js +32 -2
- package/dist/apps/control-plane/core/path-layout.js.map +1 -1
- package/dist/apps/control-plane/core/path-rules.js +9 -3
- package/dist/apps/control-plane/core/path-rules.js.map +1 -1
- package/dist/apps/control-plane/core/plan-submit-recovery.d.ts +22 -0
- package/dist/apps/control-plane/core/plan-submit-recovery.js +78 -0
- package/dist/apps/control-plane/core/plan-submit-recovery.js.map +1 -0
- package/dist/apps/control-plane/core/questions.d.ts +40 -0
- package/dist/apps/control-plane/core/questions.js +2 -0
- package/dist/apps/control-plane/core/questions.js.map +1 -0
- package/dist/apps/control-plane/core/runtime-sessions.d.ts +4 -0
- package/dist/apps/control-plane/core/schemas.d.ts +2 -0
- package/dist/apps/control-plane/core/schemas.js +31 -1
- package/dist/apps/control-plane/core/schemas.js.map +1 -1
- package/dist/apps/control-plane/core/tool-caller.d.ts +18 -1
- package/dist/apps/control-plane/core/utils/index-normalizer.js +17 -4
- package/dist/apps/control-plane/core/utils/index-normalizer.js.map +1 -1
- package/dist/apps/control-plane/core/worktree-diff.d.ts +4 -0
- package/dist/apps/control-plane/core/worktree-diff.js +52 -0
- package/dist/apps/control-plane/core/worktree-diff.js.map +1 -0
- package/dist/apps/control-plane/index.d.ts +10 -2
- package/dist/apps/control-plane/index.js +9 -2
- package/dist/apps/control-plane/index.js.map +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +236 -6
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js +16 -0
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-runtime.d.ts +5 -0
- package/dist/apps/control-plane/mcp/tool-runtime.js +40 -5
- package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
- package/dist/apps/control-plane/providers/api-worker-provider.d.ts +2 -2
- package/dist/apps/control-plane/providers/api-worker-provider.js +40 -9
- package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +59 -3
- package/dist/apps/control-plane/providers/cli-worker-provider.js +758 -46
- package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js +91 -1
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js.map +1 -1
- package/dist/apps/control-plane/providers/output-parsers/types.d.ts +2 -0
- package/dist/apps/control-plane/providers/provider-defaults.d.ts +12 -0
- package/dist/apps/control-plane/providers/provider-defaults.js +103 -7
- package/dist/apps/control-plane/providers/provider-defaults.js.map +1 -1
- package/dist/apps/control-plane/providers/providers.d.ts +50 -4
- package/dist/apps/control-plane/providers/providers.js +145 -14
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +2 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js +8 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
- package/dist/apps/control-plane/supervisor/artifact-stager.d.ts +5 -0
- package/dist/apps/control-plane/supervisor/artifact-stager.js +45 -0
- package/dist/apps/control-plane/supervisor/artifact-stager.js.map +1 -0
- package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +24 -1
- package/dist/apps/control-plane/supervisor/build-wave-executor.js +362 -150
- package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.d.ts +41 -0
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.js +311 -0
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.js.map +1 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.d.ts +15 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js +93 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js.map +1 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.d.ts +44 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js +311 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js.map +1 -0
- package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js +2 -5
- package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js.map +1 -1
- package/dist/apps/control-plane/supervisor/planner-phase.d.ts +3 -0
- package/dist/apps/control-plane/supervisor/planner-phase.js +70 -0
- package/dist/apps/control-plane/supervisor/planner-phase.js.map +1 -0
- package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +42 -0
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js +753 -55
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js +19 -1
- package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js.map +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +21 -0
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js +287 -156
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +30 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.js +561 -17
- package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.d.ts +84 -0
- package/dist/apps/control-plane/supervisor/runtime.js +393 -3
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/session-orchestrator.d.ts +54 -0
- package/dist/apps/control-plane/supervisor/session-orchestrator.js +176 -1
- package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/types.d.ts +142 -1
- package/dist/apps/control-plane/supervisor/types.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +68 -2
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +723 -89
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/docs/core/ARCHITECTURE.md +227 -0
- package/docs/core/DECISIONS.md +94 -0
- package/docs/core/DOMAIN-LOGIC.md +60 -0
- package/docs/core/PATTERNS.md +201 -0
- package/docs/core/TROUBLESHOOTING.md +347 -0
- package/docs/core/intentgraph-dependencies.json +39860 -0
- package/docs/core/intentgraph.index.json +46580 -0
- package/docs/plans/2026-03-10-gate-failure-targeted-repair-design.md +224 -0
- package/docs/plans/2026-03-10-gate-failure-targeted-repair.md +1032 -0
- package/docs/superpowers/plans/2026-03-16-provider-cli-config.md +743 -0
- package/docs/superpowers/plans/2026-03-23-reconcile-divergence-fix.md +777 -0
- package/docs/superpowers/plans/2026-03-28-ordering-agent-implementation.md +1754 -0
- package/docs/superpowers/plans/2026-03-29-drop-zone-and-provider-optimization.md +1108 -0
- package/docs/superpowers/plans/2026-03-29-merge-target-feature-branch.md +685 -0
- package/docs/superpowers/plans/2026-03-29-organizer-sidecar-runtime-loop.md +1289 -0
- package/docs/superpowers/specs/2026-03-23-reconcile-divergence-fix-design.md +118 -0
- package/docs/superpowers/specs/2026-03-28-ordering-agent-spec-audit-design.md +50 -0
- package/docs/superpowers/specs/2026-03-29-drop-zone-and-provider-optimization-design.md +254 -0
- package/docs/superpowers/specs/2026-03-29-merge-target-feature-branch-design.md +152 -0
- package/docs/superpowers/specs/2026-03-29-organizer-sidecar-runtime-loop-design.md +225 -0
- package/package.json +3 -2
- package/packages/web-dashboard/package.json +2 -1
- package/packages/web-dashboard/src/app/analytics/page.tsx +36 -2
- package/packages/web-dashboard/src/app/api/actions/route.ts +274 -63
- package/packages/web-dashboard/src/app/api/actions/status/route.ts +35 -0
- package/packages/web-dashboard/src/app/api/analytics/provider/route.ts +18 -0
- package/packages/web-dashboard/src/app/api/collisions/approve/route.ts +58 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoint-diff/route.ts +36 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/route.ts +29 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/abort/route.ts +29 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/files/route.ts +30 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/resolve/route.ts +51 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/route.ts +75 -0
- package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +16 -2
- package/packages/web-dashboard/src/app/api/features/[id]/files/route.ts +26 -0
- package/packages/web-dashboard/src/app/api/features/[id]/gate-history/route.ts +27 -0
- package/packages/web-dashboard/src/app/api/features/[id]/genealogy/route.ts +26 -0
- package/packages/web-dashboard/src/app/api/features/[id]/history/run/[runId]/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/history/runs/route.ts +34 -0
- package/packages/web-dashboard/src/app/api/features/[id]/intake-workspace/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/live-output/route.ts +74 -0
- package/packages/web-dashboard/src/app/api/features/[id]/plan/amend/route.ts +21 -0
- package/packages/web-dashboard/src/app/api/features/[id]/plan-progress/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planner-artifacts/[artifact]/route.ts +78 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planner-lifecycle/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planning-workspace/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/questions/[questionId]/answer/route.ts +27 -0
- package/packages/web-dashboard/src/app/api/features/[id]/questions/route.ts +18 -0
- package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +14 -7
- package/packages/web-dashboard/src/app/api/features/[id]/route.ts +57 -2
- package/packages/web-dashboard/src/app/api/features/[id]/spec/route.ts +30 -0
- package/packages/web-dashboard/src/app/api/features/[id]/triage/route.ts +83 -0
- package/packages/web-dashboard/src/app/api/features/[id]/worker-events/route.ts +40 -0
- package/packages/web-dashboard/src/app/api/launch/preview/route.ts +86 -0
- package/packages/web-dashboard/src/app/api/launch/submit/route.ts +180 -0
- package/packages/web-dashboard/src/app/api/mainline/status/route.ts +74 -0
- package/packages/web-dashboard/src/app/api/merge-queue/route.ts +13 -0
- package/packages/web-dashboard/src/app/api/policy/budget/route.ts +14 -0
- package/packages/web-dashboard/src/app/api/projects/route.ts +11 -7
- package/packages/web-dashboard/src/app/api/reconciler/queue/route.ts +47 -0
- package/packages/web-dashboard/src/app/api/run/route.ts +26 -2
- package/packages/web-dashboard/src/app/api/runtime/events/route.ts +227 -0
- package/packages/web-dashboard/src/app/api/runtime/operations/route.ts +269 -0
- package/packages/web-dashboard/src/app/api/runtime/questions/route.ts +11 -0
- package/packages/web-dashboard/src/app/api/runtime/runs/route.ts +80 -0
- package/packages/web-dashboard/src/app/api/status/route.ts +4 -2
- package/packages/web-dashboard/src/app/feature/[id]/page.tsx +32 -42
- package/packages/web-dashboard/src/app/globals.css +34 -3
- package/packages/web-dashboard/src/app/launch/page.tsx +357 -0
- package/packages/web-dashboard/src/app/layout.tsx +23 -1
- package/packages/web-dashboard/src/app/page.tsx +263 -272
- package/packages/web-dashboard/src/components/dashboard/attention-strip.tsx +52 -0
- package/packages/web-dashboard/src/components/dashboard/collision-approval-drawer.tsx +185 -0
- package/packages/web-dashboard/src/components/dashboard/command-center-header.tsx +102 -0
- package/packages/web-dashboard/src/components/dashboard/mainline-status-banner.tsx +84 -0
- package/packages/web-dashboard/src/components/dashboard/merged-archive.tsx +36 -0
- package/packages/web-dashboard/src/components/dashboard/prioritized-queues.tsx +98 -0
- package/packages/web-dashboard/src/components/dashboard/reconciler-queue-card.tsx +115 -0
- package/packages/web-dashboard/src/components/dashboard/secondary-diagnostics-rail.tsx +48 -0
- package/packages/web-dashboard/src/components/dashboard/task-filter-bar.tsx +74 -0
- package/packages/web-dashboard/src/components/dashboard/triage-drawer.tsx +455 -0
- package/packages/web-dashboard/src/components/diff-viewer.tsx +19 -3
- package/packages/web-dashboard/src/components/evidence-viewer.tsx +65 -51
- package/packages/web-dashboard/src/components/feature-card.tsx +90 -7
- package/packages/web-dashboard/src/components/feature-cost-panel.tsx +112 -11
- package/packages/web-dashboard/src/components/feature-list-view.tsx +25 -4
- package/packages/web-dashboard/src/components/features/runtime-inspector/EventsTimelineView.tsx +260 -0
- package/packages/web-dashboard/src/components/features/runtime-inspector/OperationsListView.tsx +172 -0
- package/packages/web-dashboard/src/components/features/runtime-inspector/RuntimeInspectorPanel.tsx +896 -0
- package/packages/web-dashboard/src/components/filter-bar.tsx +7 -39
- package/packages/web-dashboard/src/components/focus/ActionableRiskList.tsx +46 -0
- package/packages/web-dashboard/src/components/focus/AgentRolePerformanceCard.tsx +200 -0
- package/packages/web-dashboard/src/components/focus/BlockedGuidanceBanner.tsx +149 -0
- package/packages/web-dashboard/src/components/focus/CheckpointInspector.tsx +123 -0
- package/packages/web-dashboard/src/components/focus/CheckpointRail.tsx +118 -0
- package/packages/web-dashboard/src/components/focus/CheckpointScrubber.tsx +249 -0
- package/packages/web-dashboard/src/components/focus/CollisionApprovalBanner.tsx +192 -0
- package/packages/web-dashboard/src/components/focus/CollisionRadar.tsx +136 -0
- package/packages/web-dashboard/src/components/focus/ConflictStatusCard.tsx +52 -0
- package/packages/web-dashboard/src/components/focus/ContextSidebar.tsx +108 -0
- package/packages/web-dashboard/src/components/focus/DiagnosisPanel.tsx +68 -0
- package/packages/web-dashboard/src/components/focus/FeatureDecisionBanner.tsx +68 -0
- package/packages/web-dashboard/src/components/focus/FeatureQuestionAnswerPanel.tsx +167 -0
- package/packages/web-dashboard/src/components/focus/FocusHeader.tsx +54 -0
- package/packages/web-dashboard/src/components/focus/FocusLayout.tsx +283 -0
- package/packages/web-dashboard/src/components/focus/GateFlakinessSummary.tsx +144 -0
- package/packages/web-dashboard/src/components/focus/GenealogyTree.tsx +34 -0
- package/packages/web-dashboard/src/components/focus/HeroBlock.tsx +67 -0
- package/packages/web-dashboard/src/components/focus/LiveAgentConsole.tsx +277 -0
- package/packages/web-dashboard/src/components/focus/MergeQueueCard.tsx +78 -0
- package/packages/web-dashboard/src/components/focus/OperationalSummaryCard.tsx +227 -0
- package/packages/web-dashboard/src/components/focus/PinnedActions.tsx +96 -0
- package/packages/web-dashboard/src/components/focus/PlanAmendmentPanel.tsx +250 -0
- package/packages/web-dashboard/src/components/focus/PlanProgressPanel.tsx +133 -0
- package/packages/web-dashboard/src/components/focus/PlannerArtifactViewer.tsx +158 -0
- package/packages/web-dashboard/src/components/focus/PlannerLifecycleHeader.tsx +141 -0
- package/packages/web-dashboard/src/components/focus/ProgressSnapshotCard.tsx +113 -0
- package/packages/web-dashboard/src/components/focus/RecentMaterialChanges.tsx +69 -0
- package/packages/web-dashboard/src/components/focus/RoleLogViewer.tsx +436 -0
- package/packages/web-dashboard/src/components/focus/RunHistoryBrowser.tsx +62 -0
- package/packages/web-dashboard/src/components/focus/SpecViewer.tsx +172 -0
- package/packages/web-dashboard/src/components/focus/TabBar.tsx +33 -0
- package/packages/web-dashboard/src/components/focus/UsageBurnChart.tsx +212 -0
- package/packages/web-dashboard/src/components/focus/VerificationSummaryCard.tsx +122 -0
- package/packages/web-dashboard/src/components/focus/tabs/ChangesTab.tsx +325 -0
- package/packages/web-dashboard/src/components/focus/tabs/ConflictsTab.tsx +395 -0
- package/packages/web-dashboard/src/components/focus/tabs/GatesQaTab.tsx +38 -0
- package/packages/web-dashboard/src/components/focus/tabs/HistoryTab.tsx +213 -0
- package/packages/web-dashboard/src/components/focus/tabs/IntakeTab.tsx +429 -0
- package/packages/web-dashboard/src/components/focus/tabs/OverviewTab.tsx +217 -0
- package/packages/web-dashboard/src/components/focus/tabs/PlanningTab.tsx +390 -0
- package/packages/web-dashboard/src/components/focus/tabs/ReviewTab.tsx +497 -0
- package/packages/web-dashboard/src/components/focus/tabs/RuntimeTab.tsx +213 -0
- package/packages/web-dashboard/src/components/focus/tabs/TranscriptTab.tsx +315 -0
- package/packages/web-dashboard/src/components/gate-results.tsx +2 -2
- package/packages/web-dashboard/src/components/human-input-panel.tsx +33 -57
- package/packages/web-dashboard/src/components/kanban-board.tsx +4 -0
- package/packages/web-dashboard/src/components/launch/launch-draft-card.tsx +131 -0
- package/packages/web-dashboard/src/components/plan-viewer.tsx +147 -69
- package/packages/web-dashboard/src/components/quick-launch-panel.tsx +20 -47
- package/packages/web-dashboard/src/components/summary-bar.tsx +30 -76
- package/packages/web-dashboard/src/lib/aop-client.ts +2484 -36
- package/packages/web-dashboard/src/lib/blocked-state-guidance.ts +475 -0
- package/packages/web-dashboard/src/lib/collision-radar.ts +136 -0
- package/packages/web-dashboard/src/lib/dashboard-action-states.ts +204 -0
- package/packages/web-dashboard/src/lib/dashboard-runtime-client.ts +439 -0
- package/packages/web-dashboard/src/lib/dashboard-utils.ts +179 -18
- package/packages/web-dashboard/src/lib/drop-zone-utils.ts +92 -0
- package/packages/web-dashboard/src/lib/focus-detail-derivations.ts +958 -0
- package/packages/web-dashboard/src/lib/focus-view.ts +300 -0
- package/packages/web-dashboard/src/lib/health-diagnosis.ts +356 -0
- package/packages/web-dashboard/src/lib/launch-contracts.ts +77 -0
- package/packages/web-dashboard/src/lib/launch-markdown.ts +107 -0
- package/packages/web-dashboard/src/lib/launch-page-preview.ts +89 -0
- package/packages/web-dashboard/src/lib/live-feed.ts +1 -1
- package/packages/web-dashboard/src/lib/multi-project-config.ts +33 -0
- package/packages/web-dashboard/src/lib/orchestrator-tools.ts +845 -59
- package/packages/web-dashboard/src/lib/planner-workspace.ts +1285 -0
- package/packages/web-dashboard/src/lib/review-contracts.ts +5 -3
- package/packages/web-dashboard/src/lib/runtime-files.ts +285 -0
- package/packages/web-dashboard/src/lib/tool-catalog.ts +51 -0
- package/packages/web-dashboard/src/lib/types.ts +731 -3
- package/packages/web-dashboard/src/lib/usage-burn.ts +175 -0
- package/packages/web-dashboard/src/lib/worktree-diff.ts +128 -0
- package/packages/web-dashboard/src/styles/dashboard.module.css +1742 -459
- package/packages/web-dashboard/test/api/actions/route.spec.ts +675 -0
- package/packages/web-dashboard/test/api/features/diff.route.spec.ts +57 -0
- package/packages/web-dashboard/test/api/features/feature.route.spec.ts +99 -0
- package/packages/web-dashboard/test/api/features/live-output.route.spec.ts +123 -0
- package/packages/web-dashboard/test/api/features/plan-amend.route.spec.ts +95 -0
- package/packages/web-dashboard/test/api/features/planner-workspaces.route.spec.ts +162 -0
- package/packages/web-dashboard/test/api/features/question-answer.route.spec.ts +99 -0
- package/packages/web-dashboard/test/api/features/triage.route.spec.ts +195 -0
- package/packages/web-dashboard/test/api/launch/preview.route.spec.ts +149 -0
- package/packages/web-dashboard/test/api/launch/submit.route.spec.ts +382 -0
- package/packages/web-dashboard/test/api/runtime/events/route.spec.ts +164 -0
- package/packages/web-dashboard/test/api/runtime/operations/route.spec.ts +156 -0
- package/packages/web-dashboard/test/api/runtime/runs/route.spec.ts +112 -0
- package/packages/web-dashboard/test/components/changes-tab.spec.tsx +76 -0
- package/packages/web-dashboard/test/components/command-center-root.spec.tsx +87 -0
- package/packages/web-dashboard/test/components/diagnosis-panel.spec.tsx +59 -0
- package/packages/web-dashboard/test/components/feature-card.spec.tsx +45 -0
- package/packages/web-dashboard/test/components/focus-layout.spec.tsx +299 -0
- package/packages/web-dashboard/test/components/gate-results.spec.tsx +39 -0
- package/packages/web-dashboard/test/components/gates-qa-tab.spec.tsx +118 -0
- package/packages/web-dashboard/test/components/human-input-panel.spec.tsx +54 -0
- package/packages/web-dashboard/test/components/intake-tab.spec.tsx +210 -0
- package/packages/web-dashboard/test/components/kanban-board.spec.tsx +35 -0
- package/packages/web-dashboard/test/components/launch-draft-card.spec.tsx +54 -0
- package/packages/web-dashboard/test/components/launch-page.spec.tsx +79 -0
- package/packages/web-dashboard/test/components/overview-tab.spec.tsx +236 -0
- package/packages/web-dashboard/test/components/planning-tab.spec.tsx +202 -0
- package/packages/web-dashboard/test/components/review-tab.spec.tsx +169 -0
- package/packages/web-dashboard/test/components/role-log-viewer.spec.ts +42 -0
- package/packages/web-dashboard/test/components/runtime-inspector.spec.tsx +22 -0
- package/packages/web-dashboard/test/components/runtime-tab.spec.tsx +133 -0
- package/packages/web-dashboard/test/components/transcript-tab.spec.tsx +46 -0
- package/packages/web-dashboard/test/components/triage-drawer.spec.tsx +159 -0
- package/packages/web-dashboard/test/lib/aop-client.spec.ts +235 -0
- package/packages/web-dashboard/test/lib/dashboard-runtime-client.spec.ts +144 -0
- package/packages/web-dashboard/test/lib/focus-detail-derivations.spec.ts +314 -0
- package/packages/web-dashboard/test/lib/focus-view.spec.ts +248 -0
- package/packages/web-dashboard/test/lib/health-diagnosis.spec.ts +277 -0
- package/packages/web-dashboard/test/lib/launch-markdown.spec.ts +36 -0
- package/packages/web-dashboard/test/lib/multi-project-config.spec.ts +54 -0
- package/packages/web-dashboard/test/lib/orchestrator-tools.spec.ts +352 -0
- package/packages/web-dashboard/test/lib/planner-workspace.spec.ts +289 -0
- package/packages/web-dashboard/test/lib/worktree-diff.spec.ts +119 -0
- package/packages/web-dashboard/vitest.config.ts +2 -0
- package/spec-files/completed/agentic_orchestrator_add_feature_to_active_execution_spec.md +557 -0
- package/spec-files/completed/agentic_orchestrator_dashboard_command_center_redesign_spec.md +1147 -0
- package/spec-files/completed/agentic_orchestrator_execution_mode_spec.md +18 -16
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_a_spec.md +672 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_b_spec.md +794 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_c_decision_centric_remediation_spec.md +1037 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_ux_redesign_spec.md +1432 -0
- package/spec-files/completed/agentic_orchestrator_focus_plan_tab_intake_planning_workspace_spec.md +921 -0
- package/spec-files/completed/agentic_orchestrator_intentional_collision_override_spec.md +584 -0
- package/spec-files/completed/agentic_orchestrator_interactive_planning_intake_and_requirements_verification_spec.md +1185 -0
- package/spec-files/completed/agentic_orchestrator_reactive_execution_enrollment_spec.md +864 -0
- package/spec-files/{outstanding → completed}/agentic_orchestrator_runtime_inspection_spec.md +92 -19
- package/spec-files/completed/agentic_orchestrator_scope_aware_run_lease_spec.md +408 -0
- package/spec-files/completed/git-reconciliation-engine.md +827 -0
- package/spec-files/outstanding/agentic_orchestrator_dashboard_quick_launch_and_control_surface_spec.md +331 -0
- package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +16 -6
- package/spec-files/outstanding/agentic_orchestrator_evidence_integrity_doctor_spec.md +60 -9
- package/spec-files/outstanding/agentic_orchestrator_focus_plan_tab_execution_contract_workspace_spec.md +616 -0
- package/spec-files/outstanding/agentic_orchestrator_headless_standby_dashboard_runtime_spec.md +310 -0
- package/spec-files/outstanding/agentic_orchestrator_human_input_interaction_protocol_spec.md +175 -72
- package/spec-files/outstanding/agentic_orchestrator_interactive_rename_cleanup_spec.md +197 -0
- package/spec-files/outstanding/agentic_orchestrator_interactive_resume_and_reconciliation_disposition_spec.md +412 -0
- package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +166 -137
- package/spec-files/outstanding/agentic_orchestrator_observability_replay_spec.md +3 -3
- package/spec-files/outstanding/agentic_orchestrator_phase_specific_agent_profiles_and_token_telemetry_spec.md +303 -0
- package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +18 -5
- package/spec-files/outstanding/agentic_orchestrator_policy_stratification_spec.md +225 -0
- package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +77 -50
- package/spec-files/outstanding/agentic_orchestrator_ready_to_merge_branch_handoff_spec.md +724 -0
- package/spec-files/outstanding/agentic_orchestrator_remove_deterministic_mode_spec.md +263 -0
- package/spec-files/outstanding/agentic_orchestrator_request_more_context_and_dashboard_human_input_spec.md +456 -0
- package/spec-files/outstanding/agentic_orchestrator_spec_coverage_and_reconciliation_enforcement_spec.md +1411 -0
- package/spec-files/outstanding/agentic_orchestrator_spec_ordering_agent_spec.md +370 -0
- package/spec-files/outstanding/shadow_workspace_implementation_spec.md +1 -1
- package/spec-files/progress.md +2026 -120
- package/specs/001-runtime-inspection/checklists/requirements.md +35 -0
- package/specs/001-runtime-inspection/design.md +338 -0
- package/specs/001-runtime-inspection/spec.md +95 -0
- package/specs/002-scope-aware-lease/checklists/requirements.md +35 -0
- package/specs/002-scope-aware-lease/contracts/lease-registry.schema.json +101 -0
- package/specs/002-scope-aware-lease/data-model.md +236 -0
- package/specs/002-scope-aware-lease/plan.md +766 -0
- package/specs/002-scope-aware-lease/quickstart.md +150 -0
- package/specs/002-scope-aware-lease/research.md +135 -0
- package/specs/002-scope-aware-lease/spec.md +128 -0
- package/specs/002-scope-aware-lease/tasks.md +767 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +28 -0
- package/ARCHITECTURE_ADHERENCE_ANALYSIS.md +0 -871
- package/packages/web-dashboard/next-env.d.ts +0 -6
- package/packages/web-dashboard/src/components/detail-panel.tsx +0 -1124
- package/packages/web-dashboard/src/components/review-workspace.tsx +0 -1162
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_artifact_database_publishing_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_cli_shell_tab_completion_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_dashboard_diff_and_agent_console_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_performance_improvements_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_persistent_worker_runtime_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_provider_auth_bootstrap_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_real_worker_provider_execution_spec.md +0 -0
|
@@ -0,0 +1,1754 @@
|
|
|
1
|
+
# Ordering Agent Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Implement a dependency-aware spec ordering agent that analyzes pending enrollment requests, determines execution order based on spec dependencies, and feeds the existing enrollment pipeline — so users can load many features simultaneously without manually managing execution ordering.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Two-layer design: (1) an organizer sidecar LLM session that reads spec files from pending enrollment requests and produces a structured ordering artifact on disk, and (2) a stateless `OrganizerAgentEnrollmentScheduler` adapter that reads the artifact during per-request `schedule()` calls and translates it into `EnrollmentDecision[]`. The sidecar follows the same global-session pattern as the reconciler in `session-orchestrator.ts`.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, Vitest, AJV schema validation, existing supervisor infrastructure
|
|
10
|
+
|
|
11
|
+
**Spec:** `spec-files/outstanding/agentic_orchestrator_spec_ordering_agent_spec.md` (v1.2)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Pre-Implementation: Fix Existing Defects
|
|
16
|
+
|
|
17
|
+
### Task 0: Commit divergence fix formatting cleanup and fix review-tab test
|
|
18
|
+
|
|
19
|
+
**Files:**
|
|
20
|
+
|
|
21
|
+
- Modify: `packages/web-dashboard/test/components/review-tab.spec.tsx:122` (already done in this session)
|
|
22
|
+
- Modify: `apps/control-plane/src/supervisor/run-coordinator.ts` (formatting — unstaged)
|
|
23
|
+
- Modify: `apps/control-plane/test/git-reconciliation-service.spec.ts` (formatting — unstaged)
|
|
24
|
+
- Modify: `apps/control-plane/test/kernel.coverage2.spec.ts` (formatting — unstaged)
|
|
25
|
+
- Modify: `apps/control-plane/test/run-coordinator.spec.ts` (formatting — unstaged)
|
|
26
|
+
|
|
27
|
+
- [ ] **Step 1: Verify review-tab test fix passes**
|
|
28
|
+
|
|
29
|
+
Run: `npx vitest run packages/web-dashboard/test/components/review-tab.spec.tsx`
|
|
30
|
+
Expected: 3 tests passing
|
|
31
|
+
|
|
32
|
+
- [ ] **Step 2: Stage all formatting cleanup and test fix**
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git add packages/web-dashboard/test/components/review-tab.spec.tsx \
|
|
36
|
+
apps/control-plane/src/supervisor/run-coordinator.ts \
|
|
37
|
+
apps/control-plane/test/git-reconciliation-service.spec.ts \
|
|
38
|
+
apps/control-plane/test/kernel.coverage2.spec.ts \
|
|
39
|
+
apps/control-plane/test/run-coordinator.spec.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- [ ] **Step 3: Run full test suite to confirm no regressions**
|
|
43
|
+
|
|
44
|
+
Run: `npx vitest run`
|
|
45
|
+
Expected: 168 test files, 2403 tests passing (0 failures)
|
|
46
|
+
|
|
47
|
+
- [ ] **Step 4: Commit**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git commit -m "fix: update review-tab test assertion and format divergence fix files
|
|
51
|
+
|
|
52
|
+
The ReviewTab component button text changed from 'Approve' to
|
|
53
|
+
'Approve & Merge' but the test was not updated. Also commits
|
|
54
|
+
remaining formatting cleanup from the divergence fix work."
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Layer 2: Deterministic Adapter (build bottom-up)
|
|
60
|
+
|
|
61
|
+
### Task 1: Add `OrganizerOrderingArtifact` type and JSON schema
|
|
62
|
+
|
|
63
|
+
**Files:**
|
|
64
|
+
|
|
65
|
+
- Modify: `apps/control-plane/src/supervisor/types.ts:80-90` (add type after `RuntimeSessionsSnapshot`)
|
|
66
|
+
- Create: `agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json`
|
|
67
|
+
- Test: `apps/control-plane/test/organizer-ordering-artifact.spec.ts`
|
|
68
|
+
|
|
69
|
+
- [ ] **Step 1: Write the failing test — artifact type validation**
|
|
70
|
+
|
|
71
|
+
Create `apps/control-plane/test/organizer-ordering-artifact.spec.ts`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { describe, expect, it } from 'vitest';
|
|
75
|
+
import Ajv from 'ajv';
|
|
76
|
+
import { readFileSync } from 'node:fs';
|
|
77
|
+
import path from 'node:path';
|
|
78
|
+
|
|
79
|
+
const schema = JSON.parse(
|
|
80
|
+
readFileSync(
|
|
81
|
+
path.resolve('agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json'),
|
|
82
|
+
'utf8',
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const ajv = new Ajv({ strict: false });
|
|
87
|
+
|
|
88
|
+
describe('OrganizerOrderingArtifact schema', () => {
|
|
89
|
+
it('GIVEN_valid_complete_artifact_WHEN_validated_THEN_passes', () => {
|
|
90
|
+
const artifact = {
|
|
91
|
+
version: 1,
|
|
92
|
+
generated_at: '2026-03-28T12:00:00.000Z',
|
|
93
|
+
expires_at: '2026-03-28T12:01:00.000Z',
|
|
94
|
+
completion_status: 'complete',
|
|
95
|
+
backlog_fingerprint: 'sha256:abc123',
|
|
96
|
+
analyzed_requests: ['req_1'],
|
|
97
|
+
dependency_graph: {
|
|
98
|
+
spec_a: { depends_on: [], classification: 'no_dependency_found' },
|
|
99
|
+
spec_b: { depends_on: ['spec_a'], classification: 'explicit_dependency' },
|
|
100
|
+
},
|
|
101
|
+
ready_set: ['spec_a'],
|
|
102
|
+
deferred_set: [
|
|
103
|
+
{ feature_id: 'spec_b', blocked_by: ['spec_a'], reason: 'explicit dependency' },
|
|
104
|
+
],
|
|
105
|
+
blocked_set: [],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const validate = ajv.compile(schema);
|
|
109
|
+
expect(validate(artifact)).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('GIVEN_partial_completion_status_WHEN_validated_THEN_passes', () => {
|
|
113
|
+
const artifact = {
|
|
114
|
+
version: 1,
|
|
115
|
+
generated_at: '2026-03-28T12:00:00.000Z',
|
|
116
|
+
expires_at: '2026-03-28T12:01:00.000Z',
|
|
117
|
+
completion_status: 'partial',
|
|
118
|
+
backlog_fingerprint: 'sha256:abc123',
|
|
119
|
+
analyzed_requests: [],
|
|
120
|
+
dependency_graph: {},
|
|
121
|
+
ready_set: [],
|
|
122
|
+
deferred_set: [],
|
|
123
|
+
blocked_set: [],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const validate = ajv.compile(schema);
|
|
127
|
+
expect(validate(artifact)).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('GIVEN_missing_required_field_WHEN_validated_THEN_fails', () => {
|
|
131
|
+
const artifact = {
|
|
132
|
+
version: 1,
|
|
133
|
+
generated_at: '2026-03-28T12:00:00.000Z',
|
|
134
|
+
// missing expires_at, completion_status, backlog_fingerprint
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const validate = ajv.compile(schema);
|
|
138
|
+
expect(validate(artifact)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('GIVEN_invalid_classification_WHEN_validated_THEN_fails', () => {
|
|
142
|
+
const artifact = {
|
|
143
|
+
version: 1,
|
|
144
|
+
generated_at: '2026-03-28T12:00:00.000Z',
|
|
145
|
+
expires_at: '2026-03-28T12:01:00.000Z',
|
|
146
|
+
completion_status: 'complete',
|
|
147
|
+
backlog_fingerprint: 'sha256:abc123',
|
|
148
|
+
analyzed_requests: [],
|
|
149
|
+
dependency_graph: {
|
|
150
|
+
spec_a: { depends_on: [], classification: 'made_up_classification' },
|
|
151
|
+
},
|
|
152
|
+
ready_set: [],
|
|
153
|
+
deferred_set: [],
|
|
154
|
+
blocked_set: [],
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const validate = ajv.compile(schema);
|
|
158
|
+
expect(validate(artifact)).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
164
|
+
|
|
165
|
+
Run: `npx vitest run apps/control-plane/test/organizer-ordering-artifact.spec.ts`
|
|
166
|
+
Expected: FAIL — schema file does not exist
|
|
167
|
+
|
|
168
|
+
- [ ] **Step 3: Create the JSON schema**
|
|
169
|
+
|
|
170
|
+
Create `agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json`:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
175
|
+
"$id": "https://example.local/agentic/organizer-ordering-artifact.schema.json",
|
|
176
|
+
"description": "Schema for the organizer sidecar ordering artifact persisted at .aop/runtime/<instanceId>/organizer-ordering.json",
|
|
177
|
+
"type": "object",
|
|
178
|
+
"required": [
|
|
179
|
+
"version",
|
|
180
|
+
"generated_at",
|
|
181
|
+
"expires_at",
|
|
182
|
+
"completion_status",
|
|
183
|
+
"backlog_fingerprint",
|
|
184
|
+
"analyzed_requests",
|
|
185
|
+
"dependency_graph",
|
|
186
|
+
"ready_set",
|
|
187
|
+
"deferred_set",
|
|
188
|
+
"blocked_set"
|
|
189
|
+
],
|
|
190
|
+
"additionalProperties": false,
|
|
191
|
+
"properties": {
|
|
192
|
+
"version": {
|
|
193
|
+
"type": "integer",
|
|
194
|
+
"const": 1
|
|
195
|
+
},
|
|
196
|
+
"generated_at": {
|
|
197
|
+
"type": "string",
|
|
198
|
+
"format": "date-time"
|
|
199
|
+
},
|
|
200
|
+
"expires_at": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"format": "date-time"
|
|
203
|
+
},
|
|
204
|
+
"completion_status": {
|
|
205
|
+
"type": "string",
|
|
206
|
+
"enum": ["complete", "partial"]
|
|
207
|
+
},
|
|
208
|
+
"backlog_fingerprint": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"description": "Hash of pending request IDs + feature IDs analyzed"
|
|
211
|
+
},
|
|
212
|
+
"analyzed_requests": {
|
|
213
|
+
"type": "array",
|
|
214
|
+
"items": { "type": "string" }
|
|
215
|
+
},
|
|
216
|
+
"dependency_graph": {
|
|
217
|
+
"type": "object",
|
|
218
|
+
"additionalProperties": {
|
|
219
|
+
"$ref": "#/$defs/dependencyEntry"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"ready_set": {
|
|
223
|
+
"type": "array",
|
|
224
|
+
"items": { "type": "string" }
|
|
225
|
+
},
|
|
226
|
+
"deferred_set": {
|
|
227
|
+
"type": "array",
|
|
228
|
+
"items": { "$ref": "#/$defs/deferredEntry" }
|
|
229
|
+
},
|
|
230
|
+
"blocked_set": {
|
|
231
|
+
"type": "array",
|
|
232
|
+
"items": { "$ref": "#/$defs/blockedEntry" }
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"$defs": {
|
|
236
|
+
"dependencyEntry": {
|
|
237
|
+
"type": "object",
|
|
238
|
+
"required": ["depends_on", "classification"],
|
|
239
|
+
"additionalProperties": false,
|
|
240
|
+
"properties": {
|
|
241
|
+
"depends_on": {
|
|
242
|
+
"type": "array",
|
|
243
|
+
"items": { "type": "string" }
|
|
244
|
+
},
|
|
245
|
+
"classification": {
|
|
246
|
+
"type": "string",
|
|
247
|
+
"enum": [
|
|
248
|
+
"explicit_dependency",
|
|
249
|
+
"inferred_dependency",
|
|
250
|
+
"no_dependency_found",
|
|
251
|
+
"ambiguous_dependency_requires_human"
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"deferredEntry": {
|
|
257
|
+
"type": "object",
|
|
258
|
+
"required": ["feature_id", "blocked_by", "reason"],
|
|
259
|
+
"additionalProperties": false,
|
|
260
|
+
"properties": {
|
|
261
|
+
"feature_id": { "type": "string" },
|
|
262
|
+
"blocked_by": {
|
|
263
|
+
"type": "array",
|
|
264
|
+
"items": { "type": "string" }
|
|
265
|
+
},
|
|
266
|
+
"reason": { "type": "string" }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"blockedEntry": {
|
|
270
|
+
"type": "object",
|
|
271
|
+
"required": ["feature_id", "reason"],
|
|
272
|
+
"additionalProperties": false,
|
|
273
|
+
"properties": {
|
|
274
|
+
"feature_id": { "type": "string" },
|
|
275
|
+
"reason": { "type": "string" }
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
- [ ] **Step 4: Add TypeScript type to `types.ts`**
|
|
283
|
+
|
|
284
|
+
Add after line 90 in `apps/control-plane/src/supervisor/types.ts` (after `RuntimeSessionsSnapshot`):
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
export interface OrganizerDependencyEntry {
|
|
288
|
+
depends_on: string[];
|
|
289
|
+
classification:
|
|
290
|
+
| 'explicit_dependency'
|
|
291
|
+
| 'inferred_dependency'
|
|
292
|
+
| 'no_dependency_found'
|
|
293
|
+
| 'ambiguous_dependency_requires_human';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface OrganizerDeferredEntry {
|
|
297
|
+
feature_id: string;
|
|
298
|
+
blocked_by: string[];
|
|
299
|
+
reason: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface OrganizerBlockedEntry {
|
|
303
|
+
feature_id: string;
|
|
304
|
+
reason: string;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export interface OrganizerOrderingArtifact {
|
|
308
|
+
version: 1;
|
|
309
|
+
generated_at: string;
|
|
310
|
+
expires_at: string;
|
|
311
|
+
completion_status: 'complete' | 'partial';
|
|
312
|
+
backlog_fingerprint: string;
|
|
313
|
+
analyzed_requests: string[];
|
|
314
|
+
dependency_graph: Record<string, OrganizerDependencyEntry>;
|
|
315
|
+
ready_set: string[];
|
|
316
|
+
deferred_set: OrganizerDeferredEntry[];
|
|
317
|
+
blocked_set: OrganizerBlockedEntry[];
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
- [ ] **Step 5: Run test to verify it passes**
|
|
322
|
+
|
|
323
|
+
Run: `npx vitest run apps/control-plane/test/organizer-ordering-artifact.spec.ts`
|
|
324
|
+
Expected: 4 tests passing
|
|
325
|
+
|
|
326
|
+
- [ ] **Step 6: Commit**
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
git add apps/control-plane/src/supervisor/types.ts \
|
|
330
|
+
agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json \
|
|
331
|
+
apps/control-plane/test/organizer-ordering-artifact.spec.ts
|
|
332
|
+
git commit -m "feat: add OrganizerOrderingArtifact type and JSON schema
|
|
333
|
+
|
|
334
|
+
Defines the ordering artifact contract for the organizer sidecar,
|
|
335
|
+
including dependency_graph, ready_set, deferred_set, blocked_set,
|
|
336
|
+
artifact lifecycle fields (expires_at, completion_status, backlog_fingerprint),
|
|
337
|
+
and AJV-validated JSON schema."
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
### Task 2: Implement `OrganizerAgentEnrollmentScheduler` adapter
|
|
343
|
+
|
|
344
|
+
**Files:**
|
|
345
|
+
|
|
346
|
+
- Create: `apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts`
|
|
347
|
+
- Test: `apps/control-plane/test/organizer-enrollment-scheduler.spec.ts`
|
|
348
|
+
|
|
349
|
+
- [ ] **Step 1: Write the failing tests**
|
|
350
|
+
|
|
351
|
+
Create `apps/control-plane/test/organizer-enrollment-scheduler.spec.ts`:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
355
|
+
import fs from 'node:fs/promises';
|
|
356
|
+
import os from 'node:os';
|
|
357
|
+
import path from 'node:path';
|
|
358
|
+
import { OrganizerAgentEnrollmentScheduler } from '../src/supervisor/organizer-enrollment-scheduler.js';
|
|
359
|
+
import { CapacityAwareEnrollmentScheduler } from '../src/supervisor/execution-enrollment-service.js';
|
|
360
|
+
import type {
|
|
361
|
+
EnrollmentSchedulingInput,
|
|
362
|
+
OrganizerOrderingArtifact,
|
|
363
|
+
} from '../src/supervisor/types.js';
|
|
364
|
+
|
|
365
|
+
function makeInput(overrides: Partial<EnrollmentSchedulingInput> = {}): EnrollmentSchedulingInput {
|
|
366
|
+
return {
|
|
367
|
+
activeFeatureIds: [],
|
|
368
|
+
queuedFeatureIds: [],
|
|
369
|
+
assignedFeatureIds: [],
|
|
370
|
+
maxActiveFeatures: 3,
|
|
371
|
+
request: {
|
|
372
|
+
request_id: 'req_1',
|
|
373
|
+
request_type: 'add_features',
|
|
374
|
+
status: 'pending',
|
|
375
|
+
requested_at: new Date().toISOString(),
|
|
376
|
+
processed_at: null,
|
|
377
|
+
requested_by: 'cli:add',
|
|
378
|
+
operation_id: 'op:1',
|
|
379
|
+
features: [
|
|
380
|
+
{ feature_id: 'spec_a', spec_path: '.aop/features/spec_a/spec.md' },
|
|
381
|
+
{ feature_id: 'spec_b', spec_path: '.aop/features/spec_b/spec.md' },
|
|
382
|
+
],
|
|
383
|
+
progress: null,
|
|
384
|
+
outcome: null,
|
|
385
|
+
},
|
|
386
|
+
features: [
|
|
387
|
+
{ feature_id: 'spec_a', status: null },
|
|
388
|
+
{ feature_id: 'spec_b', status: null },
|
|
389
|
+
],
|
|
390
|
+
...overrides,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function makeArtifact(
|
|
395
|
+
overrides: Partial<OrganizerOrderingArtifact> = {},
|
|
396
|
+
): OrganizerOrderingArtifact {
|
|
397
|
+
return {
|
|
398
|
+
version: 1,
|
|
399
|
+
generated_at: new Date().toISOString(),
|
|
400
|
+
expires_at: new Date(Date.now() + 60_000).toISOString(),
|
|
401
|
+
completion_status: 'complete',
|
|
402
|
+
backlog_fingerprint: 'sha256:test',
|
|
403
|
+
analyzed_requests: ['req_1'],
|
|
404
|
+
dependency_graph: {
|
|
405
|
+
spec_a: { depends_on: [], classification: 'no_dependency_found' },
|
|
406
|
+
spec_b: { depends_on: ['spec_a'], classification: 'explicit_dependency' },
|
|
407
|
+
},
|
|
408
|
+
ready_set: ['spec_a'],
|
|
409
|
+
deferred_set: [{ feature_id: 'spec_b', blocked_by: ['spec_a'], reason: 'explicit dependency' }],
|
|
410
|
+
blocked_set: [],
|
|
411
|
+
...overrides,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
describe('OrganizerAgentEnrollmentScheduler', () => {
|
|
416
|
+
let tmpDir: string;
|
|
417
|
+
let artifactPath: string;
|
|
418
|
+
|
|
419
|
+
beforeEach(async () => {
|
|
420
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'organizer-test-'));
|
|
421
|
+
artifactPath = path.join(tmpDir, 'organizer-ordering.json');
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
afterEach(async () => {
|
|
425
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it('GIVEN_ready_feature_in_artifact_WHEN_schedule_THEN_returns_queue_now_with_organizer_ready', async () => {
|
|
429
|
+
await fs.writeFile(artifactPath, JSON.stringify(makeArtifact()), 'utf8');
|
|
430
|
+
|
|
431
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
432
|
+
orderingArtifactPath: artifactPath,
|
|
433
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const result = await scheduler.schedule(
|
|
437
|
+
makeInput({ features: [{ feature_id: 'spec_a', status: null }] }),
|
|
438
|
+
);
|
|
439
|
+
expect(result.decisions).toHaveLength(1);
|
|
440
|
+
expect(result.decisions[0]).toMatchObject({
|
|
441
|
+
feature_id: 'spec_a',
|
|
442
|
+
disposition: 'queue_now',
|
|
443
|
+
reason: 'organizer_ready',
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('GIVEN_deferred_feature_in_artifact_WHEN_schedule_THEN_returns_defer_with_dependency_blocked', async () => {
|
|
448
|
+
await fs.writeFile(artifactPath, JSON.stringify(makeArtifact()), 'utf8');
|
|
449
|
+
|
|
450
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
451
|
+
orderingArtifactPath: artifactPath,
|
|
452
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const result = await scheduler.schedule(
|
|
456
|
+
makeInput({ features: [{ feature_id: 'spec_b', status: null }] }),
|
|
457
|
+
);
|
|
458
|
+
expect(result.decisions).toHaveLength(1);
|
|
459
|
+
expect(result.decisions[0]).toMatchObject({
|
|
460
|
+
feature_id: 'spec_b',
|
|
461
|
+
disposition: 'defer',
|
|
462
|
+
reason: 'dependency_blocked',
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('GIVEN_blocked_feature_in_artifact_WHEN_schedule_THEN_returns_defer_with_dependency_blocked', async () => {
|
|
467
|
+
const artifact = makeArtifact({
|
|
468
|
+
blocked_set: [{ feature_id: 'spec_c', reason: 'ambiguous' }],
|
|
469
|
+
dependency_graph: {
|
|
470
|
+
spec_c: { depends_on: ['spec_a'], classification: 'ambiguous_dependency_requires_human' },
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
await fs.writeFile(artifactPath, JSON.stringify(artifact), 'utf8');
|
|
474
|
+
|
|
475
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
476
|
+
orderingArtifactPath: artifactPath,
|
|
477
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const result = await scheduler.schedule(
|
|
481
|
+
makeInput({ features: [{ feature_id: 'spec_c', status: null }] }),
|
|
482
|
+
);
|
|
483
|
+
expect(result.decisions[0]).toMatchObject({
|
|
484
|
+
disposition: 'defer',
|
|
485
|
+
reason: 'dependency_blocked',
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('GIVEN_feature_not_in_artifact_WHEN_schedule_THEN_delegates_to_fallback', async () => {
|
|
490
|
+
await fs.writeFile(artifactPath, JSON.stringify(makeArtifact()), 'utf8');
|
|
491
|
+
|
|
492
|
+
const fallback = new CapacityAwareEnrollmentScheduler();
|
|
493
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
494
|
+
orderingArtifactPath: artifactPath,
|
|
495
|
+
fallback,
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
const result = await scheduler.schedule(
|
|
499
|
+
makeInput({ features: [{ feature_id: 'unknown_spec', status: null }] }),
|
|
500
|
+
);
|
|
501
|
+
expect(result.decisions[0]).toMatchObject({
|
|
502
|
+
feature_id: 'unknown_spec',
|
|
503
|
+
disposition: 'queue_now',
|
|
504
|
+
reason: 'capacity_available',
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it('GIVEN_artifact_missing_WHEN_schedule_THEN_delegates_to_fallback', async () => {
|
|
509
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
510
|
+
orderingArtifactPath: path.join(tmpDir, 'nonexistent.json'),
|
|
511
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const result = await scheduler.schedule(
|
|
515
|
+
makeInput({ features: [{ feature_id: 'spec_a', status: null }] }),
|
|
516
|
+
);
|
|
517
|
+
expect(result.decisions[0]).toMatchObject({
|
|
518
|
+
disposition: 'queue_now',
|
|
519
|
+
reason: 'capacity_available',
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it('GIVEN_artifact_with_partial_status_WHEN_schedule_THEN_delegates_to_fallback', async () => {
|
|
524
|
+
const artifact = makeArtifact({ completion_status: 'partial' });
|
|
525
|
+
await fs.writeFile(artifactPath, JSON.stringify(artifact), 'utf8');
|
|
526
|
+
|
|
527
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
528
|
+
orderingArtifactPath: artifactPath,
|
|
529
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
const result = await scheduler.schedule(
|
|
533
|
+
makeInput({ features: [{ feature_id: 'spec_a', status: null }] }),
|
|
534
|
+
);
|
|
535
|
+
expect(result.decisions[0].reason).toBe('capacity_available');
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('GIVEN_artifact_expired_WHEN_schedule_THEN_delegates_to_fallback', async () => {
|
|
539
|
+
const artifact = makeArtifact({ expires_at: new Date(Date.now() - 1000).toISOString() });
|
|
540
|
+
await fs.writeFile(artifactPath, JSON.stringify(artifact), 'utf8');
|
|
541
|
+
|
|
542
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
543
|
+
orderingArtifactPath: artifactPath,
|
|
544
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const result = await scheduler.schedule(
|
|
548
|
+
makeInput({ features: [{ feature_id: 'spec_a', status: null }] }),
|
|
549
|
+
);
|
|
550
|
+
expect(result.decisions[0].reason).toBe('capacity_available');
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it('GIVEN_corrupt_artifact_WHEN_schedule_THEN_delegates_to_fallback', async () => {
|
|
554
|
+
await fs.writeFile(artifactPath, 'NOT VALID JSON{{{', 'utf8');
|
|
555
|
+
|
|
556
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
557
|
+
orderingArtifactPath: artifactPath,
|
|
558
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
const result = await scheduler.schedule(
|
|
562
|
+
makeInput({ features: [{ feature_id: 'spec_a', status: null }] }),
|
|
563
|
+
);
|
|
564
|
+
expect(result.decisions[0].reason).toBe('capacity_available');
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it('GIVEN_ready_feature_but_capacity_full_WHEN_schedule_THEN_returns_defer_capacity_full', async () => {
|
|
568
|
+
await fs.writeFile(artifactPath, JSON.stringify(makeArtifact()), 'utf8');
|
|
569
|
+
|
|
570
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
571
|
+
orderingArtifactPath: artifactPath,
|
|
572
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const result = await scheduler.schedule(
|
|
576
|
+
makeInput({
|
|
577
|
+
activeFeatureIds: ['x', 'y', 'z'],
|
|
578
|
+
maxActiveFeatures: 3,
|
|
579
|
+
features: [{ feature_id: 'spec_a', status: null }],
|
|
580
|
+
}),
|
|
581
|
+
);
|
|
582
|
+
expect(result.decisions[0]).toMatchObject({
|
|
583
|
+
disposition: 'defer',
|
|
584
|
+
reason: 'capacity_full',
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it('GIVEN_mixed_features_WHEN_schedule_THEN_returns_correct_decisions_per_feature', async () => {
|
|
589
|
+
await fs.writeFile(artifactPath, JSON.stringify(makeArtifact()), 'utf8');
|
|
590
|
+
|
|
591
|
+
const scheduler = new OrganizerAgentEnrollmentScheduler({
|
|
592
|
+
orderingArtifactPath: artifactPath,
|
|
593
|
+
fallback: new CapacityAwareEnrollmentScheduler(),
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
const result = await scheduler.schedule(makeInput());
|
|
597
|
+
|
|
598
|
+
const decisionA = result.decisions.find((d) => d.feature_id === 'spec_a');
|
|
599
|
+
const decisionB = result.decisions.find((d) => d.feature_id === 'spec_b');
|
|
600
|
+
expect(decisionA?.disposition).toBe('queue_now');
|
|
601
|
+
expect(decisionA?.reason).toBe('organizer_ready');
|
|
602
|
+
expect(decisionB?.disposition).toBe('defer');
|
|
603
|
+
expect(decisionB?.reason).toBe('dependency_blocked');
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
- [ ] **Step 2: Run tests to verify they fail**
|
|
609
|
+
|
|
610
|
+
Run: `npx vitest run apps/control-plane/test/organizer-enrollment-scheduler.spec.ts`
|
|
611
|
+
Expected: FAIL — module not found
|
|
612
|
+
|
|
613
|
+
- [ ] **Step 3: Implement the adapter**
|
|
614
|
+
|
|
615
|
+
Create `apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts`:
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import { readFile } from 'node:fs/promises';
|
|
619
|
+
import type {
|
|
620
|
+
EnrollmentDecision,
|
|
621
|
+
EnrollmentScheduler,
|
|
622
|
+
EnrollmentSchedulingInput,
|
|
623
|
+
EnrollmentSchedulingResult,
|
|
624
|
+
OrganizerOrderingArtifact,
|
|
625
|
+
} from './types.js';
|
|
626
|
+
|
|
627
|
+
interface OrganizerAgentEnrollmentSchedulerDeps {
|
|
628
|
+
orderingArtifactPath: string;
|
|
629
|
+
fallback: EnrollmentScheduler;
|
|
630
|
+
maxArtifactAgeSecs?: number;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const DEFAULT_MAX_ARTIFACT_AGE_SECS = 60;
|
|
634
|
+
|
|
635
|
+
export class OrganizerAgentEnrollmentScheduler implements EnrollmentScheduler {
|
|
636
|
+
private readonly orderingArtifactPath: string;
|
|
637
|
+
private readonly fallback: EnrollmentScheduler;
|
|
638
|
+
private readonly maxArtifactAgeSecs: number;
|
|
639
|
+
|
|
640
|
+
constructor(deps: OrganizerAgentEnrollmentSchedulerDeps) {
|
|
641
|
+
this.orderingArtifactPath = deps.orderingArtifactPath;
|
|
642
|
+
this.fallback = deps.fallback;
|
|
643
|
+
this.maxArtifactAgeSecs = deps.maxArtifactAgeSecs ?? DEFAULT_MAX_ARTIFACT_AGE_SECS;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
async schedule(input: EnrollmentSchedulingInput): Promise<EnrollmentSchedulingResult> {
|
|
647
|
+
const artifact = await this.readArtifact();
|
|
648
|
+
if (!artifact) {
|
|
649
|
+
return this.fallback.schedule(input);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const readySet = new Set(artifact.ready_set);
|
|
653
|
+
const deferredIds = new Set(artifact.deferred_set.map((d) => d.feature_id));
|
|
654
|
+
const blockedIds = new Set(artifact.blocked_set.map((b) => b.feature_id));
|
|
655
|
+
const capacityAvailable = input.activeFeatureIds.length < input.maxActiveFeatures;
|
|
656
|
+
|
|
657
|
+
const decisions: EnrollmentDecision[] = [];
|
|
658
|
+
const fallbackFeatures: Array<{ feature_id: string; status: string | null }> = [];
|
|
659
|
+
|
|
660
|
+
for (const feature of input.features) {
|
|
661
|
+
const featureId = feature.feature_id;
|
|
662
|
+
|
|
663
|
+
if (readySet.has(featureId)) {
|
|
664
|
+
if (!capacityAvailable) {
|
|
665
|
+
decisions.push({
|
|
666
|
+
request_id: input.request.request_id,
|
|
667
|
+
feature_id: featureId,
|
|
668
|
+
disposition: 'defer',
|
|
669
|
+
reason: 'capacity_full',
|
|
670
|
+
});
|
|
671
|
+
} else {
|
|
672
|
+
decisions.push({
|
|
673
|
+
request_id: input.request.request_id,
|
|
674
|
+
feature_id: featureId,
|
|
675
|
+
disposition: 'queue_now',
|
|
676
|
+
reason: 'organizer_ready',
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
} else if (deferredIds.has(featureId) || blockedIds.has(featureId)) {
|
|
680
|
+
decisions.push({
|
|
681
|
+
request_id: input.request.request_id,
|
|
682
|
+
feature_id: featureId,
|
|
683
|
+
disposition: 'defer',
|
|
684
|
+
reason: 'dependency_blocked',
|
|
685
|
+
});
|
|
686
|
+
} else {
|
|
687
|
+
fallbackFeatures.push(feature);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (fallbackFeatures.length > 0) {
|
|
692
|
+
const fallbackResult = await this.fallback.schedule({
|
|
693
|
+
...input,
|
|
694
|
+
features: fallbackFeatures,
|
|
695
|
+
});
|
|
696
|
+
decisions.push(...fallbackResult.decisions);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return { decisions };
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private async readArtifact(): Promise<OrganizerOrderingArtifact | null> {
|
|
703
|
+
let raw: string;
|
|
704
|
+
try {
|
|
705
|
+
raw = await readFile(this.orderingArtifactPath, 'utf8');
|
|
706
|
+
} catch {
|
|
707
|
+
console.warn('[organizer-scheduler] Artifact missing, falling back to capacity scheduler');
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
let artifact: OrganizerOrderingArtifact;
|
|
712
|
+
try {
|
|
713
|
+
artifact = JSON.parse(raw) as OrganizerOrderingArtifact;
|
|
714
|
+
} catch {
|
|
715
|
+
console.warn(
|
|
716
|
+
'[organizer-scheduler] Artifact unparseable, falling back to capacity scheduler',
|
|
717
|
+
);
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (artifact.completion_status === 'partial') {
|
|
722
|
+
console.warn('[organizer-scheduler] Artifact partial, falling back to capacity scheduler');
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const expiresAt = new Date(artifact.expires_at).getTime();
|
|
727
|
+
if (Number.isNaN(expiresAt) || expiresAt < Date.now()) {
|
|
728
|
+
console.warn('[organizer-scheduler] Artifact expired, falling back to capacity scheduler');
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return artifact;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
- [ ] **Step 4: Run tests to verify they pass**
|
|
738
|
+
|
|
739
|
+
Run: `npx vitest run apps/control-plane/test/organizer-enrollment-scheduler.spec.ts`
|
|
740
|
+
Expected: 10 tests passing
|
|
741
|
+
|
|
742
|
+
- [ ] **Step 5: Run lint and typecheck**
|
|
743
|
+
|
|
744
|
+
Run: `npm run lint && npm run typecheck`
|
|
745
|
+
Expected: Both pass clean
|
|
746
|
+
|
|
747
|
+
- [ ] **Step 6: Commit**
|
|
748
|
+
|
|
749
|
+
```bash
|
|
750
|
+
git add apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts \
|
|
751
|
+
apps/control-plane/test/organizer-enrollment-scheduler.spec.ts
|
|
752
|
+
git commit -m "feat: implement OrganizerAgentEnrollmentScheduler adapter
|
|
753
|
+
|
|
754
|
+
Stateless adapter that reads the organizer ordering artifact on each
|
|
755
|
+
schedule() call and translates ready/deferred/blocked sets into
|
|
756
|
+
EnrollmentDecision[]. Falls back to CapacityAwareEnrollmentScheduler
|
|
757
|
+
when artifact is missing, corrupt, partial, or expired."
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
## Layer 1 Support: Types, Config, and Session Infrastructure
|
|
763
|
+
|
|
764
|
+
### Task 3: Extend types for organizer session tracking
|
|
765
|
+
|
|
766
|
+
**Files:**
|
|
767
|
+
|
|
768
|
+
- Modify: `apps/control-plane/src/supervisor/types.ts:80-90,117-121,137-151,261-269`
|
|
769
|
+
|
|
770
|
+
- [ ] **Step 1: Add `organizer_session_id` to `RuntimeSessionsSnapshot`**
|
|
771
|
+
|
|
772
|
+
In `apps/control-plane/src/supervisor/types.ts`, add after `reconciler_session_id` (line ~86):
|
|
773
|
+
|
|
774
|
+
```typescript
|
|
775
|
+
organizer_session_id?: string;
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
- [ ] **Step 2: Add `UpdateOrganizerSessionInput` type**
|
|
779
|
+
|
|
780
|
+
Add after `UpdateReconcilerSessionInput` (line ~121):
|
|
781
|
+
|
|
782
|
+
```typescript
|
|
783
|
+
export interface UpdateOrganizerSessionInput {
|
|
784
|
+
run_id: string;
|
|
785
|
+
owner_instance_id: string;
|
|
786
|
+
organizer_session_id: string;
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
- [ ] **Step 3: Add `updateOrganizerSession` to `FeatureOrchestrationPort`**
|
|
791
|
+
|
|
792
|
+
Add after `updateReconcilerSession` in `FeatureOrchestrationPort` (line ~149):
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
updateOrganizerSession(
|
|
796
|
+
params: UpdateOrganizerSessionInput,
|
|
797
|
+
): Promise<{ data: { runtime_sessions: RuntimeSessionsSnapshot } }>;
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
- [ ] **Step 4: Add `organizerSessionId` to `SupervisorRuntimeState`**
|
|
801
|
+
|
|
802
|
+
Add after `reconcilerSessionId` (line ~265):
|
|
803
|
+
|
|
804
|
+
```typescript
|
|
805
|
+
organizerSessionId?: string | null;
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
- [ ] **Step 5: Add `organizer` to `PromptBundle`**
|
|
809
|
+
|
|
810
|
+
Add after `reconciler` (line ~71):
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
organizer?: string | null;
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
- [ ] **Step 6: Run typecheck**
|
|
817
|
+
|
|
818
|
+
Run: `npm run typecheck`
|
|
819
|
+
Expected: Errors for unimplemented `updateOrganizerSession` in kernel — expected at this stage, will be implemented in Task 4
|
|
820
|
+
|
|
821
|
+
- [ ] **Step 7: Commit**
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
git add apps/control-plane/src/supervisor/types.ts
|
|
825
|
+
git commit -m "feat: add organizer session types to supervisor type definitions
|
|
826
|
+
|
|
827
|
+
Adds organizer_session_id to RuntimeSessionsSnapshot,
|
|
828
|
+
UpdateOrganizerSessionInput, updateOrganizerSession to
|
|
829
|
+
FeatureOrchestrationPort, organizerSessionId to
|
|
830
|
+
SupervisorRuntimeState, and organizer to PromptBundle."
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
### Task 4: Implement `updateOrganizerSession` in kernel and run-lease-service
|
|
836
|
+
|
|
837
|
+
**Files:**
|
|
838
|
+
|
|
839
|
+
- Modify: `apps/control-plane/src/application/services/run-lease-service.ts:420+`
|
|
840
|
+
- Modify: `apps/control-plane/src/core/kernel.ts:798+`
|
|
841
|
+
- Test: `apps/control-plane/test/kernel.coverage2.spec.ts` (add organizer session test)
|
|
842
|
+
|
|
843
|
+
- [ ] **Step 1: Write the failing test**
|
|
844
|
+
|
|
845
|
+
Add to `apps/control-plane/test/kernel.coverage2.spec.ts` in the session management describe block:
|
|
846
|
+
|
|
847
|
+
```typescript
|
|
848
|
+
it('GIVEN_active_run_WHEN_updateOrganizerSession_called_THEN_persists_organizer_session_id', async () => {
|
|
849
|
+
const kernel = new AopKernel(repoRoot);
|
|
850
|
+
await kernel.ensureLoaded();
|
|
851
|
+
|
|
852
|
+
await kernel.acquireRunLease({
|
|
853
|
+
run_id: 'run:org-test',
|
|
854
|
+
owner_instance_id: 'owner:org-test',
|
|
855
|
+
provider: 'custom',
|
|
856
|
+
model: 'test-model',
|
|
857
|
+
provider_config_ref_hash: 'hash',
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
const result = await kernel.updateOrganizerSession({
|
|
861
|
+
run_id: 'run:org-test',
|
|
862
|
+
owner_instance_id: 'owner:org-test',
|
|
863
|
+
organizer_session_id: 'organizer:session-1',
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
expect(result.data.runtime_sessions.organizer_session_id).toBe('organizer:session-1');
|
|
867
|
+
});
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
871
|
+
|
|
872
|
+
Run: `npx vitest run apps/control-plane/test/kernel.coverage2.spec.ts -t "updateOrganizerSession"`
|
|
873
|
+
Expected: FAIL — method does not exist
|
|
874
|
+
|
|
875
|
+
- [ ] **Step 3: Implement `updateOrganizerSession` in run-lease-service**
|
|
876
|
+
|
|
877
|
+
Add after `updateReconcilerSession` in `apps/control-plane/src/application/services/run-lease-service.ts` (~line 460):
|
|
878
|
+
|
|
879
|
+
```typescript
|
|
880
|
+
async updateOrganizerSession(
|
|
881
|
+
params: RuntimeOrganizerSessionUpdateParams,
|
|
882
|
+
): Promise<{ data: { runtime_sessions: RuntimeSessionsSnapshot } }> {
|
|
883
|
+
const { run_id, owner_instance_id, organizer_session_id } = params;
|
|
884
|
+
if (!run_id || !owner_instance_id || !organizer_session_id) {
|
|
885
|
+
throw {
|
|
886
|
+
normalizedResponse: fail(
|
|
887
|
+
ERROR_CODES.INVALID_ARGUMENT,
|
|
888
|
+
'run_id, owner_instance_id, and organizer_session_id are required',
|
|
889
|
+
{
|
|
890
|
+
retryable: false,
|
|
891
|
+
requires_human: true,
|
|
892
|
+
},
|
|
893
|
+
),
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
return await this.port.withIndexLock(async () => {
|
|
898
|
+
const current = this.port.normalizeRuntimeSessions(await this.port.readRunLease());
|
|
899
|
+
if (current.run_id !== run_id || current.owner_instance_id !== owner_instance_id) {
|
|
900
|
+
throw {
|
|
901
|
+
normalizedResponse: fail(
|
|
902
|
+
ERROR_CODES.RUN_LEASE_NOT_OWNED,
|
|
903
|
+
'Cannot update organizer session without run ownership',
|
|
904
|
+
{
|
|
905
|
+
run_id,
|
|
906
|
+
owner_instance_id,
|
|
907
|
+
active_run_id: current.run_id,
|
|
908
|
+
active_owner_instance_id: current.owner_instance_id,
|
|
909
|
+
retryable: false,
|
|
910
|
+
requires_human: true,
|
|
911
|
+
},
|
|
912
|
+
),
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
const updated: RuntimeSessionsSnapshot = {
|
|
917
|
+
...current,
|
|
918
|
+
organizer_session_id,
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
await this.port.writeRunLease(updated);
|
|
922
|
+
return { data: { runtime_sessions: updated } };
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Also add the params type near the other runtime param types in the same file:
|
|
928
|
+
|
|
929
|
+
```typescript
|
|
930
|
+
interface RuntimeOrganizerSessionUpdateParams {
|
|
931
|
+
run_id: string;
|
|
932
|
+
owner_instance_id: string;
|
|
933
|
+
organizer_session_id: string;
|
|
934
|
+
}
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
- [ ] **Step 4: Add kernel delegation method**
|
|
938
|
+
|
|
939
|
+
Add after `updateReconcilerSession` in `apps/control-plane/src/core/kernel.ts` (~line 804):
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
async updateOrganizerSession(params: {
|
|
943
|
+
run_id: string;
|
|
944
|
+
owner_instance_id: string;
|
|
945
|
+
organizer_session_id: string;
|
|
946
|
+
}): Promise<{ data: { runtime_sessions: RuntimeSessionsSnapshot } }> {
|
|
947
|
+
return await this.runLeaseService.updateOrganizerSession(params);
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
- [ ] **Step 5: Run test to verify it passes**
|
|
952
|
+
|
|
953
|
+
Run: `npx vitest run apps/control-plane/test/kernel.coverage2.spec.ts -t "updateOrganizerSession"`
|
|
954
|
+
Expected: PASS
|
|
955
|
+
|
|
956
|
+
- [ ] **Step 6: Run full typecheck and lint**
|
|
957
|
+
|
|
958
|
+
Run: `npm run typecheck && npm run lint`
|
|
959
|
+
Expected: Both pass clean
|
|
960
|
+
|
|
961
|
+
- [ ] **Step 7: Commit**
|
|
962
|
+
|
|
963
|
+
```bash
|
|
964
|
+
git add apps/control-plane/src/application/services/run-lease-service.ts \
|
|
965
|
+
apps/control-plane/src/core/kernel.ts \
|
|
966
|
+
apps/control-plane/test/kernel.coverage2.spec.ts
|
|
967
|
+
git commit -m "feat: implement updateOrganizerSession in kernel and run-lease-service
|
|
968
|
+
|
|
969
|
+
Follows the same pattern as updateReconcilerSession: validates
|
|
970
|
+
ownership, acquires index lock, persists organizer_session_id
|
|
971
|
+
to RuntimeSessionsSnapshot."
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
---
|
|
975
|
+
|
|
976
|
+
### Task 5: Add organizer to agents config, schema, and prompt loader
|
|
977
|
+
|
|
978
|
+
**Files:**
|
|
979
|
+
|
|
980
|
+
- Modify: `config/agentic/orchestrator/agents.yaml`
|
|
981
|
+
- Modify: `agentic/orchestrator/schemas/agents.schema.json:227-249`
|
|
982
|
+
- Modify: `apps/control-plane/src/supervisor/prompt-bundle-loader.ts:30`
|
|
983
|
+
- Create: `config/agentic/orchestrator/prompts/organizer.system.md`
|
|
984
|
+
- Test: Existing schema validation tests cover agents.yaml
|
|
985
|
+
|
|
986
|
+
- [ ] **Step 1: Add organizer role to `agents.yaml`**
|
|
987
|
+
|
|
988
|
+
Add after the reconciler entry in `config/agentic/orchestrator/agents.yaml`:
|
|
989
|
+
|
|
990
|
+
```yaml
|
|
991
|
+
organizer:
|
|
992
|
+
system_prompt_path: config/agentic/orchestrator/prompts/organizer.system.md
|
|
993
|
+
description: Analyzes pending specs to determine dependency-aware execution ordering
|
|
994
|
+
capabilities:
|
|
995
|
+
- dependency_analysis
|
|
996
|
+
- spec_ordering
|
|
997
|
+
- backlog_prioritization
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
- [ ] **Step 2: Add organizer to `agents.schema.json` provider_overrides**
|
|
1001
|
+
|
|
1002
|
+
In `agentic/orchestrator/schemas/agents.schema.json`, add to the `role_provider_overrides` properties (after the reconciler entry):
|
|
1003
|
+
|
|
1004
|
+
```json
|
|
1005
|
+
"organizer": {
|
|
1006
|
+
"$ref": "#/$defs/roleProviderOverride",
|
|
1007
|
+
"description": "Overrides for the organizer role."
|
|
1008
|
+
}
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
- [ ] **Step 3: Add `'organizer'` to prompt-bundle-loader role iteration**
|
|
1012
|
+
|
|
1013
|
+
In `apps/control-plane/src/supervisor/prompt-bundle-loader.ts`, change line 30:
|
|
1014
|
+
|
|
1015
|
+
From:
|
|
1016
|
+
|
|
1017
|
+
```typescript
|
|
1018
|
+
for (const role of ['planner', 'builder', 'qa', 'reconciler'] as const) {
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
To:
|
|
1022
|
+
|
|
1023
|
+
```typescript
|
|
1024
|
+
for (const role of ['planner', 'builder', 'qa', 'reconciler', 'organizer'] as const) {
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
Also update the initial `prompts` object (around line 28):
|
|
1028
|
+
|
|
1029
|
+
From:
|
|
1030
|
+
|
|
1031
|
+
```typescript
|
|
1032
|
+
const prompts: PromptBundle = {
|
|
1033
|
+
planner: null,
|
|
1034
|
+
builder: null,
|
|
1035
|
+
qa: null,
|
|
1036
|
+
reconciler: null,
|
|
1037
|
+
};
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
To:
|
|
1041
|
+
|
|
1042
|
+
```typescript
|
|
1043
|
+
const prompts: PromptBundle = {
|
|
1044
|
+
planner: null,
|
|
1045
|
+
builder: null,
|
|
1046
|
+
qa: null,
|
|
1047
|
+
reconciler: null,
|
|
1048
|
+
organizer: null,
|
|
1049
|
+
};
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
- [ ] **Step 4: Create the organizer system prompt**
|
|
1053
|
+
|
|
1054
|
+
Create `config/agentic/orchestrator/prompts/organizer.system.md`:
|
|
1055
|
+
|
|
1056
|
+
````markdown
|
|
1057
|
+
You are the organizer role.
|
|
1058
|
+
|
|
1059
|
+
Your job is to analyze pending feature specs and determine the optimal execution ordering based on dependency relationships. You do NOT implement features — you decide which features can start now and which must wait.
|
|
1060
|
+
|
|
1061
|
+
## Organizer objective
|
|
1062
|
+
|
|
1063
|
+
Read all pending spec files, identify dependency relationships between them, and produce a structured ordering artifact that the enrollment scheduler uses to admit features in the correct order.
|
|
1064
|
+
|
|
1065
|
+
## Analysis discipline
|
|
1066
|
+
|
|
1067
|
+
For each pending spec:
|
|
1068
|
+
|
|
1069
|
+
1. Read the full spec content from the provided spec_path
|
|
1070
|
+
2. Check for explicit `Depends On:` declarations in frontmatter and body
|
|
1071
|
+
3. Identify shared file paths or overlapping areas that suggest implicit dependencies
|
|
1072
|
+
4. If semantic analysis suggests a dependency but confidence is low, classify as `ambiguous_dependency_requires_human` rather than guessing
|
|
1073
|
+
|
|
1074
|
+
## Dependency classification
|
|
1075
|
+
|
|
1076
|
+
Every dependency edge MUST be classified as exactly one of:
|
|
1077
|
+
|
|
1078
|
+
- `explicit_dependency` — declared in spec metadata or body (e.g. `Depends On:` field)
|
|
1079
|
+
- `inferred_dependency` — derived from your semantic analysis of spec content and shared code areas
|
|
1080
|
+
- `no_dependency_found` — specs analyzed and found to be independent
|
|
1081
|
+
- `ambiguous_dependency_requires_human` — confidence too low to decide; escalate rather than guess
|
|
1082
|
+
|
|
1083
|
+
## Cycle detection
|
|
1084
|
+
|
|
1085
|
+
If you detect a dependency cycle (A depends on B, B depends on A), report all features in the cycle in the `blocked_set` with a clear explanation of the cycle.
|
|
1086
|
+
|
|
1087
|
+
## Output format
|
|
1088
|
+
|
|
1089
|
+
Return exactly one JSON object. Do not wrap in markdown code fences.
|
|
1090
|
+
|
|
1091
|
+
```json
|
|
1092
|
+
{
|
|
1093
|
+
"type": "ORDERING",
|
|
1094
|
+
"ordering": {
|
|
1095
|
+
"dependency_graph": {
|
|
1096
|
+
"<feature_id>": { "depends_on": ["<dep_id>"], "classification": "<classification>" }
|
|
1097
|
+
},
|
|
1098
|
+
"ready_set": ["<feature_ids with no unresolved deps>"],
|
|
1099
|
+
"deferred_set": [
|
|
1100
|
+
{ "feature_id": "<id>", "blocked_by": ["<dep_ids>"], "reason": "<explanation>" }
|
|
1101
|
+
],
|
|
1102
|
+
"blocked_set": [{ "feature_id": "<id>", "reason": "<explanation>" }]
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
```
|
|
1106
|
+
````
|
|
1107
|
+
|
|
1108
|
+
## Constraints
|
|
1109
|
+
|
|
1110
|
+
- Never invent dependencies where none exist — independent features should run in parallel
|
|
1111
|
+
- Never silently drop a `Depends On:` declaration — explicit dependencies are authoritative
|
|
1112
|
+
- Do not attempt to implement, plan, or modify any feature
|
|
1113
|
+
- If unsure whether a dependency is real, classify as `ambiguous_dependency_requires_human`
|
|
1114
|
+
|
|
1115
|
+
````
|
|
1116
|
+
|
|
1117
|
+
- [ ] **Step 5: Run typecheck and lint**
|
|
1118
|
+
|
|
1119
|
+
Run: `npm run typecheck && npm run lint`
|
|
1120
|
+
Expected: Both pass clean
|
|
1121
|
+
|
|
1122
|
+
- [ ] **Step 6: Commit**
|
|
1123
|
+
|
|
1124
|
+
```bash
|
|
1125
|
+
git add config/agentic/orchestrator/agents.yaml \
|
|
1126
|
+
config/agentic/orchestrator/prompts/organizer.system.md \
|
|
1127
|
+
agentic/orchestrator/schemas/agents.schema.json \
|
|
1128
|
+
apps/control-plane/src/supervisor/prompt-bundle-loader.ts
|
|
1129
|
+
git commit -m "feat: add organizer role config, prompt, schema, and prompt loading
|
|
1130
|
+
|
|
1131
|
+
Adds organizer entry to agents.yaml (same pattern as reconciler),
|
|
1132
|
+
organizer system prompt for spec dependency analysis, organizer to
|
|
1133
|
+
agents.schema.json provider_overrides, and 'organizer' to the
|
|
1134
|
+
prompt-bundle-loader role iteration list."
|
|
1135
|
+
````
|
|
1136
|
+
|
|
1137
|
+
---
|
|
1138
|
+
|
|
1139
|
+
### Task 6: Add `ensureGlobalOrganizerSession()` to SessionOrchestrator
|
|
1140
|
+
|
|
1141
|
+
**Files:**
|
|
1142
|
+
|
|
1143
|
+
- Modify: `apps/control-plane/src/supervisor/session-orchestrator.ts:98-136`
|
|
1144
|
+
- Test: `apps/control-plane/test/session-management.spec.ts`
|
|
1145
|
+
|
|
1146
|
+
- [ ] **Step 1: Write the failing test**
|
|
1147
|
+
|
|
1148
|
+
Add to `apps/control-plane/test/session-management.spec.ts`:
|
|
1149
|
+
|
|
1150
|
+
```typescript
|
|
1151
|
+
describe('organizer session lifecycle', () => {
|
|
1152
|
+
it('GIVEN_no_previous_organizer_session_WHEN_ensureGlobalOrchestratorSession_THEN_creates_organizer_session', async () => {
|
|
1153
|
+
const repoRoot = await makeTempRepo(process.cwd());
|
|
1154
|
+
const kernel = new AopKernel(repoRoot);
|
|
1155
|
+
await kernel.ensureLoaded();
|
|
1156
|
+
|
|
1157
|
+
await kernel.acquireRunLease({
|
|
1158
|
+
run_id: 'run:org-session',
|
|
1159
|
+
owner_instance_id: 'owner:org-session',
|
|
1160
|
+
provider: 'custom',
|
|
1161
|
+
model: 'test-model',
|
|
1162
|
+
provider_config_ref_hash: 'hash',
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
const provider = makeProvider({
|
|
1166
|
+
createSession: vi.fn(async (role: string) => ({
|
|
1167
|
+
session_id: `${role}:session-1`,
|
|
1168
|
+
})),
|
|
1169
|
+
reattachSession: vi.fn(async () => null),
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
const state: SupervisorRuntimeState = {
|
|
1173
|
+
runId: 'run:org-session',
|
|
1174
|
+
ownerInstanceId: 'owner:org-session',
|
|
1175
|
+
orchestratorSessionId: null,
|
|
1176
|
+
reconcilerSessionId: null,
|
|
1177
|
+
organizerSessionId: null,
|
|
1178
|
+
sessionsByFeature: new Map(),
|
|
1179
|
+
queue: [],
|
|
1180
|
+
runMetadata: {},
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1183
|
+
const sessionOrchestrator = new SessionOrchestrator({
|
|
1184
|
+
kernel: kernel as never,
|
|
1185
|
+
runtimeStateReader: kernel as never,
|
|
1186
|
+
provider: provider as never,
|
|
1187
|
+
promptProvider: {
|
|
1188
|
+
loadRolePrompts: async () => ({
|
|
1189
|
+
planner: null,
|
|
1190
|
+
builder: null,
|
|
1191
|
+
qa: null,
|
|
1192
|
+
reconciler: null,
|
|
1193
|
+
organizer: null,
|
|
1194
|
+
}),
|
|
1195
|
+
} as never,
|
|
1196
|
+
toolCaller: { callTool: vi.fn(async () => ({ ok: true, data: {} })) } as never,
|
|
1197
|
+
state: state as never,
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
await sessionOrchestrator.ensureGlobalOrchestratorSession();
|
|
1201
|
+
|
|
1202
|
+
expect(state.organizerSessionId).toBe('organizer:session-1');
|
|
1203
|
+
expect(provider.createSession).toHaveBeenCalledWith('organizer', 'global', null);
|
|
1204
|
+
|
|
1205
|
+
const sessions = await kernel.getRuntimeSessions();
|
|
1206
|
+
expect(sessions.organizer_session_id).toBe('organizer:session-1');
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
1212
|
+
|
|
1213
|
+
Run: `npx vitest run apps/control-plane/test/session-management.spec.ts -t "organizer session lifecycle"`
|
|
1214
|
+
Expected: FAIL — `ensureGlobalOrganizerSession` not called / `organizerSessionId` is null
|
|
1215
|
+
|
|
1216
|
+
- [ ] **Step 3: Add `ensureGlobalOrganizerSession()` to SessionOrchestrator**
|
|
1217
|
+
|
|
1218
|
+
Add after `ensureGlobalReconcilerSession()` in `apps/control-plane/src/supervisor/session-orchestrator.ts` (after line 136):
|
|
1219
|
+
|
|
1220
|
+
```typescript
|
|
1221
|
+
private async ensureGlobalOrganizerSession(): Promise<void> {
|
|
1222
|
+
const runtimeSessions = await this.runtimeStateReader.getRuntimeSessions();
|
|
1223
|
+
const candidate = runtimeSessions.organizer_session_id;
|
|
1224
|
+
const canReuse =
|
|
1225
|
+
runtimeSessions.run_id === this.state.runId &&
|
|
1226
|
+
runtimeSessions.owner_instance_id === this.state.ownerInstanceId &&
|
|
1227
|
+
runtimeSessions.provider === this.provider.selection.provider &&
|
|
1228
|
+
typeof candidate === 'string' &&
|
|
1229
|
+
candidate.length > 0 &&
|
|
1230
|
+
candidate !== 'unknown';
|
|
1231
|
+
|
|
1232
|
+
if (canReuse) {
|
|
1233
|
+
const reattachSucceeded = await this.attemptReattach(candidate);
|
|
1234
|
+
if (reattachSucceeded) {
|
|
1235
|
+
this.state.organizerSessionId = candidate;
|
|
1236
|
+
this.state.runMetadata.organizer_reattached = true;
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
const prompts = await this.promptProvider.loadRolePrompts();
|
|
1242
|
+
const organizerSession = await this.provider.createSession(
|
|
1243
|
+
'organizer',
|
|
1244
|
+
'global',
|
|
1245
|
+
prompts.organizer ?? null,
|
|
1246
|
+
);
|
|
1247
|
+
this.state.organizerSessionId = organizerSession.session_id;
|
|
1248
|
+
this.state.runMetadata.organizer_reattached = false;
|
|
1249
|
+
|
|
1250
|
+
await this.kernel.updateOrganizerSession({
|
|
1251
|
+
run_id: this.state.runId,
|
|
1252
|
+
owner_instance_id: this.state.ownerInstanceId,
|
|
1253
|
+
organizer_session_id: organizerSession.session_id,
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
if (canReuse && candidate) {
|
|
1257
|
+
await this.provider.closeSession(candidate).catch(() => ({ closed: true }));
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
Then add `await this.ensureGlobalOrganizerSession();` at the end of both paths in `ensureGlobalOrchestratorSession()` — after the `ensureGlobalReconcilerSession()` calls on lines 75 and 95:
|
|
1263
|
+
|
|
1264
|
+
```typescript
|
|
1265
|
+
await this.ensureGlobalReconcilerSession();
|
|
1266
|
+
await this.ensureGlobalOrganizerSession();
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
1270
|
+
|
|
1271
|
+
Run: `npx vitest run apps/control-plane/test/session-management.spec.ts -t "organizer session lifecycle"`
|
|
1272
|
+
Expected: PASS
|
|
1273
|
+
|
|
1274
|
+
- [ ] **Step 5: Run full test suite**
|
|
1275
|
+
|
|
1276
|
+
Run: `npx vitest run`
|
|
1277
|
+
Expected: All tests passing
|
|
1278
|
+
|
|
1279
|
+
- [ ] **Step 6: Commit**
|
|
1280
|
+
|
|
1281
|
+
```bash
|
|
1282
|
+
git add apps/control-plane/src/supervisor/session-orchestrator.ts \
|
|
1283
|
+
apps/control-plane/test/session-management.spec.ts
|
|
1284
|
+
git commit -m "feat: add ensureGlobalOrganizerSession to SessionOrchestrator
|
|
1285
|
+
|
|
1286
|
+
Creates/reattaches the organizer sidecar session following the same
|
|
1287
|
+
pattern as ensureGlobalReconcilerSession. Called during orchestrator
|
|
1288
|
+
session setup alongside the reconciler."
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
---
|
|
1292
|
+
|
|
1293
|
+
## Wiring: Connect the Layers
|
|
1294
|
+
|
|
1295
|
+
### Task 7: Wire `OrganizerAgentEnrollmentScheduler` into runtime startup
|
|
1296
|
+
|
|
1297
|
+
**Files:**
|
|
1298
|
+
|
|
1299
|
+
- Modify: `apps/control-plane/src/supervisor/runtime.ts:512-517`
|
|
1300
|
+
- Modify: `apps/control-plane/src/core/path-layout.ts:48-50`
|
|
1301
|
+
|
|
1302
|
+
- [ ] **Step 1: Add organizer artifact path to PathLayout**
|
|
1303
|
+
|
|
1304
|
+
In `apps/control-plane/src/core/path-layout.ts`, add after `executionControlPath`:
|
|
1305
|
+
|
|
1306
|
+
```typescript
|
|
1307
|
+
organizerOrderingPath(instanceId: string): string {
|
|
1308
|
+
return path.join(this.instanceRuntimeRoot(instanceId), 'organizer-ordering.json');
|
|
1309
|
+
}
|
|
1310
|
+
```
|
|
1311
|
+
|
|
1312
|
+
- [ ] **Step 2: Wire the organizer scheduler in runtime.ts**
|
|
1313
|
+
|
|
1314
|
+
Replace the `CapacityAwareEnrollmentScheduler` instantiation in `apps/control-plane/src/supervisor/runtime.ts` (line ~515):
|
|
1315
|
+
|
|
1316
|
+
From:
|
|
1317
|
+
|
|
1318
|
+
```typescript
|
|
1319
|
+
this.executionEnrollmentService = new ExecutionEnrollmentService({
|
|
1320
|
+
kernel: this.kernel,
|
|
1321
|
+
state: this.state,
|
|
1322
|
+
scheduler: new CapacityAwareEnrollmentScheduler(),
|
|
1323
|
+
maxActiveFeatures: this.maxActiveFeatures,
|
|
1324
|
+
});
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
To:
|
|
1328
|
+
|
|
1329
|
+
```typescript
|
|
1330
|
+
const capacityScheduler = new CapacityAwareEnrollmentScheduler();
|
|
1331
|
+
const organizerEnabled = this.kernel.getAgentsConfig().roles?.organizer != null;
|
|
1332
|
+
const scheduler: EnrollmentScheduler = organizerEnabled
|
|
1333
|
+
? new OrganizerAgentEnrollmentScheduler({
|
|
1334
|
+
orderingArtifactPath: this.kernel
|
|
1335
|
+
.getPathLayout()
|
|
1336
|
+
.organizerOrderingPath(this.state.ownerInstanceId),
|
|
1337
|
+
fallback: capacityScheduler,
|
|
1338
|
+
})
|
|
1339
|
+
: capacityScheduler;
|
|
1340
|
+
|
|
1341
|
+
this.executionEnrollmentService = new ExecutionEnrollmentService({
|
|
1342
|
+
kernel: this.kernel,
|
|
1343
|
+
state: this.state,
|
|
1344
|
+
scheduler,
|
|
1345
|
+
maxActiveFeatures: this.maxActiveFeatures,
|
|
1346
|
+
});
|
|
1347
|
+
```
|
|
1348
|
+
|
|
1349
|
+
Add imports at the top of runtime.ts:
|
|
1350
|
+
|
|
1351
|
+
```typescript
|
|
1352
|
+
import { OrganizerAgentEnrollmentScheduler } from './organizer-enrollment-scheduler.js';
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
- [ ] **Step 3: Run typecheck and lint**
|
|
1356
|
+
|
|
1357
|
+
Run: `npm run typecheck && npm run lint`
|
|
1358
|
+
Expected: Both pass clean
|
|
1359
|
+
|
|
1360
|
+
- [ ] **Step 4: Run full test suite**
|
|
1361
|
+
|
|
1362
|
+
Run: `npx vitest run`
|
|
1363
|
+
Expected: All tests passing (existing tests use mocked enrollment service so this wiring doesn't affect them)
|
|
1364
|
+
|
|
1365
|
+
- [ ] **Step 5: Commit**
|
|
1366
|
+
|
|
1367
|
+
```bash
|
|
1368
|
+
git add apps/control-plane/src/supervisor/runtime.ts \
|
|
1369
|
+
apps/control-plane/src/core/path-layout.ts
|
|
1370
|
+
git commit -m "feat: wire OrganizerAgentEnrollmentScheduler into supervisor startup
|
|
1371
|
+
|
|
1372
|
+
Conditionally uses OrganizerAgentEnrollmentScheduler when the
|
|
1373
|
+
organizer role is configured in agents.yaml, falling back to
|
|
1374
|
+
CapacityAwareEnrollmentScheduler when not configured."
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
---
|
|
1378
|
+
|
|
1379
|
+
### Task 8: Add terminal-state trigger for enrollment re-evaluation
|
|
1380
|
+
|
|
1381
|
+
**Files:**
|
|
1382
|
+
|
|
1383
|
+
- Modify: `apps/control-plane/src/supervisor/run-coordinator.ts:1036-1041`
|
|
1384
|
+
- Test: `apps/control-plane/test/run-coordinator.spec.ts`
|
|
1385
|
+
|
|
1386
|
+
- [ ] **Step 1: Write the failing test**
|
|
1387
|
+
|
|
1388
|
+
Add to `apps/control-plane/test/run-coordinator.spec.ts`:
|
|
1389
|
+
|
|
1390
|
+
```typescript
|
|
1391
|
+
it('GIVEN_feature_reaches_merged_WHEN_status_transitions_THEN_calls_notifyNewRequestHint', async () => {
|
|
1392
|
+
vi.useFakeTimers();
|
|
1393
|
+
try {
|
|
1394
|
+
let callCount = 0;
|
|
1395
|
+
const statusByFeature: Record<string, string> = {
|
|
1396
|
+
feature_trigger: STATUS.READY_TO_MERGE,
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
const executionEnrollmentService = {
|
|
1400
|
+
start: vi.fn(async () => undefined),
|
|
1401
|
+
stop: vi.fn(async () => undefined),
|
|
1402
|
+
notifyNewRequestHint: vi.fn(async () => {
|
|
1403
|
+
callCount += 1;
|
|
1404
|
+
}),
|
|
1405
|
+
noteSafeCheckpoint: vi.fn(async () => undefined),
|
|
1406
|
+
hasPendingWork: vi.fn(() => false),
|
|
1407
|
+
drainReadyDecisions: vi.fn(async () => []),
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
const kernel = {
|
|
1411
|
+
ensureLoaded: vi.fn(async () => undefined),
|
|
1412
|
+
recoverFromState: vi.fn(async () => ({ data: { recovered: true } })),
|
|
1413
|
+
acquireRunLease: vi.fn(async () => ({ data: { took_over_stale: false } })),
|
|
1414
|
+
releaseRunLease: vi.fn(async () => ({ data: { released: true } })),
|
|
1415
|
+
pruneFeatureSessionAssignments: vi.fn(async () => ({ data: { removed: [] as string[] } })),
|
|
1416
|
+
getRuntimeSessions: vi.fn(async () => ({
|
|
1417
|
+
run_id: 'run:test',
|
|
1418
|
+
owner_instance_id: 'owner:test',
|
|
1419
|
+
orchestrator_session_id: 'orch:test',
|
|
1420
|
+
feature_sessions: {},
|
|
1421
|
+
})),
|
|
1422
|
+
getPolicySnapshot: vi.fn(() => ({
|
|
1423
|
+
reactions: {
|
|
1424
|
+
gate_failed: { enabled: true, action: 'retry_with_agent_repair', max_retries: 2 },
|
|
1425
|
+
},
|
|
1426
|
+
})),
|
|
1427
|
+
updateState: vi.fn(async () => ({})),
|
|
1428
|
+
checkBudget: vi.fn(async () => ({
|
|
1429
|
+
over_budget: false,
|
|
1430
|
+
alert_threshold_reached: false,
|
|
1431
|
+
current_cost_usd: 0,
|
|
1432
|
+
limit_usd: -1,
|
|
1433
|
+
alert_threshold: 0.8,
|
|
1434
|
+
})),
|
|
1435
|
+
drainPendingExecutionRequests: vi.fn(async () => ({ data: { items: [] } })),
|
|
1436
|
+
markExecutionRequestProcessed: vi.fn(async () => ({ data: { updated: true } })),
|
|
1437
|
+
};
|
|
1438
|
+
|
|
1439
|
+
const toolCaller = {
|
|
1440
|
+
callTool: vi.fn(async (_role: string, toolName: string) => {
|
|
1441
|
+
if (toolName === TOOLS.REPORT_DASHBOARD) return { ok: true, data: { features: [] } };
|
|
1442
|
+
if (toolName === TOOLS.FEATURE_STATE_GET) {
|
|
1443
|
+
return { ok: true, data: { front_matter: { status: statusByFeature.feature_trigger } } };
|
|
1444
|
+
}
|
|
1445
|
+
if (toolName === TOOLS.FEATURE_MERGE) {
|
|
1446
|
+
statusByFeature.feature_trigger = STATUS.MERGED;
|
|
1447
|
+
return { ok: true, data: { merged: true } };
|
|
1448
|
+
}
|
|
1449
|
+
return { ok: true, data: {} };
|
|
1450
|
+
}),
|
|
1451
|
+
};
|
|
1452
|
+
|
|
1453
|
+
const notifier = { notify: vi.fn(async () => undefined) };
|
|
1454
|
+
|
|
1455
|
+
const state = {
|
|
1456
|
+
runId: 'run:test',
|
|
1457
|
+
ownerInstanceId: 'owner:test',
|
|
1458
|
+
orchestratorSessionId: 'orch:test',
|
|
1459
|
+
sessionsByFeature: new Map(),
|
|
1460
|
+
queue: [] as Array<{ feature_id: string }>,
|
|
1461
|
+
runMetadata: {},
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
const sessionOrchestrator = {
|
|
1465
|
+
ensureGlobalOrchestratorSession: vi.fn(async () => undefined),
|
|
1466
|
+
cleanupOrphanWorkerSessions: vi.fn(async () => undefined),
|
|
1467
|
+
initializeFeatureCluster: vi.fn(async (fid: string) => {
|
|
1468
|
+
state.sessionsByFeature.set(fid, {
|
|
1469
|
+
planner: `${fid}:p`,
|
|
1470
|
+
builder: `${fid}:b`,
|
|
1471
|
+
qa: `${fid}:q`,
|
|
1472
|
+
});
|
|
1473
|
+
}),
|
|
1474
|
+
closeFeatureCluster: vi.fn(async () => undefined),
|
|
1475
|
+
reconcileQueuedFeatures: vi.fn(async () => undefined),
|
|
1476
|
+
enforceActiveFeatureInvariant: vi.fn(async () => undefined),
|
|
1477
|
+
};
|
|
1478
|
+
|
|
1479
|
+
const planningWaveExecutor = {
|
|
1480
|
+
run: vi.fn(async () => {
|
|
1481
|
+
statusByFeature.feature_trigger = STATUS.MERGED;
|
|
1482
|
+
}),
|
|
1483
|
+
runPostQaReconciliation: vi.fn(async () => undefined),
|
|
1484
|
+
clearFeatureTracking: vi.fn(),
|
|
1485
|
+
};
|
|
1486
|
+
|
|
1487
|
+
const coordinator = new RunCoordinator({
|
|
1488
|
+
kernel: kernel as never,
|
|
1489
|
+
provider: { selection: { provider: 'custom', model: 'test' } } as never,
|
|
1490
|
+
toolCaller: toolCaller as never,
|
|
1491
|
+
state: state as never,
|
|
1492
|
+
sessionOrchestrator: sessionOrchestrator as never,
|
|
1493
|
+
planningWaveExecutor: planningWaveExecutor as never,
|
|
1494
|
+
buildWaveExecutor: {
|
|
1495
|
+
run: vi.fn(async () => undefined),
|
|
1496
|
+
clearFeatureTracking: vi.fn(),
|
|
1497
|
+
} as never,
|
|
1498
|
+
qaWaveExecutor: { run: vi.fn(async () => undefined), clearFeatureTracking: vi.fn() } as never,
|
|
1499
|
+
leaseHeartbeatService: { renew: vi.fn(async () => undefined) } as never,
|
|
1500
|
+
maxActiveFeatures: 1,
|
|
1501
|
+
maxParallelGateRuns: 2,
|
|
1502
|
+
maxIterationsPerPhase: 1,
|
|
1503
|
+
takeoverStaleRun: false,
|
|
1504
|
+
providerConfigRefHash: () => 'hash',
|
|
1505
|
+
executionEnrollmentService: executionEnrollmentService as never,
|
|
1506
|
+
notifier: notifier as never,
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
await coordinator.start([{ feature_id: 'feature_trigger' }]);
|
|
1510
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
1511
|
+
|
|
1512
|
+
// notifyNewRequestHint is called at startup + once on terminal state
|
|
1513
|
+
expect(callCount).toBeGreaterThanOrEqual(2);
|
|
1514
|
+
} finally {
|
|
1515
|
+
vi.useRealTimers();
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
```
|
|
1519
|
+
|
|
1520
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
1521
|
+
|
|
1522
|
+
Run: `npx vitest run apps/control-plane/test/run-coordinator.spec.ts -t "notifyNewRequestHint"`
|
|
1523
|
+
Expected: FAIL — callCount is only 1 (startup only)
|
|
1524
|
+
|
|
1525
|
+
- [ ] **Step 3: Add terminal-state trigger in run-coordinator**
|
|
1526
|
+
|
|
1527
|
+
In `apps/control-plane/src/supervisor/run-coordinator.ts`, find the merged status handling (around line 1036):
|
|
1528
|
+
|
|
1529
|
+
```typescript
|
|
1530
|
+
} else if (newStatus === STATUS.MERGED) {
|
|
1531
|
+
await this.notifier.notify('feature_merged', {
|
|
1532
|
+
feature_id: featureId,
|
|
1533
|
+
message: `Feature ${featureId} was merged`,
|
|
1534
|
+
});
|
|
1535
|
+
```
|
|
1536
|
+
|
|
1537
|
+
Add after the notifier call:
|
|
1538
|
+
|
|
1539
|
+
```typescript
|
|
1540
|
+
await this.executionEnrollmentService.notifyNewRequestHint();
|
|
1541
|
+
```
|
|
1542
|
+
|
|
1543
|
+
Also find any other terminal status handling in the same method for `STATUS.FAILED` and `STATUS.PAUSED_BUDGET`, and add the same call. If there's a general terminal-status check, add a single call there instead. The key code to add after any transition to a terminal enrollment status:
|
|
1544
|
+
|
|
1545
|
+
```typescript
|
|
1546
|
+
if (RunCoordinator.ENROLLMENT_TERMINAL_STATUSES.has(newStatus)) {
|
|
1547
|
+
await this.executionEnrollmentService.notifyNewRequestHint();
|
|
1548
|
+
}
|
|
1549
|
+
```
|
|
1550
|
+
|
|
1551
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
1552
|
+
|
|
1553
|
+
Run: `npx vitest run apps/control-plane/test/run-coordinator.spec.ts -t "notifyNewRequestHint"`
|
|
1554
|
+
Expected: PASS
|
|
1555
|
+
|
|
1556
|
+
- [ ] **Step 5: Run full test suite**
|
|
1557
|
+
|
|
1558
|
+
Run: `npx vitest run`
|
|
1559
|
+
Expected: All tests passing
|
|
1560
|
+
|
|
1561
|
+
- [ ] **Step 6: Commit**
|
|
1562
|
+
|
|
1563
|
+
```bash
|
|
1564
|
+
git add apps/control-plane/src/supervisor/run-coordinator.ts \
|
|
1565
|
+
apps/control-plane/test/run-coordinator.spec.ts
|
|
1566
|
+
git commit -m "feat: trigger enrollment re-evaluation on terminal state transitions
|
|
1567
|
+
|
|
1568
|
+
When a feature reaches a terminal enrollment status (merged, failed,
|
|
1569
|
+
paused_budget, ready_to_merge), calls notifyNewRequestHint() so the
|
|
1570
|
+
enrollment service re-evaluates deferred features that may now be
|
|
1571
|
+
unblocked."
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
---
|
|
1575
|
+
|
|
1576
|
+
### Task 9: Add organizer path layout method to `path-layout.ts`
|
|
1577
|
+
|
|
1578
|
+
This was partially done in Task 7. Verify it's working by adding a test.
|
|
1579
|
+
|
|
1580
|
+
**Files:**
|
|
1581
|
+
|
|
1582
|
+
- Test: `apps/control-plane/test/organizer-ordering-artifact.spec.ts` (add path layout test)
|
|
1583
|
+
|
|
1584
|
+
- [ ] **Step 1: Add path layout test to existing artifact spec**
|
|
1585
|
+
|
|
1586
|
+
Add to `apps/control-plane/test/organizer-ordering-artifact.spec.ts`:
|
|
1587
|
+
|
|
1588
|
+
```typescript
|
|
1589
|
+
import { PathLayout } from '../src/core/path-layout.js';
|
|
1590
|
+
|
|
1591
|
+
describe('OrganizerOrderingArtifact path', () => {
|
|
1592
|
+
it('GIVEN_instance_id_WHEN_organizerOrderingPath_THEN_returns_correct_path', () => {
|
|
1593
|
+
const layout = new PathLayout('/repo/.aop');
|
|
1594
|
+
const result = layout.organizerOrderingPath('default');
|
|
1595
|
+
expect(result).toBe('/repo/.aop/runtime/default/organizer-ordering.json');
|
|
1596
|
+
});
|
|
1597
|
+
});
|
|
1598
|
+
```
|
|
1599
|
+
|
|
1600
|
+
- [ ] **Step 2: Run test**
|
|
1601
|
+
|
|
1602
|
+
Run: `npx vitest run apps/control-plane/test/organizer-ordering-artifact.spec.ts`
|
|
1603
|
+
Expected: PASS
|
|
1604
|
+
|
|
1605
|
+
- [ ] **Step 3: Commit**
|
|
1606
|
+
|
|
1607
|
+
```bash
|
|
1608
|
+
git add apps/control-plane/test/organizer-ordering-artifact.spec.ts
|
|
1609
|
+
git commit -m "test: add path layout test for organizer ordering artifact"
|
|
1610
|
+
```
|
|
1611
|
+
|
|
1612
|
+
---
|
|
1613
|
+
|
|
1614
|
+
### Task 10: Update dashboard types and status route
|
|
1615
|
+
|
|
1616
|
+
**Files:**
|
|
1617
|
+
|
|
1618
|
+
- Modify: `packages/web-dashboard/src/lib/types.ts`
|
|
1619
|
+
- Modify: `packages/web-dashboard/src/app/api/status/route.ts`
|
|
1620
|
+
|
|
1621
|
+
- [ ] **Step 1: Add organizer types to dashboard**
|
|
1622
|
+
|
|
1623
|
+
In `packages/web-dashboard/src/lib/types.ts`, add:
|
|
1624
|
+
|
|
1625
|
+
```typescript
|
|
1626
|
+
export interface OrganizerDeferredSummary {
|
|
1627
|
+
feature_id: string;
|
|
1628
|
+
blocked_by: string[];
|
|
1629
|
+
reason: string;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
export interface OrganizerBlockedSummary {
|
|
1633
|
+
feature_id: string;
|
|
1634
|
+
reason: string;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
export interface OrganizerStatusProjection {
|
|
1638
|
+
available: boolean;
|
|
1639
|
+
generated_at: string | null;
|
|
1640
|
+
ready_set: string[];
|
|
1641
|
+
deferred_set: OrganizerDeferredSummary[];
|
|
1642
|
+
blocked_set: OrganizerBlockedSummary[];
|
|
1643
|
+
}
|
|
1644
|
+
```
|
|
1645
|
+
|
|
1646
|
+
- [ ] **Step 2: Expose organizer status in the status route**
|
|
1647
|
+
|
|
1648
|
+
In `packages/web-dashboard/src/app/api/status/route.ts`, find where the status response is constructed and add an `organizer` field that reads the ordering artifact from the `.aop/runtime/<instanceId>/organizer-ordering.json` path. If the file doesn't exist, return `{ available: false, generated_at: null, ready_set: [], deferred_set: [], blocked_set: [] }`.
|
|
1649
|
+
|
|
1650
|
+
Read the file path and parse logic following the existing pattern in the route for reading runtime files. The exact implementation depends on the current route structure — read it first.
|
|
1651
|
+
|
|
1652
|
+
- [ ] **Step 3: Run dashboard tests**
|
|
1653
|
+
|
|
1654
|
+
Run: `npx vitest run packages/web-dashboard/test/`
|
|
1655
|
+
Expected: All dashboard tests passing
|
|
1656
|
+
|
|
1657
|
+
- [ ] **Step 4: Commit**
|
|
1658
|
+
|
|
1659
|
+
```bash
|
|
1660
|
+
git add packages/web-dashboard/src/lib/types.ts \
|
|
1661
|
+
packages/web-dashboard/src/app/api/status/route.ts
|
|
1662
|
+
git commit -m "feat: expose organizer ordering status in dashboard API
|
|
1663
|
+
|
|
1664
|
+
Adds OrganizerStatusProjection type and surfaces ready/deferred/blocked
|
|
1665
|
+
sets from the organizer ordering artifact in the status endpoint."
|
|
1666
|
+
```
|
|
1667
|
+
|
|
1668
|
+
---
|
|
1669
|
+
|
|
1670
|
+
### Task 11: Update `progress.md` with all completed entries
|
|
1671
|
+
|
|
1672
|
+
**Files:**
|
|
1673
|
+
|
|
1674
|
+
- Modify: `spec-files/progress.md`
|
|
1675
|
+
|
|
1676
|
+
- [ ] **Step 1: Append numbered entries for each task completed**
|
|
1677
|
+
|
|
1678
|
+
Follow the format in CLAUDE.md. Each task gets its own entry with Goal, Changes made, and Result sections. Use sequential numbering from the last entry in progress.md.
|
|
1679
|
+
|
|
1680
|
+
- [ ] **Step 2: Commit**
|
|
1681
|
+
|
|
1682
|
+
```bash
|
|
1683
|
+
git add spec-files/progress.md
|
|
1684
|
+
git commit -m "docs: update progress.md with ordering agent implementation entries"
|
|
1685
|
+
```
|
|
1686
|
+
|
|
1687
|
+
---
|
|
1688
|
+
|
|
1689
|
+
### Task 12: Final verification
|
|
1690
|
+
|
|
1691
|
+
- [ ] **Step 1: Run full test suite**
|
|
1692
|
+
|
|
1693
|
+
Run: `npx vitest run`
|
|
1694
|
+
Expected: All tests passing, coverage above 90% thresholds
|
|
1695
|
+
|
|
1696
|
+
- [ ] **Step 2: Run lint**
|
|
1697
|
+
|
|
1698
|
+
Run: `npm run lint`
|
|
1699
|
+
Expected: Zero warnings
|
|
1700
|
+
|
|
1701
|
+
- [ ] **Step 3: Run typecheck**
|
|
1702
|
+
|
|
1703
|
+
Run: `npm run typecheck`
|
|
1704
|
+
Expected: Clean compilation
|
|
1705
|
+
|
|
1706
|
+
- [ ] **Step 4: Run architecture validator**
|
|
1707
|
+
|
|
1708
|
+
Run: `npm run validate:architecture`
|
|
1709
|
+
Expected: Silent pass
|
|
1710
|
+
|
|
1711
|
+
- [ ] **Step 5: Verify organizer is opt-in**
|
|
1712
|
+
|
|
1713
|
+
Confirm that when `agents.yaml` does NOT have an `organizer` role entry, the system uses `CapacityAwareEnrollmentScheduler` as before (no behavioral change for existing users).
|
|
1714
|
+
|
|
1715
|
+
---
|
|
1716
|
+
|
|
1717
|
+
## Task Dependency Summary
|
|
1718
|
+
|
|
1719
|
+
```
|
|
1720
|
+
Task 0 (defect fixes) → independent, do first
|
|
1721
|
+
Task 1 (types + schema) → independent foundation
|
|
1722
|
+
Task 2 (adapter) → depends on Task 1
|
|
1723
|
+
Task 3 (session types) → independent, parallel with Task 1
|
|
1724
|
+
Task 4 (kernel session) → depends on Task 3
|
|
1725
|
+
Task 5 (config + prompt) → depends on Task 3 (PromptBundle type)
|
|
1726
|
+
Task 6 (session orchestrator) → depends on Tasks 4, 5
|
|
1727
|
+
Task 7 (runtime wiring) → depends on Tasks 2, 6
|
|
1728
|
+
Task 8 (terminal trigger) → independent, can parallel with Tasks 5-7
|
|
1729
|
+
Task 9 (path test) → depends on Task 7
|
|
1730
|
+
Task 10 (dashboard) → depends on Task 1 (types)
|
|
1731
|
+
Task 11 (progress.md) → after all implementation tasks
|
|
1732
|
+
Task 12 (final verification) → after everything
|
|
1733
|
+
```
|
|
1734
|
+
|
|
1735
|
+
---
|
|
1736
|
+
|
|
1737
|
+
## Scope Note: Organizer Sidecar Runtime (Layer 1)
|
|
1738
|
+
|
|
1739
|
+
This plan covers the **full infrastructure** for the ordering agent: types, schemas, adapter, session lifecycle, runtime wiring, triggers, config, prompt, and dashboard integration. After this plan is complete, the system will:
|
|
1740
|
+
|
|
1741
|
+
- Create and manage an organizer LLM session alongside the reconciler
|
|
1742
|
+
- Read ordering artifacts from disk and translate them into enrollment decisions
|
|
1743
|
+
- Fall back to capacity-aware scheduling when no artifact exists
|
|
1744
|
+
- Re-evaluate deferred features when blocking dependencies reach terminal states
|
|
1745
|
+
|
|
1746
|
+
**Not included in this plan:** The organizer sidecar's runtime loop that actually invokes the LLM session to analyze spec files and write the ordering artifact to disk. This is the "brain" of Layer 1 — it requires:
|
|
1747
|
+
|
|
1748
|
+
1. Reading pending `ExecutionRequestFeature` spec files from disk
|
|
1749
|
+
2. Sending them to the organizer session via the provider abstraction
|
|
1750
|
+
3. Parsing the LLM's structured ordering response
|
|
1751
|
+
4. Writing the ordering artifact atomically to `.aop/runtime/<instanceId>/organizer-ordering.json`
|
|
1752
|
+
5. Re-running analysis on trigger events
|
|
1753
|
+
|
|
1754
|
+
This will be a follow-up plan once the infrastructure from this plan is in place, as it depends on the provider interaction patterns and the organizer session being fully wired.
|