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,1289 @@
|
|
|
1
|
+
# Organizer Sidecar Runtime Loop 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 the polling-based organizer sidecar service that invokes the LLM to analyze feature specs and writes the ordering artifact to disk (Layer 1 of the ordering agent).
|
|
6
|
+
|
|
7
|
+
**Architecture:** A standalone `OrganizerSidecarService` class polls on a timer, collects spec paths from execution control and runtime state, calls `provider.runWorker()` with the organizer role, validates the JSON response against the AJV schema, and writes the artifact atomically. Wired into `SupervisorRuntime` alongside the enrollment service.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, Vitest, AJV (JSON Schema draft-2020-12), Node.js fs (atomic writes)
|
|
10
|
+
|
|
11
|
+
**Spec:** `docs/superpowers/specs/2026-03-29-organizer-sidecar-runtime-loop-design.md`
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## File Map
|
|
16
|
+
|
|
17
|
+
| File | Action | Responsibility |
|
|
18
|
+
| :--------------------------------------------------------------- | :----- | :------------------------------------------------------------------------------ |
|
|
19
|
+
| `apps/control-plane/src/supervisor/organizer-sidecar-service.ts` | Create | Polling loop, spec collection, LLM dispatch, response parsing, artifact writing |
|
|
20
|
+
| `apps/control-plane/src/supervisor/runtime.ts` | Modify | Wire sidecar into lifecycle, add `organizer` to `resolveRoleSessionId()` |
|
|
21
|
+
| `config/agentic/orchestrator/prompts/organizer.system.md` | Modify | Add dependency detection signals section |
|
|
22
|
+
| `apps/control-plane/test/organizer-sidecar-service.spec.ts` | Create | Unit tests for the sidecar service |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### Task 1: Enhance Organizer System Prompt
|
|
27
|
+
|
|
28
|
+
**Files:**
|
|
29
|
+
|
|
30
|
+
- Modify: `config/agentic/orchestrator/prompts/organizer.system.md`
|
|
31
|
+
|
|
32
|
+
- [ ] **Step 1: Add dependency detection signals section**
|
|
33
|
+
|
|
34
|
+
Insert the following between the "Analysis discipline" section and "Dependency classification" section in `config/agentic/orchestrator/prompts/organizer.system.md`:
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
## Dependency detection signals
|
|
38
|
+
|
|
39
|
+
### Explicit signals (highest confidence)
|
|
40
|
+
|
|
41
|
+
- `Depends On:` field in spec frontmatter or body — authoritative, never ignore
|
|
42
|
+
- Spec A references spec B by feature ID (e.g. "requires feature-xyz to be merged first")
|
|
43
|
+
- Spec B references spec A — if spec B says "builds on feature-xyz" or "extends the work in feature-xyz," that means B depends on A
|
|
44
|
+
- Spec explicitly lists file paths that another spec also explicitly lists — when both specs declare they will modify the same file(s), the one that creates/restructures goes first
|
|
45
|
+
- "After X is complete" / "Once X lands" language in either direction
|
|
46
|
+
|
|
47
|
+
### Structural signals (medium confidence — classify as `inferred_dependency`)
|
|
48
|
+
|
|
49
|
+
- Two specs modify the same file paths — the one that creates/restructures should go first
|
|
50
|
+
- Spec A adds an interface that spec B consumes (import/type dependency)
|
|
51
|
+
- Spec A creates a database table/schema that spec B queries
|
|
52
|
+
- Spec A introduces a configuration key that spec B reads
|
|
53
|
+
|
|
54
|
+
### Semantic signals (lower confidence — classify carefully)
|
|
55
|
+
|
|
56
|
+
- Specs in the same domain area (e.g. both touch auth) don't necessarily depend on each other — only flag if one's changes would conflict with or build upon the other's
|
|
57
|
+
- Shared terminology alone is not a dependency — look for actual data/control flow relationships
|
|
58
|
+
- If two specs could be implemented in either order without merge conflicts or behavioral issues, they are independent
|
|
59
|
+
|
|
60
|
+
### Not dependencies
|
|
61
|
+
|
|
62
|
+
- Specs that happen to be in the same directory but touch different concerns
|
|
63
|
+
- Specs that share a programming language or framework
|
|
64
|
+
- Specs that were submitted in the same request (ordering within a request is the organizer's job to determine, not assume)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- [ ] **Step 2: Verify the prompt file is well-formed**
|
|
68
|
+
|
|
69
|
+
Read the file back and confirm the sections flow: "Organizer objective" → "Analysis discipline" → "Dependency detection signals" → "Dependency classification" → "Cycle detection" → "Output format" → "Constraints".
|
|
70
|
+
|
|
71
|
+
- [ ] **Step 3: Commit**
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git add config/agentic/orchestrator/prompts/organizer.system.md
|
|
75
|
+
git commit -m "feat: add dependency detection signals to organizer system prompt"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Task 2: Implement OrganizerSidecarService
|
|
81
|
+
|
|
82
|
+
**Files:**
|
|
83
|
+
|
|
84
|
+
- Create: `apps/control-plane/src/supervisor/organizer-sidecar-service.ts`
|
|
85
|
+
|
|
86
|
+
- [ ] **Step 1: Create the service file with types and constructor**
|
|
87
|
+
|
|
88
|
+
Create `apps/control-plane/src/supervisor/organizer-sidecar-service.ts`:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { readFile, writeFile, rename } from 'node:fs/promises';
|
|
92
|
+
import type { ValidateFunction } from 'ajv';
|
|
93
|
+
import { stableHash, nowIso } from '../core/fs.js';
|
|
94
|
+
import type { ExecutionRequestItem } from '../core/execution-control.js';
|
|
95
|
+
import type {
|
|
96
|
+
OrganizerOrderingArtifact,
|
|
97
|
+
SupervisorKernelPort,
|
|
98
|
+
SupervisorRuntimeState,
|
|
99
|
+
} from './types.js';
|
|
100
|
+
import type { WorkerProvider, WorkerRunOutput } from '../providers/providers.js';
|
|
101
|
+
|
|
102
|
+
export interface OrganizerSidecarDependencies {
|
|
103
|
+
provider: WorkerProvider;
|
|
104
|
+
organizerSessionId: () => string | null;
|
|
105
|
+
kernel: SupervisorKernelPort;
|
|
106
|
+
state: SupervisorRuntimeState;
|
|
107
|
+
artifactPath: string;
|
|
108
|
+
schemaValidator: ValidateFunction;
|
|
109
|
+
pollIntervalMs?: number;
|
|
110
|
+
maxSpecContentBytes?: number;
|
|
111
|
+
artifactTtlMs?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface SpecEntry {
|
|
115
|
+
feature_id: string;
|
|
116
|
+
spec_path: string;
|
|
117
|
+
status: string;
|
|
118
|
+
content: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const DEFAULT_POLL_INTERVAL_MS = 10_000;
|
|
122
|
+
const DEFAULT_MAX_SPEC_CONTENT_BYTES = 102_400;
|
|
123
|
+
const DEFAULT_ARTIFACT_TTL_MS = 120_000;
|
|
124
|
+
|
|
125
|
+
export class OrganizerSidecarService {
|
|
126
|
+
private readonly provider: WorkerProvider;
|
|
127
|
+
private readonly organizerSessionId: () => string | null;
|
|
128
|
+
private readonly kernel: SupervisorKernelPort;
|
|
129
|
+
private readonly state: SupervisorRuntimeState;
|
|
130
|
+
private readonly artifactPath: string;
|
|
131
|
+
private readonly schemaValidator: ValidateFunction;
|
|
132
|
+
private readonly pollIntervalMs: number;
|
|
133
|
+
private readonly maxSpecContentBytes: number;
|
|
134
|
+
private readonly artifactTtlMs: number;
|
|
135
|
+
|
|
136
|
+
private lastFingerprint: string | null = null;
|
|
137
|
+
private timer: NodeJS.Timeout | null = null;
|
|
138
|
+
private reconcileInFlight: Promise<void> | null = null;
|
|
139
|
+
private started = false;
|
|
140
|
+
|
|
141
|
+
constructor(deps: OrganizerSidecarDependencies) {
|
|
142
|
+
this.provider = deps.provider;
|
|
143
|
+
this.organizerSessionId = deps.organizerSessionId;
|
|
144
|
+
this.kernel = deps.kernel;
|
|
145
|
+
this.state = deps.state;
|
|
146
|
+
this.artifactPath = deps.artifactPath;
|
|
147
|
+
this.schemaValidator = deps.schemaValidator;
|
|
148
|
+
this.pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
149
|
+
this.maxSpecContentBytes = deps.maxSpecContentBytes ?? DEFAULT_MAX_SPEC_CONTENT_BYTES;
|
|
150
|
+
this.artifactTtlMs = deps.artifactTtlMs ?? DEFAULT_ARTIFACT_TTL_MS;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
start(): void {
|
|
154
|
+
if (this.started) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.started = true;
|
|
158
|
+
this.timer = setInterval(() => {
|
|
159
|
+
void this.reconcile();
|
|
160
|
+
}, this.pollIntervalMs);
|
|
161
|
+
if (typeof this.timer.unref === 'function') {
|
|
162
|
+
this.timer.unref();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async stop(): Promise<void> {
|
|
167
|
+
this.started = false;
|
|
168
|
+
if (this.timer) {
|
|
169
|
+
clearInterval(this.timer);
|
|
170
|
+
this.timer = null;
|
|
171
|
+
}
|
|
172
|
+
if (this.reconcileInFlight !== null) {
|
|
173
|
+
await this.reconcileInFlight;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private async reconcile(): Promise<void> {
|
|
178
|
+
if (this.reconcileInFlight !== null) {
|
|
179
|
+
await this.reconcileInFlight;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
this.reconcileInFlight = this.performReconcile()
|
|
183
|
+
.catch((error: unknown) => {
|
|
184
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
185
|
+
console.warn(`[organizer-sidecar] reconcile failed: ${message}`);
|
|
186
|
+
})
|
|
187
|
+
.finally(() => {
|
|
188
|
+
this.reconcileInFlight = null;
|
|
189
|
+
});
|
|
190
|
+
await this.reconcileInFlight;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private async performReconcile(): Promise<void> {
|
|
194
|
+
const sessionId = this.organizerSessionId();
|
|
195
|
+
if (!sessionId || sessionId === 'unknown' || sessionId === 'unassigned') {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const specs = await this.collectSpecs();
|
|
200
|
+
if (specs.length === 0) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const requestIds = await this.collectRequestIds();
|
|
205
|
+
const fingerprint = this.computeFingerprint(specs, requestIds);
|
|
206
|
+
if (fingerprint === this.lastFingerprint) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const { prompt, partial } = this.buildPrompt(specs);
|
|
211
|
+
const artifact = await this.dispatchAndParse(prompt, partial, fingerprint, requestIds);
|
|
212
|
+
if (!artifact) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
await this.writeArtifactAtomically(artifact);
|
|
217
|
+
this.lastFingerprint = fingerprint;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private async collectSpecs(): Promise<SpecEntry[]> {
|
|
221
|
+
const specMap = new Map<string, { spec_path: string; status: string }>();
|
|
222
|
+
|
|
223
|
+
// Source 1: execution control (pending requests)
|
|
224
|
+
try {
|
|
225
|
+
const pending = await this.kernel.drainPendingExecutionRequests(
|
|
226
|
+
this.state.runId,
|
|
227
|
+
this.state.ownerInstanceId,
|
|
228
|
+
);
|
|
229
|
+
for (const request of pending.data.items) {
|
|
230
|
+
if (request.status !== 'pending') {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
for (const feature of request.features) {
|
|
234
|
+
if (!specMap.has(feature.feature_id)) {
|
|
235
|
+
specMap.set(feature.feature_id, {
|
|
236
|
+
spec_path: feature.spec_path,
|
|
237
|
+
status: 'pending',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
console.warn('[organizer-sidecar] failed to read execution control');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Source 2: active/queued features from runtime state
|
|
247
|
+
for (const featureId of this.state.sessionsByFeature.keys()) {
|
|
248
|
+
if (!specMap.has(featureId)) {
|
|
249
|
+
await this.addFeatureFromState(specMap, featureId);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
for (const queued of this.state.queue) {
|
|
253
|
+
if (!specMap.has(queued.feature_id)) {
|
|
254
|
+
await this.addFeatureFromState(specMap, queued.feature_id);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Read spec file contents
|
|
259
|
+
const entries: SpecEntry[] = [];
|
|
260
|
+
for (const [featureId, meta] of specMap) {
|
|
261
|
+
try {
|
|
262
|
+
const content = await readFile(meta.spec_path, 'utf8');
|
|
263
|
+
entries.push({
|
|
264
|
+
feature_id: featureId,
|
|
265
|
+
spec_path: meta.spec_path,
|
|
266
|
+
status: meta.status,
|
|
267
|
+
content,
|
|
268
|
+
});
|
|
269
|
+
} catch {
|
|
270
|
+
console.warn(`[organizer-sidecar] spec file missing for ${featureId}: ${meta.spec_path}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return entries;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private async addFeatureFromState(
|
|
278
|
+
specMap: Map<string, { spec_path: string; status: string }>,
|
|
279
|
+
featureId: string,
|
|
280
|
+
): Promise<void> {
|
|
281
|
+
try {
|
|
282
|
+
const state = await this.kernel.readState(featureId);
|
|
283
|
+
const fm = state.frontMatter;
|
|
284
|
+
const specPath = typeof fm.spec_path === 'string' ? fm.spec_path : null;
|
|
285
|
+
const status = typeof fm.status === 'string' ? fm.status : 'unknown';
|
|
286
|
+
if (specPath) {
|
|
287
|
+
specMap.set(featureId, { spec_path: specPath, status });
|
|
288
|
+
}
|
|
289
|
+
} catch {
|
|
290
|
+
// Feature state unreadable — skip
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private async collectRequestIds(): Promise<string[]> {
|
|
295
|
+
try {
|
|
296
|
+
const pending = await this.kernel.drainPendingExecutionRequests(
|
|
297
|
+
this.state.runId,
|
|
298
|
+
this.state.ownerInstanceId,
|
|
299
|
+
);
|
|
300
|
+
return pending.data.items
|
|
301
|
+
.filter((item) => item.status === 'pending')
|
|
302
|
+
.map((item) => item.request_id)
|
|
303
|
+
.sort();
|
|
304
|
+
} catch {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private computeFingerprint(specs: SpecEntry[], requestIds: string[]): string {
|
|
310
|
+
return stableHash(
|
|
311
|
+
JSON.stringify({
|
|
312
|
+
featureIds: specs.map((s) => s.feature_id).sort(),
|
|
313
|
+
specPaths: specs.map((s) => s.spec_path).sort(),
|
|
314
|
+
requestIds,
|
|
315
|
+
}),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private buildPrompt(specs: SpecEntry[]): { prompt: string; partial: boolean } {
|
|
320
|
+
let totalBytes = 0;
|
|
321
|
+
let partial = false;
|
|
322
|
+
const included: SpecEntry[] = [];
|
|
323
|
+
|
|
324
|
+
for (const spec of specs) {
|
|
325
|
+
const specBytes = Buffer.byteLength(spec.content, 'utf8');
|
|
326
|
+
if (totalBytes + specBytes > this.maxSpecContentBytes) {
|
|
327
|
+
partial = true;
|
|
328
|
+
console.warn(
|
|
329
|
+
`[organizer-sidecar] spec content limit reached at ${included.length}/${specs.length} features`,
|
|
330
|
+
);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
totalBytes += specBytes;
|
|
334
|
+
included.push(spec);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const sections = included.map(
|
|
338
|
+
(spec) =>
|
|
339
|
+
`--- FEATURE: ${spec.feature_id} ---\nspec_path: ${spec.spec_path}\nstatus: ${spec.status}\n\n${spec.content}`,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const prompt = [
|
|
343
|
+
'Analyze the following feature specs and produce an ordering artifact.',
|
|
344
|
+
'',
|
|
345
|
+
`Active instance: ${this.state.ownerInstanceId}`,
|
|
346
|
+
`Total features: ${included.length}`,
|
|
347
|
+
'',
|
|
348
|
+
...sections,
|
|
349
|
+
'',
|
|
350
|
+
'---',
|
|
351
|
+
'',
|
|
352
|
+
'Produce a single JSON object with the ordering analysis. No markdown fences.',
|
|
353
|
+
].join('\n');
|
|
354
|
+
|
|
355
|
+
return { prompt, partial };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private async dispatchAndParse(
|
|
359
|
+
prompt: string,
|
|
360
|
+
partial: boolean,
|
|
361
|
+
fingerprint: string,
|
|
362
|
+
requestIds: string[],
|
|
363
|
+
): Promise<OrganizerOrderingArtifact | null> {
|
|
364
|
+
const output = await this.invokeOrganizer(prompt);
|
|
365
|
+
const firstAttempt = this.parseAndValidate(output, partial, fingerprint, requestIds);
|
|
366
|
+
if (firstAttempt) {
|
|
367
|
+
return firstAttempt;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Retry once with correction
|
|
371
|
+
const errors = this.schemaValidator.errors;
|
|
372
|
+
const errorSummary = errors
|
|
373
|
+
? errors.map((e) => `${e.instancePath} ${e.message}`).join('; ')
|
|
374
|
+
: 'invalid JSON structure';
|
|
375
|
+
const correctionPrompt = `Your previous response was invalid: ${errorSummary}. Please produce the ordering JSON again with the same specs.`;
|
|
376
|
+
|
|
377
|
+
const retryOutput = await this.invokeOrganizer(correctionPrompt);
|
|
378
|
+
const secondAttempt = this.parseAndValidate(retryOutput, partial, fingerprint, requestIds);
|
|
379
|
+
if (secondAttempt) {
|
|
380
|
+
return secondAttempt;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
console.warn('[organizer-sidecar] artifact validation failed after retry, skipping write');
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private async invokeOrganizer(instructions: string): Promise<WorkerRunOutput> {
|
|
388
|
+
return await this.provider.runWorker({
|
|
389
|
+
role: 'organizer',
|
|
390
|
+
feature_id: 'global',
|
|
391
|
+
instructions,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private parseAndValidate(
|
|
396
|
+
output: WorkerRunOutput,
|
|
397
|
+
partial: boolean,
|
|
398
|
+
fingerprint: string,
|
|
399
|
+
requestIds: string[],
|
|
400
|
+
): OrganizerOrderingArtifact | null {
|
|
401
|
+
const text = this.extractText(output);
|
|
402
|
+
if (!text) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
let parsed: Record<string, unknown>;
|
|
407
|
+
try {
|
|
408
|
+
parsed = JSON.parse(text) as Record<string, unknown>;
|
|
409
|
+
} catch {
|
|
410
|
+
// Try extracting JSON from embedded text
|
|
411
|
+
const firstBrace = text.indexOf('{');
|
|
412
|
+
const lastBrace = text.lastIndexOf('}');
|
|
413
|
+
if (firstBrace === -1 || lastBrace <= firstBrace) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
parsed = JSON.parse(text.slice(firstBrace, lastBrace + 1)) as Record<string, unknown>;
|
|
418
|
+
} catch {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Unwrap { type: "ORDERING", ordering: { ... } } envelope
|
|
424
|
+
const ordering =
|
|
425
|
+
parsed.type === 'ORDERING' && parsed.ordering && typeof parsed.ordering === 'object'
|
|
426
|
+
? (parsed.ordering as Record<string, unknown>)
|
|
427
|
+
: parsed;
|
|
428
|
+
|
|
429
|
+
const artifact: OrganizerOrderingArtifact = {
|
|
430
|
+
version: 1,
|
|
431
|
+
generated_at: nowIso(),
|
|
432
|
+
expires_at: new Date(Date.now() + this.artifactTtlMs).toISOString(),
|
|
433
|
+
completion_status: partial ? 'partial' : 'complete',
|
|
434
|
+
backlog_fingerprint: fingerprint,
|
|
435
|
+
analyzed_requests: requestIds,
|
|
436
|
+
dependency_graph: (ordering.dependency_graph as Record<string, unknown>) ?? {},
|
|
437
|
+
ready_set: (ordering.ready_set as string[]) ?? [],
|
|
438
|
+
deferred_set:
|
|
439
|
+
(ordering.deferred_set as Array<{
|
|
440
|
+
feature_id: string;
|
|
441
|
+
blocked_by: string[];
|
|
442
|
+
reason: string;
|
|
443
|
+
}>) ?? [],
|
|
444
|
+
blocked_set: (ordering.blocked_set as Array<{ feature_id: string; reason: string }>) ?? [],
|
|
445
|
+
} as OrganizerOrderingArtifact;
|
|
446
|
+
|
|
447
|
+
const valid = this.schemaValidator(artifact);
|
|
448
|
+
if (!valid) {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return artifact;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private extractText(output: WorkerRunOutput): string | null {
|
|
456
|
+
// Try common provider output text fields
|
|
457
|
+
if (typeof output.content === 'string' && output.content.length > 0) {
|
|
458
|
+
return output.content;
|
|
459
|
+
}
|
|
460
|
+
if (typeof output.text === 'string' && output.text.length > 0) {
|
|
461
|
+
return output.text;
|
|
462
|
+
}
|
|
463
|
+
if (typeof output.response === 'string' && output.response.length > 0) {
|
|
464
|
+
return output.response;
|
|
465
|
+
}
|
|
466
|
+
// Fallback: check outputs array (structured provider envelope)
|
|
467
|
+
if (Array.isArray(output.outputs)) {
|
|
468
|
+
for (const item of output.outputs) {
|
|
469
|
+
const record = item as Record<string, unknown>;
|
|
470
|
+
if (typeof record.content === 'string' && record.content.length > 0) {
|
|
471
|
+
return record.content;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Last resort: stringify the entire output
|
|
476
|
+
try {
|
|
477
|
+
const str = JSON.stringify(output);
|
|
478
|
+
if (str.length > 2) {
|
|
479
|
+
return str;
|
|
480
|
+
}
|
|
481
|
+
} catch {
|
|
482
|
+
// empty
|
|
483
|
+
}
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
private async writeArtifactAtomically(artifact: OrganizerOrderingArtifact): Promise<void> {
|
|
488
|
+
const tmpPath = this.artifactPath + '.tmp';
|
|
489
|
+
await writeFile(tmpPath, JSON.stringify(artifact, null, 2), 'utf8');
|
|
490
|
+
await rename(tmpPath, this.artifactPath);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
- [ ] **Step 2: Verify the file compiles**
|
|
496
|
+
|
|
497
|
+
Run: `npx tsc --noEmit`
|
|
498
|
+
Expected: Clean (no errors in the new file).
|
|
499
|
+
|
|
500
|
+
- [ ] **Step 3: Commit**
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
git add apps/control-plane/src/supervisor/organizer-sidecar-service.ts
|
|
504
|
+
git commit -m "feat: implement OrganizerSidecarService with polling loop and artifact writer"
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
### Task 3: Write Unit Tests for OrganizerSidecarService
|
|
510
|
+
|
|
511
|
+
**Files:**
|
|
512
|
+
|
|
513
|
+
- Create: `apps/control-plane/test/organizer-sidecar-service.spec.ts`
|
|
514
|
+
|
|
515
|
+
- [ ] **Step 1: Create the test file with helpers and mocks**
|
|
516
|
+
|
|
517
|
+
Create `apps/control-plane/test/organizer-sidecar-service.spec.ts`:
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
521
|
+
import { mkdtemp, rm, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
522
|
+
import { existsSync } from 'node:fs';
|
|
523
|
+
import { tmpdir } from 'node:os';
|
|
524
|
+
import { join } from 'node:path';
|
|
525
|
+
import Ajv2020Import from 'ajv/dist/2020.js';
|
|
526
|
+
import type { ValidateFunction } from 'ajv';
|
|
527
|
+
import { OrganizerSidecarService } from '../src/supervisor/organizer-sidecar-service.js';
|
|
528
|
+
import type { OrganizerOrderingArtifact, SupervisorRuntimeState } from '../src/supervisor/types.js';
|
|
529
|
+
import type { WorkerProvider, WorkerRunOutput } from '../src/providers/providers.js';
|
|
530
|
+
import artifactSchema from '../../../agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json';
|
|
531
|
+
|
|
532
|
+
function createAjvValidator(): ValidateFunction {
|
|
533
|
+
const Ajv2020Ctor = Ajv2020Import as unknown as new (opts: Record<string, unknown>) => {
|
|
534
|
+
compile(schema: Record<string, unknown>): ValidateFunction;
|
|
535
|
+
addFormat(name: string, format: { type?: string; validate: (v: string) => boolean }): void;
|
|
536
|
+
};
|
|
537
|
+
const ajv = new Ajv2020Ctor({ allErrors: true, strict: false });
|
|
538
|
+
ajv.addFormat('date-time', {
|
|
539
|
+
type: 'string',
|
|
540
|
+
validate: (v: string) => !Number.isNaN(Date.parse(v)),
|
|
541
|
+
});
|
|
542
|
+
return ajv.compile(artifactSchema as unknown as Record<string, unknown>);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function makeValidOrderingResponse(): WorkerRunOutput {
|
|
546
|
+
return {
|
|
547
|
+
content: JSON.stringify({
|
|
548
|
+
type: 'ORDERING',
|
|
549
|
+
ordering: {
|
|
550
|
+
dependency_graph: {
|
|
551
|
+
feat_a: { depends_on: [], classification: 'no_dependency_found' },
|
|
552
|
+
feat_b: { depends_on: ['feat_a'], classification: 'explicit_dependency' },
|
|
553
|
+
},
|
|
554
|
+
ready_set: ['feat_a'],
|
|
555
|
+
deferred_set: [{ feature_id: 'feat_b', blocked_by: ['feat_a'], reason: 'explicit dep' }],
|
|
556
|
+
blocked_set: [],
|
|
557
|
+
},
|
|
558
|
+
}),
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function makeMalformedResponse(): WorkerRunOutput {
|
|
563
|
+
return { content: '{ not valid json' };
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function makeInvalidClassificationResponse(): WorkerRunOutput {
|
|
567
|
+
return {
|
|
568
|
+
content: JSON.stringify({
|
|
569
|
+
type: 'ORDERING',
|
|
570
|
+
ordering: {
|
|
571
|
+
dependency_graph: {
|
|
572
|
+
feat_a: { depends_on: [], classification: 'INVALID_ENUM_VALUE' },
|
|
573
|
+
},
|
|
574
|
+
ready_set: ['feat_a'],
|
|
575
|
+
deferred_set: [],
|
|
576
|
+
blocked_set: [],
|
|
577
|
+
},
|
|
578
|
+
}),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
let tempDir: string;
|
|
583
|
+
let artifactPath: string;
|
|
584
|
+
let specDir: string;
|
|
585
|
+
let validator: ValidateFunction;
|
|
586
|
+
|
|
587
|
+
function makeState(overrides: Partial<SupervisorRuntimeState> = {}): SupervisorRuntimeState {
|
|
588
|
+
return {
|
|
589
|
+
runId: 'run:test',
|
|
590
|
+
ownerInstanceId: 'supervisor:test',
|
|
591
|
+
orchestratorSessionId: 'orch-1',
|
|
592
|
+
reconcilerSessionId: null,
|
|
593
|
+
organizerSessionId: 'org-1',
|
|
594
|
+
sessionsByFeature: new Map(),
|
|
595
|
+
queue: [],
|
|
596
|
+
runMetadata: {},
|
|
597
|
+
...overrides,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function makeKernel(specPaths: Record<string, string> = {}) {
|
|
602
|
+
return {
|
|
603
|
+
drainPendingExecutionRequests: vi.fn().mockResolvedValue({
|
|
604
|
+
data: {
|
|
605
|
+
items: [
|
|
606
|
+
{
|
|
607
|
+
request_id: 'req_1',
|
|
608
|
+
request_type: 'add_features',
|
|
609
|
+
status: 'pending',
|
|
610
|
+
requested_at: new Date().toISOString(),
|
|
611
|
+
processed_at: null,
|
|
612
|
+
requested_by: 'cli:add',
|
|
613
|
+
operation_id: 'op:1',
|
|
614
|
+
features: Object.entries(specPaths).map(([featureId, specPath]) => ({
|
|
615
|
+
feature_id: featureId,
|
|
616
|
+
spec_path: specPath,
|
|
617
|
+
})),
|
|
618
|
+
progress: null,
|
|
619
|
+
outcome: null,
|
|
620
|
+
},
|
|
621
|
+
],
|
|
622
|
+
},
|
|
623
|
+
}),
|
|
624
|
+
readState: vi.fn().mockImplementation(async (featureId: string) => ({
|
|
625
|
+
frontMatter: {
|
|
626
|
+
status: 'active',
|
|
627
|
+
spec_path: specPaths[featureId] ?? `/tmp/missing/${featureId}.md`,
|
|
628
|
+
},
|
|
629
|
+
body: '',
|
|
630
|
+
})),
|
|
631
|
+
getRuntimeSessions: vi.fn().mockResolvedValue({}),
|
|
632
|
+
getRepoRoot: vi.fn().mockReturnValue(tempDir),
|
|
633
|
+
getAgentsConfig: vi.fn().mockReturnValue({ roles: { organizer: {} } }),
|
|
634
|
+
getPolicySnapshot: vi.fn().mockReturnValue({}),
|
|
635
|
+
getAdaptersConfig: vi.fn().mockReturnValue({}),
|
|
636
|
+
ensureLoaded: vi.fn().mockResolvedValue(undefined),
|
|
637
|
+
renewRunLease: vi.fn(),
|
|
638
|
+
releaseRunLease: vi.fn(),
|
|
639
|
+
markExecutionRequestProcessed: vi.fn(),
|
|
640
|
+
updateExecutionRequestProgress: vi.fn(),
|
|
641
|
+
repoDiff: vi.fn(),
|
|
642
|
+
worktreePath: vi.fn(),
|
|
643
|
+
featurePath: vi.fn(),
|
|
644
|
+
readState_: vi.fn(),
|
|
645
|
+
validatePatchDiff: vi.fn(),
|
|
646
|
+
updateState: vi.fn(),
|
|
647
|
+
checkBudget: vi.fn(),
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function makeProvider(responses: WorkerRunOutput[]): WorkerProvider {
|
|
652
|
+
let callIndex = 0;
|
|
653
|
+
return {
|
|
654
|
+
mode: 'stub' as const,
|
|
655
|
+
selection: {
|
|
656
|
+
provider: 'test',
|
|
657
|
+
model: 'test-model',
|
|
658
|
+
provider_config_ref: 'test-ref',
|
|
659
|
+
},
|
|
660
|
+
createSession: vi
|
|
661
|
+
.fn()
|
|
662
|
+
.mockResolvedValue({
|
|
663
|
+
session_id: 'org-1',
|
|
664
|
+
role: 'organizer',
|
|
665
|
+
feature_id: 'global',
|
|
666
|
+
system_prompt_loaded: true,
|
|
667
|
+
}),
|
|
668
|
+
closeSession: vi.fn().mockResolvedValue({ closed: true }),
|
|
669
|
+
reattachSession: vi.fn().mockResolvedValue(true),
|
|
670
|
+
runWorker: vi.fn().mockImplementation(async () => {
|
|
671
|
+
const response = responses[callIndex] ?? responses[responses.length - 1];
|
|
672
|
+
callIndex++;
|
|
673
|
+
return response;
|
|
674
|
+
}),
|
|
675
|
+
} as unknown as WorkerProvider;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
beforeEach(async () => {
|
|
679
|
+
tempDir = await mkdtemp(join(tmpdir(), 'organizer-sidecar-test-'));
|
|
680
|
+
artifactPath = join(tempDir, 'organizer-ordering.json');
|
|
681
|
+
specDir = join(tempDir, 'specs');
|
|
682
|
+
await mkdir(specDir, { recursive: true });
|
|
683
|
+
validator = createAjvValidator();
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
afterEach(async () => {
|
|
687
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
688
|
+
});
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
- [ ] **Step 2: Add test — backlog unchanged, no LLM call**
|
|
692
|
+
|
|
693
|
+
Append to the test file:
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
describe('OrganizerSidecarService', () => {
|
|
697
|
+
it('GIVEN_backlog_unchanged_WHEN_tick_fires_THEN_no_runWorker_call', async () => {
|
|
698
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
699
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
700
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
701
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
702
|
+
const state = makeState();
|
|
703
|
+
|
|
704
|
+
const service = new OrganizerSidecarService({
|
|
705
|
+
provider,
|
|
706
|
+
organizerSessionId: () => 'org-1',
|
|
707
|
+
kernel: kernel as any,
|
|
708
|
+
state,
|
|
709
|
+
artifactPath,
|
|
710
|
+
schemaValidator: validator,
|
|
711
|
+
pollIntervalMs: 100_000,
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
// First call — triggers LLM
|
|
715
|
+
await (service as any).performReconcile();
|
|
716
|
+
expect(provider.runWorker).toHaveBeenCalledTimes(1);
|
|
717
|
+
|
|
718
|
+
// Second call — fingerprint unchanged, no LLM call
|
|
719
|
+
await (service as any).performReconcile();
|
|
720
|
+
expect(provider.runWorker).toHaveBeenCalledTimes(1);
|
|
721
|
+
});
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
- [ ] **Step 3: Add test — new pending request triggers LLM**
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
it('GIVEN_new_pending_request_WHEN_tick_fires_THEN_sends_spec_content_to_organizer', async () => {
|
|
728
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
729
|
+
await writeFile(specPath, '# Feature A\nImplement widget system', 'utf8');
|
|
730
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
731
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
732
|
+
const state = makeState();
|
|
733
|
+
|
|
734
|
+
const service = new OrganizerSidecarService({
|
|
735
|
+
provider,
|
|
736
|
+
organizerSessionId: () => 'org-1',
|
|
737
|
+
kernel: kernel as any,
|
|
738
|
+
state,
|
|
739
|
+
artifactPath,
|
|
740
|
+
schemaValidator: validator,
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
await (service as any).performReconcile();
|
|
744
|
+
|
|
745
|
+
expect(provider.runWorker).toHaveBeenCalledTimes(1);
|
|
746
|
+
const call = (provider.runWorker as any).mock.calls[0][0];
|
|
747
|
+
expect(call.role).toBe('organizer');
|
|
748
|
+
expect(call.feature_id).toBe('global');
|
|
749
|
+
expect(call.instructions).toContain('--- FEATURE: feat_a ---');
|
|
750
|
+
expect(call.instructions).toContain('# Feature A');
|
|
751
|
+
expect(call.instructions).toContain('Implement widget system');
|
|
752
|
+
});
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
- [ ] **Step 4: Add test — valid response writes artifact atomically**
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
it('GIVEN_valid_LLM_response_WHEN_parsed_THEN_writes_artifact_atomically', async () => {
|
|
759
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
760
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
761
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
762
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
763
|
+
const state = makeState();
|
|
764
|
+
|
|
765
|
+
const service = new OrganizerSidecarService({
|
|
766
|
+
provider,
|
|
767
|
+
organizerSessionId: () => 'org-1',
|
|
768
|
+
kernel: kernel as any,
|
|
769
|
+
state,
|
|
770
|
+
artifactPath,
|
|
771
|
+
schemaValidator: validator,
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
await (service as any).performReconcile();
|
|
775
|
+
|
|
776
|
+
expect(existsSync(artifactPath)).toBe(true);
|
|
777
|
+
const written = JSON.parse(await readFile(artifactPath, 'utf8')) as OrganizerOrderingArtifact;
|
|
778
|
+
expect(written.version).toBe(1);
|
|
779
|
+
expect(written.completion_status).toBe('complete');
|
|
780
|
+
expect(written.ready_set).toEqual(['feat_a']);
|
|
781
|
+
expect(written.deferred_set).toHaveLength(1);
|
|
782
|
+
expect(written.deferred_set[0].feature_id).toBe('feat_b');
|
|
783
|
+
expect(written.dependency_graph.feat_a.classification).toBe('no_dependency_found');
|
|
784
|
+
expect(written.dependency_graph.feat_b.classification).toBe('explicit_dependency');
|
|
785
|
+
// Verify temp file is cleaned up
|
|
786
|
+
expect(existsSync(artifactPath + '.tmp')).toBe(false);
|
|
787
|
+
});
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
- [ ] **Step 5: Add test — malformed response triggers retry**
|
|
791
|
+
|
|
792
|
+
```typescript
|
|
793
|
+
it('GIVEN_malformed_LLM_response_WHEN_first_attempt_fails_THEN_retries_with_correction', async () => {
|
|
794
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
795
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
796
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
797
|
+
// First call returns malformed, retry returns valid
|
|
798
|
+
const provider = makeProvider([makeMalformedResponse(), makeValidOrderingResponse()]);
|
|
799
|
+
const state = makeState();
|
|
800
|
+
|
|
801
|
+
const service = new OrganizerSidecarService({
|
|
802
|
+
provider,
|
|
803
|
+
organizerSessionId: () => 'org-1',
|
|
804
|
+
kernel: kernel as any,
|
|
805
|
+
state,
|
|
806
|
+
artifactPath,
|
|
807
|
+
schemaValidator: validator,
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
await (service as any).performReconcile();
|
|
811
|
+
|
|
812
|
+
expect(provider.runWorker).toHaveBeenCalledTimes(2);
|
|
813
|
+
const retryCall = (provider.runWorker as any).mock.calls[1][0];
|
|
814
|
+
expect(retryCall.instructions).toContain('Your previous response was invalid');
|
|
815
|
+
expect(existsSync(artifactPath)).toBe(true);
|
|
816
|
+
});
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
- [ ] **Step 6: Add test — both attempts fail, no artifact written**
|
|
820
|
+
|
|
821
|
+
```typescript
|
|
822
|
+
it('GIVEN_malformed_response_on_retry_WHEN_second_attempt_fails_THEN_logs_warning_and_skips', async () => {
|
|
823
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
824
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
825
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
826
|
+
const provider = makeProvider([makeMalformedResponse(), makeMalformedResponse()]);
|
|
827
|
+
const state = makeState();
|
|
828
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
829
|
+
|
|
830
|
+
const service = new OrganizerSidecarService({
|
|
831
|
+
provider,
|
|
832
|
+
organizerSessionId: () => 'org-1',
|
|
833
|
+
kernel: kernel as any,
|
|
834
|
+
state,
|
|
835
|
+
artifactPath,
|
|
836
|
+
schemaValidator: validator,
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
await (service as any).performReconcile();
|
|
840
|
+
|
|
841
|
+
expect(provider.runWorker).toHaveBeenCalledTimes(2);
|
|
842
|
+
expect(existsSync(artifactPath)).toBe(false);
|
|
843
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
844
|
+
expect.stringContaining('artifact validation failed after retry'),
|
|
845
|
+
);
|
|
846
|
+
warnSpy.mockRestore();
|
|
847
|
+
});
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
- [ ] **Step 7: Add test — no organizer session skips gracefully**
|
|
851
|
+
|
|
852
|
+
```typescript
|
|
853
|
+
it('GIVEN_no_organizer_session_WHEN_tick_fires_THEN_skips_gracefully', async () => {
|
|
854
|
+
const kernel = makeKernel({});
|
|
855
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
856
|
+
const state = makeState();
|
|
857
|
+
|
|
858
|
+
const service = new OrganizerSidecarService({
|
|
859
|
+
provider,
|
|
860
|
+
organizerSessionId: () => null,
|
|
861
|
+
kernel: kernel as any,
|
|
862
|
+
state,
|
|
863
|
+
artifactPath,
|
|
864
|
+
schemaValidator: validator,
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
await (service as any).performReconcile();
|
|
868
|
+
|
|
869
|
+
expect(provider.runWorker).not.toHaveBeenCalled();
|
|
870
|
+
expect(existsSync(artifactPath)).toBe(false);
|
|
871
|
+
});
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
- [ ] **Step 8: Add test — missing spec file skips feature with warning**
|
|
875
|
+
|
|
876
|
+
```typescript
|
|
877
|
+
it('GIVEN_spec_file_missing_WHEN_collecting_specs_THEN_skips_that_feature', async () => {
|
|
878
|
+
const kernel = makeKernel({ feat_a: '/nonexistent/path/spec.md' });
|
|
879
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
880
|
+
const state = makeState();
|
|
881
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
882
|
+
|
|
883
|
+
const service = new OrganizerSidecarService({
|
|
884
|
+
provider,
|
|
885
|
+
organizerSessionId: () => 'org-1',
|
|
886
|
+
kernel: kernel as any,
|
|
887
|
+
state,
|
|
888
|
+
artifactPath,
|
|
889
|
+
schemaValidator: validator,
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
await (service as any).performReconcile();
|
|
893
|
+
|
|
894
|
+
// No specs collected, so no LLM call
|
|
895
|
+
expect(provider.runWorker).not.toHaveBeenCalled();
|
|
896
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('spec file missing for feat_a'));
|
|
897
|
+
warnSpy.mockRestore();
|
|
898
|
+
});
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
- [ ] **Step 9: Add test — size guard produces partial artifact**
|
|
902
|
+
|
|
903
|
+
```typescript
|
|
904
|
+
it('GIVEN_spec_content_exceeds_limit_WHEN_building_prompt_THEN_produces_partial_artifact', async () => {
|
|
905
|
+
const specPathA = join(specDir, 'feat_a.md');
|
|
906
|
+
const specPathB = join(specDir, 'feat_b.md');
|
|
907
|
+
// Write large spec content
|
|
908
|
+
await writeFile(specPathA, 'A'.repeat(500), 'utf8');
|
|
909
|
+
await writeFile(specPathB, 'B'.repeat(500), 'utf8');
|
|
910
|
+
const kernel = makeKernel({ feat_a: specPathA, feat_b: specPathB });
|
|
911
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
912
|
+
const state = makeState();
|
|
913
|
+
|
|
914
|
+
const service = new OrganizerSidecarService({
|
|
915
|
+
provider,
|
|
916
|
+
organizerSessionId: () => 'org-1',
|
|
917
|
+
kernel: kernel as any,
|
|
918
|
+
state,
|
|
919
|
+
artifactPath,
|
|
920
|
+
schemaValidator: validator,
|
|
921
|
+
maxSpecContentBytes: 600, // Only room for ~1 spec
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
await (service as any).performReconcile();
|
|
925
|
+
|
|
926
|
+
expect(existsSync(artifactPath)).toBe(true);
|
|
927
|
+
const written = JSON.parse(await readFile(artifactPath, 'utf8')) as OrganizerOrderingArtifact;
|
|
928
|
+
expect(written.completion_status).toBe('partial');
|
|
929
|
+
});
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
- [ ] **Step 10: Add test — stop awaits in-flight reconcile**
|
|
933
|
+
|
|
934
|
+
```typescript
|
|
935
|
+
it('GIVEN_service_started_WHEN_stop_called_THEN_awaits_inflight_reconcile', async () => {
|
|
936
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
937
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
938
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
939
|
+
// Slow provider response
|
|
940
|
+
const provider = makeProvider([]);
|
|
941
|
+
(provider.runWorker as any).mockImplementation(async () => {
|
|
942
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
943
|
+
return makeValidOrderingResponse();
|
|
944
|
+
});
|
|
945
|
+
const state = makeState();
|
|
946
|
+
|
|
947
|
+
const service = new OrganizerSidecarService({
|
|
948
|
+
provider,
|
|
949
|
+
organizerSessionId: () => 'org-1',
|
|
950
|
+
kernel: kernel as any,
|
|
951
|
+
state,
|
|
952
|
+
artifactPath,
|
|
953
|
+
schemaValidator: validator,
|
|
954
|
+
pollIntervalMs: 50,
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
service.start();
|
|
958
|
+
// Wait for at least one tick
|
|
959
|
+
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
960
|
+
await service.stop();
|
|
961
|
+
|
|
962
|
+
// After stop, if reconcile was in-flight it should have completed
|
|
963
|
+
// (no assertion on artifact because timing is non-deterministic,
|
|
964
|
+
// but stop() should resolve without hanging)
|
|
965
|
+
});
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
- [ ] **Step 11: Add test — schema validation passes for valid artifact**
|
|
969
|
+
|
|
970
|
+
```typescript
|
|
971
|
+
it('GIVEN_valid_artifact_WHEN_schema_validation_runs_THEN_passes', async () => {
|
|
972
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
973
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
974
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
975
|
+
const provider = makeProvider([makeValidOrderingResponse()]);
|
|
976
|
+
const state = makeState();
|
|
977
|
+
|
|
978
|
+
const service = new OrganizerSidecarService({
|
|
979
|
+
provider,
|
|
980
|
+
organizerSessionId: () => 'org-1',
|
|
981
|
+
kernel: kernel as any,
|
|
982
|
+
state,
|
|
983
|
+
artifactPath,
|
|
984
|
+
schemaValidator: validator,
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
await (service as any).performReconcile();
|
|
988
|
+
|
|
989
|
+
expect(existsSync(artifactPath)).toBe(true);
|
|
990
|
+
const written = JSON.parse(await readFile(artifactPath, 'utf8'));
|
|
991
|
+
expect(validator(written)).toBe(true);
|
|
992
|
+
});
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
- [ ] **Step 12: Add test — invalid classification enum is rejected by schema**
|
|
996
|
+
|
|
997
|
+
```typescript
|
|
998
|
+
it('GIVEN_invalid_classification_enum_WHEN_schema_validation_runs_THEN_rejects', async () => {
|
|
999
|
+
const specPath = join(specDir, 'feat_a.md');
|
|
1000
|
+
await writeFile(specPath, '# Feature A spec', 'utf8');
|
|
1001
|
+
const kernel = makeKernel({ feat_a: specPath });
|
|
1002
|
+
// Both attempts return invalid classification
|
|
1003
|
+
const provider = makeProvider([
|
|
1004
|
+
makeInvalidClassificationResponse(),
|
|
1005
|
+
makeInvalidClassificationResponse(),
|
|
1006
|
+
]);
|
|
1007
|
+
const state = makeState();
|
|
1008
|
+
|
|
1009
|
+
const service = new OrganizerSidecarService({
|
|
1010
|
+
provider,
|
|
1011
|
+
organizerSessionId: () => 'org-1',
|
|
1012
|
+
kernel: kernel as any,
|
|
1013
|
+
state,
|
|
1014
|
+
artifactPath,
|
|
1015
|
+
schemaValidator: validator,
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
1019
|
+
await (service as any).performReconcile();
|
|
1020
|
+
|
|
1021
|
+
expect(existsSync(artifactPath)).toBe(false);
|
|
1022
|
+
warnSpy.mockRestore();
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
- [ ] **Step 13: Run the tests**
|
|
1028
|
+
|
|
1029
|
+
Run: `npx vitest run apps/control-plane/test/organizer-sidecar-service.spec.ts`
|
|
1030
|
+
Expected: All 11 tests pass.
|
|
1031
|
+
|
|
1032
|
+
- [ ] **Step 14: Commit**
|
|
1033
|
+
|
|
1034
|
+
```bash
|
|
1035
|
+
git add apps/control-plane/test/organizer-sidecar-service.spec.ts
|
|
1036
|
+
git commit -m "test: add unit tests for OrganizerSidecarService"
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
---
|
|
1040
|
+
|
|
1041
|
+
### Task 4: Wire Sidecar into SupervisorRuntime
|
|
1042
|
+
|
|
1043
|
+
**Files:**
|
|
1044
|
+
|
|
1045
|
+
- Modify: `apps/control-plane/src/supervisor/runtime.ts:937-966` (`resolveRoleSessionId`)
|
|
1046
|
+
- Modify: `apps/control-plane/src/supervisor/runtime.ts:243-267` (class fields)
|
|
1047
|
+
- Modify: `apps/control-plane/src/supervisor/runtime.ts:515-523` (scheduler wiring)
|
|
1048
|
+
- Modify: `apps/control-plane/src/supervisor/runtime.ts:633-640` (`start`/`stop`)
|
|
1049
|
+
|
|
1050
|
+
- [ ] **Step 1: Add import for OrganizerSidecarService**
|
|
1051
|
+
|
|
1052
|
+
In `apps/control-plane/src/supervisor/runtime.ts`, add to the imports (near line 25 where `OrganizerAgentEnrollmentScheduler` is imported):
|
|
1053
|
+
|
|
1054
|
+
```typescript
|
|
1055
|
+
import { OrganizerSidecarService } from './organizer-sidecar-service.js';
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
Also add the AJV import for schema compilation:
|
|
1059
|
+
|
|
1060
|
+
```typescript
|
|
1061
|
+
import Ajv2020Import from 'ajv/dist/2020.js';
|
|
1062
|
+
import type { ValidateFunction } from 'ajv';
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
And add a filesystem import for reading the schema:
|
|
1066
|
+
|
|
1067
|
+
```typescript
|
|
1068
|
+
import { readFileSync } from 'node:fs';
|
|
1069
|
+
import { fileURLToPath } from 'node:url';
|
|
1070
|
+
```
|
|
1071
|
+
|
|
1072
|
+
- [ ] **Step 2: Add organizer sidecar field to SupervisorRuntime class**
|
|
1073
|
+
|
|
1074
|
+
After the `executionEnrollmentService` field declaration (~line 263), add:
|
|
1075
|
+
|
|
1076
|
+
```typescript
|
|
1077
|
+
private readonly organizerSidecar: OrganizerSidecarService | null;
|
|
1078
|
+
```
|
|
1079
|
+
|
|
1080
|
+
- [ ] **Step 3: Instantiate sidecar in the constructor**
|
|
1081
|
+
|
|
1082
|
+
After the `executionEnrollmentService` instantiation (~line 530), add the sidecar creation:
|
|
1083
|
+
|
|
1084
|
+
```typescript
|
|
1085
|
+
if (organizerEnabled) {
|
|
1086
|
+
const sidecarSchemaPath = pathLayout.organizerOrderingSchemaPath();
|
|
1087
|
+
const sidecarValidator = this.compileOrganizerSchema(sidecarSchemaPath);
|
|
1088
|
+
this.organizerSidecar = new OrganizerSidecarService({
|
|
1089
|
+
provider: this.provider,
|
|
1090
|
+
organizerSessionId: () => this.state.organizerSessionId ?? null,
|
|
1091
|
+
kernel: this.kernel,
|
|
1092
|
+
state: this.state,
|
|
1093
|
+
artifactPath: pathLayout.organizerOrderingPath(this.state.ownerInstanceId),
|
|
1094
|
+
schemaValidator: sidecarValidator,
|
|
1095
|
+
});
|
|
1096
|
+
} else {
|
|
1097
|
+
this.organizerSidecar = null;
|
|
1098
|
+
}
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
Add a private helper method to compile the schema:
|
|
1102
|
+
|
|
1103
|
+
```typescript
|
|
1104
|
+
private compileOrganizerSchema(schemaPath: string): ValidateFunction {
|
|
1105
|
+
const Ajv2020Ctor = Ajv2020Import as unknown as new (
|
|
1106
|
+
opts: Record<string, unknown>,
|
|
1107
|
+
) => { compile(schema: Record<string, unknown>): ValidateFunction; addFormat(name: string, format: { type?: string; validate: (v: string) => boolean }): void };
|
|
1108
|
+
const ajv = new Ajv2020Ctor({ allErrors: true, strict: false });
|
|
1109
|
+
ajv.addFormat('date-time', {
|
|
1110
|
+
type: 'string',
|
|
1111
|
+
validate: (v: string) => !Number.isNaN(Date.parse(v)),
|
|
1112
|
+
});
|
|
1113
|
+
const schema = JSON.parse(readFileSync(schemaPath, 'utf8')) as Record<string, unknown>;
|
|
1114
|
+
return ajv.compile(schema);
|
|
1115
|
+
}
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
- [ ] **Step 4: Add `organizerOrderingSchemaPath()` to PathLayout**
|
|
1119
|
+
|
|
1120
|
+
In `apps/control-plane/src/core/path-layout.ts`, after `organizerOrderingPath()`:
|
|
1121
|
+
|
|
1122
|
+
```typescript
|
|
1123
|
+
organizerOrderingSchemaPath(): string {
|
|
1124
|
+
return path.join(this.legacyOrchestratorRoot, 'schemas', 'organizer-ordering-artifact.schema.json');
|
|
1125
|
+
}
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
- [ ] **Step 5: Add organizer to resolveRoleSessionId**
|
|
1129
|
+
|
|
1130
|
+
In `apps/control-plane/src/supervisor/runtime.ts`, in the `resolveRoleSessionId` method (~line 942), add after the reconciler case:
|
|
1131
|
+
|
|
1132
|
+
```typescript
|
|
1133
|
+
if (role === 'organizer') {
|
|
1134
|
+
return this.state.organizerSessionId ?? null;
|
|
1135
|
+
}
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
- [ ] **Step 6: Wire start/stop into run lifecycle**
|
|
1139
|
+
|
|
1140
|
+
Modify the `start()` method (~line 633):
|
|
1141
|
+
|
|
1142
|
+
```typescript
|
|
1143
|
+
async start(features: FeatureInput[]): Promise<Record<string, unknown>> {
|
|
1144
|
+
await this.executionEnrollmentService.start();
|
|
1145
|
+
this.organizerSidecar?.start();
|
|
1146
|
+
try {
|
|
1147
|
+
return await this.runCoordinator.start(features);
|
|
1148
|
+
} finally {
|
|
1149
|
+
await this.organizerSidecar?.stop();
|
|
1150
|
+
await this.executionEnrollmentService.stop();
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
- [ ] **Step 7: Verify compilation**
|
|
1156
|
+
|
|
1157
|
+
Run: `npx tsc --noEmit`
|
|
1158
|
+
Expected: Clean.
|
|
1159
|
+
|
|
1160
|
+
- [ ] **Step 8: Run full test suite**
|
|
1161
|
+
|
|
1162
|
+
Run: `npx vitest run`
|
|
1163
|
+
Expected: All tests pass (including new organizer-sidecar-service tests and existing supervisor tests).
|
|
1164
|
+
|
|
1165
|
+
- [ ] **Step 9: Commit**
|
|
1166
|
+
|
|
1167
|
+
```bash
|
|
1168
|
+
git add apps/control-plane/src/supervisor/runtime.ts apps/control-plane/src/supervisor/organizer-sidecar-service.ts apps/control-plane/src/core/path-layout.ts
|
|
1169
|
+
git commit -m "feat: wire OrganizerSidecarService into supervisor runtime lifecycle"
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
---
|
|
1173
|
+
|
|
1174
|
+
### Task 5: Update Existing Tests for Runtime Changes
|
|
1175
|
+
|
|
1176
|
+
**Files:**
|
|
1177
|
+
|
|
1178
|
+
- Modify: `apps/control-plane/test/supervisor.unit.spec.ts`
|
|
1179
|
+
|
|
1180
|
+
- [ ] **Step 1: Check if supervisor tests need updates**
|
|
1181
|
+
|
|
1182
|
+
Run: `npx vitest run apps/control-plane/test/supervisor.unit.spec.ts`
|
|
1183
|
+
|
|
1184
|
+
If tests fail due to the new `organizerSidecar` field or `resolveRoleSessionId` change, proceed to fix them. If all pass, skip to the commit step.
|
|
1185
|
+
|
|
1186
|
+
- [ ] **Step 2: Fix any failing supervisor tests**
|
|
1187
|
+
|
|
1188
|
+
Common fixes needed:
|
|
1189
|
+
|
|
1190
|
+
- If `resolveRoleSessionId` tests exist, add an `organizer` role test case
|
|
1191
|
+
- If runtime constructor tests exist, the mock may need `organizerOrderingSchemaPath` on `PathLayout`
|
|
1192
|
+
|
|
1193
|
+
- [ ] **Step 3: Run the full test suite**
|
|
1194
|
+
|
|
1195
|
+
Run: `npx vitest run`
|
|
1196
|
+
Expected: All tests pass.
|
|
1197
|
+
|
|
1198
|
+
- [ ] **Step 4: Run lint**
|
|
1199
|
+
|
|
1200
|
+
Run: `npm run lint`
|
|
1201
|
+
Expected: Clean.
|
|
1202
|
+
|
|
1203
|
+
- [ ] **Step 5: Commit**
|
|
1204
|
+
|
|
1205
|
+
```bash
|
|
1206
|
+
git add apps/control-plane/test/supervisor.unit.spec.ts
|
|
1207
|
+
git commit -m "test: update supervisor tests for organizer sidecar wiring"
|
|
1208
|
+
```
|
|
1209
|
+
|
|
1210
|
+
---
|
|
1211
|
+
|
|
1212
|
+
### Task 6: Final Verification & Progress Update
|
|
1213
|
+
|
|
1214
|
+
**Files:**
|
|
1215
|
+
|
|
1216
|
+
- Modify: `spec-files/progress.md`
|
|
1217
|
+
|
|
1218
|
+
- [ ] **Step 1: Run full test suite**
|
|
1219
|
+
|
|
1220
|
+
Run: `npx vitest run`
|
|
1221
|
+
Expected: All tests pass, >=90% coverage.
|
|
1222
|
+
|
|
1223
|
+
- [ ] **Step 2: Run typecheck**
|
|
1224
|
+
|
|
1225
|
+
Run: `npx tsc --noEmit`
|
|
1226
|
+
Expected: Clean.
|
|
1227
|
+
|
|
1228
|
+
- [ ] **Step 3: Run lint**
|
|
1229
|
+
|
|
1230
|
+
Run: `npm run lint`
|
|
1231
|
+
Expected: Clean.
|
|
1232
|
+
|
|
1233
|
+
- [ ] **Step 4: Verify organizer is opt-in**
|
|
1234
|
+
|
|
1235
|
+
Confirm that when `agents.yaml` does NOT have an organizer role, `organizerSidecar` is `null` and no `OrganizerSidecarService` is created. Check this by reading the conditional in `runtime.ts`.
|
|
1236
|
+
|
|
1237
|
+
- [ ] **Step 5: Update progress.md**
|
|
1238
|
+
|
|
1239
|
+
Append entries to `spec-files/progress.md`:
|
|
1240
|
+
|
|
1241
|
+
```markdown
|
|
1242
|
+
✅ **Entry N — Organizer System Prompt Enhancement**
|
|
1243
|
+
|
|
1244
|
+
- **Goal:** Add dependency detection signals section to teach the LLM how to identify dependencies.
|
|
1245
|
+
- **Changes made:**
|
|
1246
|
+
- `config/agentic/orchestrator/prompts/organizer.system.md` — added "Dependency detection signals" section with explicit, structural, semantic, and not-dependency subsections.
|
|
1247
|
+
- **Result:** Prompt file well-formed. `npm run lint` ✅.
|
|
1248
|
+
|
|
1249
|
+
✅ **Entry N+1 — OrganizerSidecarService Implementation**
|
|
1250
|
+
|
|
1251
|
+
- **Goal:** Implement Layer 1 runtime loop that polls for backlog changes, dispatches specs to organizer LLM, validates response, and writes ordering artifact atomically.
|
|
1252
|
+
- **Changes made:**
|
|
1253
|
+
- `apps/control-plane/src/supervisor/organizer-sidecar-service.ts` — new service with polling loop, spec collection from execution control + runtime state, prompt construction with size guard, response parsing with JSON extraction and AJV validation, retry on failure, atomic file write.
|
|
1254
|
+
- `apps/control-plane/test/organizer-sidecar-service.spec.ts` — 11 tests covering: fingerprint skip, LLM dispatch, artifact write, retry on malformed, persistent failure, no session, missing spec, size guard, stop lifecycle, schema validation pass, invalid enum rejection.
|
|
1255
|
+
- **Result:** `npm test` ✅. `npm run lint` ✅.
|
|
1256
|
+
|
|
1257
|
+
✅ **Entry N+2 — Wire Sidecar into Supervisor Runtime**
|
|
1258
|
+
|
|
1259
|
+
- **Goal:** Integrate OrganizerSidecarService into the supervisor lifecycle so it starts/stops with the run.
|
|
1260
|
+
- **Changes made:**
|
|
1261
|
+
- `apps/control-plane/src/supervisor/runtime.ts` — added sidecar field, conditional instantiation when organizer role configured, `start()`/`stop()` lifecycle wiring, `organizer` case in `resolveRoleSessionId()`, AJV schema compilation.
|
|
1262
|
+
- `apps/control-plane/src/core/path-layout.ts` — added `organizerOrderingSchemaPath()` method.
|
|
1263
|
+
- **Result:** `npm test` ✅. `npm run lint` ✅. `npm run typecheck` ✅.
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
- [ ] **Step 6: Commit progress update**
|
|
1267
|
+
|
|
1268
|
+
```bash
|
|
1269
|
+
git add spec-files/progress.md
|
|
1270
|
+
git commit -m "docs: update progress.md with organizer sidecar entries"
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
---
|
|
1274
|
+
|
|
1275
|
+
## Task Dependency Graph
|
|
1276
|
+
|
|
1277
|
+
```
|
|
1278
|
+
Task 1 (system prompt) ─────────────────────────────────┐
|
|
1279
|
+
Task 2 (service implementation) ──┬── Task 4 (wiring) ──┤
|
|
1280
|
+
Task 3 (unit tests) ─────────────┘ │ │
|
|
1281
|
+
Task 5 (test fixes) ─┤
|
|
1282
|
+
│
|
|
1283
|
+
Task 6 (verification) ┘
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
- Tasks 1, 2, 3 are independent and can run in parallel.
|
|
1287
|
+
- Task 4 depends on Task 2 (needs the service class to exist).
|
|
1288
|
+
- Task 5 depends on Task 4 (needs the wiring to exist to know what breaks).
|
|
1289
|
+
- Task 6 depends on all prior tasks.
|