@yemi33/minions 0.1.2447 → 0.1.2449
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/bin/cli-api-client.js +1 -1
- package/bin/install-internal-minions.js +1382 -44
- package/bin/install-layout.js +150 -0
- package/bin/minions.js +460 -167
- package/dashboard/docs/typography.md +65 -12
- package/dashboard/js/command-center.js +66 -7
- package/dashboard/js/detail-panel.js +36 -0
- package/dashboard/js/memory-panel.js +59 -12
- package/dashboard/js/qa.js +186 -45
- package/dashboard/js/refresh.js +148 -12
- package/dashboard/js/render-dispatch.js +3 -4
- package/dashboard/js/render-inbox.js +2 -2
- package/dashboard/js/render-other.js +3 -3
- package/dashboard/js/render-pipelines.js +14 -0
- package/dashboard/js/render-plans.js +57 -9
- package/dashboard/js/render-prd.js +132 -23
- package/dashboard/js/render-prs.js +195 -166
- package/dashboard/js/render-schedules.js +63 -3
- package/dashboard/js/render-utils.js +3 -3
- package/dashboard/js/render-watches.js +19 -3
- package/dashboard/js/render-work-items.js +238 -30
- package/dashboard/js/settings.js +205 -54
- package/dashboard/js/utils.js +51 -1
- package/dashboard/pages/home.html +1 -1
- package/dashboard/pages/qa.html +1 -16
- package/dashboard/pages/work.html +40 -0
- package/dashboard/shared/cc-limits.js +79 -0
- package/dashboard/shared/pr-filters.js +21 -38
- package/dashboard/shared/project-git-summary.js +1 -1
- package/dashboard/shared/record-filters.js +169 -0
- package/dashboard/shared/watches-source.js +1 -1
- package/dashboard/shared/welcome-popup.js +1 -1
- package/dashboard/shared/wi-filters.js +302 -0
- package/dashboard/slim/body.html +1 -0
- package/dashboard/slim/js/command-send.js +26 -0
- package/dashboard/slim/js/modals-tiles.js +380 -39
- package/dashboard/slim/js/status.js +13 -21
- package/dashboard/slim/layout.html +1 -0
- package/dashboard/slim/panel-bootstrap.js +6 -2
- package/dashboard/slim/styles.css +38 -0
- package/dashboard/styles.css +159 -55
- package/dashboard-build.js +52 -6
- package/dashboard.js +956 -423
- package/docs/README.md +11 -6
- package/docs/api-errors.md +2 -2
- package/docs/architecture-review-2026-07-09.md +1 -1
- package/docs/architecture.excalidraw +2 -2
- package/docs/auto-discovery.md +18 -9
- package/docs/branch-derivation.md +4 -4
- package/docs/capture-demos.js +39 -2
- package/docs/ci-runner-canary.md +123 -0
- package/docs/claude-md-propagation.md +2 -2
- package/docs/cloud-agent-dispatch.md +204 -0
- package/docs/command-center.md +7 -7
- package/docs/completion-reports.md +43 -20
- package/docs/constants.md +10 -3
- package/docs/constellation-bridge.md +134 -6
- package/docs/constellation-style-telemetry.md +4 -4
- package/docs/contracts/capability-protocol.v1.json +165 -0
- package/docs/cooldown-merge-semantics.md +12 -12
- package/docs/copilot-cli-schema.md +7 -7
- package/docs/cross-repo-plans.md +10 -10
- package/docs/dead-code-audit-retractions.md +5 -5
- package/docs/default-branch-ci.md +173 -0
- package/docs/deprecated.json +31 -31
- package/docs/design-inbox-entries-schema.md +3 -3
- package/docs/design-language.md +1051 -0
- package/docs/design-state-storage.md +11 -11
- package/docs/diagnostics-crash-reports.md +9 -9
- package/docs/diagnostics-memory.md +5 -5
- package/docs/documentation-audit-2026-07-09.md +7 -7
- package/docs/engine-restart.md +90 -5
- package/docs/harness-mode.md +1 -1
- package/docs/internal-install.md +338 -39
- package/docs/kb-dedup-duplicate-pair-investigation.md +5 -5
- package/docs/kb-pr3223-cascade-archiving.md +1 -1
- package/docs/kb-pr696-merge-conflict-docs.md +6 -6
- package/docs/kb-sweep.md +35 -35
- package/docs/keep-processes.md +1 -1
- package/docs/live-checkout-mode.md +30 -30
- package/docs/managed-spawn.md +18 -14
- package/docs/named-agents.md +7 -7
- package/docs/plan-lifecycle.md +69 -2
- package/docs/pr-author-identity.md +114 -0
- package/docs/pr-auto-fix-dispatch.md +19 -4
- package/docs/pr-comment-followup.md +6 -6
- package/docs/pr-review-fix-loop.md +59 -10
- package/docs/process-termination.md +40 -0
- package/docs/proposals/repo-pool-for-live-checkout.md +13 -13
- package/docs/qa-runbook-lifecycle.md +367 -17
- package/docs/qa-runbooks.md +3 -3
- package/docs/rfc-completion-json.md +18 -18
- package/docs/runtime-adapters.md +26 -21
- package/docs/security.md +6 -6
- package/docs/self-improvement.md +4 -4
- package/docs/shared-lifecycle-module-map.md +473 -472
- package/docs/skills.md +52 -3
- package/docs/slim-ux/concepts.md +121 -116
- package/docs/specs/agent-configurability.md +18 -18
- package/docs/specs/agent-rename.md +18 -18
- package/docs/team-memory.md +38 -21
- package/docs/timeouts-and-liveness.md +118 -10
- package/docs/tutorials/01-install-and-connect.md +1 -1
- package/docs/watches.md +40 -39
- package/docs/workspace-manifests.md +4 -4
- package/docs/worktree-lifecycle.md +293 -14
- package/engine/README.md +46 -0
- package/engine/{ado-comment.js → ado/comment.js} +8 -8
- package/engine/{ado-git-auth.js → ado/git-auth.js} +4 -4
- package/engine/{ado.js → ado/index.js} +417 -63
- package/engine/{ado-status.js → ado/status.js} +6 -8
- package/engine/{ado-token.js → ado/token.js} +1 -1
- package/engine/{acp-transport.js → agents/acp-transport.js} +62 -22
- package/engine/{agent-worker-pool.js → agents/agent-worker-pool.js} +17 -8
- package/engine/{cc-worker-pool.js → agents/cc-worker-pool.js} +16 -6
- package/engine/{claude-md-context.js → agents/claude-md-context.js} +5 -5
- package/engine/{harness-context.js → agents/harness-context.js} +5 -5
- package/engine/{harness.js → agents/harness.js} +3 -3
- package/engine/{llm.js → agents/llm.js} +18 -14
- package/engine/{model-discovery.js → agents/model-discovery.js} +2 -2
- package/engine/{playbook.js → agents/playbook.js} +155 -22
- package/engine/{pooled-agent-process.js → agents/pooled-agent-process.js} +14 -12
- package/engine/{preflight.js → agents/preflight.js} +29 -10
- package/engine/{spawn-agent.js → agents/spawn-agent.js} +25 -14
- package/engine/{spawn-phase-watchdog.js → agents/spawn-phase-watchdog.js} +16 -7
- package/engine/{steering.js → agents/steering.js} +5 -5
- package/engine/{tools-inventory.js → agents/tools-inventory.js} +2 -2
- package/engine/{agent-api-validation.js → api/agent-api-validation.js} +2 -2
- package/engine/{api-validation.js → api/api-validation.js} +1 -1
- package/engine/api/bridge.js +787 -0
- package/engine/{cc-api-validation.js → api/cc-api-validation.js} +1 -1
- package/engine/api/companion.js +560 -0
- package/engine/{content-api-validation.js → api/content-api-validation.js} +2 -2
- package/engine/{pr-issue-validation.js → api/pr-issue-validation.js} +33 -6
- package/engine/{settings-validation.js → api/settings-validation.js} +32 -4
- package/engine/api-contracts/agent-content.js +4 -4
- package/engine/api-contracts/capability-manifest.js +236 -0
- package/engine/api-contracts/capability-protocol.js +333 -0
- package/engine/api-contracts/cc-ops.js +1 -1
- package/engine/api-contracts/config-runtime.js +5 -0
- package/engine/api-contracts/core.js +28 -1
- package/engine/api-contracts/index.js +100 -0
- package/engine/api-contracts/orchestration.js +18 -5
- package/engine/api-contracts/pull-requests.js +37 -6
- package/engine/api-contracts/qa-process.js +29 -6
- package/engine/api-contracts/work-plan-prd.js +21 -1
- package/engine/cloud/contract.js +212 -0
- package/engine/cloud/index.js +159 -0
- package/engine/{execution-model.js → core/execution-model.js} +1 -1
- package/engine/{features.js → core/features.js} +4 -4
- package/engine/{operator-identity.js → core/operator-identity.js} +1 -1
- package/engine/{queries.js → core/queries.js} +201 -36
- package/engine/{safe-expr.js → core/safe-expr.js} +1 -1
- package/engine/{shared.js → core/shared.js} +1637 -175
- package/engine/{stdio-timestamps.js → core/stdio-timestamps.js} +1 -1
- package/engine/{untrusted-fence.js → core/untrusted-fence.js} +3 -3
- package/engine/db/index.js +11 -2
- package/engine/db/migrations/002-dispatches.js +3 -3
- package/engine/db/migrations/003-work-items.js +1 -1
- package/engine/db/migrations/004-pull-requests.js +1 -1
- package/engine/db/migrations/006-metrics.js +1 -1
- package/engine/db/migrations/007-watches.js +2 -2
- package/engine/db/migrations/008-small-state.js +1 -1
- package/engine/db/migrations/009-qa.js +1 -1
- package/engine/db/migrations/010-pr-links.js +1 -1
- package/engine/db/migrations/011-remaining-state.js +1 -1
- package/engine/db/migrations/012-steering-deliveries.js +2 -2
- package/engine/db/migrations/013-backfill-broken-note-links.js +1 -1
- package/engine/db/migrations/014-pr-fix-target-prefs.js +2 -2
- package/engine/db/migrations/015-plans-prds.js +0 -0
- package/engine/db/migrations/018-sql-only-cutover.js +2 -2
- package/engine/db/migrations/021-archived-work-items.js +1 -1
- package/engine/db/migrations/022-global-cc-session.js +1 -1
- package/engine/db/migrations/023-engine-state.js +1 -1
- package/engine/db/migrations/025-malformed-work-item-phantoms.js +1 -1
- package/engine/db/migrations/027-review-learning-lifecycle.js +1 -1
- package/engine/db/migrations/029-repair-reused-versions.js +20 -0
- package/engine/db/migrations/031-pr-author-identity.js +137 -0
- package/engine/{consolidation.js → memory/consolidation.js} +6 -6
- package/engine/{kb-sweep-runner.js → memory/kb-sweep-runner.js} +2 -2
- package/engine/{kb-sweep.js → memory/kb-sweep.js} +9 -7
- package/engine/{memory-retrieval.js → memory/memory-retrieval.js} +46 -4
- package/engine/{memory-store.js → memory/memory-store.js} +3 -3
- package/engine/{promotion.js → memory/promotion.js} +3 -3
- package/engine/{review-learning-backfill.js → memory/review-learning-backfill.js} +6 -6
- package/engine/{review-learning.js → memory/review-learning.js} +10 -5
- package/engine/{diagnostics-memory.js → observability/diagnostics-memory.js} +1 -1
- package/engine/{logs-store.js → observability/logs-store.js} +5 -5
- package/engine/{metrics-store.js → observability/metrics-store.js} +4 -4
- package/engine/{check-status.js → operations/check-status.js} +3 -3
- package/engine/{cli.js → operations/cli.js} +271 -113
- package/engine/{distribution.js → operations/distribution.js} +5 -6
- package/engine/{cleanup.js → orchestration/cleanup.js} +72 -45
- package/engine/{cooldown.js → orchestration/cooldown.js} +5 -5
- package/engine/{dispatch-events.js → orchestration/dispatch-events.js} +2 -2
- package/engine/{dispatch.js → orchestration/dispatch.js} +129 -36
- package/engine/orchestration/failed-scheduled-cleanup.js +274 -0
- package/engine/{lifecycle.js → orchestration/lifecycle.js} +198 -90
- package/engine/{meeting.js → orchestration/meeting.js} +6 -16
- package/engine/{pipeline.js → orchestration/pipeline.js} +12 -12
- package/engine/{pre-dispatch-eval.js → orchestration/pre-dispatch-eval.js} +10 -9
- package/engine/{routing.js → orchestration/routing.js} +3 -3
- package/engine/{schedule-bootstrap.js → orchestration/schedule-bootstrap.js} +4 -4
- package/engine/{scheduler.js → orchestration/scheduler.js} +38 -8
- package/engine/{timeout.js → orchestration/timeout.js} +158 -109
- package/engine/{db-events.js → persistence/db-events.js} +2 -2
- package/engine/{dispatch-store.js → persistence/dispatch-store.js} +7 -7
- package/engine/{inbox-store.js → persistence/inbox-store.js} +2 -2
- package/engine/{note-link-backfill.js → persistence/note-link-backfill.js} +4 -4
- package/engine/{pr-fix-target-store.js → persistence/pr-fix-target-store.js} +8 -8
- package/engine/{pull-requests-store.js → persistence/pull-requests-store.js} +21 -7
- package/engine/{small-state-store.js → persistence/small-state-store.js} +31 -31
- package/engine/persistence/state-operations.js +350 -0
- package/engine/{steering-store.js → persistence/steering-store.js} +6 -6
- package/engine/{issues.js → planning/issues.js} +2 -2
- package/engine/{plan-prd-validation.js → planning/plan-prd-validation.js} +8 -2
- package/engine/planning/prd-result-sidecar.js +190 -0
- package/engine/{prd-store.js → planning/prd-store.js} +17 -17
- package/engine/{project-discovery.js → planning/project-discovery.js} +5 -5
- package/engine/{projects.js → planning/projects.js} +10 -10
- package/engine/{resolve-area.js → planning/resolve-area.js} +1 -1
- package/engine/{work-item-validation.js → planning/work-item-validation.js} +39 -3
- package/engine/{work-items-store.js → planning/work-items-store.js} +29 -21
- package/engine/{keep-process-sweep.js → processes/keep-process-sweep.js} +57 -17
- package/engine/{managed-spawn-launcher.js → processes/managed-spawn-launcher.js} +3 -3
- package/engine/{managed-spawn.js → processes/managed-spawn.js} +97 -46
- package/engine/{process-utils.js → processes/process-utils.js} +599 -55
- package/engine/{abandoned-pr-reconciliation.js → providers/abandoned-pr-reconciliation.js} +17 -7
- package/engine/{comment-classifier.js → providers/comment-classifier.js} +85 -17
- package/engine/{comment-format.js → providers/comment-format.js} +5 -5
- package/engine/{gh-comment.js → providers/gh-comment.js} +15 -15
- package/engine/{gh-token.js → providers/gh-token.js} +4 -4
- package/engine/{github.js → providers/github.js} +131 -54
- package/engine/{pr-action.js → providers/pr-action.js} +13 -12
- package/engine/{pr-clone-keep.js → providers/pr-clone-keep.js} +7 -7
- package/engine/{pr-devbox.js → providers/pr-devbox.js} +6 -6
- package/engine/{pr-fix-target.js → providers/pr-fix-target.js} +13 -13
- package/engine/{pr-remote-patch.js → providers/pr-remote-patch.js} +4 -4
- package/engine/{pr-resolve.js → providers/pr-resolve.js} +7 -7
- package/engine/{pr-temp-clone.js → providers/pr-temp-clone.js} +5 -5
- package/engine/{pr-track.js → providers/pr-track.js} +11 -13
- package/engine/{shared-branch-pr-reconcile.js → providers/shared-branch-pr-reconcile.js} +4 -4
- package/engine/qa/auto-prd-qa.js +313 -0
- package/engine/{qa-from-prd.js → qa/from-prd.js} +42 -12
- package/engine/qa/prd-session.js +240 -0
- package/engine/{qa-process-validation.js → qa/process-validation.js} +14 -9
- package/engine/{qa-runbooks.js → qa/runbooks.js} +1 -1
- package/engine/{qa-runs.js → qa/runs.js} +286 -15
- package/engine/{qa-sessions.js → qa/sessions.js} +595 -49
- package/engine/qa/visual-journey.js +654 -0
- package/engine/{qa-runners.js → qa-runners/index.js} +7 -7
- package/engine/qa-runners/maestro.js +3 -3
- package/engine/qa-runners/playwright.js +2 -2
- package/engine/{restart-health.js → recovery/restart-health.js} +48 -4
- package/engine/recovery/stop-stack.js +607 -0
- package/engine/{supervisor.js → recovery/supervisor.js} +105 -175
- package/engine/{watchdog.js → recovery/watchdog.js} +136 -13
- package/engine/runtimes/claude.js +14 -12
- package/engine/runtimes/codex.js +8 -6
- package/engine/runtimes/copilot.js +17 -16
- package/engine/{watch-actions.js → watches/actions.js} +13 -13
- package/engine/{watches.js → watches/index.js} +43 -32
- package/engine/{watches-store.js → watches/store.js} +4 -4
- package/engine/{create-pr-worktree.js → worktrees/create-pr.js} +1 -1
- package/engine/{worktree-gc.js → worktrees/gc.js} +70 -22
- package/engine/worktrees/inventory.js +671 -0
- package/engine/{live-checkout.js → worktrees/live-checkout.js} +4 -4
- package/engine/{worktree-pool.js → worktrees/pool.js} +2 -2
- package/engine/{worktree-preflight.js → worktrees/preflight.js} +1 -0
- package/engine/worktrees/quarantine-refs.js +173 -0
- package/engine.js +1137 -208
- package/minions.js +147 -77
- package/package.json +10 -6
- package/playbooks/_pr-description-audit.md +110 -78
- package/playbooks/build-fix-complex.md +2 -0
- package/playbooks/fix.md +16 -12
- package/playbooks/implement-shared.md +2 -0
- package/playbooks/implement.md +19 -20
- package/playbooks/plan-to-prd.md +18 -3
- package/playbooks/qa-session-draft.md +136 -1
- package/playbooks/qa-session-execute.md +80 -2
- package/playbooks/qa-session-setup.md +17 -1
- package/playbooks/qa-validate.md +1 -1
- package/playbooks/setup.md +2 -0
- package/playbooks/shared-rules.md +25 -32
- package/playbooks/templates/followup-dispatch.md +4 -3
- package/playbooks/verify.md +1 -1
- package/prompts/cc-system.md +19 -27
- package/watch-plugins/README.md +92 -0
- package/watch-plugins/ado-author-prs.js +336 -0
- package/watch-plugins/gh-author-prs.js +375 -0
- package/watch-plugins/http.js +474 -0
- package/watch-plugins/teams-channel.js +869 -0
- package/docs/dev-composite-workflow.md +0 -101
- package/docs/pr-screenshots/pr-886/after-single-header.png +0 -0
- package/docs/pr-screenshots/pr-886/before-duplicate-header.png +0 -0
- package/docs/pr-screenshots/pr-895/01-cancellation-reason-detail.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-901/projects-tab-default.png +0 -0
- package/docs/pr-screenshots/pr-901/projects-tab-fmf-selected.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-dropdown-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
- package/docs/visual-evidence-ci.md +0 -103
- package/engine/bridge.js +0 -379
- package/engine/quarantine-refs.js +0 -103
- package/engine/state-operations.js +0 -178
- /package/engine/{steering-constraints.js → agents/steering-constraints.js} +0 -0
|
@@ -46,7 +46,7 @@ The Constellation agent polls:
|
|
|
46
46
|
GET http://127.0.0.1:7331/api/constellation/v1/snapshot
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
The endpoint is loopback-only because the Minions dashboard binds `127.0.0.1`. It supports `ETag` and `If-None-Match`; unchanged state returns `304` with no body. A `200` response is a **complete replacement snapshot**, so consumers must remove previously mirrored entities that are absent from the latest response.
|
|
49
|
+
The endpoint is loopback-only because the Minions dashboard binds `127.0.0.1`. It is gated by `bridge.isBridgeEnabled` — it returns `404` with `{"error": "Constellation bridge is disabled", "code": "bridge-disabled"}` unless `engine.constellationBridge.enabled` is literally `true`, so `minions bridge disable` severs the metadata projection at the HTTP layer rather than merely asking the agent to stop polling. When enabled it supports `ETag` and `If-None-Match`; unchanged state returns `304` with no body. A `200` response is a **complete replacement snapshot**, so consumers must remove previously mirrored entities that are absent from the latest response.
|
|
50
50
|
|
|
51
51
|
```json
|
|
52
52
|
{
|
|
@@ -72,7 +72,7 @@ The endpoint is loopback-only because the Minions dashboard binds `127.0.0.1`. I
|
|
|
72
72
|
|
|
73
73
|
### Privacy boundary
|
|
74
74
|
|
|
75
|
-
Every entity is rebuilt from an explicit allowlist in `engine/bridge.js`; raw dashboard records are never forwarded. The snapshot excludes task descriptions, prompts, acceptance criteria, completion reports, diffs, comments, human feedback, notes, logs, filesystem paths, environment variables, tokens, and secrets. Strings are length-capped to the matching Constellation schema limits.
|
|
75
|
+
Every entity is rebuilt from an explicit allowlist in `engine/api/bridge.js`; raw dashboard records are never forwarded. The snapshot excludes task descriptions, prompts, acceptance criteria, completion reports, diffs, comments, human feedback, notes, logs, filesystem paths, environment variables, tokens, and secrets. Strings are length-capped to the matching Constellation schema limits.
|
|
76
76
|
|
|
77
77
|
The entity shapes match `packages/shared/src/orchestrator-messages.ts` in the Constellation repository:
|
|
78
78
|
|
|
@@ -84,11 +84,53 @@ The entity shapes match `packages/shared/src/orchestrator-messages.ts` in the Co
|
|
|
84
84
|
- `agent_status`: agent/status/project, current task identifiers/title and update time.
|
|
85
85
|
- `device_summary`: aggregate counts plus protocol, Minions version and engine health.
|
|
86
86
|
|
|
87
|
+
## Capability protocol contract
|
|
88
|
+
|
|
89
|
+
The bridge snapshot above is one-way telemetry. The **capability protocol** is the other half: the vocabulary Minions uses to describe the operations Constellation may invoke. Minions is the producer, Constellation is the consumer, and the vocabulary has exactly one definition:
|
|
90
|
+
|
|
91
|
+
- **Source of truth:** [`engine/api-contracts/capability-protocol.js`](../engine/api-contracts/capability-protocol.js) — plain CommonJS on Node built-ins only (the repo has zero runtime dependencies, so a schema library is not an option). It is the sole definition of the scope vocabulary, the confirmation enum (`none` / `per-call`), the parameter-type set, the capability-entry and manifest-envelope field lists, and the version rule.
|
|
92
|
+
- **Machine-readable artifact:** [`docs/contracts/capability-protocol.v1.json`](contracts/capability-protocol.v1.json), generated with `node engine/api-contracts/capability-protocol.js --emit` and checked in. A unit test fails if the checked-in bytes and the module disagree, and a second test fails if a scope string appears anywhere in this repo outside those two files.
|
|
93
|
+
- **Live negotiation:** `GET http://127.0.0.1:7331/api/capabilities/protocol` serves the same artifact with an `ETag` derived from its checksum. Like every Constellation surface it is gated by `bridge.isBridgeEnabled` — it returns `404` unless `engine.constellationBridge.enabled` is literally `true`.
|
|
94
|
+
|
|
95
|
+
The artifact carries `protocolVersion` and a `sha256:` content `checksum` computed over every other field with object keys sorted, so a consumer can pin the exact contract revision it generated against and detect an edited or swapped copy. Regenerating from unchanged sources reproduces the same bytes — the artifact is content-addressed, not time-stamped.
|
|
96
|
+
|
|
97
|
+
The version rule is the snapshot rule stated above — reused verbatim as `CAPABILITY_VERSION_RULE` rather than restated, so the two cannot drift apart.
|
|
98
|
+
|
|
99
|
+
**Consumers generate, they never transcribe.** Constellation code-generates its enums and types from the artifact and gates on drift; a hand-maintained parallel enum without a drift gate is outside this contract. On the producer side, `validateCapabilityManifest()` **throws** — a manifest declaring a scope, confirmation mode or parameter type outside the contract fails at build time rather than shipping something the consumer cannot generate against.
|
|
100
|
+
|
|
101
|
+
## Capability manifest (`GET /api/capabilities`)
|
|
102
|
+
|
|
103
|
+
The protocol contract above is the vocabulary; the **capability manifest** is what Minions actually publishes with it. It is built by [`engine/api-contracts/capability-manifest.js`](../engine/api-contracts/capability-manifest.js) from the route-contract catalog and served at `GET http://127.0.0.1:7331/api/capabilities`, behind the same strict `bridge.isBridgeEnabled` gate (`404` unless `engine.constellationBridge.enabled` is literally `true`) and with an `ETag`/`If-None-Match` `304` revalidation path.
|
|
104
|
+
|
|
105
|
+
The envelope is `{ protocol, protocolVersion, generatedAt, minionsVersion, capabilities[] }` and each entry is `{ id, title, description, method, path, scopes[], destructive, confirm, params[] }` — both key sets are generated by walking the protocol contract's field lists, never maintained as a copy alongside them.
|
|
106
|
+
|
|
107
|
+
Two properties define the producer contract:
|
|
108
|
+
|
|
109
|
+
- **Opt-in and fail-closed.** A route reaches the manifest only when its owning module in `engine/api-contracts/` declares an explicit `capability` block on its override. A route that declares nothing is absent — there is no heuristic and no derived-by-default entry. An incomplete block (missing `id`, `title`, `description`, a non-empty `scopes[]`, `destructive` or `confirm`, or an out-of-vocabulary value for any of them) fails the catalog build with a throw.
|
|
110
|
+
- **Authorization is declared, never inferred.** `destructive` and `confirm` come from that block alone. They are deliberately **not** derived from `dashboard.js#_routeDestructive`, which is a fail-open regex over the route path *and its free-text description* — reusing it would let rewording a description silently reclassify a capability's safety posture for a remote caller. The method-derived read-only/state-changing split is used only to **contradict** a claim: a `destructive: false` capability on a state-changing route must supply a `nonDestructiveRationale`, and a `destructive: true` capability must require per-call confirmation.
|
|
111
|
+
|
|
112
|
+
`params[]` is projected from the audited route contract's `request.{path,query,body,headers}.fields` — the same source `GET /api/routes` uses — so a published parameter type cannot drift from the contract the route actually validates against. Contract types that refine a JSON type (`identifier`, `basename`, `path`, `array<object>`) normalize to their protocol type; an ambiguous union (`string|array<string>`) has no honest protocol type and throws, which is the signal to tighten the route contract before publishing it as a capability.
|
|
113
|
+
|
|
114
|
+
### Phase-0 allowlist
|
|
115
|
+
|
|
116
|
+
The set of annotated routes is deliberately tiny. Phase 0 exists to prove the producer → consumer round trip end to end, so it exposes **four read-only projections and no mutation at all**:
|
|
117
|
+
|
|
118
|
+
| Capability id | Route |
|
|
119
|
+
| ---------------- | ------------------------- |
|
|
120
|
+
| `plan.list` | `GET /api/plans` |
|
|
121
|
+
| `pr.list` | `GET /api/pull-requests` |
|
|
122
|
+
| `status.summary` | `GET /api/status` |
|
|
123
|
+
| `work.list` | `GET /api/work-items` |
|
|
124
|
+
|
|
125
|
+
Every one declares `destructive: false`, `confirm: "none"`, and a single read scope. `status.summary` grants one scope rather than the union of the read scopes: since issue #2949 the status snapshot is only the live engine/throttle/project envelope, and the work, plan, and PR slices it used to carry are separately-declared capabilities of their own.
|
|
126
|
+
|
|
127
|
+
The allowlist is pinned as a snapshot in `test/unit/capability-allowlist.test.js`, which also asserts that every manifest entry uses a read-only HTTP method. Widening it therefore cannot happen quietly — it is a reviewed diff in that table. **Mutating capabilities are not part of this phase**; they arrive with `engine.constellationBridge.commandsEnabled` (default off), which must keep them out of the manifest *and* refuse them at execution while it is false.
|
|
128
|
+
|
|
87
129
|
## Marker-file contract
|
|
88
130
|
|
|
89
131
|
The Constellation agent's bridge writes a marker file on every successful poll. Minions reads it with `minions bridge status` so a local operator can verify the bridge is alive and Constellation is talking to it.
|
|
90
132
|
|
|
91
|
-
- **Path:** `~/.minions/engine/constellation-bridge.json` (exposed as `CONSTELLATION_BRIDGE_MARKER_PATH` in `engine/shared.js`).
|
|
133
|
+
- **Path:** `~/.minions/engine/constellation-bridge.json` (exposed as `CONSTELLATION_BRIDGE_MARKER_PATH` in `engine/core/shared.js`).
|
|
92
134
|
- **Owner:** the Constellation agent. The Minions engine **never** writes this file — it is a one-way breadcrumb from Constellation → Minions.
|
|
93
135
|
|
|
94
136
|
### Schema (`schemaVersion: 1`)
|
|
@@ -104,13 +146,85 @@ The Constellation agent's bridge writes a marker file on every successful poll.
|
|
|
104
146
|
|
|
105
147
|
| Field | Required | Notes |
|
|
106
148
|
| --------------- | -------- | ------------------------------------------------------------------------ |
|
|
107
|
-
| `schemaVersion` | yes | Must equal `1`. Any other value causes Minions to ignore the marker entirely (treated as no-marker, same as a missing file). New fields are added behind a deliberate version bump. |
|
|
149
|
+
| `schemaVersion` | yes | Must equal `1`. Any other value causes Minions to ignore the marker entirely (treated as no-marker, same as a missing file). New required fields are added behind a deliberate version bump. |
|
|
108
150
|
| `lastSeenAt` | yes | ISO-8601 UTC timestamp of the last successful poll. |
|
|
109
|
-
| `agentVersion` | no | Constellation agent semver string, surfaced in `bridge status
|
|
151
|
+
| `agentVersion` | no | Constellation agent semver string, surfaced in `bridge status` and used by the companion probe below. |
|
|
110
152
|
| `source` | no | Free-form identifier, expected `"constellation-agent"` today. |
|
|
153
|
+
| `healthUrl` | no | Loopback URL of the companion's own health endpoint. Optional and additive: readers must tolerate its absence, and Minions refuses any non-loopback value without requesting it. |
|
|
111
154
|
|
|
112
155
|
Writers MUST use an atomic-replace pattern (`write to tmp + rename`) so a partial write never leaves Minions reading a half-baked JSON blob.
|
|
113
156
|
|
|
157
|
+
## Companion probe
|
|
158
|
+
|
|
159
|
+
Minions reports whether a **compatible Constellation companion** is present. It only reports — Minions **never downloads, executes, or installs Constellation**, there is no recursion marker and no reciprocal-bootstrap handshake, and companion absence is a visible degraded state that is never fatal. Minions installs and operates independently.
|
|
160
|
+
|
|
161
|
+
The probe lives in `engine/api/companion.js` and is surfaced by:
|
|
162
|
+
|
|
163
|
+
- `minions doctor` — one `Constellation companion` row (always `warn`, never a critical failure, so the doctor exit code is unchanged on hosts without Constellation).
|
|
164
|
+
- `minions bridge health` — printed before the snapshot probe, so it still says something useful when the dashboard is down.
|
|
165
|
+
- `minions init` and `minions update` — non-fatal informational output.
|
|
166
|
+
|
|
167
|
+
### Statuses
|
|
168
|
+
|
|
169
|
+
| Status | Meaning |
|
|
170
|
+
| ------------------------- | ------------------------------------------------------------------------------------------- |
|
|
171
|
+
| `companion-ok` | A companion registered and its version is inside the declared compatible range. |
|
|
172
|
+
| `companion-incompatible` | A companion is present but its version is outside the range, or its marker uses a `schemaVersion` this Minions build does not read. |
|
|
173
|
+
| `companion-missing` | No marker — no companion has ever registered with this Minions instance. |
|
|
174
|
+
| `companion-unknown` | A companion is present but its state could not be determined: unreadable marker, no declared version, or a refused/failed/timed-out health probe. |
|
|
175
|
+
|
|
176
|
+
Every report prints the **detected version** and the **declared compatible range**, so an incompatibility is always actionable rather than a bare "not supported".
|
|
177
|
+
|
|
178
|
+
### How detection works
|
|
179
|
+
|
|
180
|
+
1. **Marker** — `~/.minions/engine/constellation-bridge.json` (the same file documented above) is the presence signal. There is no PATH lookup and no directory-name heuristic anywhere in the probe.
|
|
181
|
+
2. **Bounded health request (optional)** — when the marker declares a `healthUrl` (or an operator configures one), Minions issues **one** `GET` under an explicit timeout to resolve a version the marker omitted. An operator-configured `healthUrl` is probed even when no marker exists, so a companion that is installed but not yet bridged is not misreported as absent. The URL must be loopback (`127.0.0.1`, `localhost`, `::1`) over `http`/`https`; anything else is refused **without being requested**, so the probe can never make an outbound network request. A refusal, failure, or timeout reports `companion-unknown` — never `companion-missing`.
|
|
182
|
+
|
|
183
|
+
With no `healthUrl` anywhere — the default — the marker alone decides, and no request of any kind is made.
|
|
184
|
+
|
|
185
|
+
Both stages are bounded, so a hung companion can never stall `minions doctor`, `minions bridge health`, `minions init`, `minions update`, or engine start. The probe uses Node built-ins only; Minions stays zero-dependency at runtime.
|
|
186
|
+
|
|
187
|
+
### Setup guidance
|
|
188
|
+
|
|
189
|
+
On anything other than `companion-ok`, Minions prints the documented Constellation install command for the current platform as **text for the operator to run**:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
Constellation companion: companion-missing
|
|
193
|
+
version: (unknown) compatible range: >=0.2.0 <1.0.0
|
|
194
|
+
no Constellation companion has registered with this Minions instance
|
|
195
|
+
Minions runs fine without it — Constellation only mirrors state into its HUD.
|
|
196
|
+
To install or update the companion, run it yourself (PowerShell):
|
|
197
|
+
irm https://icy-water-0224cc51e.2.azurestaticapps.net/install.ps1 | iex
|
|
198
|
+
Docs: https://icy-water-0224cc51e.2.azurestaticapps.net/
|
|
199
|
+
Minions never runs it for you — this is guidance, not an action.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
On macOS/Linux the printed command is `curl -fsSL https://icy-water-0224cc51e.2.azurestaticapps.net/install.sh | sh`. Minions never executes either command.
|
|
203
|
+
|
|
204
|
+
### Config + opt-out
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"engine": {
|
|
209
|
+
"constellationCompanion": {
|
|
210
|
+
"probeEnabled": true,
|
|
211
|
+
"probeTimeoutMs": 2000,
|
|
212
|
+
"healthUrl": null
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
| Key | Default | Notes |
|
|
219
|
+
| ---------------- | ------- | -------------------------------------------------------------------------------------- |
|
|
220
|
+
| `probeEnabled` | `true` | Set to `false` to suppress the companion probe **entirely** — no marker read, no health request, no output anywhere. Intended for managed deployments that already know the companion topology. |
|
|
221
|
+
| `probeTimeoutMs` | `2000` | Hard bound on the optional health request. Clamped to `[250, 15000]` ms at read time. |
|
|
222
|
+
| `healthUrl` | `null` | Operator override for the companion health endpoint. Wins over the marker's own `healthUrl`. Loopback-only. |
|
|
223
|
+
|
|
224
|
+
The environment variable **`MINIONS_DISABLE_COMPANION_PROBE=1`** does the same as `probeEnabled: false` and wins over config, so a fleet image can suppress the probe without editing `config.json`.
|
|
225
|
+
|
|
226
|
+
This block is CLI/config-managed like `engine.constellationBridge` — neither Constellation surface has a dashboard Settings control.
|
|
227
|
+
|
|
114
228
|
## `minions bridge health`
|
|
115
229
|
|
|
116
230
|
`bridge health` performs a synchronous probe of the versioned snapshot endpoint and prints its aggregate metadata. This verifies both dashboard reachability and protocol compatibility.
|
|
@@ -136,8 +250,22 @@ bridge: dashboard reachable on http://127.0.0.1:7331
|
|
|
136
250
|
|
|
137
251
|
If the dashboard is not listening, `bridge health` prints `dashboard not running on :7331 — start it with \`minions dash\`` and exits 1. Use this exit code to gate scripted health checks.
|
|
138
252
|
|
|
253
|
+
Because the snapshot endpoint is gated, probing it with the bridge disabled is not a dashboard fault. `bridge health` recognizes the `bridge-disabled` response and reports the flag instead of a bare status code, still exiting 1:
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
error: Constellation bridge is disabled — enable it with `minions bridge enable`
|
|
257
|
+
config: engine.constellationBridge.enabled = false
|
|
258
|
+
```
|
|
259
|
+
|
|
139
260
|
## Cross-repo coordination
|
|
140
261
|
|
|
141
|
-
The Minions producer lands before the Constellation consumer. During rollout, Constellation may fall back to the legacy per-endpoint projection only when the versioned endpoint
|
|
262
|
+
The Minions producer lands before the Constellation consumer. During rollout, Constellation may fall back to the legacy per-endpoint projection only when the versioned endpoint is genuinely absent; a malformed versioned response must fail closed rather than silently downgrading.
|
|
263
|
+
|
|
264
|
+
**A `404` is not by itself proof of absence.** The same status now also means "this operator turned the bridge off", and those two cases require opposite behavior — fall back in one, stop entirely in the other. Discriminate on the response body, not the status code:
|
|
265
|
+
|
|
266
|
+
- `404` with `"code": "bridge-disabled"` → the bridge is deliberately off. **Stop projecting.** Do not fall back to the legacy per-endpoint projection; doing so would keep mirroring the machine the operator just withdrew, which is precisely what `enabled` exists to prevent.
|
|
267
|
+
- Any other `404` (or a non-JSON body) → the route is not served by this Minions build; the legacy fallback applies.
|
|
268
|
+
|
|
269
|
+
In practice an unmatched path on the Minions dashboard falls through to the SPA catch-all and answers `200 text/html`, never `404`, so on any build that has this route a `404` here is always the gate.
|
|
142
270
|
|
|
143
271
|
The Constellation agent's bridge reads `~/.minions/config.json` directly (no Minions HTTP API call) so config edits propagate without waiting for the engine to restart.
|
|
@@ -65,10 +65,10 @@ Key design properties:
|
|
|
65
65
|
| `metrics_daily` rollups | SQL metrics `_daily.<YYYY-MM-DD>` → `{costUsd, inputTokens, outputTokens, cacheRead, tasks}` |
|
|
66
66
|
| Per-entity aggregates | Per-agent counters: `tasksCompleted/Errored`, `prsCreated/Approved/Rejected/Merged`, `reviewsDone`, `totalCostUsd`, `totalInputTokens/OutputTokens/CacheRead`, `totalRuntimeMs`, `model`, `timedTasks` |
|
|
67
67
|
| App/engine analytics | SQL metrics `_engine`: `command-center`, `agent-dispatch`, `consolidation`, `agent_memory_reconcile` |
|
|
68
|
-
| Emit helpers | `llm.trackEngineUsage()`, `trackReviewMetric()`, `updateMetrics()` (`engine/lifecycle.js`, `engine/llm.js`, `engine/shared.js`) |
|
|
68
|
+
| Emit helpers | `llm.trackEngineUsage()`, `trackReviewMetric()`, `updateMetrics()` (`engine/orchestration/lifecycle.js`, `engine/agents/llm.js`, `engine/core/shared.js`) |
|
|
69
69
|
| Structured error taxonomy | `FAILURE_CLASS` constants (recorded per work-item; not yet aggregated as a metric) |
|
|
70
70
|
| Diagnostic stream | SQL log tail (secret-redacted via `redactSecrets()`) + `engine/dashboard-diagnostics.log` |
|
|
71
|
-
| Admin overview query | `getMetrics()` (`engine/queries.js`) surfaced via `/api/status` |
|
|
71
|
+
| Admin overview query | `getMetrics()` (`engine/core/queries.js`) surfaced via `/api/status` |
|
|
72
72
|
|
|
73
73
|
## The gap (the 40% worth building)
|
|
74
74
|
|
|
@@ -156,6 +156,6 @@ the other HTML entry points; counters from an in-memory registry, no client libr
|
|
|
156
156
|
`packages/server/src/api/prism.ts`, `packages/dashboard/src/prism/prism-telemetry.ts`
|
|
157
157
|
- Constellation taxonomy/privacy: `packages/shared/src/constants.ts`,
|
|
158
158
|
`packages/shared/src/privacy.ts`
|
|
159
|
-
- Minions today: `engine/state.db` metrics, `getMetrics()` (`engine/queries.js`),
|
|
160
|
-
`trackEngineUsage()` (`engine/llm.js`), `FAILURE_CLASS` (`engine/shared.js`),
|
|
159
|
+
- Minions today: `engine/state.db` metrics, `getMetrics()` (`engine/core/queries.js`),
|
|
160
|
+
`trackEngineUsage()` (`engine/agents/llm.js`), `FAILURE_CLASS` (`engine/core/shared.js`),
|
|
161
161
|
related design doc `design-state-storage.md`.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"protocol": "minions.capability.manifest",
|
|
3
|
+
"protocolVersion": 1,
|
|
4
|
+
"generator": "engine/api-contracts/capability-protocol.js",
|
|
5
|
+
"versionRule": "`protocolVersion` changes only for a breaking schema change. Additive optional fields do not require a version bump.",
|
|
6
|
+
"scopes": [
|
|
7
|
+
"work:read",
|
|
8
|
+
"work:write",
|
|
9
|
+
"plan:read",
|
|
10
|
+
"plan:write",
|
|
11
|
+
"pr:read",
|
|
12
|
+
"notes:write",
|
|
13
|
+
"watch:write",
|
|
14
|
+
"engine:control",
|
|
15
|
+
"cc:converse",
|
|
16
|
+
"docchat:write",
|
|
17
|
+
"qa:read"
|
|
18
|
+
],
|
|
19
|
+
"confirmModes": [
|
|
20
|
+
"none",
|
|
21
|
+
"per-call"
|
|
22
|
+
],
|
|
23
|
+
"paramTypes": [
|
|
24
|
+
"string",
|
|
25
|
+
"number",
|
|
26
|
+
"integer",
|
|
27
|
+
"boolean",
|
|
28
|
+
"array",
|
|
29
|
+
"object"
|
|
30
|
+
],
|
|
31
|
+
"manifestEnvelopeFields": [
|
|
32
|
+
{
|
|
33
|
+
"name": "protocol",
|
|
34
|
+
"type": "string",
|
|
35
|
+
"required": true,
|
|
36
|
+
"constant": "minions.capability.manifest",
|
|
37
|
+
"description": "Protocol identifier."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "protocolVersion",
|
|
41
|
+
"type": "integer",
|
|
42
|
+
"required": true,
|
|
43
|
+
"constant": 1,
|
|
44
|
+
"description": "Protocol version; see versionRule."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "generatedAt",
|
|
48
|
+
"type": "string",
|
|
49
|
+
"required": true,
|
|
50
|
+
"description": "ISO-8601 UTC timestamp of manifest generation."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "minionsVersion",
|
|
54
|
+
"type": "string",
|
|
55
|
+
"required": false,
|
|
56
|
+
"description": "Optional Minions package version of the producer."
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "capabilities",
|
|
60
|
+
"type": "array",
|
|
61
|
+
"required": true,
|
|
62
|
+
"itemsOf": "capabilityEntryFields",
|
|
63
|
+
"description": "Capability entries."
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"capabilityEntryFields": [
|
|
67
|
+
{
|
|
68
|
+
"name": "id",
|
|
69
|
+
"type": "string",
|
|
70
|
+
"required": true,
|
|
71
|
+
"description": "Stable capability identifier, unique within a manifest."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "title",
|
|
75
|
+
"type": "string",
|
|
76
|
+
"required": true,
|
|
77
|
+
"description": "Short human-readable label."
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "description",
|
|
81
|
+
"type": "string",
|
|
82
|
+
"required": true,
|
|
83
|
+
"description": "One-line description of the effect."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "method",
|
|
87
|
+
"type": "string",
|
|
88
|
+
"required": true,
|
|
89
|
+
"description": "HTTP method of the backing Minions route."
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "path",
|
|
93
|
+
"type": "string",
|
|
94
|
+
"required": true,
|
|
95
|
+
"description": "Canonical route path template of the backing Minions route."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "scopes",
|
|
99
|
+
"type": "array",
|
|
100
|
+
"required": true,
|
|
101
|
+
"itemsOf": "scopes",
|
|
102
|
+
"description": "Scopes consumed, drawn from the scope vocabulary."
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "destructive",
|
|
106
|
+
"type": "boolean",
|
|
107
|
+
"required": true,
|
|
108
|
+
"description": "Whether invoking the capability destroys or irreversibly mutates state. A consumer authorization input, so it is always declared explicitly and never inferred from the route name, method, or description."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "confirm",
|
|
112
|
+
"type": "string",
|
|
113
|
+
"required": true,
|
|
114
|
+
"allowedValuesOf": "confirmModes",
|
|
115
|
+
"description": "Confirmation policy for invocation."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "params",
|
|
119
|
+
"type": "array",
|
|
120
|
+
"required": true,
|
|
121
|
+
"itemsOf": "capabilityParamFields",
|
|
122
|
+
"description": "Parameter descriptors; may be empty."
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"capabilityParamFields": [
|
|
126
|
+
{
|
|
127
|
+
"name": "name",
|
|
128
|
+
"type": "string",
|
|
129
|
+
"required": true,
|
|
130
|
+
"description": "Parameter name as sent to the route."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "type",
|
|
134
|
+
"type": "string",
|
|
135
|
+
"required": true,
|
|
136
|
+
"allowedValuesOf": "paramTypes",
|
|
137
|
+
"description": "Parameter type from the parameter-type set."
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "required",
|
|
141
|
+
"type": "boolean",
|
|
142
|
+
"required": true,
|
|
143
|
+
"description": "Whether the caller must supply the parameter."
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "description",
|
|
147
|
+
"type": "string",
|
|
148
|
+
"required": false,
|
|
149
|
+
"description": "Optional one-line parameter description."
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "allowedValues",
|
|
153
|
+
"type": "array",
|
|
154
|
+
"required": false,
|
|
155
|
+
"description": "Optional closed value set."
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "maxLength",
|
|
159
|
+
"type": "integer",
|
|
160
|
+
"required": false,
|
|
161
|
+
"description": "Optional maximum length for string parameters."
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"checksum": "sha256:28a2266d5b4f4a4618073461a06b07380121419603ca31f2539eb8263cfe9318"
|
|
165
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# `saveCooldowns` merge semantics
|
|
2
2
|
|
|
3
3
|
> **Historical design record:** this predates the SQL-only cutover. Cooldowns now
|
|
4
|
-
> persist through `engine/small-state-store.js`; file and lock references below
|
|
4
|
+
> persist through `engine/persistence/small-state-store.js`; file and lock references below
|
|
5
5
|
> describe the superseded implementation evaluated by the original PRD.
|
|
6
6
|
|
|
7
7
|
Scoping deliverable for PRD item **P-bfa3a-scope-cooldown-merge** (Wave 3, PR10
|
|
8
8
|
pre-work) of the 2026-05-27 weekly bug-audit plan. Decides the merge strategy
|
|
9
9
|
the implementation PR (**P-bfa3b-cooldown-lost-update**) will apply at
|
|
10
|
-
`engine/cooldown.js:63-101`. No code is modified by this scoping artefact.
|
|
10
|
+
`engine/orchestration/cooldown.js:63-101`. No code is modified by this scoping artefact.
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
`engine/cooldown.js:63-101` (`saveCooldowns`) handles only **deletions** across
|
|
14
|
+
`engine/orchestration/cooldown.js:63-101` (`saveCooldowns`) handles only **deletions** across
|
|
15
15
|
the debounced in-memory ↔ on-disk boundary. Any key added to `cooldowns.json`
|
|
16
16
|
by a concurrent writer between two of our writes is **silently overwritten**
|
|
17
17
|
when the in-memory `dispatchCooldowns` Map is flushed via
|
|
@@ -20,7 +20,7 @@ the window.
|
|
|
20
20
|
|
|
21
21
|
`mutateCooldowns` already runs through `mutateJsonFileLocked`, which acquires
|
|
22
22
|
an exclusive `withFileLock` for the read-modify-write
|
|
23
|
-
(source: `engine/shared.js` `mutateCooldowns` ~L1625 and `mutateJsonFileLocked` ~L1542), so the callback
|
|
23
|
+
(source: `engine/core/shared.js` `mutateCooldowns` ~L1625 and `mutateJsonFileLocked` ~L1542), so the callback
|
|
24
24
|
receives the freshly-read `diskCooldowns` snapshot — but the current code
|
|
25
25
|
throws that snapshot away.
|
|
26
26
|
|
|
@@ -53,7 +53,7 @@ acceptance from P-bfa3b verbatim.
|
|
|
53
53
|
after the next `loadCooldowns()` on writer B.
|
|
54
54
|
|
|
55
55
|
2. **Deletion-merge preserved (regression).** The existing
|
|
56
|
-
`_lastDiskCooldownKeys` logic at `engine/cooldown.js:70-74` runs first,
|
|
56
|
+
`_lastDiskCooldownKeys` logic at `engine/orchestration/cooldown.js:70-74` runs first,
|
|
57
57
|
before the union — any key present in `_lastDiskCooldownKeys` (i.e. we
|
|
58
58
|
wrote it on our previous flush) but absent from the freshly-read
|
|
59
59
|
`diskCooldowns` is treated as a deliberate delete by another writer and is
|
|
@@ -73,7 +73,7 @@ acceptance from P-bfa3b verbatim.
|
|
|
73
73
|
## Trade-offs for the three options NOT chosen
|
|
74
74
|
|
|
75
75
|
- **(b) per-key timestamp-tagged merge** — The entry schema already carries
|
|
76
|
-
`timestamp` (source: `engine/cooldown.js:154, 171, 195`), so this would add
|
|
76
|
+
`timestamp` (source: `engine/orchestration/cooldown.js:154, 171, 195`), so this would add
|
|
77
77
|
no new field; but it adds per-key branching in the flush hot path while
|
|
78
78
|
converging on the same winner as (a) in every realistic case, because the
|
|
79
79
|
in-memory entry whose mutation triggered the debounce is by construction at
|
|
@@ -88,12 +88,12 @@ acceptance from P-bfa3b verbatim.
|
|
|
88
88
|
`setCooldown` / `setCooldownFailure` / `isOnCooldown` call adds one fs read
|
|
89
89
|
to the per-dispatch evaluation hot path, contradicts the module-level
|
|
90
90
|
`dispatchCooldowns` Map cache that exists specifically to avoid that cost
|
|
91
|
-
(source: `engine/cooldown.js:39`), and the lock-protected merge in (a)
|
|
91
|
+
(source: `engine/orchestration/cooldown.js:39`), and the lock-protected merge in (a)
|
|
92
92
|
achieves the same correctness without the per-read penalty.
|
|
93
93
|
|
|
94
94
|
## Implementation notes for the P-bfa3b dispatch (dallas)
|
|
95
95
|
|
|
96
|
-
- Touch only `engine/cooldown.js:63-101` (`saveCooldowns`) — no API or signature
|
|
96
|
+
- Touch only `engine/orchestration/cooldown.js:63-101` (`saveCooldowns`) — no API or signature
|
|
97
97
|
changes, no caller-side migration. Expected diff: ~10–15 LoC inside the
|
|
98
98
|
existing `mutateCooldowns` callback.
|
|
99
99
|
- The expiry-prune loop and the `pendingContexts` cap/truncate loop must run on
|
|
@@ -115,10 +115,10 @@ acceptance from P-bfa3b verbatim.
|
|
|
115
115
|
|
|
116
116
|
## Source references
|
|
117
117
|
|
|
118
|
-
- `engine/cooldown.js:63-101` — current lost-update site
|
|
119
|
-
- `engine/cooldown.js:38-60` — `loadCooldowns` + `_lastDiskCooldownKeys` baseline
|
|
120
|
-
- `engine/shared.js` `mutateCooldowns` (~L1625) — already lock-protected
|
|
121
|
-
- `engine/shared.js` `mutateJsonFileLocked` (~L1542) — reads disk inside the
|
|
118
|
+
- `engine/orchestration/cooldown.js:63-101` — current lost-update site
|
|
119
|
+
- `engine/orchestration/cooldown.js:38-60` — `loadCooldowns` + `_lastDiskCooldownKeys` baseline
|
|
120
|
+
- `engine/core/shared.js` `mutateCooldowns` (~L1625) — already lock-protected
|
|
121
|
+
- `engine/core/shared.js` `mutateJsonFileLocked` (~L1542) — reads disk inside the
|
|
122
122
|
lock; `skipWriteIfUnchanged` enabled for cooldowns
|
|
123
123
|
- `prd/bug-fix-plan-from-weekly-audit-2026-05-27.json` — P-bfa3a (this scoping)
|
|
124
124
|
and P-bfa3b (implementation acceptance criteria)
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
| `capabilities.claudeMdNativeDiscovery` | **`false`** | Copilot loads its native `AGENTS.md`, not repo-authored `CLAUDE.md`; the engine may inject the latter through its separate propagation layer. |
|
|
29
29
|
| `capabilities.fallbackModel` | **`false`** | No `--fallback-model` flag. |
|
|
30
30
|
| `capabilities.sessionPersistenceControl` | **`false`** | Copilot manages session state internally in `~/.copilot/session-state/`. Engine cannot opt out without `--config-dir`. |
|
|
31
|
-
| `capabilities.streamConsumer` | **`true`** | The adapter supplies the stream accumulator used by `engine/llm.js`. |
|
|
31
|
+
| `capabilities.streamConsumer` | **`true`** | The adapter supplies the stream accumulator used by `engine/agents/llm.js`. |
|
|
32
32
|
| `capabilities.imageInput` | **`true`** | Base64 image payloads are materialized to temp files and passed as `--attachment <path>` (repeatable flag, W-mqv7324u0021db5d). See §10a. |
|
|
33
33
|
| `capabilities.acpWorkerPool` | **`true`** | `copilot --acp` supports the capability-gated CC and fleet worker pools. |
|
|
34
34
|
|
|
@@ -88,7 +88,7 @@ When falling back to the gh-hosted form, the adapter must return:
|
|
|
88
88
|
{ bin: '<path-to-gh.exe>', native: true, leadingArgs: ['copilot'] }
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
so that `engine/spawn-agent.js` invokes `gh copilot <flags>` rather than
|
|
91
|
+
so that `engine/agents/spawn-agent.js` invokes `gh copilot <flags>` rather than
|
|
92
92
|
`copilot <flags>`. The availability probe does not guarantee that every
|
|
93
93
|
built-in/extension version accepts the standalone agent flags. The path remains
|
|
94
94
|
best-effort; preflight invokes the resolved command with `leadingArgs` and
|
|
@@ -130,7 +130,7 @@ copilot -p $big --output-format json -s --allow-all --no-ask-user --autopilot
|
|
|
130
130
|
### Decision
|
|
131
131
|
|
|
132
132
|
Set `capabilities.promptViaArg = false`. The adapter **does not** emit
|
|
133
|
-
`--prompt <text>` in args; instead, `engine/spawn-agent.js` pipes the final
|
|
133
|
+
`--prompt <text>` in args; instead, `engine/agents/spawn-agent.js` pipes the final
|
|
134
134
|
prompt (system block prepended) via stdin. This:
|
|
135
135
|
|
|
136
136
|
- Sidesteps the Windows 32 KB ARG_MAX cliff for any prompt that bundles
|
|
@@ -176,7 +176,7 @@ Empirically confirmed flags for non-interactive Copilot invocations:
|
|
|
176
176
|
| `--allow-all` | **required** | Equivalent to `--allow-all-tools --allow-all-paths --allow-all-urls`. Without this the CLI prompts for every tool/path use, which deadlocks in stdin/stdout mode. |
|
|
177
177
|
| `--no-ask-user` | **required** | Removes the `ask_user` tool. Without it the agent can stall waiting for human input. |
|
|
178
178
|
| `--autopilot` | for multi-turn agency | Enables `task_complete`-driven multi-turn loop. **Without it** the session ends after one assistant response (see §3.1). |
|
|
179
|
-
| `--log-level <level>` | **do not emit** | Copilot CLI 1.0.76-1
|
|
179
|
+
| `--log-level <level>` | **do not emit** | Copilot CLI 1.0.76-1 and 1.0.76-2 exit silently with code 1 for explicit non-default levels. Omit the flag and use the CLI default; `--output-format json` still keeps stdout machine-readable. |
|
|
180
180
|
| `--disable-builtin-mcps` | gated by config | Disables `github-mcp-server`. Default-on for Minions (`copilotDisableBuiltinMcps: true`) to prevent split-brain PR creation. |
|
|
181
181
|
| `--no-color` | always emitted | Keeps any incidental CLI rendering free of ANSI color. |
|
|
182
182
|
| `--plain-diff` | always emitted | Keeps incidental diff rendering plain even though normal output is JSONL. |
|
|
@@ -187,7 +187,7 @@ Empirically confirmed flags for non-interactive Copilot invocations:
|
|
|
187
187
|
| `--stream on` / `--stream off` | optional | Default is `on`. See §4. |
|
|
188
188
|
| `--enable-reasoning-summaries` | optional | Maps from `opts.reasoningSummaries`; only Anthropic models populate `assistant.reasoning_delta`. |
|
|
189
189
|
| `--add-dir <path>` | adapter-supported, normally omitted | Registers extra read-allowed dirs when `opts.addDirs` is supplied. Normal Minions dispatch leaves this empty and relies on Copilot's native cwd/user-config discovery. |
|
|
190
|
-
| `--attachment <path>` | injected for image inputs | Passes an image file to the model. Repeatable. The adapter writes each base64 image payload inside the call-scoped temp directory and emits one `--attachment` per file; `engine/llm.js` removes the directory after the process settles. Gated by `capabilities.imageInput`. |
|
|
190
|
+
| `--attachment <path>` | injected for image inputs | Passes an image file to the model. Repeatable. The adapter writes each base64 image payload inside the call-scoped temp directory and emits one `--attachment` per file; `engine/agents/llm.js` removes the directory after the process settles. Gated by `capabilities.imageInput`. |
|
|
191
191
|
| `-v` / `--verbose` | **never emit** | Does not exist on Copilot. The Claude adapter emits `--verbose`; the Copilot adapter MUST NOT. |
|
|
192
192
|
|
|
193
193
|
### 3.1 `--autopilot` vs single-shot
|
|
@@ -198,7 +198,7 @@ Empirically confirmed flags for non-interactive Copilot invocations:
|
|
|
198
198
|
| no `--autopilot` | `assistant.turn_end` → `result` | One-shot Q&A. Fewer events; no `session.task_complete`, no `session.info`. Closer match for CC / doc-chat use cases that don't need multi-turn. |
|
|
199
199
|
|
|
200
200
|
The Minions agent path (engine.js dispatch) uses autopilot. CC and doc-chat in
|
|
201
|
-
`engine/llm.js` should also use autopilot — they need tool use even when only
|
|
201
|
+
`engine/agents/llm.js` should also use autopilot — they need tool use even when only
|
|
202
202
|
one assistant turn is expected — but the parser must tolerate the absence of
|
|
203
203
|
`session.task_complete` because some early-exit paths skip it.
|
|
204
204
|
|
|
@@ -652,7 +652,7 @@ When the spike's findings disagree with the plan text, **this document wins**
|
|
|
652
652
|
`capabilities.imageInput: true`. The Copilot CLI accepts image files via
|
|
653
653
|
`--attachment <path>` (the flag is repeatable). The adapter's `buildArgs(opts)`
|
|
654
654
|
materializes each base64 payload from `opts.images` to a temp file in
|
|
655
|
-
`opts.tmpDir` and appends `--attachment <path>` per file. `engine/llm.js`
|
|
655
|
+
`opts.tmpDir` and appends `--attachment <path>` per file. `engine/agents/llm.js`
|
|
656
656
|
removes that call-scoped directory after the process settles.
|
|
657
657
|
|
|
658
658
|
```js
|
package/docs/cross-repo-plans.md
CHANGED
|
@@ -34,7 +34,7 @@ A cross-repo plan is detected by a single signal at parse time: `shared.extractP
|
|
|
34
34
|
**Projects:** minions, minions-opg
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Both forms accept `,`, `|`, or `;` as separators with surrounding whitespace, and strip surrounding quotes. See `engine/shared.js:4516-4559` (`extractPlanDeclaredProject` / `extractPlanTargetProjects`) for the exact regexes.
|
|
37
|
+
Both forms accept `,`, `|`, or `;` as separators with surrounding whitespace, and strip surrounding quotes. See `engine/core/shared.js:4516-4559` (`extractPlanDeclaredProject` / `extractPlanTargetProjects`) for the exact regexes.
|
|
38
38
|
|
|
39
39
|
The dashboard's Create-Plan modal (P-b51c08af) renders a multi-select project picker. Submitting two or more projects normalizes to a deduped array and `POST /api/plans/create` writes the plan with the plural `**Projects:**` header + HTML comment marker, no singular `**Project:**` line. Selecting zero or one project keeps the legacy singular header (no behavioural change for single-project plans).
|
|
40
40
|
|
|
@@ -136,18 +136,18 @@ This is what makes the per-project dispatcher's later `git worktree add ... orig
|
|
|
136
136
|
|
|
137
137
|
`engine.js#discoverFromWorkItems(config, project)` reads exactly one project SQL scope per call, routes pending items via `routing.md`, and returns `newWork[]` entries for the dispatcher. Cross-repo plans don't change this loop; the engine iterates all configured projects per tick.
|
|
138
138
|
|
|
139
|
-
Module-level `_claimedAgents` in `engine/routing.js` persists across in-process calls but is cleared at the start of each discovery pass (`routing.resetClaimedAgents()`), so two items in different projects routed to the same agent in the same pass contend correctly for the single agent slot.
|
|
139
|
+
Module-level `_claimedAgents` in `engine/orchestration/routing.js` persists across in-process calls but is cleared at the start of each discovery pass (`routing.resetClaimedAgents()`), so two items in different projects routed to the same agent in the same pass contend correctly for the single agent slot.
|
|
140
140
|
|
|
141
141
|
## Per-project verify fan-out
|
|
142
142
|
|
|
143
|
-
`engine/lifecycle.js#checkPlanCompletion` (`engine/lifecycle.js:26-155`, fan-out at `:279-494`) gates on two conditions:
|
|
143
|
+
`engine/orchestration/lifecycle.js#checkPlanCompletion` (`engine/orchestration/lifecycle.js:26-155`, fan-out at `:279-494`) gates on two conditions:
|
|
144
144
|
|
|
145
145
|
1. Every PRD `missing_features` item has been materialized into a WI.
|
|
146
146
|
2. Every materialized WI is in `PLAN_TERMINAL_STATUSES` (`DONE_STATUSES`, `failed`, or `cancelled`).
|
|
147
147
|
|
|
148
148
|
When both gates pass, the function groups **active PRs** by project from the SQL PR store and joins them to done items through the `pr_links` table. The result is a `touchedProjects` array: every project that has at least one active PR linked to one of the plan's done items.
|
|
149
149
|
|
|
150
|
-
For each touched project the fan-out (`engine/lifecycle.js:312-494`):
|
|
150
|
+
For each touched project the fan-out (`engine/orchestration/lifecycle.js:312-494`):
|
|
151
151
|
|
|
152
152
|
- Looks up any existing verify WI keyed on `(sourcePlan, itemType:'verify', project)`. Legacy single-WI plans match against the primary project name when `existingVerify.project` is unset.
|
|
153
153
|
- Skips if the existing verify is active; re-opens if it's eligible (`isReopenableVerify`).
|
|
@@ -165,7 +165,7 @@ The verify agents then run in parallel — one per touched project, each in its
|
|
|
165
165
|
|
|
166
166
|
Plan card and detail views surface the cross-repo shape:
|
|
167
167
|
|
|
168
|
-
- **`i.projects[]` per PRD item + plan `_projects` rollup** (P-e8d49105, `engine/queries.js`) — populated when at least one PRD item carries a `project` field. Plan card uses `_projects.length >= 2` as the gate for cross-repo UI variations.
|
|
168
|
+
- **`i.projects[]` per PRD item + plan `_projects` rollup** (P-e8d49105, `engine/core/queries.js`) — populated when at least one PRD item carries a `project` field. Plan card uses `_projects.length >= 2` as the gate for cross-repo UI variations.
|
|
169
169
|
- **Per-project status rollup pills** (P-66b1faec, `dashboard.js#handlePlansList`) — when `Object.keys(_perProjectProgress).length >= 2`, the plan card meta line renders one pill per project with a per-project completion count (e.g. `minions 3/4 · minions-opg 1/2`). Single-project plans render the legacy aggregate progress bar unchanged.
|
|
170
170
|
- **Per-project verify badges in plan detail** (P-d7e592b1, `dashboard/js/render-plans.js`) — when `verifyWis.length >= 2`, the detail view renders one labelled verify badge per project; single-project plans render the legacy single badge unchanged.
|
|
171
171
|
|
|
@@ -214,7 +214,7 @@ Plan markdown `plans/cross-repo-launch.md`:
|
|
|
214
214
|
Add a new compliance check + matching engine plumbing.
|
|
215
215
|
```
|
|
216
216
|
|
|
217
|
-
Operator approves the plan. Plan-to-prd dispatches against the `minions` project (read-only worktree, first in the target list). The agent writes `agents/<agent-id>/prd-result.json`; the engine validates the envelope, imports its `prd` object into SQLite under filename `cross-repo-launch.json`, and
|
|
217
|
+
Operator approves the plan. Plan-to-prd dispatches against the `minions` project (read-only worktree, first in the target list). The agent writes `agents/<agent-id>/prd-result.json` declaring the engine-pinned `filename` and the dispatched `work_item`; the engine validates the envelope, imports its `prd` object into SQLite under filename `cross-repo-launch.json`, and consumes the sidecar. The cross-repo filename (`cross-<uid>-<date>.json`) is generated once and then pinned on the work item, so a retry keeps the same expected identity instead of orphaning the previous attempt's result — see [plan-lifecycle.md](plan-lifecycle.md#plan-to-prd-result-sidecar). The imported PRD shape is:
|
|
218
218
|
|
|
219
219
|
```json
|
|
220
220
|
{
|
|
@@ -258,7 +258,7 @@ When you need to change the cross-repo path, the load-bearing seams are:
|
|
|
258
258
|
|
|
259
259
|
| Concern | File:line | Notes |
|
|
260
260
|
| --- | --- | --- |
|
|
261
|
-
| Parse plan markdown projects | `engine/shared.js:4516` (`extractPlanDeclaredProject`), `engine/shared.js:4539` (`extractPlanTargetProjects`) | Both scan first 80 lines; HTML comment marker preferred over `**Projects:**` fallback. |
|
|
261
|
+
| Parse plan markdown projects | `engine/core/shared.js:4516` (`extractPlanDeclaredProject`), `engine/core/shared.js:4539` (`extractPlanTargetProjects`) | Both scan first 80 lines; HTML comment marker preferred over `**Projects:**` fallback. |
|
|
262
262
|
| `POST /api/plans/create` array normalization | `dashboard.js:13958-14006` | Dedup + per-name validation via `shared.findProjectByName`; 0–1 → singular header, 2+ → plural header + marker. |
|
|
263
263
|
| Plan-to-prd dispatch wiring | `engine.js:10319-10506` (`discoverCentralWorkItems`) | Sets `vars.target_projects` when plan is cross-repo; picks first listed project for the read-only worktree. |
|
|
264
264
|
| Plan-to-prd playbook contract | `playbooks/plan-to-prd.md` (P-3b8c40d9) | Tells the agent to omit top-level `project`, set per-item `project`, default to `parallel`. |
|
|
@@ -267,11 +267,11 @@ When you need to change the cross-repo path, the load-bearing seams are:
|
|
|
267
267
|
| Shared-branch pre-create per project | `engine.js:7718-7756` | Idempotent `rev-parse` → `branch` → `push -u`; per-project failure isolation. |
|
|
268
268
|
| Cross-repo dep partitioning + advisory fetch | `engine.js:4457-4658` (`spawnAgent` dep loop) | `isCrossRepo` split; transfer-fetch via filesystem-path remote into `refs/cross-repo-deps/<branch>`. |
|
|
269
269
|
| Cross-repo dep prompt section | `engine.js:793-823` (`buildCrossRepoDepsSection`) | Renders one section per dep with repo, branch, SHA, files, local ref. |
|
|
270
|
-
| Per-project verify fan-out | `engine/lifecycle.js:279-494` (`checkPlanCompletion`) | Group active PRs by project via SQL links; one verify WI per touched project. |
|
|
271
|
-
| Verify WI creation | `engine/lifecycle.js:350-410`, `engine/lifecycle.js:445-494` | `itemType:'verify'`, `project: projName`, project-prefixed title when `touchedProjects.length > 1`. |
|
|
270
|
+
| Per-project verify fan-out | `engine/orchestration/lifecycle.js:279-494` (`checkPlanCompletion`) | Group active PRs by project via SQL links; one verify WI per touched project. |
|
|
271
|
+
| Verify WI creation | `engine/orchestration/lifecycle.js:350-410`, `engine/orchestration/lifecycle.js:445-494` | `itemType:'verify'`, `project: projName`, project-prefixed title when `touchedProjects.length > 1`. |
|
|
272
272
|
| Per-project rollup pills | `dashboard.js:7826-7845`, `dashboard/js/render-plans.js:389-417` | Gate `Object.keys(_perProjectProgress).length >= 2`. |
|
|
273
273
|
| Per-project verify badges | `dashboard/js/render-plans.js:351-417` | Gate `verifyWis.length >= 2`. |
|
|
274
|
-
| `i.projects[]` + plan `_projects` rollup | `engine/queries.js:2442-2444`, `dashboard.js:7813-7826` | Populated when at least one PRD item has a `project` field. |
|
|
274
|
+
| `i.projects[]` + plan `_projects` rollup | `engine/core/queries.js:2442-2444`, `dashboard.js:7813-7826` | Populated when at least one PRD item has a `project` field. |
|
|
275
275
|
|
|
276
276
|
## Executable spec
|
|
277
277
|
|
|
@@ -9,12 +9,12 @@ This file records false-positive findings from past dead-code audits so subseque
|
|
|
9
9
|
"id": "reviewFeedbackSourceMatches-not-dead-exported",
|
|
10
10
|
"retractedOn": "2026-06-03",
|
|
11
11
|
"retractedBy": "Dead Code Review meeting (Lambert, Dallas, Ripley unanimous)",
|
|
12
|
-
"claim": "engine/lifecycle.js reviewFeedbackSourceMatches is still dead-exported",
|
|
13
|
-
"correction": "The function is NOT exported (verify: grep `reviewFeedbackSourceMatches` in engine/lifecycle.js module.exports block at :5161-5220 returns zero hits) and IS live-called intra-file at engine/lifecycle.js:2939 inside createReviewFeedbackForAuthor.",
|
|
12
|
+
"claim": "engine/orchestration/lifecycle.js reviewFeedbackSourceMatches is still dead-exported",
|
|
13
|
+
"correction": "The function is NOT exported (verify: grep `reviewFeedbackSourceMatches` in engine/orchestration/lifecycle.js module.exports block at :5161-5220 returns zero hits) and IS live-called intra-file at engine/orchestration/lifecycle.js:2939 inside createReviewFeedbackForAuthor.",
|
|
14
14
|
"sources": [
|
|
15
|
-
"engine/lifecycle.js:2883 (definition)",
|
|
16
|
-
"engine/lifecycle.js:2939 (live caller inside createReviewFeedbackForAuthor)",
|
|
17
|
-
"engine/lifecycle.js:5161-5220 (module.exports block — function absent)",
|
|
15
|
+
"engine/orchestration/lifecycle.js:2883 (definition)",
|
|
16
|
+
"engine/orchestration/lifecycle.js:2939 (live caller inside createReviewFeedbackForAuthor)",
|
|
17
|
+
"engine/orchestration/lifecycle.js:5161-5220 (module.exports block — function absent)",
|
|
18
18
|
"knowledge/project-notes/2026-06-03-ripley-meeting-conclusion-dead-code-review-2026-06-03.md",
|
|
19
19
|
"notes/inbox/ripley-2026-06-03-1012.md (R2 retraction)"
|
|
20
20
|
],
|