agentic-orchestrator 0.1.6 → 0.1.8
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/.prettierignore +10 -0
- package/.prettierrc.json +24 -0
- package/CLAUDE.md +3 -2
- package/README.md +71 -48
- package/agentic/orchestrator/defaults/policy.defaults.yaml +1 -1
- package/agentic/orchestrator/prompts/planner.system.md +1 -0
- package/agentic/orchestrator/schemas/agents.schema.json +5 -22
- package/agentic/orchestrator/schemas/gates.schema.json +4 -19
- package/agentic/orchestrator/schemas/index.schema.json +3 -14
- package/agentic/orchestrator/schemas/multi-project.schema.json +2 -8
- package/agentic/orchestrator/schemas/plan.schema.json +6 -26
- package/agentic/orchestrator/schemas/policy.schema.json +19 -81
- package/agentic/orchestrator/schemas/policy.user.schema.json +1 -5
- package/agentic/orchestrator/schemas/qa_test_index.schema.json +5 -29
- package/agentic/orchestrator/schemas/state.schema.json +11 -61
- package/agentic/orchestrator/tools/catalog.json +33 -164
- package/agentic/orchestrator/tools/schemas/input/evidence.latest.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/feature.delete.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/feature.get_context.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/feature.init.input.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/input/feature.log_append.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/feature.ready_to_merge.input.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/input/feature.state_get.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/feature.state_patch.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/gates.run.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/locks.acquire.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/locks.release.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/performance.record_outcome.input.schema.json +10 -1
- package/agentic/orchestrator/tools/schemas/input/plan.get.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/plan.submit.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/plan.update.input.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/input/qa.test_index_get.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/qa.test_index_update.input.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/input/repo.apply_patch.input.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/input/repo.diff.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/repo.diff_bundle.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/repo.ensure_worktree.input.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/input/repo.read_file.input.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/input/repo.search.input.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/input/repo.status.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/input/report.feature_summary.input.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/output/collisions.scan.output.schema.json +1 -3
- package/agentic/orchestrator/tools/schemas/output/evidence.latest.output.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/output/feature.delete.output.schema.json +4 -20
- package/agentic/orchestrator/tools/schemas/output/feature.discover_specs.output.schema.json +2 -7
- package/agentic/orchestrator/tools/schemas/output/feature.get_context.output.schema.json +1 -8
- package/agentic/orchestrator/tools/schemas/output/feature.init.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/feature.log_append.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/output/feature.state_get.output.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/output/feature.state_patch.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/gates.list.output.schema.json +2 -7
- package/agentic/orchestrator/tools/schemas/output/gates.run.output.schema.json +1 -8
- package/agentic/orchestrator/tools/schemas/output/locks.acquire.output.schema.json +1 -7
- package/agentic/orchestrator/tools/schemas/output/locks.release.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/performance.get_analytics.output.schema.json +22 -2
- package/agentic/orchestrator/tools/schemas/output/plan.get.output.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/output/plan.submit.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/plan.update.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/qa.test_index_get.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/qa.test_index_update.output.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/output/repo.apply_patch.output.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/output/repo.diff.output.schema.json +1 -4
- package/agentic/orchestrator/tools/schemas/output/repo.diff_bundle.output.schema.json +1 -7
- package/agentic/orchestrator/tools/schemas/output/repo.ensure_worktree.output.schema.json +1 -6
- package/agentic/orchestrator/tools/schemas/output/repo.read_file.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/repo.search.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/repo.status.output.schema.json +1 -5
- package/agentic/orchestrator/tools/schemas/output/report.dashboard.output.schema.json +1 -4
- package/apps/control-plane/scripts/validate-architecture-rules.mjs +16 -5
- package/apps/control-plane/scripts/validate-docker-mcp-contract.mjs +30 -8
- package/apps/control-plane/scripts/validate-mcp-contracts.ts +13 -7
- package/apps/control-plane/src/application/adapters/adapter-registry.ts +35 -15
- package/apps/control-plane/src/application/multi-project-loader.ts +27 -10
- package/apps/control-plane/src/application/services/activity-monitor-service.ts +26 -14
- package/apps/control-plane/src/application/services/collision-queue-service.ts +31 -17
- package/apps/control-plane/src/application/services/cost-tracking-service.ts +23 -16
- package/apps/control-plane/src/application/services/dependency-scheduler-service.ts +12 -4
- package/apps/control-plane/src/application/services/feature-deletion-service.ts +94 -58
- package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +19 -13
- package/apps/control-plane/src/application/services/feature-state-service.ts +29 -19
- package/apps/control-plane/src/application/services/gate-interpolation-service.ts +7 -2
- package/apps/control-plane/src/application/services/gate-service.ts +64 -41
- package/apps/control-plane/src/application/services/instance-isolation-service.ts +1 -1
- package/apps/control-plane/src/application/services/issue-tracker-service.ts +49 -38
- package/apps/control-plane/src/application/services/lock-service.ts +75 -49
- package/apps/control-plane/src/application/services/merge-service.ts +91 -50
- package/apps/control-plane/src/application/services/notifier-service.ts +42 -20
- package/apps/control-plane/src/application/services/patch-service.ts +73 -44
- package/apps/control-plane/src/application/services/performance-analytics-service.ts +8 -6
- package/apps/control-plane/src/application/services/plan-service.ts +148 -89
- package/apps/control-plane/src/application/services/policy-loader-service.ts +10 -4
- package/apps/control-plane/src/application/services/pr-monitor-service.ts +33 -14
- package/apps/control-plane/src/application/services/qa-index-service.ts +20 -16
- package/apps/control-plane/src/application/services/reactions-service.ts +30 -15
- package/apps/control-plane/src/application/services/reporting-service.ts +16 -12
- package/apps/control-plane/src/application/services/run-lease-service.ts +138 -81
- package/apps/control-plane/src/application/tools/tool-metadata.ts +5 -5
- package/apps/control-plane/src/application/tools/tool-router.ts +6 -3
- package/apps/control-plane/src/cli/aop.ts +2 -2
- package/apps/control-plane/src/cli/attach-command-handler.ts +9 -9
- package/apps/control-plane/src/cli/cleanup-command-handler.ts +16 -11
- package/apps/control-plane/src/cli/cli-argument-parser.ts +6 -3
- package/apps/control-plane/src/cli/dashboard-command-handler.ts +28 -8
- package/apps/control-plane/src/cli/delete-command-handler.ts +7 -7
- package/apps/control-plane/src/cli/env-file.ts +115 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +61 -32
- package/apps/control-plane/src/cli/init-command-handler.ts +182 -56
- package/apps/control-plane/src/cli/io.ts +7 -3
- package/apps/control-plane/src/cli/resume-command-handler.ts +21 -13
- package/apps/control-plane/src/cli/retry-command-handler.ts +12 -11
- package/apps/control-plane/src/cli/run-command-handler.ts +12 -8
- package/apps/control-plane/src/cli/send-command-handler.ts +6 -6
- package/apps/control-plane/src/cli/spec-ingestion-service.ts +14 -8
- package/apps/control-plane/src/cli/spec-input-resolver.ts +6 -1
- package/apps/control-plane/src/cli/spec-utils.ts +2 -2
- package/apps/control-plane/src/cli/status-command-handler.ts +13 -12
- package/apps/control-plane/src/cli/tooling.ts +3 -3
- package/apps/control-plane/src/cli/types.ts +1 -1
- package/apps/control-plane/src/core/collisions.ts +27 -10
- package/apps/control-plane/src/core/constants.ts +13 -7
- package/apps/control-plane/src/core/error-codes.ts +1 -1
- package/apps/control-plane/src/core/fs.ts +11 -5
- package/apps/control-plane/src/core/gates.ts +53 -27
- package/apps/control-plane/src/core/git.ts +18 -6
- package/apps/control-plane/src/core/kernel.ts +513 -227
- package/apps/control-plane/src/core/patch.ts +7 -3
- package/apps/control-plane/src/core/path-layout.ts +5 -1
- package/apps/control-plane/src/core/path-rules.ts +19 -5
- package/apps/control-plane/src/core/qa-index.ts +26 -12
- package/apps/control-plane/src/core/response.ts +9 -6
- package/apps/control-plane/src/core/schemas.ts +29 -10
- package/apps/control-plane/src/core/tool-caller.ts +1 -1
- package/apps/control-plane/src/core/workspace-hooks.ts +5 -5
- package/apps/control-plane/src/index.ts +3 -9
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +79 -35
- package/apps/control-plane/src/mcp/kernel-tool-executor.ts +7 -3
- package/apps/control-plane/src/mcp/mcp-server-adapter.ts +12 -10
- package/apps/control-plane/src/mcp/operation-ledger.ts +18 -8
- package/apps/control-plane/src/mcp/protocol-contract.ts +2 -2
- package/apps/control-plane/src/mcp/runtime-factory.ts +15 -6
- package/apps/control-plane/src/mcp/token-auth-verifier.ts +3 -2
- package/apps/control-plane/src/mcp/token-claims-validator.ts +11 -7
- package/apps/control-plane/src/mcp/tool-authorizer.ts +1 -3
- package/apps/control-plane/src/mcp/tool-client.ts +17 -5
- package/apps/control-plane/src/mcp/tool-contract-validator.ts +17 -8
- package/apps/control-plane/src/mcp/tool-registry-loader.ts +7 -3
- package/apps/control-plane/src/mcp/tool-runtime.ts +66 -39
- package/apps/control-plane/src/mcp/tools-markdown-generator.ts +6 -1
- package/apps/control-plane/src/providers/providers.ts +137 -54
- package/apps/control-plane/src/supervisor/build-wave-executor.ts +44 -25
- package/apps/control-plane/src/supervisor/planning-wave-executor.ts +46 -33
- package/apps/control-plane/src/supervisor/prompt-bundle-loader.ts +1 -1
- package/apps/control-plane/src/supervisor/qa-wave-executor.ts +38 -23
- package/apps/control-plane/src/supervisor/run-coordinator.ts +71 -36
- package/apps/control-plane/src/supervisor/runtime.ts +59 -35
- package/apps/control-plane/src/supervisor/session-orchestrator.ts +48 -31
- package/apps/control-plane/src/supervisor/types.ts +22 -7
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +30 -20
- package/apps/control-plane/test/activity-monitor.spec.ts +54 -30
- package/apps/control-plane/test/adapter-registry.spec.ts +5 -5
- package/apps/control-plane/test/aop.spec.ts +4 -4
- package/apps/control-plane/test/batch-operations.spec.ts +20 -18
- package/apps/control-plane/test/bootstrap-attach.spec.ts +52 -19
- package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +58 -27
- package/apps/control-plane/test/bootstrap.spec.ts +72 -40
- package/apps/control-plane/test/cleanup-command.spec.ts +86 -32
- package/apps/control-plane/test/cli-helpers.spec.ts +119 -66
- package/apps/control-plane/test/cli.spec.ts +1 -1
- package/apps/control-plane/test/cli.unit.spec.ts +226 -167
- package/apps/control-plane/test/collision-queue.spec.ts +49 -40
- package/apps/control-plane/test/collisions.spec.ts +30 -30
- package/apps/control-plane/test/core-utils.spec.ts +29 -15
- package/apps/control-plane/test/cost-tracking.spec.ts +38 -22
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +68 -36
- package/apps/control-plane/test/dashboard-client.spec.ts +18 -12
- package/apps/control-plane/test/dashboard-command.spec.ts +11 -7
- package/apps/control-plane/test/delete-command-handler.spec.ts +49 -41
- package/apps/control-plane/test/dependency-scheduler.spec.ts +47 -20
- package/apps/control-plane/test/epoch-tracking.spec.ts +9 -9
- package/apps/control-plane/test/feature-deletion-service.spec.ts +60 -52
- package/apps/control-plane/test/feature-lifecycle.spec.ts +36 -17
- package/apps/control-plane/test/gates.spec.ts +101 -81
- package/apps/control-plane/test/git-spawn-error.spec.ts +1 -1
- package/apps/control-plane/test/helpers.ts +10 -6
- package/apps/control-plane/test/incremental-gates.spec.ts +59 -20
- package/apps/control-plane/test/init-wizard.spec.ts +328 -68
- package/apps/control-plane/test/instance-isolation.spec.ts +43 -10
- package/apps/control-plane/test/issue-tracker.spec.ts +368 -128
- package/apps/control-plane/test/kernel-collision-replay.spec.ts +50 -29
- package/apps/control-plane/test/kernel.branches.spec.ts +64 -40
- package/apps/control-plane/test/kernel.coverage.spec.ts +85 -49
- package/apps/control-plane/test/kernel.coverage2.spec.ts +109 -65
- package/apps/control-plane/test/kernel.spec.ts +134 -51
- package/apps/control-plane/test/lock-service.spec.ts +92 -68
- package/apps/control-plane/test/mcp-helpers.spec.ts +53 -39
- package/apps/control-plane/test/mcp.spec.ts +231 -115
- package/apps/control-plane/test/merge-service.spec.ts +142 -94
- package/apps/control-plane/test/multi-project.spec.ts +28 -22
- package/apps/control-plane/test/notifier-service.spec.ts +136 -92
- package/apps/control-plane/test/parallel-gates.spec.ts +51 -35
- package/apps/control-plane/test/patch-service.spec.ts +128 -48
- package/apps/control-plane/test/performance-analytics.spec.ts +99 -63
- package/apps/control-plane/test/plan-service.spec.ts +50 -39
- package/apps/control-plane/test/planning-wave-executor.spec.ts +95 -71
- package/apps/control-plane/test/policy-loader-service.spec.ts +41 -19
- package/apps/control-plane/test/pr-monitor.spec.ts +113 -64
- package/apps/control-plane/test/providers.spec.ts +208 -104
- package/apps/control-plane/test/qa-index-service.spec.ts +31 -33
- package/apps/control-plane/test/qa-index.spec.ts +58 -61
- package/apps/control-plane/test/reactions.spec.ts +88 -45
- package/apps/control-plane/test/response.spec.ts +5 -5
- package/apps/control-plane/test/resume-command.spec.ts +121 -80
- package/apps/control-plane/test/run-coordinator.spec.ts +205 -136
- package/apps/control-plane/test/schema-date-time.spec.ts +49 -41
- package/apps/control-plane/test/service-retry-paths.spec.ts +77 -57
- package/apps/control-plane/test/services.spec.ts +147 -129
- package/apps/control-plane/test/session-management.spec.ts +136 -74
- package/apps/control-plane/test/spec-ingestion.spec.ts +23 -21
- package/apps/control-plane/test/spec-input-resolver.spec.ts +11 -10
- package/apps/control-plane/test/supervisor-collaborators.spec.ts +168 -121
- package/apps/control-plane/test/supervisor.calltool.spec.ts +21 -18
- package/apps/control-plane/test/supervisor.spec.ts +67 -43
- package/apps/control-plane/test/supervisor.unit.spec.ts +195 -126
- package/apps/control-plane/test/token-auth-verifier.spec.ts +29 -14
- package/apps/control-plane/test/tool-registry-loader.spec.ts +51 -27
- package/apps/control-plane/test/tool-runtime.spec.ts +63 -46
- package/apps/control-plane/test/worker-decision-loop.spec.ts +143 -122
- package/apps/control-plane/test/workspace-hooks.spec.ts +61 -23
- package/apps/control-plane/tsconfig.build.json +2 -7
- package/apps/control-plane/tsconfig.json +1 -5
- package/apps/control-plane/vitest.config.ts +7 -7
- package/config/agentic/orchestrator/adapters.yaml +3 -0
- package/config/agentic/orchestrator/agents.yaml +14 -0
- package/config/agentic/orchestrator/gates.yaml +28 -0
- package/config/agentic/orchestrator/policy.yaml +22 -0
- package/config/agentic/orchestrator/prompts/builder.system.md +1 -0
- package/config/agentic/orchestrator/prompts/planner.system.md +16 -0
- package/config/agentic/orchestrator/prompts/qa.system.md +1 -0
- package/dist/apps/control-plane/application/adapters/adapter-registry.js +12 -5
- package/dist/apps/control-plane/application/adapters/adapter-registry.js.map +1 -1
- package/dist/apps/control-plane/application/multi-project-loader.js +26 -9
- package/dist/apps/control-plane/application/multi-project-loader.js.map +1 -1
- package/dist/apps/control-plane/application/services/activity-monitor-service.js +7 -7
- package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/collision-queue-service.js +7 -7
- package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/cost-tracking-service.js +6 -8
- package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/dependency-scheduler-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-deletion-service.js +37 -29
- package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +10 -10
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-state-service.js +11 -11
- package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/gate-interpolation-service.js +3 -1
- package/dist/apps/control-plane/application/services/gate-interpolation-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/gate-service.js +26 -26
- package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/instance-isolation-service.js +1 -1
- package/dist/apps/control-plane/application/services/instance-isolation-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/issue-tracker-service.js +25 -15
- package/dist/apps/control-plane/application/services/issue-tracker-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/lock-service.js +32 -32
- package/dist/apps/control-plane/application/services/lock-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/merge-service.js +41 -27
- package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/notifier-service.js +29 -15
- package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/patch-service.js +21 -19
- package/dist/apps/control-plane/application/services/patch-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/performance-analytics-service.js +4 -4
- package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/plan-service.js +33 -33
- package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/policy-loader-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/pr-monitor-service.js +23 -11
- package/dist/apps/control-plane/application/services/pr-monitor-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/qa-index-service.js +11 -11
- package/dist/apps/control-plane/application/services/qa-index-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/reactions-service.js +13 -9
- package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/reporting-service.js +11 -9
- package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/run-lease-service.js +34 -33
- package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
- package/dist/apps/control-plane/application/tools/tool-metadata.js +2 -2
- package/dist/apps/control-plane/application/tools/tool-router.js.map +1 -1
- package/dist/apps/control-plane/cli/attach-command-handler.js +9 -9
- package/dist/apps/control-plane/cli/cleanup-command-handler.js +11 -9
- package/dist/apps/control-plane/cli/cleanup-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/cli-argument-parser.js +4 -3
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/dashboard-command-handler.js +23 -7
- package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/delete-command-handler.js +7 -7
- package/dist/apps/control-plane/cli/env-file.d.ts +4 -0
- package/dist/apps/control-plane/cli/env-file.js +89 -0
- package/dist/apps/control-plane/cli/env-file.js.map +1 -0
- package/dist/apps/control-plane/cli/help-command-handler.js +58 -30
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +97 -37
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/io.js +2 -2
- package/dist/apps/control-plane/cli/io.js.map +1 -1
- package/dist/apps/control-plane/cli/resume-command-handler.js +9 -9
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-command-handler.js +12 -11
- package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/run-command-handler.js +12 -8
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/send-command-handler.js +6 -6
- package/dist/apps/control-plane/cli/spec-ingestion-service.js +10 -8
- package/dist/apps/control-plane/cli/spec-ingestion-service.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-input-resolver.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-utils.js.map +1 -1
- package/dist/apps/control-plane/cli/status-command-handler.js +8 -8
- package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/tooling.js +1 -1
- package/dist/apps/control-plane/core/collisions.js +11 -8
- package/dist/apps/control-plane/core/collisions.js.map +1 -1
- package/dist/apps/control-plane/core/constants.js +13 -7
- package/dist/apps/control-plane/core/constants.js.map +1 -1
- package/dist/apps/control-plane/core/error-codes.js +1 -1
- package/dist/apps/control-plane/core/fs.js.map +1 -1
- package/dist/apps/control-plane/core/gates.d.ts +2 -2
- package/dist/apps/control-plane/core/gates.js +26 -19
- package/dist/apps/control-plane/core/gates.js.map +1 -1
- package/dist/apps/control-plane/core/git.js +3 -3
- package/dist/apps/control-plane/core/git.js.map +1 -1
- package/dist/apps/control-plane/core/kernel.d.ts +1 -0
- package/dist/apps/control-plane/core/kernel.js +134 -81
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/patch.js +7 -3
- package/dist/apps/control-plane/core/patch.js.map +1 -1
- package/dist/apps/control-plane/core/path-layout.d.ts +1 -0
- package/dist/apps/control-plane/core/path-layout.js +4 -1
- package/dist/apps/control-plane/core/path-layout.js.map +1 -1
- package/dist/apps/control-plane/core/path-rules.js +3 -1
- package/dist/apps/control-plane/core/path-rules.js.map +1 -1
- package/dist/apps/control-plane/core/qa-index.js +5 -5
- package/dist/apps/control-plane/core/qa-index.js.map +1 -1
- package/dist/apps/control-plane/core/response.js +3 -3
- package/dist/apps/control-plane/core/response.js.map +1 -1
- package/dist/apps/control-plane/core/schemas.js +10 -6
- package/dist/apps/control-plane/core/schemas.js.map +1 -1
- package/dist/apps/control-plane/core/workspace-hooks.js +3 -3
- package/dist/apps/control-plane/index.d.ts +1 -1
- package/dist/apps/control-plane/index.js +1 -1
- package/dist/apps/control-plane/index.js.map +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +40 -23
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js +1 -1
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js.map +1 -1
- package/dist/apps/control-plane/mcp/mcp-server-adapter.js +6 -7
- package/dist/apps/control-plane/mcp/mcp-server-adapter.js.map +1 -1
- package/dist/apps/control-plane/mcp/operation-ledger.js +5 -5
- package/dist/apps/control-plane/mcp/operation-ledger.js.map +1 -1
- package/dist/apps/control-plane/mcp/protocol-contract.js +2 -2
- package/dist/apps/control-plane/mcp/runtime-factory.js +2 -2
- package/dist/apps/control-plane/mcp/runtime-factory.js.map +1 -1
- package/dist/apps/control-plane/mcp/token-auth-verifier.js +1 -1
- package/dist/apps/control-plane/mcp/token-auth-verifier.js.map +1 -1
- package/dist/apps/control-plane/mcp/token-claims-validator.js +5 -5
- package/dist/apps/control-plane/mcp/token-claims-validator.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-authorizer.js +1 -3
- package/dist/apps/control-plane/mcp/tool-authorizer.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-client.js +2 -2
- package/dist/apps/control-plane/mcp/tool-client.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-contract-validator.js +3 -3
- package/dist/apps/control-plane/mcp/tool-contract-validator.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-registry-loader.js +1 -1
- package/dist/apps/control-plane/mcp/tool-registry-loader.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-runtime.js +17 -17
- package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
- package/dist/apps/control-plane/mcp/tools-markdown-generator.js +6 -1
- package/dist/apps/control-plane/mcp/tools-markdown-generator.js.map +1 -1
- package/dist/apps/control-plane/providers/providers.d.ts +3 -2
- package/dist/apps/control-plane/providers/providers.js +81 -39
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/supervisor/build-wave-executor.js +12 -12
- package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js +19 -16
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js +13 -13
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.js +37 -20
- package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.js +25 -21
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/session-orchestrator.js +29 -23
- package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/types.d.ts +3 -3
- package/dist/apps/control-plane/supervisor/types.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +14 -16
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/eslint.config.mjs +20 -20
- package/example-configurations/README.md +1 -1
- package/example-configurations/java/agents.yaml +3 -3
- package/example-configurations/java/policy.yaml +1 -1
- package/example-configurations/node/agents.yaml +3 -3
- package/example-configurations/node/policy.yaml +1 -1
- package/package.json +10 -5
- package/packages/web-dashboard/next.config.js +2 -2
- package/packages/web-dashboard/src/app/api/actions/route.ts +25 -9
- package/packages/web-dashboard/src/app/api/events/route.ts +20 -6
- package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +88 -37
- package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +8 -5
- package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +27 -9
- package/packages/web-dashboard/src/app/api/features/[id]/route.ts +5 -2
- package/packages/web-dashboard/src/app/api/projects/route.ts +5 -5
- package/packages/web-dashboard/src/app/globals.css +10 -2
- package/packages/web-dashboard/src/app/page.tsx +100 -37
- package/packages/web-dashboard/src/lib/aop-client.ts +68 -37
- package/packages/web-dashboard/src/lib/multi-project-config.ts +28 -7
- package/packages/web-dashboard/src/lib/orchestrator-tools.ts +59 -36
- package/packages/web-dashboard/tsconfig.json +3 -11
- package/scripts/nx-safe.mjs +10 -10
- package/spec-files/completed/agentic_orchestrator_cli_delete_command_spec.md +5 -0
- package/spec-files/completed/agentic_orchestrator_feature_gaps_closure_spec.md +189 -90
- package/spec-files/completed/agentic_orchestrator_init_policy_ux_simplification_spec.md +49 -16
- package/spec-files/completed/agentic_orchestrator_mcp_formalization_spec.md +24 -1
- package/spec-files/completed/agentic_orchestrator_single_global_orchestrator_spec.md +9 -0
- package/spec-files/completed/agentic_orchestrator_spec.md +171 -75
- package/spec-files/completed/agentic_orchestrator_validator_hardening_spec.md +25 -17
- package/spec-files/outstanding/agentic_orchestrator_artifact_database_publishing_spec.md +40 -5
- package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +23 -12
- package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +16 -4
- package/spec-files/outstanding/agentic_orchestrator_observability_integrity_diagnostics_spec.md +42 -2
- package/spec-files/outstanding/agentic_orchestrator_performance_improvements_spec.md +209 -130
- package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +56 -3
- package/spec-files/outstanding/agentic_orchestrator_productization_commercial_spec.md +77 -10
- package/spec-files/outstanding/agentic_orchestrator_provider_auth_bootstrap_spec.md +384 -0
- package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +29 -14
- package/spec-files/progress.md +186 -175
- package/tsconfig.json +2 -8
|
@@ -38,20 +38,20 @@ All new and modified code MUST follow the testing standards already established
|
|
|
38
38
|
|
|
39
39
|
The following issues were identified in the v1.0 spec during architect review against the actual codebase. Each issue is assigned a severity and cross-references the task where it is resolved.
|
|
40
40
|
|
|
41
|
-
| #
|
|
42
|
-
|
|
43
|
-
| A-1
|
|
44
|
-
| A-2
|
|
45
|
-
| A-3
|
|
46
|
-
| A-4
|
|
47
|
-
| A-5
|
|
48
|
-
| A-6
|
|
49
|
-
| A-7
|
|
50
|
-
| A-8
|
|
51
|
-
| A-9
|
|
52
|
-
| A-10 | **MEDIUM**
|
|
53
|
-
| A-11 | **MEDIUM**
|
|
54
|
-
| A-12 | **LOW**
|
|
41
|
+
| # | Severity | Issue | Resolution |
|
|
42
|
+
| ---- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| A-1 | **CRITICAL** | **`latest.json` does not exist.** Finding I-5 and PER-T-005/006 claim `gates.ts:430` writes a `latest.json` sentinel. The actual code at line 429–430 writes `latest-${mode}.json` (e.g., `latest-fast.json`). PER-T-005's fix of reading `path.join(evidenceDir, 'latest.json')` would always return null, silently breaking `featureGetContext` for all agent roles. PER-T-006's pruning filter `f !== 'latest.json'` would delete all mode-specific sentinels. | PER-T-005 now writes a canonical `latest.json` in `gates.ts` alongside the per-mode sentinel; PER-T-006 pruning filter excludes `latest-*.json` patterns. |
|
|
44
|
+
| A-2 | **CRITICAL** | **PER-T-003 is a write-ordering behavioral change.** The v1.0 fix eliminates the sequential `for` loop (lines 41–52) and moves `workerDecisionRunner.execute()` into the parallel `executing` map. `workerDecisionRunner.execute()` for the builder role can call PATCH_APPLY, LOCK_ACQUIRE, and PLAN_UPDATE — all writes to shared state. Making these concurrent violates §0.2. | PER-T-003 is redesigned as a **context-capture Map pattern**: the sequential loop is preserved; context is stored in a Map and reused by the parallel executing map, eliminating the duplicate fetch without changing write ordering. |
|
|
45
|
+
| A-3 | **CRITICAL** | **PER-T-003 reused pre-decision context for repair loop.** After `workerDecisionRunner.execute()` applies patches (changing working-tree state) and potentially acquires or releases locks (mutating `state.md`), the captured pre-decision context is stale. The repair loop needs fresh state to give agents accurate `locks.held` data. | PER-T-003 redesign fetches repair context as a fresh call after gate failure, which is the minimal re-fetch (one call per failure, not one per retry). |
|
|
46
|
+
| A-4 | **HIGH** | **Coverage thresholds wrong.** §0.1 specified Lines ≥70%, Branches ≥70%, Functions ≥85%. CLAUDE.md mandates 90% on all metrics. Implementing to v1.0 thresholds would pass spec-level gates but fail CI. | §0.1 corrected to 90% everywhere. |
|
|
47
|
+
| A-5 | **HIGH** | **`normalizeSet` extraction incomplete.** PER-T-013 identified 4 files but the codebase has 7 copies: `reporting-service.ts`, `merge-service.ts`, `feature-lifecycle-service.ts`, `feature-deletion-service.ts`, `kernel.ts`, `lock-service.ts`, `plan-service.ts`. Leaving 3 copies behind is worse than a partial refactor because it creates a false sense of completeness. | PER-T-013 scope expanded to all 7 files. |
|
|
48
|
+
| A-6 | **HIGH** | **§0.2 constraint conflict with PER-T-008.** §0.2 stated "Input/output schemas for all 33 MCP tools remain unchanged." PER-T-008 adds an optional `role` parameter to `feature.get_context`. These directly contradict each other; §4 item 6 tried to paper over this by calling it "backward-compatible." | §0.2 amended to "no breaking changes" with explicit allowance for backward-compatible optional input additions. |
|
|
49
|
+
| A-7 | **HIGH** | **Output schema implicit shape change in PER-T-008.** When `role=builder`, `qa_test_index` in the response payload becomes `{summary}` instead of the full object. The tool's output JSON schema doesn't account for this. Validators would fail at runtime when trying to validate the projected payload against the existing schema. | PER-T-008 adds a note that the existing output schema validates the `full` projection only; partial projections bypass output schema validation and return raw AOP objects. |
|
|
50
|
+
| A-8 | **MEDIUM** | **`QaIndexRecord` type undefined.** PER-T-009 uses `QaIndexRecord` as a type in `projectQaIndex` but this type does not exist in the codebase. No import path is given. | PER-T-009 defines a local `QaIndexSnapshot` interface inline and derives the projection from `AnyRecord`. |
|
|
51
|
+
| A-9 | **MEDIUM** | **Projection table vs implementation inconsistency.** PER-T-008 table shows QA role gets `summary + failed + pending` from `qa_test_index`, but PER-T-009 code returns `{ passed: _omitted, ...rest }` — all fields except `passed`, including `running`, `flaky`, etc. The table and code must agree. | PER-T-009 implementation updated to return only `{ summary, failed, pending }` for QA role, matching the table. |
|
|
52
|
+
| A-10 | **MEDIUM** | **`schema_version` guard requires manual discipline.** PER-T-011 relies on developers remembering to bump `CURRENT_INDEX_SCHEMA_VERSION` when `normalizeIndexShape` changes shape. If forgotten, stale indices never migrate and the performance optimization yields incorrect behavior. | PER-T-011 adds a mandatory developer protocol note with a co-located integration test that detects shape drift. |
|
|
53
|
+
| A-11 | **MEDIUM** | **PER-T-007 leaves planning context fetches sequential.** After pre-filtering with `FEATURE_STATE_GET`, the full context fetches for `planningFeatureIds` remain sequential in a `for` loop. Parallelizing these fetches extends the savings from PER-T-001's parallel-reads principle. | PER-T-007 updated to use `Promise.all` for the planning context fetches; `runPostQaReconciliation` pre-filter is fully specified with concrete code. |
|
|
54
|
+
| A-12 | **LOW** | **`gate-service.spec.ts` does not exist.** PER-T-005 says "add cases to `gate-service.spec.ts` (create if not existing)" — should be explicit. | PER-T-005 updated to say "create `gate-service.spec.ts`." |
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -143,6 +143,7 @@ The dashboard loop reads `state.md` and the cost JSON file for each feature one
|
|
|
143
143
|
On every `featureGetContext` call, `evidenceLatest` lists the entire evidence directory, calls `fs.stat()` on every `.json` file to read mtimes, sorts by mtime, then reads the newest file.
|
|
144
144
|
|
|
145
145
|
`gates.ts:429–430` already writes a per-mode sentinel file on every gate run:
|
|
146
|
+
|
|
146
147
|
```typescript
|
|
147
148
|
const latestPath = path.join(evidenceDirectory, `latest-${mode}.json`);
|
|
148
149
|
await fs.writeFile(latestPath, `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
|
|
@@ -228,12 +229,12 @@ Every gate run appends a new timestamped JSON file to `.aop/features/<id>/eviden
|
|
|
228
229
|
|
|
229
230
|
The context bundle returned to every agent role includes the complete QA test index (all test records, including passed), the full gate evidence JSON (verbose stdout/stderr), and the complete state frontmatter (all historical lock, gate, and PR metadata). A feature with 200 tests and 50 gate retry cycles produces a bundle exceeding 80–100 KB — roughly 20,000–25,000 tokens per agent invocation.
|
|
230
231
|
|
|
231
|
-
| Field
|
|
232
|
-
|
|
233
|
-
| `qa_test_index`
|
|
234
|
-
| `latest_evidence`
|
|
235
|
-
| `state.front_matter` | All historical locks/gates/PR metadata — agents need current status + held locks
|
|
236
|
-
| `plan`
|
|
232
|
+
| Field | Problem |
|
|
233
|
+
| -------------------- | ------------------------------------------------------------------------------------- |
|
|
234
|
+
| `qa_test_index` | All test records including passed — agents only need `summary` + `failed` + `pending` |
|
|
235
|
+
| `latest_evidence` | Full verbose gate output — agents need overall result + top failing steps |
|
|
236
|
+
| `state.front_matter` | All historical locks/gates/PR metadata — agents need current status + held locks |
|
|
237
|
+
| `plan` | Full plan when builder/QA roles only need current-phase tasks |
|
|
237
238
|
|
|
238
239
|
---
|
|
239
240
|
|
|
@@ -263,24 +264,24 @@ See Finding I-8. The structural fix (hoist above the loop) also ensures prompts
|
|
|
263
264
|
|
|
264
265
|
### 2.4 Complete Findings Table
|
|
265
266
|
|
|
266
|
-
| ID
|
|
267
|
-
|
|
268
|
-
| I-1 | `feature-lifecycle-service.ts`
|
|
269
|
-
| I-2 | `build-wave-executor.ts`
|
|
270
|
-
| I-3 | `build-wave-executor.ts`, `qa-wave-executor.ts`
|
|
271
|
-
| I-4 | `reporting-service.ts`
|
|
272
|
-
| I-5 | `gate-service.ts`
|
|
273
|
-
| I-6 | `kernel.ts`
|
|
274
|
-
| I-7 | `reporting-service.ts`
|
|
275
|
-
| I-8 | `qa-wave-executor.ts`
|
|
276
|
-
| M-1 | 7 service/core files
|
|
277
|
-
| M-2 | `planning-wave-executor.ts`
|
|
278
|
-
| M-3 | `run-coordinator.ts`
|
|
279
|
-
| M-4 | `core/gates.ts`
|
|
280
|
-
| C-1 | `feature-lifecycle-service.ts`
|
|
281
|
-
| C-2 | `planning-wave-executor.ts`
|
|
282
|
-
| C-3 | `planning-wave-executor.ts`
|
|
283
|
-
| C-4 | `qa-wave-executor.ts`, `prompt-bundle-loader.ts` | 196, 15–52
|
|
267
|
+
| ID | File | Lines | Severity | Category | Task |
|
|
268
|
+
| --- | ------------------------------------------------ | ------------ | -------- | -------- | -------------------- |
|
|
269
|
+
| I-1 | `feature-lifecycle-service.ts` | 142–146 | HIGH | I/O | PER-T-001 |
|
|
270
|
+
| I-2 | `build-wave-executor.ts` | 42, 95 | HIGH | I/O | PER-T-003 |
|
|
271
|
+
| I-3 | `build-wave-executor.ts`, `qa-wave-executor.ts` | 30–38, 54–62 | HIGH | I/O | PER-T-002 |
|
|
272
|
+
| I-4 | `reporting-service.ts` | 81–108 | MEDIUM | I/O | PER-T-004 |
|
|
273
|
+
| I-5 | `gate-service.ts` | 236–256 | MEDIUM | I/O | PER-T-005 |
|
|
274
|
+
| I-6 | `kernel.ts` | 758 | MEDIUM | CPU | PER-T-011 |
|
|
275
|
+
| I-7 | `reporting-service.ts` | 40–68 | MEDIUM | CPU/I/O | Deferred |
|
|
276
|
+
| I-8 | `qa-wave-executor.ts` | 196 | LOW | I/O | PER-T-014 |
|
|
277
|
+
| M-1 | 7 service/core files | various | LOW | Memory | PER-T-013 |
|
|
278
|
+
| M-2 | `planning-wave-executor.ts` | 298 | LOW | Memory | PER-T-012 |
|
|
279
|
+
| M-3 | `run-coordinator.ts` | 61–62, 272 | MEDIUM | Memory | PER-T-010 |
|
|
280
|
+
| M-4 | `core/gates.ts` | 427–430 | HIGH | Disk | PER-T-006 |
|
|
281
|
+
| C-1 | `feature-lifecycle-service.ts` | 132–158 | HIGH | Context | PER-T-008, PER-T-009 |
|
|
282
|
+
| C-2 | `planning-wave-executor.ts` | 125–133 | MEDIUM | Context | PER-T-007 |
|
|
283
|
+
| C-3 | `planning-wave-executor.ts` | 313 | LOW | Context | Deferred |
|
|
284
|
+
| C-4 | `qa-wave-executor.ts`, `prompt-bundle-loader.ts` | 196, 15–52 | LOW | Context | PER-T-014 |
|
|
284
285
|
|
|
285
286
|
---
|
|
286
287
|
|
|
@@ -299,29 +300,33 @@ See Finding I-8. The structural fix (hoist above the loop) also ensures prompts
|
|
|
299
300
|
**Lines:** 142–146
|
|
300
301
|
|
|
301
302
|
**Before:**
|
|
303
|
+
|
|
302
304
|
```typescript
|
|
303
|
-
const state
|
|
304
|
-
const plan
|
|
305
|
-
const qaIndex
|
|
305
|
+
const state = await this.port.featureStateGet(featureId);
|
|
306
|
+
const plan = await this.port.planGet(featureId);
|
|
307
|
+
const qaIndex = await this.port.qaTestIndexGet(featureId);
|
|
306
308
|
const evidence = await this.port.evidenceLatest(featureId);
|
|
307
309
|
const specText = await fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => '');
|
|
308
310
|
```
|
|
309
311
|
|
|
310
312
|
**After:**
|
|
313
|
+
|
|
311
314
|
```typescript
|
|
312
315
|
const [state, plan, qaIndex, evidence, specText] = await Promise.all([
|
|
313
316
|
this.port.featureStateGet(featureId),
|
|
314
317
|
this.port.planGet(featureId),
|
|
315
318
|
this.port.qaTestIndexGet(featureId),
|
|
316
319
|
this.port.evidenceLatest(featureId),
|
|
317
|
-
fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => '')
|
|
320
|
+
fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => ''),
|
|
318
321
|
]);
|
|
319
322
|
```
|
|
320
323
|
|
|
321
324
|
**Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
|
|
325
|
+
|
|
322
326
|
- `GIVEN_featureGetContext_WHEN_called_THEN_all_reads_are_parallel` — assert each port method is called exactly once and all are called before any result is consumed.
|
|
323
327
|
|
|
324
328
|
**Acceptance criteria:**
|
|
329
|
+
|
|
325
330
|
1. `featureGetContext` returns identical output before and after.
|
|
326
331
|
2. All five port method spies are called; the individual calls are non-ordered.
|
|
327
332
|
3. A single I/O error in any one read propagates as a rejected promise (existing behavior).
|
|
@@ -332,16 +337,22 @@ const [state, plan, qaIndex, evidence, specText] = await Promise.all([
|
|
|
332
337
|
|
|
333
338
|
**Fixes:** Finding I-3
|
|
334
339
|
**Files:**
|
|
340
|
+
|
|
335
341
|
- `apps/control-plane/src/supervisor/build-wave-executor.ts` (lines 30–38)
|
|
336
342
|
- `apps/control-plane/src/supervisor/qa-wave-executor.ts` (lines 54–62)
|
|
337
343
|
|
|
338
344
|
**Before (BuildWaveExecutor):**
|
|
345
|
+
|
|
339
346
|
```typescript
|
|
340
347
|
const batch: string[] = [];
|
|
341
348
|
for (const featureId of featureIds) {
|
|
342
|
-
const state = await this.toolCaller.callTool<FeatureStatePayload>(
|
|
343
|
-
|
|
344
|
-
|
|
349
|
+
const state = await this.toolCaller.callTool<FeatureStatePayload>(
|
|
350
|
+
'builder',
|
|
351
|
+
TOOLS.FEATURE_STATE_GET,
|
|
352
|
+
{
|
|
353
|
+
feature_id: featureId,
|
|
354
|
+
},
|
|
355
|
+
);
|
|
345
356
|
if (state.data.front_matter.status === STATUS.BUILDING) {
|
|
346
357
|
batch.push(featureId);
|
|
347
358
|
}
|
|
@@ -349,13 +360,14 @@ for (const featureId of featureIds) {
|
|
|
349
360
|
```
|
|
350
361
|
|
|
351
362
|
**After (BuildWaveExecutor):**
|
|
363
|
+
|
|
352
364
|
```typescript
|
|
353
365
|
const states = await Promise.all(
|
|
354
366
|
featureIds.map((featureId) =>
|
|
355
367
|
this.toolCaller.callTool<FeatureStatePayload>('builder', TOOLS.FEATURE_STATE_GET, {
|
|
356
|
-
feature_id: featureId
|
|
357
|
-
})
|
|
358
|
-
)
|
|
368
|
+
feature_id: featureId,
|
|
369
|
+
}),
|
|
370
|
+
),
|
|
359
371
|
);
|
|
360
372
|
const batch = featureIds.filter((_, i) => states[i].data.front_matter.status === STATUS.BUILDING);
|
|
361
373
|
```
|
|
@@ -363,10 +375,12 @@ const batch = featureIds.filter((_, i) => states[i].data.front_matter.status ===
|
|
|
363
375
|
Apply the same transformation to `QaWaveExecutor` substituting role `'qa'` and status `STATUS.QA`.
|
|
364
376
|
|
|
365
377
|
**Tests to write:** `apps/control-plane/test/batch-operations.spec.ts` (existing — add cases)
|
|
378
|
+
|
|
366
379
|
- `GIVEN_BuildWaveExecutor_run_WHEN_multiple_features_THEN_state_reads_are_parallel`
|
|
367
380
|
- `GIVEN_QaWaveExecutor_run_WHEN_multiple_features_THEN_state_reads_are_parallel`
|
|
368
381
|
|
|
369
382
|
**Acceptance criteria:**
|
|
383
|
+
|
|
370
384
|
1. Identical `batch` array produced before and after (same filter logic, same contents).
|
|
371
385
|
2. All `FEATURE_STATE_GET` calls are issued concurrently (spy call ordering is non-sequential).
|
|
372
386
|
3. `selected` slice behavior (`batch.slice(0, maxParallelGateRuns)`) is unchanged.
|
|
@@ -382,6 +396,7 @@ Apply the same transformation to `QaWaveExecutor` substituting role `'qa'` and s
|
|
|
382
396
|
**Design rationale:** The sequential `for` loop at lines 41–52 MUST remain sequential (§0.2) because `workerDecisionRunner.execute()` can call write-producing tools (PATCH_APPLY, LOCK_ACQUIRE). The duplicate fetch at line 95 is eliminated by capturing each feature's context in a Map during the sequential phase, then looking it up in the parallel phase for the repair loop. The repair-loop context is still re-fetched once per feature on gate failure (not once per retry as it was before) to capture any state changes from the initial decision. This reduces the duplicate from O(retries) to O(1) on the failure path.
|
|
383
397
|
|
|
384
398
|
**Before:**
|
|
399
|
+
|
|
385
400
|
```typescript
|
|
386
401
|
// Sequential loop (lines 41–52): initial worker decision
|
|
387
402
|
for (const featureId of selected) {
|
|
@@ -409,27 +424,32 @@ const executing = selected.map(async (featureId) => {
|
|
|
409
424
|
```
|
|
410
425
|
|
|
411
426
|
**After:**
|
|
427
|
+
|
|
412
428
|
```typescript
|
|
413
429
|
// Phase 1: Sequential — initial worker decisions (write ordering preserved)
|
|
414
430
|
const preDecisionContextByFeature = new Map<string, unknown>();
|
|
415
431
|
for (const featureId of selected) {
|
|
416
432
|
const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
|
|
417
|
-
feature_id: featureId
|
|
433
|
+
feature_id: featureId,
|
|
418
434
|
});
|
|
419
435
|
preDecisionContextByFeature.set(featureId, context.data);
|
|
420
436
|
await this.workerDecisionRunner.execute({
|
|
421
437
|
role: 'builder',
|
|
422
438
|
featureId,
|
|
423
439
|
contextBundle: context.data,
|
|
424
|
-
instructions: '...'
|
|
440
|
+
instructions: '...',
|
|
425
441
|
});
|
|
426
442
|
}
|
|
427
443
|
|
|
428
444
|
// Phase 2: Parallel — gate runs and repair
|
|
429
445
|
const executing = selected.map(async (featureId) => {
|
|
430
|
-
const stateForRetry = await this.toolCaller.callTool<FeatureStatePayload>(
|
|
431
|
-
|
|
432
|
-
|
|
446
|
+
const stateForRetry = await this.toolCaller.callTool<FeatureStatePayload>(
|
|
447
|
+
'builder',
|
|
448
|
+
TOOLS.FEATURE_STATE_GET,
|
|
449
|
+
{
|
|
450
|
+
feature_id: featureId,
|
|
451
|
+
},
|
|
452
|
+
);
|
|
433
453
|
const initialRetryCount = stateForRetry.data.front_matter.gate_retry_count ?? 0;
|
|
434
454
|
|
|
435
455
|
// ... gate run (unchanged) ...
|
|
@@ -440,7 +460,7 @@ const executing = selected.map(async (featureId) => {
|
|
|
440
460
|
// This is one fetch per failing feature — eliminates the per-retry fetch
|
|
441
461
|
// that occurred in the v1.0 repair loop.
|
|
442
462
|
const repairContext = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
|
|
443
|
-
feature_id: featureId
|
|
463
|
+
feature_id: featureId,
|
|
444
464
|
});
|
|
445
465
|
let retryCount = initialRetryCount;
|
|
446
466
|
while (this.reactionsService.shouldRetry(featureId, retryCount)) {
|
|
@@ -449,7 +469,7 @@ const executing = selected.map(async (featureId) => {
|
|
|
449
469
|
role: 'builder',
|
|
450
470
|
featureId,
|
|
451
471
|
contextBundle: repairContext.data,
|
|
452
|
-
instructions: repairPrompt
|
|
472
|
+
instructions: repairPrompt,
|
|
453
473
|
});
|
|
454
474
|
// ... gate re-run, retryCount increment ...
|
|
455
475
|
}
|
|
@@ -461,11 +481,13 @@ await Promise.allSettled(executing);
|
|
|
461
481
|
**Rationale for still re-fetching on gate failure:** After `workerDecisionRunner.execute()` in Phase 1, the feature may have acquired locks or had patches applied, mutating `state.md`. The repair loop needs `locks.held` to be accurate to avoid incorrect lock-conflict decisions. The re-fetch is gated on `gateOverall === GATE_RESULT.FAIL` — on the fast-path (gate passes), no additional context fetch occurs at all.
|
|
462
482
|
|
|
463
483
|
**Tests to write:** `apps/control-plane/test/batch-operations.spec.ts`
|
|
484
|
+
|
|
464
485
|
- `GIVEN_BuildWaveExecutor_gate_passes_WHEN_run_THEN_FEATURE_GET_CONTEXT_called_exactly_once_per_feature`
|
|
465
486
|
- `GIVEN_BuildWaveExecutor_gate_fails_WHEN_run_THEN_FEATURE_GET_CONTEXT_called_twice_per_failing_feature`
|
|
466
487
|
- `GIVEN_BuildWaveExecutor_multiple_retries_WHEN_gate_fails_THEN_repair_context_not_re_fetched_per_retry`
|
|
467
488
|
|
|
468
489
|
**Acceptance criteria:**
|
|
490
|
+
|
|
469
491
|
1. When gate passes, `FEATURE_GET_CONTEXT` is called exactly once per feature per `run()` invocation.
|
|
470
492
|
2. When gate fails, `FEATURE_GET_CONTEXT` is called exactly twice per failing feature: once in Phase 1 (pre-decision), once in Phase 2 (repair context) — never per retry.
|
|
471
493
|
3. Sequential write ordering of `workerDecisionRunner.execute()` across features is preserved.
|
|
@@ -480,6 +502,7 @@ await Promise.allSettled(executing);
|
|
|
480
502
|
**Lines:** 81–108
|
|
481
503
|
|
|
482
504
|
**Before:**
|
|
505
|
+
|
|
483
506
|
```typescript
|
|
484
507
|
const features = [];
|
|
485
508
|
for (const featureId of featureIds) {
|
|
@@ -494,6 +517,7 @@ for (const featureId of featureIds) {
|
|
|
494
517
|
```
|
|
495
518
|
|
|
496
519
|
**After:**
|
|
520
|
+
|
|
497
521
|
```typescript
|
|
498
522
|
const features = (
|
|
499
523
|
await Promise.all(
|
|
@@ -504,16 +528,20 @@ const features = (
|
|
|
504
528
|
}
|
|
505
529
|
const [state, costData] = await Promise.all([
|
|
506
530
|
this.port.readState(featureId),
|
|
507
|
-
readJson<{ estimated_cost_usd: number; tokens_used: number }>(
|
|
531
|
+
readJson<{ estimated_cost_usd: number; tokens_used: number }>(
|
|
532
|
+
this.port.featureCostPath(featureId),
|
|
533
|
+
null,
|
|
534
|
+
),
|
|
508
535
|
]);
|
|
509
536
|
return {
|
|
510
537
|
feature_id: featureId,
|
|
511
538
|
status: state.frontMatter.status,
|
|
512
|
-
branch:
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
539
|
+
branch:
|
|
540
|
+
typeof state.frontMatter.worktree_branch === 'string'
|
|
541
|
+
? state.frontMatter.worktree_branch
|
|
542
|
+
: typeof state.frontMatter.branch === 'string'
|
|
543
|
+
? state.frontMatter.branch
|
|
544
|
+
: null,
|
|
517
545
|
locks: readHeldLocks(state.frontMatter),
|
|
518
546
|
gate_profile: state.frontMatter.gate_profile,
|
|
519
547
|
gates: state.frontMatter.gates,
|
|
@@ -524,18 +552,20 @@ const features = (
|
|
|
524
552
|
activity_detected_via: state.frontMatter.activity_detected_via,
|
|
525
553
|
cost: costData
|
|
526
554
|
? { estimated_cost_usd: costData.estimated_cost_usd, tokens_used: costData.tokens_used }
|
|
527
|
-
: null
|
|
555
|
+
: null,
|
|
528
556
|
};
|
|
529
|
-
})
|
|
557
|
+
}),
|
|
530
558
|
)
|
|
531
559
|
).filter((entry): entry is NonNullable<typeof entry> => entry !== null);
|
|
532
560
|
```
|
|
533
561
|
|
|
534
562
|
**Tests to write:** `apps/control-plane/test/services.spec.ts` (existing) — add cases:
|
|
563
|
+
|
|
535
564
|
- `GIVEN_reportDashboard_WHEN_multiple_features_exist_THEN_reads_are_parallel`
|
|
536
565
|
- `GIVEN_reportDashboard_WHEN_state_file_missing_THEN_feature_is_omitted`
|
|
537
566
|
|
|
538
567
|
**Acceptance criteria:**
|
|
568
|
+
|
|
539
569
|
1. Returned `features` array contains identical entries in the same order as before.
|
|
540
570
|
2. Features without a state file are omitted from output (unchanged behavior).
|
|
541
571
|
3. `readState` and `readJson` (cost) are called in parallel per feature.
|
|
@@ -552,10 +582,12 @@ const features = (
|
|
|
552
582
|
|
|
553
583
|
**Fixes:** Finding I-5
|
|
554
584
|
**Files:**
|
|
585
|
+
|
|
555
586
|
- `apps/control-plane/src/core/gates.ts` (add canonical sentinel write)
|
|
556
587
|
- `apps/control-plane/src/application/services/gate-service.ts` (read sentinel directly)
|
|
557
588
|
|
|
558
589
|
**Context:** `gates.ts:427–430` currently writes two files per gate run:
|
|
590
|
+
|
|
559
591
|
- `gate-${mode}-${Date.now()}.json` — the timestamped archive record
|
|
560
592
|
- `latest-${mode}.json` — a per-mode sentinel (e.g., `latest-fast.json`, `latest-full.json`)
|
|
561
593
|
|
|
@@ -564,6 +596,7 @@ const features = (
|
|
|
564
596
|
**Fix:** Add a third write in `gates.ts` — a canonical `latest.json` — updated after every gate run regardless of mode. This is the single O(1) read target for `evidenceLatest`.
|
|
565
597
|
|
|
566
598
|
**Change to `gates.ts`** (after line 430):
|
|
599
|
+
|
|
567
600
|
```typescript
|
|
568
601
|
// Existing:
|
|
569
602
|
const evidencePath = path.join(evidenceDirectory, `gate-${mode}-${Date.now()}.json`);
|
|
@@ -577,6 +610,7 @@ await fs.writeFile(latestPath, `${JSON.stringify(evidence, null, 2)}\n`, 'utf8')
|
|
|
577
610
|
```
|
|
578
611
|
|
|
579
612
|
**Change to `gate-service.ts` `evidenceLatest`** — replace O(N) scan:
|
|
613
|
+
|
|
580
614
|
```typescript
|
|
581
615
|
// Before (O(N) stat scan):
|
|
582
616
|
const files = (await fs.readdir(evidenceDir))
|
|
@@ -594,12 +628,13 @@ return {
|
|
|
594
628
|
data: {
|
|
595
629
|
feature_id: featureId,
|
|
596
630
|
latest,
|
|
597
|
-
path: normalizeRepoPathForState(repoRoot, latestPath)
|
|
598
|
-
}
|
|
631
|
+
path: normalizeRepoPathForState(repoRoot, latestPath),
|
|
632
|
+
},
|
|
599
633
|
};
|
|
600
634
|
```
|
|
601
635
|
|
|
602
636
|
**Tests to write:** Create `apps/control-plane/test/gate-service.spec.ts`
|
|
637
|
+
|
|
603
638
|
- `GIVEN_evidenceLatest_WHEN_latest_json_exists_THEN_returns_its_contents`
|
|
604
639
|
- `GIVEN_evidenceLatest_WHEN_no_evidence_dir_exists_THEN_returns_null`
|
|
605
640
|
- `GIVEN_evidenceLatest_WHEN_latest_json_missing_THEN_returns_null`
|
|
@@ -607,6 +642,7 @@ return {
|
|
|
607
642
|
- `GIVEN_gates_run_WHEN_gate_completes_THEN_latest_json_matches_per_mode_sentinel`
|
|
608
643
|
|
|
609
644
|
**Acceptance criteria:**
|
|
645
|
+
|
|
610
646
|
1. `evidenceLatest` reads only `latest.json`; no `readdir` or `stat` calls.
|
|
611
647
|
2. Return shape `{ data: { feature_id, latest, path? } }` is identical to the existing interface.
|
|
612
648
|
3. `gates.ts` writes `latest.json` after every gate run; its content equals the evidence object.
|
|
@@ -619,20 +655,23 @@ return {
|
|
|
619
655
|
|
|
620
656
|
**Fixes:** Finding M-4
|
|
621
657
|
**Files:**
|
|
658
|
+
|
|
622
659
|
- `agentic/orchestrator/policy.yaml` — add `evidence_retention_count` field
|
|
623
660
|
- `agentic/orchestrator/defaults/policy.defaults.yaml` — add default value
|
|
624
661
|
- `agentic/orchestrator/schemas/policy.schema.json` — add field to `cleanup` object
|
|
625
662
|
- `apps/control-plane/src/core/gates.ts` — prune after writing new evidence file
|
|
626
663
|
|
|
627
664
|
**Policy change (`policy.yaml`):**
|
|
665
|
+
|
|
628
666
|
```yaml
|
|
629
667
|
cleanup:
|
|
630
668
|
grace_period_seconds: 300
|
|
631
669
|
auto_after_merge: true
|
|
632
|
-
evidence_retention_count: 10
|
|
670
|
+
evidence_retention_count: 10 # NEW: keep the N most recent timestamped evidence files per feature
|
|
633
671
|
```
|
|
634
672
|
|
|
635
673
|
**Schema change (`schemas/policy.schema.json`):** Add to the `cleanup` object properties:
|
|
674
|
+
|
|
636
675
|
```json
|
|
637
676
|
"evidence_retention_count": {
|
|
638
677
|
"type": "integer",
|
|
@@ -644,6 +683,7 @@ cleanup:
|
|
|
644
683
|
```
|
|
645
684
|
|
|
646
685
|
**Implementation in `gates.ts`** — after writing all three evidence files, add pruning:
|
|
686
|
+
|
|
647
687
|
```typescript
|
|
648
688
|
await pruneEvidenceFiles(evidenceDir, retentionCount);
|
|
649
689
|
|
|
@@ -666,12 +706,14 @@ async function pruneEvidenceFiles(dir: string, keep: number): Promise<void> {
|
|
|
666
706
|
The `retentionCount` value is read from the policy snapshot, defaulting to `10` if absent.
|
|
667
707
|
|
|
668
708
|
**Tests to write:** `apps/control-plane/test/incremental-gates.spec.ts` (existing) — add cases:
|
|
709
|
+
|
|
669
710
|
- `GIVEN_pruneEvidenceFiles_WHEN_archived_count_exceeds_retention_THEN_oldest_are_deleted`
|
|
670
711
|
- `GIVEN_pruneEvidenceFiles_WHEN_archived_count_within_retention_THEN_nothing_deleted`
|
|
671
712
|
- `GIVEN_pruneEvidenceFiles_WHEN_latest_json_present_THEN_it_is_never_pruned`
|
|
672
713
|
- `GIVEN_pruneEvidenceFiles_WHEN_latest_mode_sentinels_present_THEN_they_are_never_pruned`
|
|
673
714
|
|
|
674
715
|
**Acceptance criteria:**
|
|
716
|
+
|
|
675
717
|
1. After every gate run, the evidence directory contains at most `evidence_retention_count` timestamped `gate-*.json` files.
|
|
676
718
|
2. `latest.json` is never deleted by pruning.
|
|
677
719
|
3. `latest-${mode}.json` sentinel files (e.g., `latest-fast.json`) are never deleted by pruning.
|
|
@@ -694,6 +736,7 @@ The `retentionCount` value is read from the policy snapshot, defaulting to `10`
|
|
|
694
736
|
**Lines:** 124–153 (`run`) and 156–228 (`runPostQaReconciliation`)
|
|
695
737
|
|
|
696
738
|
**Before (`run`):**
|
|
739
|
+
|
|
697
740
|
```typescript
|
|
698
741
|
async run(featureIds: string[]): Promise<void> {
|
|
699
742
|
for (const featureId of featureIds) {
|
|
@@ -710,6 +753,7 @@ async run(featureIds: string[]): Promise<void> {
|
|
|
710
753
|
```
|
|
711
754
|
|
|
712
755
|
**After (`run`):**
|
|
756
|
+
|
|
713
757
|
```typescript
|
|
714
758
|
async run(featureIds: string[]): Promise<void> {
|
|
715
759
|
// Phase 1: Batch-fetch lightweight state in parallel to identify planning features
|
|
@@ -745,6 +789,7 @@ async run(featureIds: string[]): Promise<void> {
|
|
|
745
789
|
```
|
|
746
790
|
|
|
747
791
|
**Before (`runPostQaReconciliation`):**
|
|
792
|
+
|
|
748
793
|
```typescript
|
|
749
794
|
async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<void> {
|
|
750
795
|
for (const featureId of featureIds) {
|
|
@@ -762,6 +807,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
|
|
|
762
807
|
```
|
|
763
808
|
|
|
764
809
|
**After (`runPostQaReconciliation`):**
|
|
810
|
+
|
|
765
811
|
```typescript
|
|
766
812
|
async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<void> {
|
|
767
813
|
// Phase 1: Batch-fetch state in parallel to identify post-QA features
|
|
@@ -798,6 +844,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
|
|
|
798
844
|
```
|
|
799
845
|
|
|
800
846
|
**Tests to write:** `apps/control-plane/test/planning-wave-executor.spec.ts` (existing — add cases)
|
|
847
|
+
|
|
801
848
|
- `GIVEN_run_WHEN_features_not_in_planning_status_THEN_FEATURE_GET_CONTEXT_not_called`
|
|
802
849
|
- `GIVEN_run_WHEN_features_in_planning_THEN_FEATURE_GET_CONTEXT_called_only_for_those`
|
|
803
850
|
- `GIVEN_run_WHEN_multiple_planning_features_THEN_context_fetches_are_parallel`
|
|
@@ -805,6 +852,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
|
|
|
805
852
|
- `GIVEN_runPostQaReconciliation_WHEN_post_qa_features_exist_THEN_context_fetches_are_parallel`
|
|
806
853
|
|
|
807
854
|
**Acceptance criteria:**
|
|
855
|
+
|
|
808
856
|
1. `FEATURE_GET_CONTEXT` is never called for features not in `PLANNING` or `BLOCKED` status (in `run`).
|
|
809
857
|
2. `FEATURE_GET_CONTEXT` is never called for features not in a post-QA status (in `runPostQaReconciliation`).
|
|
810
858
|
3. `FEATURE_STATE_GET` batch calls are issued in parallel.
|
|
@@ -817,6 +865,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
|
|
|
817
865
|
|
|
818
866
|
**Fixes:** Finding C-1
|
|
819
867
|
**Files:**
|
|
868
|
+
|
|
820
869
|
- `apps/control-plane/src/application/services/feature-lifecycle-service.ts`
|
|
821
870
|
- `agentic/orchestrator/tools/schemas/input/feature.get_context.input.schema.json` (add optional `role` field)
|
|
822
871
|
|
|
@@ -838,14 +887,14 @@ Add an optional `role` parameter to the existing `feature.get_context` input sch
|
|
|
838
887
|
|
|
839
888
|
**Context projections by role:**
|
|
840
889
|
|
|
841
|
-
| Field
|
|
842
|
-
|
|
843
|
-
| `feature_id`
|
|
844
|
-
| `spec`
|
|
845
|
-
| `state.front_matter` | full
|
|
846
|
-
| `plan`
|
|
847
|
-
| `qa_test_index`
|
|
848
|
-
| `latest_evidence`
|
|
890
|
+
| Field | `full` | `planner` | `builder` | `qa` |
|
|
891
|
+
| -------------------- | ------ | ---------------------- | ----------------------------------------------------- | ---------------------------------------------------- |
|
|
892
|
+
| `feature_id` | ✓ | ✓ | ✓ | ✓ |
|
|
893
|
+
| `spec` | full | full | trimmed to 8 KB | trimmed to 4 KB |
|
|
894
|
+
| `state.front_matter` | full | full | `{ status, branch, locks.held, gates, gate_profile }` | `{ status, branch, gates, gate_profile }` |
|
|
895
|
+
| `plan` | full | full | `{ tasks (current phase only), acceptance_criteria }` | `{ acceptance_criteria, risk }` |
|
|
896
|
+
| `qa_test_index` | full | `{ summary }` | `{ summary }` | `{ summary, failed, pending }` (no `passed`) |
|
|
897
|
+
| `latest_evidence` | full | `{ overall, profile }` | `{ overall, profile, failed_steps[0..4] }` | `{ overall, profile, failed_steps[0..9], coverage }` |
|
|
849
898
|
|
|
850
899
|
**Implementation in `FeatureLifecycleService`:**
|
|
851
900
|
|
|
@@ -886,15 +935,17 @@ const specBudgetByRole: Record<string, number> = {
|
|
|
886
935
|
```
|
|
887
936
|
|
|
888
937
|
Wave executors pass their role when calling context:
|
|
938
|
+
|
|
889
939
|
```typescript
|
|
890
940
|
// BuildWaveExecutor
|
|
891
941
|
const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
|
|
892
942
|
feature_id: featureId,
|
|
893
|
-
role: 'builder'
|
|
943
|
+
role: 'builder', // NEW
|
|
894
944
|
});
|
|
895
945
|
```
|
|
896
946
|
|
|
897
947
|
**Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
|
|
948
|
+
|
|
898
949
|
- `GIVEN_featureGetContext_with_role_builder_WHEN_called_THEN_qa_index_is_summary_only`
|
|
899
950
|
- `GIVEN_featureGetContext_with_role_qa_WHEN_called_THEN_passed_tests_are_omitted`
|
|
900
951
|
- `GIVEN_featureGetContext_with_role_planner_WHEN_called_THEN_state_is_projected`
|
|
@@ -902,6 +953,7 @@ const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONT
|
|
|
902
953
|
- `GIVEN_featureGetContext_no_role_WHEN_called_THEN_bundle_is_unchanged` (backward compat)
|
|
903
954
|
|
|
904
955
|
**Acceptance criteria:**
|
|
956
|
+
|
|
905
957
|
1. `role: 'full'` (and omitting `role`) returns the existing complete bundle — no regression for callers that do not pass a role.
|
|
906
958
|
2. `role: 'builder'` returns `{ summary }` only for `qa_test_index`; `latest_evidence` includes at most 5 `failed_steps`.
|
|
907
959
|
3. `role: 'qa'` returns `{ summary, failed, pending }` for `qa_test_index` (no `passed`); `latest_evidence` includes at most 10 `failed_steps` plus `coverage`.
|
|
@@ -930,7 +982,7 @@ interface QaIndexSnapshot {
|
|
|
930
982
|
|
|
931
983
|
export function projectQaIndex(
|
|
932
984
|
qaIndex: QaIndexSnapshot,
|
|
933
|
-
role: 'full' | 'planner' | 'builder' | 'qa'
|
|
985
|
+
role: 'full' | 'planner' | 'builder' | 'qa',
|
|
934
986
|
): Partial<QaIndexSnapshot> {
|
|
935
987
|
if (role === 'full') return qaIndex;
|
|
936
988
|
if (role === 'planner' || role === 'builder') return { summary: qaIndex.summary };
|
|
@@ -938,13 +990,13 @@ export function projectQaIndex(
|
|
|
938
990
|
return {
|
|
939
991
|
summary: qaIndex.summary,
|
|
940
992
|
failed: qaIndex.failed,
|
|
941
|
-
pending: qaIndex.pending
|
|
993
|
+
pending: qaIndex.pending,
|
|
942
994
|
};
|
|
943
995
|
}
|
|
944
996
|
|
|
945
997
|
export function projectEvidence(
|
|
946
998
|
evidence: AnyRecord | null,
|
|
947
|
-
role: 'full' | 'planner' | 'builder' | 'qa'
|
|
999
|
+
role: 'full' | 'planner' | 'builder' | 'qa',
|
|
948
1000
|
): AnyRecord | null {
|
|
949
1001
|
if (!evidence || role === 'full') return evidence;
|
|
950
1002
|
if (role === 'planner') return { overall: evidence.overall, profile: evidence.profile };
|
|
@@ -956,16 +1008,20 @@ export function projectEvidence(
|
|
|
956
1008
|
overall: evidence.overall,
|
|
957
1009
|
profile: evidence.profile,
|
|
958
1010
|
failed_steps: failedSteps,
|
|
959
|
-
...(role === 'qa' ? { coverage: evidence.coverage } : {})
|
|
1011
|
+
...(role === 'qa' ? { coverage: evidence.coverage } : {}),
|
|
960
1012
|
};
|
|
961
1013
|
}
|
|
962
1014
|
|
|
963
|
-
export function projectState(
|
|
1015
|
+
export function projectState(
|
|
1016
|
+
stateData: AnyRecord,
|
|
1017
|
+
role: 'full' | 'planner' | 'builder' | 'qa',
|
|
1018
|
+
): AnyRecord {
|
|
964
1019
|
if (role === 'full' || role === 'planner') return stateData;
|
|
965
1020
|
const fm = stateData.front_matter ?? {};
|
|
966
|
-
const includedFields: (keyof typeof fm)[] =
|
|
967
|
-
|
|
968
|
-
|
|
1021
|
+
const includedFields: (keyof typeof fm)[] =
|
|
1022
|
+
role === 'builder'
|
|
1023
|
+
? ['status', 'branch', 'worktree_branch', 'locks', 'gates', 'gate_profile']
|
|
1024
|
+
: ['status', 'branch', 'worktree_branch', 'gates', 'gate_profile'];
|
|
969
1025
|
const projected: AnyRecord = {};
|
|
970
1026
|
for (const field of includedFields) {
|
|
971
1027
|
if (field in fm) projected[field] = fm[field];
|
|
@@ -980,6 +1036,7 @@ export function trimSpec(spec: string, budgetBytes: number): string {
|
|
|
980
1036
|
```
|
|
981
1037
|
|
|
982
1038
|
**Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
|
|
1039
|
+
|
|
983
1040
|
- `GIVEN_projectQaIndex_role_qa_WHEN_index_has_passed_tests_THEN_passed_is_omitted`
|
|
984
1041
|
- `GIVEN_projectQaIndex_role_qa_WHEN_index_has_running_field_THEN_running_is_omitted`
|
|
985
1042
|
- `GIVEN_projectQaIndex_role_full_WHEN_called_THEN_index_is_unchanged`
|
|
@@ -1008,24 +1065,26 @@ export function trimSpec(spec: string, budgetBytes: number): string {
|
|
|
1008
1065
|
When `closeFeatureCluster(featureId)` is called for a terminal-status feature, the corresponding `statusCache` entry is never deleted. Over a long run processing hundreds of features, the Map accumulates dead entries indefinitely.
|
|
1009
1066
|
|
|
1010
1067
|
**Before:**
|
|
1068
|
+
|
|
1011
1069
|
```typescript
|
|
1012
1070
|
for (const featureId of sortedCurrent) {
|
|
1013
1071
|
const status = await this.readFeatureStatus(featureId);
|
|
1014
1072
|
if (status && RunCoordinator.TERMINAL_STATUSES.has(status)) {
|
|
1015
1073
|
await this.sessionOrchestrator.closeFeatureCluster(featureId);
|
|
1016
|
-
continue;
|
|
1074
|
+
continue; // cache entry remains
|
|
1017
1075
|
}
|
|
1018
1076
|
survivingActiveFeatureIds.push(featureId);
|
|
1019
1077
|
}
|
|
1020
1078
|
```
|
|
1021
1079
|
|
|
1022
1080
|
**After:**
|
|
1081
|
+
|
|
1023
1082
|
```typescript
|
|
1024
1083
|
for (const featureId of sortedCurrent) {
|
|
1025
1084
|
const status = await this.readFeatureStatus(featureId);
|
|
1026
1085
|
if (status && RunCoordinator.TERMINAL_STATUSES.has(status)) {
|
|
1027
1086
|
await this.sessionOrchestrator.closeFeatureCluster(featureId);
|
|
1028
|
-
this.statusCache.delete(featureId);
|
|
1087
|
+
this.statusCache.delete(featureId); // NEW: evict dead entry
|
|
1029
1088
|
continue;
|
|
1030
1089
|
}
|
|
1031
1090
|
survivingActiveFeatureIds.push(featureId);
|
|
@@ -1035,10 +1094,12 @@ for (const featureId of sortedCurrent) {
|
|
|
1035
1094
|
Apply the same eviction in the queue-drain loop (lines 193–207) where features popped from `this.state.queue` are found to already be terminal.
|
|
1036
1095
|
|
|
1037
1096
|
**Tests to write:** `apps/control-plane/test/run-coordinator.spec.ts` (existing — add case)
|
|
1097
|
+
|
|
1038
1098
|
- `GIVEN_rebalanceActiveFeatures_WHEN_feature_reaches_terminal_status_THEN_statusCache_entry_is_evicted`
|
|
1039
1099
|
- `GIVEN_rebalanceActiveFeatures_WHEN_queue_feature_is_terminal_THEN_statusCache_entry_is_evicted`
|
|
1040
1100
|
|
|
1041
1101
|
**Acceptance criteria:**
|
|
1102
|
+
|
|
1042
1103
|
1. After `closeFeatureCluster` is called for a terminal feature, `statusCache.has(featureId)` returns `false`.
|
|
1043
1104
|
2. `notifyStatusTransitions` is unaffected — it reads `statusCache` only for currently active features.
|
|
1044
1105
|
3. No change to orchestration loop behavior or status transition notification logic.
|
|
@@ -1049,12 +1110,14 @@ Apply the same eviction in the queue-drain loop (lines 193–207) where features
|
|
|
1049
1110
|
|
|
1050
1111
|
**Fixes:** Finding I-6
|
|
1051
1112
|
**Files:**
|
|
1113
|
+
|
|
1052
1114
|
- `apps/control-plane/src/core/kernel.ts` (lines 755–763)
|
|
1053
1115
|
- `agentic/orchestrator/schemas/index.schema.json` (add optional `schema_version` field)
|
|
1054
1116
|
|
|
1055
1117
|
`readIndex` serializes the entire index (20–50 KB) twice on every call just to detect whether schema migration is needed — a cold-path concern paid on every hot-path read.
|
|
1056
1118
|
|
|
1057
1119
|
**Current behavior:**
|
|
1120
|
+
|
|
1058
1121
|
```typescript
|
|
1059
1122
|
const changed = JSON.stringify(existing ?? null) !== JSON.stringify(normalized);
|
|
1060
1123
|
if (changed) {
|
|
@@ -1090,12 +1153,14 @@ async readIndex(): Promise<AnyRecord> {
|
|
|
1090
1153
|
**Shape-drift detection test:** Add a test that calls `normalizeIndexShape` with the current `CURRENT_INDEX_SCHEMA_VERSION` and asserts that the output's `schema_version` equals it. If a developer changes `normalizeIndexShape` without bumping the constant, the test will still pass — but if they also change what `normalizeIndexShape` produces (e.g., new field), the test ensures the constant is documented in context. Add a comment in the test: `// If this test fails, increment CURRENT_INDEX_SCHEMA_VERSION in kernel.ts`.
|
|
1091
1154
|
|
|
1092
1155
|
**Tests to write:** `apps/control-plane/test/kernel.spec.ts` (existing — add cases)
|
|
1156
|
+
|
|
1093
1157
|
- `GIVEN_readIndex_WHEN_schema_version_matches_THEN_normalizeIndexShape_not_called`
|
|
1094
1158
|
- `GIVEN_readIndex_WHEN_schema_version_absent_THEN_migration_runs_and_writes_file`
|
|
1095
1159
|
- `GIVEN_readIndex_WHEN_index_is_null_THEN_migration_runs`
|
|
1096
1160
|
- `GIVEN_normalizeIndexShape_WHEN_called_THEN_schema_version_equals_current_constant` (shape-drift guard)
|
|
1097
1161
|
|
|
1098
1162
|
**Acceptance criteria:**
|
|
1163
|
+
|
|
1099
1164
|
1. When the on-disk index has the current `schema_version`, `normalizeIndexShape` is not called and no write occurs.
|
|
1100
1165
|
2. When the field is absent (legacy index), normalization and re-write happen exactly once.
|
|
1101
1166
|
3. The `schema_version` field is included in `index.schema.json` as an optional integer and validates correctly.
|
|
@@ -1113,6 +1178,7 @@ async readIndex(): Promise<AnyRecord> {
|
|
|
1113
1178
|
`structuredClone` serializes the entire plan object graph for a mutation that only touches five top-level fields. Since those fields are scalars or wholly replaced arrays, a shallow spread is sufficient and does not risk mutating the original.
|
|
1114
1179
|
|
|
1115
1180
|
**Before:**
|
|
1181
|
+
|
|
1116
1182
|
```typescript
|
|
1117
1183
|
private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: ReconciliationDecision): AnyRecord {
|
|
1118
1184
|
const nextPlan = structuredClone(plan);
|
|
@@ -1129,6 +1195,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
|
|
|
1129
1195
|
```
|
|
1130
1196
|
|
|
1131
1197
|
**After:**
|
|
1198
|
+
|
|
1132
1199
|
```typescript
|
|
1133
1200
|
private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: ReconciliationDecision): AnyRecord {
|
|
1134
1201
|
return {
|
|
@@ -1146,10 +1213,12 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
|
|
|
1146
1213
|
```
|
|
1147
1214
|
|
|
1148
1215
|
**Tests to write:** `apps/control-plane/test/planning-wave-executor.spec.ts` (existing — add cases)
|
|
1216
|
+
|
|
1149
1217
|
- `GIVEN_buildUpdatedPlan_WHEN_called_THEN_original_plan_is_not_mutated`
|
|
1150
1218
|
- `GIVEN_buildUpdatedPlan_WHEN_called_THEN_only_mutated_fields_change`
|
|
1151
1219
|
|
|
1152
1220
|
**Acceptance criteria:**
|
|
1221
|
+
|
|
1153
1222
|
1. Returned plan object has all fields from the original plan plus the five updated fields.
|
|
1154
1223
|
2. The original `plan` argument is not mutated.
|
|
1155
1224
|
3. `structuredClone` is not called.
|
|
@@ -1161,6 +1230,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
|
|
|
1161
1230
|
|
|
1162
1231
|
**Fixes:** Finding M-1
|
|
1163
1232
|
**Files:**
|
|
1233
|
+
|
|
1164
1234
|
- **Create:** `apps/control-plane/src/core/utils.ts`
|
|
1165
1235
|
- **Refactor** (replace local definition, add import):
|
|
1166
1236
|
- `apps/control-plane/src/core/kernel.ts`
|
|
@@ -1174,6 +1244,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
|
|
|
1174
1244
|
**Note:** The v1.0 spec missed `kernel.ts`, `lock-service.ts`, and `plan-service.ts`. All 7 files must be updated in this task for the extraction to be complete.
|
|
1175
1245
|
|
|
1176
1246
|
Add to `apps/control-plane/src/core/utils.ts`:
|
|
1247
|
+
|
|
1177
1248
|
```typescript
|
|
1178
1249
|
/** Deduplicate and sort a string array. Stable across key order. */
|
|
1179
1250
|
export function normalizeSet(array: string[]): string[] {
|
|
@@ -1182,21 +1253,25 @@ export function normalizeSet(array: string[]): string[] {
|
|
|
1182
1253
|
```
|
|
1183
1254
|
|
|
1184
1255
|
In each of the seven files, remove the local definition and add:
|
|
1256
|
+
|
|
1185
1257
|
```typescript
|
|
1186
|
-
import { normalizeSet } from '../../core/utils.js';
|
|
1258
|
+
import { normalizeSet } from '../../core/utils.js'; // adjust relative path per file
|
|
1187
1259
|
```
|
|
1188
1260
|
|
|
1189
1261
|
For `kernel.ts` the import is:
|
|
1262
|
+
|
|
1190
1263
|
```typescript
|
|
1191
1264
|
import { normalizeSet } from './utils.js';
|
|
1192
1265
|
```
|
|
1193
1266
|
|
|
1194
1267
|
**Tests to write:** `apps/control-plane/test/core-utils.spec.ts` (existing — add cases)
|
|
1268
|
+
|
|
1195
1269
|
- `GIVEN_normalizeSet_WHEN_array_has_duplicates_THEN_deduplicates`
|
|
1196
1270
|
- `GIVEN_normalizeSet_WHEN_array_is_unsorted_THEN_sorts_lexicographically`
|
|
1197
1271
|
- `GIVEN_normalizeSet_WHEN_empty_array_THEN_returns_empty`
|
|
1198
1272
|
|
|
1199
1273
|
**Acceptance criteria:**
|
|
1274
|
+
|
|
1200
1275
|
1. All seven files import from `core/utils.js`; no local `normalizeSet` definitions remain anywhere in the codebase.
|
|
1201
1276
|
2. Behavior is identical to the seven previous implementations (same Set deduplication, same `localeCompare` sort).
|
|
1202
1277
|
3. No existing tests fail.
|
|
@@ -1213,18 +1288,20 @@ import { normalizeSet } from './utils.js';
|
|
|
1213
1288
|
`loadRolePrompts()` is called once per feature inside the QA batch loop. The `PromptBundleLoader` cache makes subsequent calls cheap, but the placement is structurally fragile — cache invalidation silently causes per-feature file I/O.
|
|
1214
1289
|
|
|
1215
1290
|
**Before:**
|
|
1291
|
+
|
|
1216
1292
|
```typescript
|
|
1217
1293
|
for (const featureId of batch.slice(0, maxParallelGateRuns)) {
|
|
1218
1294
|
// ... gate run logic ...
|
|
1219
|
-
const prompts = await this.promptProvider.loadRolePrompts();
|
|
1295
|
+
const prompts = await this.promptProvider.loadRolePrompts(); // INSIDE LOOP
|
|
1220
1296
|
const newQa = await this.provider.createSession('qa', featureId, prompts.qa);
|
|
1221
1297
|
// ...
|
|
1222
1298
|
}
|
|
1223
1299
|
```
|
|
1224
1300
|
|
|
1225
1301
|
**After:**
|
|
1302
|
+
|
|
1226
1303
|
```typescript
|
|
1227
|
-
const prompts = await this.promptProvider.loadRolePrompts();
|
|
1304
|
+
const prompts = await this.promptProvider.loadRolePrompts(); // OUTSIDE LOOP
|
|
1228
1305
|
|
|
1229
1306
|
for (const featureId of batch.slice(0, maxParallelGateRuns)) {
|
|
1230
1307
|
// ... gate run logic ...
|
|
@@ -1234,9 +1311,11 @@ for (const featureId of batch.slice(0, maxParallelGateRuns)) {
|
|
|
1234
1311
|
```
|
|
1235
1312
|
|
|
1236
1313
|
**Tests to write:** `apps/control-plane/test/session-management.spec.ts` (existing — add case)
|
|
1314
|
+
|
|
1237
1315
|
- `GIVEN_QaWaveExecutor_run_WHEN_multiple_features_in_batch_THEN_loadRolePrompts_called_once`
|
|
1238
1316
|
|
|
1239
1317
|
**Acceptance criteria:**
|
|
1318
|
+
|
|
1240
1319
|
1. `loadRolePrompts` is called exactly once per `run()` invocation regardless of batch size.
|
|
1241
1320
|
2. The same `prompts` object is used for all session creations in the batch.
|
|
1242
1321
|
3. QA session rotation behavior is unchanged.
|
|
@@ -1257,37 +1336,37 @@ for (const featureId of batch.slice(0, maxParallelGateRuns)) {
|
|
|
1257
1336
|
|
|
1258
1337
|
## 5. Risks and Mitigations
|
|
1259
1338
|
|
|
1260
|
-
| Risk
|
|
1261
|
-
|
|
1262
|
-
| `Promise.all` parallelism exposes hidden race conditions in test mocks | Add ordering assertions in tests; use `vi.fn()` with explicit mock return sequences
|
|
1263
|
-
| Context projection silently drops fields agents depend on
|
|
1264
|
-
| `schema_version` constant not bumped when shape changes
|
|
1265
|
-
| `structuredClone` removal causes mutation if spread is too shallow
|
|
1266
|
-
| Evidence pruning deletes a file being read concurrently
|
|
1267
|
-
| `normalizeSet` extraction breaks an unknown caller
|
|
1268
|
-
| Repair context re-fetch in PER-T-003 is still an extra call
|
|
1269
|
-
| `latest.json` write in `gates.ts` fails mid-run
|
|
1339
|
+
| Risk | Mitigation |
|
|
1340
|
+
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1341
|
+
| `Promise.all` parallelism exposes hidden race conditions in test mocks | Add ordering assertions in tests; use `vi.fn()` with explicit mock return sequences |
|
|
1342
|
+
| Context projection silently drops fields agents depend on | Gated behind `role: 'full'` default; add integration test asserting full bundle is unchanged |
|
|
1343
|
+
| `schema_version` constant not bumped when shape changes | Developer protocol comment co-located in `kernel.ts`; shape-drift detection test in `kernel.spec.ts` |
|
|
1344
|
+
| `structuredClone` removal causes mutation if spread is too shallow | The five mutated fields are scalars or wholly replaced arrays; mutation-guard test confirms |
|
|
1345
|
+
| Evidence pruning deletes a file being read concurrently | Pruning occurs after the gate write completes; `fs.unlink` uses `.catch(() => undefined)` |
|
|
1346
|
+
| `normalizeSet` extraction breaks an unknown caller | Signature is identical; all seven files updated atomically in this task; `npm run typecheck` catches any missed callers |
|
|
1347
|
+
| Repair context re-fetch in PER-T-003 is still an extra call | This is by design: one fetch per failing feature vs one fetch per retry in v1.0; net improvement |
|
|
1348
|
+
| `latest.json` write in `gates.ts` fails mid-run | `latest.json` is non-critical metadata; `latest-${mode}.json` sentinel is still written first; `evidenceLatest` falls back to `null` gracefully |
|
|
1270
1349
|
|
|
1271
1350
|
---
|
|
1272
1351
|
|
|
1273
1352
|
## 6. Task Backlog
|
|
1274
1353
|
|
|
1275
|
-
| ID
|
|
1276
|
-
|
|
1277
|
-
| PER-T-001 | PER-M1
|
|
1278
|
-
| PER-T-002 | PER-M1
|
|
1279
|
-
| PER-T-003 | PER-M1
|
|
1280
|
-
| PER-T-004 | PER-M1
|
|
1281
|
-
| PER-T-005 | PER-M2
|
|
1282
|
-
| PER-T-006 | PER-M2
|
|
1283
|
-
| PER-T-007 | PER-M3
|
|
1284
|
-
| PER-T-008 | PER-M3
|
|
1285
|
-
| PER-T-009 | PER-M3
|
|
1286
|
-
| PER-T-010 | PER-M4
|
|
1287
|
-
| PER-T-011 | PER-M4
|
|
1288
|
-
| PER-T-012 | PER-M4
|
|
1289
|
-
| PER-T-013 | PER-M4
|
|
1290
|
-
| PER-T-014 | PER-M4
|
|
1354
|
+
| ID | Milestone | File(s) | Description |
|
|
1355
|
+
| --------- | --------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
1356
|
+
| PER-T-001 | PER-M1 | `feature-lifecycle-service.ts` | Parallelize 5 sequential reads in `featureGetContext` |
|
|
1357
|
+
| PER-T-002 | PER-M1 | `build-wave-executor.ts`, `qa-wave-executor.ts` | Parallelize status-filter loops |
|
|
1358
|
+
| PER-T-003 | PER-M1 | `build-wave-executor.ts` | Context-capture Map pattern; eliminate per-retry duplicate fetch |
|
|
1359
|
+
| PER-T-004 | PER-M1 | `reporting-service.ts` | Parallelize `reportDashboard` state+cost reads |
|
|
1360
|
+
| PER-T-005 | PER-M2 | `gate-service.ts`, `gates.ts` | Write canonical `latest.json`; read it directly in `evidenceLatest` |
|
|
1361
|
+
| PER-T-006 | PER-M2 | `policy.yaml`, `policy.defaults.yaml`, `policy.schema.json`, `gates.ts` | Add `evidence_retention_count` and pruning logic |
|
|
1362
|
+
| PER-T-007 | PER-M3 | `planning-wave-executor.ts` | Pre-filter non-planning features; parallelize context fetches |
|
|
1363
|
+
| PER-T-008 | PER-M3 | `feature-lifecycle-service.ts`, input schemas | Role-specific context projections |
|
|
1364
|
+
| PER-T-009 | PER-M3 | `feature-lifecycle-service.ts` | Extract and test projection helpers |
|
|
1365
|
+
| PER-T-010 | PER-M4 | `run-coordinator.ts` | Evict `statusCache` on feature termination |
|
|
1366
|
+
| PER-T-011 | PER-M4 | `kernel.ts`, `schemas/index.schema.json` | Replace `JSON.stringify` diff with `schema_version` guard |
|
|
1367
|
+
| PER-T-012 | PER-M4 | `planning-wave-executor.ts` | Replace `structuredClone(plan)` with spread |
|
|
1368
|
+
| PER-T-013 | PER-M4 | `core/utils.ts` + 7 files | Deduplicate `normalizeSet` into shared utility |
|
|
1369
|
+
| PER-T-014 | PER-M4 | `qa-wave-executor.ts` | Move `loadRolePrompts` outside per-feature loop |
|
|
1291
1370
|
|
|
1292
1371
|
---
|
|
1293
1372
|
|
|
@@ -1350,19 +1429,19 @@ The following 28 ordered steps represent the complete implementation sequence. S
|
|
|
1350
1429
|
|
|
1351
1430
|
## 9. Spec Gap Tracker
|
|
1352
1431
|
|
|
1353
|
-
| Task
|
|
1354
|
-
|
|
1355
|
-
| PER-T-001: Parallelize 5 reads in `featureGetContext`
|
|
1356
|
-
| PER-T-002: Parallelize status-filter loops
|
|
1357
|
-
| PER-T-003: Context-capture Map pattern
|
|
1358
|
-
| PER-T-004: Parallelize `reportDashboard` reads
|
|
1359
|
-
| PER-T-005: Write + read `latest.json` sentinel
|
|
1360
|
-
| PER-T-006: Evidence retention policy
|
|
1361
|
-
| PER-T-007: Pre-filter + parallel context in `PlanningWaveExecutor` | ⬜ Pending | `runPostQaReconciliation` fully specified
|
|
1362
|
-
| PER-T-008: Role-specific context projections
|
|
1363
|
-
| PER-T-009: Extract projection helpers
|
|
1364
|
-
| PER-T-010: Evict `statusCache` on termination
|
|
1365
|
-
| PER-T-011: `schema_version` guard in `readIndex`
|
|
1366
|
-
| PER-T-012: Replace `structuredClone` with spread
|
|
1367
|
-
| PER-T-013: Extract `normalizeSet` (7 files)
|
|
1368
|
-
| PER-T-014: Move `loadRolePrompts` out of loop
|
|
1432
|
+
| Task | Status | Notes |
|
|
1433
|
+
| ------------------------------------------------------------------ | ---------- | ------------------------------------------ |
|
|
1434
|
+
| PER-T-001: Parallelize 5 reads in `featureGetContext` | ⬜ Pending | |
|
|
1435
|
+
| PER-T-002: Parallelize status-filter loops | ⬜ Pending | |
|
|
1436
|
+
| PER-T-003: Context-capture Map pattern | ⬜ Pending | Redesigned from v1.0 |
|
|
1437
|
+
| PER-T-004: Parallelize `reportDashboard` reads | ⬜ Pending | |
|
|
1438
|
+
| PER-T-005: Write + read `latest.json` sentinel | ⬜ Pending | v1.0 had wrong filename |
|
|
1439
|
+
| PER-T-006: Evidence retention policy | ⬜ Pending | Pruning filter updated for `latest-*.json` |
|
|
1440
|
+
| PER-T-007: Pre-filter + parallel context in `PlanningWaveExecutor` | ⬜ Pending | `runPostQaReconciliation` fully specified |
|
|
1441
|
+
| PER-T-008: Role-specific context projections | ⬜ Pending | Output schema note added |
|
|
1442
|
+
| PER-T-009: Extract projection helpers | ⬜ Pending | `QaIndexSnapshot` type defined |
|
|
1443
|
+
| PER-T-010: Evict `statusCache` on termination | ⬜ Pending | |
|
|
1444
|
+
| PER-T-011: `schema_version` guard in `readIndex` | ⬜ Pending | Version-bump protocol added |
|
|
1445
|
+
| PER-T-012: Replace `structuredClone` with spread | ⬜ Pending | |
|
|
1446
|
+
| PER-T-013: Extract `normalizeSet` (7 files) | ⬜ Pending | Expanded from 4 to 7 files |
|
|
1447
|
+
| PER-T-014: Move `loadRolePrompts` out of loop | ⬜ Pending | |
|