@jterrats/open-orchestra 1.0.9 → 1.0.10

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.
Files changed (123) hide show
  1. package/AGENTS.md +4 -1
  2. package/CLAUDE.md +4 -1
  3. package/dist/autonomous-run-store.js +2 -2
  4. package/dist/autonomous-run-store.js.map +1 -1
  5. package/dist/benchmark.js +2 -1
  6. package/dist/benchmark.js.map +1 -1
  7. package/dist/clarification.js +2 -1
  8. package/dist/clarification.js.map +1 -1
  9. package/dist/collaboration-flows.d.ts +1 -2
  10. package/dist/command-manifest.js +16 -5
  11. package/dist/command-manifest.js.map +1 -1
  12. package/dist/command-routes-integrations.js +2 -1
  13. package/dist/command-routes-integrations.js.map +1 -1
  14. package/dist/command-utils.d.ts +1 -2
  15. package/dist/command-utils.js.map +1 -1
  16. package/dist/commands.d.ts +1 -1
  17. package/dist/commands.js +1 -1
  18. package/dist/commands.js.map +1 -1
  19. package/dist/constants.js +1 -0
  20. package/dist/constants.js.map +1 -1
  21. package/dist/cursor-canvas.js +21 -1
  22. package/dist/cursor-canvas.js.map +1 -1
  23. package/dist/cursor-mdc.d.ts +10 -0
  24. package/dist/cursor-mdc.js +37 -0
  25. package/dist/cursor-mdc.js.map +1 -0
  26. package/dist/fs-utils.js +2 -1
  27. package/dist/fs-utils.js.map +1 -1
  28. package/dist/generated-guidance-health.d.ts +33 -0
  29. package/dist/generated-guidance-health.js +125 -0
  30. package/dist/generated-guidance-health.js.map +1 -0
  31. package/dist/health-checks.js +2 -51
  32. package/dist/health-checks.js.map +1 -1
  33. package/dist/id-utils.d.ts +3 -0
  34. package/dist/id-utils.js +11 -0
  35. package/dist/id-utils.js.map +1 -0
  36. package/dist/instruction-blocks.js +20 -5
  37. package/dist/instruction-blocks.js.map +1 -1
  38. package/dist/mcp-oauth-proxy.js +5 -5
  39. package/dist/mcp-oauth-proxy.js.map +1 -1
  40. package/dist/memory-status.js +31 -5
  41. package/dist/memory-status.js.map +1 -1
  42. package/dist/memory.js +31 -7
  43. package/dist/memory.js.map +1 -1
  44. package/dist/notifications.js +12 -2
  45. package/dist/notifications.js.map +1 -1
  46. package/dist/phase-deterministic-output.d.ts +4 -0
  47. package/dist/phase-deterministic-output.js +62 -0
  48. package/dist/phase-deterministic-output.js.map +1 -0
  49. package/dist/phase-executor.js +4 -3
  50. package/dist/phase-executor.js.map +1 -1
  51. package/dist/provider-utils.js +11 -1
  52. package/dist/provider-utils.js.map +1 -1
  53. package/dist/runtime-bootstrap.js +23 -2
  54. package/dist/runtime-bootstrap.js.map +1 -1
  55. package/dist/runtime-commands.js +4 -0
  56. package/dist/runtime-commands.js.map +1 -1
  57. package/dist/runtime-execution.js +32 -3
  58. package/dist/runtime-execution.js.map +1 -1
  59. package/dist/runtime-lifecycle-watch-adapters.d.ts +4 -0
  60. package/dist/runtime-lifecycle-watch-adapters.js +87 -0
  61. package/dist/runtime-lifecycle-watch-adapters.js.map +1 -0
  62. package/dist/runtime-lifecycle-watch.d.ts +3 -11
  63. package/dist/runtime-lifecycle-watch.js +4 -83
  64. package/dist/runtime-lifecycle-watch.js.map +1 -1
  65. package/dist/runtime-parent-action-dispatch.d.ts +30 -0
  66. package/dist/runtime-parent-action-dispatch.js +114 -0
  67. package/dist/runtime-parent-action-dispatch.js.map +1 -0
  68. package/dist/runtime-parent-action-eligibility.d.ts +12 -0
  69. package/dist/runtime-parent-action-eligibility.js +131 -0
  70. package/dist/runtime-parent-action-eligibility.js.map +1 -0
  71. package/dist/runtime-parent-actions.js +22 -9
  72. package/dist/runtime-parent-actions.js.map +1 -1
  73. package/dist/skills-validation.js +1 -2
  74. package/dist/skills-validation.js.map +1 -1
  75. package/dist/sonar-commands.d.ts +1 -0
  76. package/dist/sonar-commands.js +36 -0
  77. package/dist/sonar-commands.js.map +1 -1
  78. package/dist/sonar-insights.d.ts +12 -0
  79. package/dist/sonar-insights.js +30 -55
  80. package/dist/sonar-insights.js.map +1 -1
  81. package/dist/sonar-payload-normalizers.d.ts +16 -0
  82. package/dist/sonar-payload-normalizers.js +67 -0
  83. package/dist/sonar-payload-normalizers.js.map +1 -0
  84. package/dist/sonar-preflight.d.ts +26 -0
  85. package/dist/sonar-preflight.js +111 -0
  86. package/dist/sonar-preflight.js.map +1 -0
  87. package/dist/sonar-redaction.d.ts +1 -0
  88. package/dist/sonar-redaction.js +13 -0
  89. package/dist/sonar-redaction.js.map +1 -0
  90. package/dist/subagent-protocol.js.map +1 -1
  91. package/dist/task-graph-commands.js +8 -1
  92. package/dist/task-graph-commands.js.map +1 -1
  93. package/dist/telemetry-redaction.js +31 -2
  94. package/dist/telemetry-redaction.js.map +1 -1
  95. package/dist/types/runtime.d.ts +32 -0
  96. package/dist/types.d.ts +1 -1
  97. package/dist/types.js.map +1 -1
  98. package/dist/web-artifacts.js +8 -3
  99. package/dist/web-artifacts.js.map +1 -1
  100. package/dist/web-console/assets/index-DA8Fs4r7.js +11 -0
  101. package/dist/web-console/index.html +1 -1
  102. package/dist/workflow-background-subagents.js +8 -4
  103. package/dist/workflow-background-subagents.js.map +1 -1
  104. package/dist/workflow-handoff-contract.js +1 -1
  105. package/dist/workflow-handoff-contract.js.map +1 -1
  106. package/dist/workflow-phase-transition.js +2 -2
  107. package/dist/workflow-phase-transition.js.map +1 -1
  108. package/dist/workflow-run-commands.js +32 -6
  109. package/dist/workflow-run-commands.js.map +1 -1
  110. package/dist/workflow-services.js +5 -1
  111. package/dist/workflow-services.js.map +1 -1
  112. package/dist/workspace.js +2 -1
  113. package/dist/workspace.js.map +1 -1
  114. package/docs/adoption-guide.md +12 -0
  115. package/docs/autonomous-workflow.md +10 -2
  116. package/docs/claude-adapter-qa-matrix.md +56 -0
  117. package/docs/orchestra-mvp.md +13 -0
  118. package/docs/release-test-matrix.md +22 -0
  119. package/docs/runtime-adapters.md +96 -16
  120. package/docs/sonar-quality-gates.md +107 -0
  121. package/package.json +2 -1
  122. package/rules/delivery-quality-gates.mdc +2 -0
  123. package/dist/web-console/assets/index-DXbrxR_d.js +0 -11
@@ -28,8 +28,9 @@ packet:
28
28
  approvals stay inside Codex; Orchestra renders briefs and packets only.
29
29
  - `claude-cli`: use the current Claude Code session. Orchestra renders the
30
30
  packet and the Claude parent launches it with the native Agent/Subagent tool
31
- when available; `Task` is treated as a legacy alias if that is what the
32
- runtime exposes.
31
+ when available. The tested auto-dispatch eligibility contract recognizes
32
+ `claude-code-agent` as the primary tool; `Task` is documented as a deferred
33
+ legacy/manual alias and is skipped as `tool-mismatch` by auto-dispatch.
33
34
  - `cursor-cli`: use the current Cursor runtime. Orchestra renders the packet
34
35
  and the Cursor parent launches it as a Background Agent so the current chat
35
36
  remains usable while the child works.
@@ -164,6 +165,7 @@ orchestra runtime spawn-request --task STORY-001 --role developer --runtime code
164
165
  orchestra runtime parent-actions --task STORY-001 --json
165
166
  orchestra runtime parent-actions --task STORY-001 --dispatch --until-idle --runtime codex-cli --timeout 5m --idle-timeout 10s --json
166
167
  orchestra runtime spawn-lifecycle --session STORY-001:manual:developer:codex-cli --status spawned --agent-id <runtime-agent-id> --json
168
+ orchestra runtime watch --task STORY-001 --once --json
167
169
  ```
168
170
 
169
171
  The matching local APIs are `GET /api/runtime/sessions`,
@@ -183,6 +185,15 @@ points to the prompt artifact, expected result artifact, ownership paths,
183
185
  allowed commands, and lifecycle commands. It does not include secrets or direct
184
186
  provider credentials.
185
187
 
188
+ Pending parent actions also include structured `eligibility` metadata. The
189
+ metadata records the checked runtime, action kind, tool name, session status,
190
+ runtime filter when supplied, and safety state. Dispatchable actions report
191
+ `status=dispatchable`; skipped actions include machine-readable reason codes
192
+ and operator-readable messages. Current skip codes are `already-dispatched`,
193
+ `queued`, `suspended`, `terminal`, `stale-or-unsafe`, `runtime-mismatch`,
194
+ `tool-mismatch`, `unsupported-runtime`, `unavailable-native-tool`, and
195
+ `manual-request`.
196
+
186
197
  When `workflow run` pauses with a pending parent runtime action, parent agents
187
198
  have two supported paths:
188
199
 
@@ -192,29 +203,98 @@ have two supported paths:
192
203
  - Auto-dispatch: run
193
204
  `runtime parent-actions --task <id> --dispatch --until-idle --runtime <runtime-id>`.
194
205
  The dispatcher repeatedly inspects pending parent actions, dispatches only
195
- safe actions for the active runtime, records spawned lifecycle events with
196
- dispatcher session ids, applies `runtime watch` completions when expected
197
- handoff artifacts appear, resumes paused workflow runs, and continues across
198
- later phases until idle or timeout.
206
+ safe actions for the active runtime, records spawned and active lifecycle
207
+ events with stable runtime child ids or deterministic fallback labels, applies
208
+ `runtime watch` completions when expected handoff artifacts appear, resumes
209
+ paused workflow runs, and continues across later phases until idle or timeout.
199
210
 
200
211
  The auto-dispatch loop is bounded by `--timeout`, `--idle-timeout`, and
201
212
  `--interval`, so it never polls forever. It skips queued actions, suspended
202
- sessions, runtime mismatches, unavailable runtimes, manual/unsupported action
203
- kinds, and tool mismatches. This keeps the boundary explicit: Orchestra emits
204
- auditable actions and lifecycle commands; the active parent runtime executes
205
- native tools such as Codex `spawn_agent`, and the dispatcher only consumes
206
- actions that are safe for the runtime declared on the command line.
213
+ sessions, terminal sessions, stale or unsafe actions, runtime mismatches,
214
+ already-dispatched sessions, unsupported runtimes, unavailable native tools,
215
+ manual requests, and tool mismatches. Skipped actions include fallback guidance
216
+ with the prompt artifact, expected result artifact, and manual lifecycle
217
+ commands so a human parent runtime can safely continue without provider API
218
+ access. This keeps the boundary explicit: Orchestra emits auditable actions and
219
+ lifecycle commands; the active parent runtime executes native tools such as
220
+ Codex `spawn_agent`, and the dispatcher only consumes actions that are safe for
221
+ the runtime declared on the command line. For Claude, the tested dispatch
222
+ contract accepts `claude-agent-request` with `tool=claude-code-agent`, records
223
+ `spawned` and `active` lifecycle states with a deterministic
224
+ `claude-code-agent:<session>` label when no native child id is available, and
225
+ remains idempotent across repeated dispatch attempts. Orchestra does not call
226
+ Claude Code, Anthropic APIs, or another provider API.
227
+
228
+ Runtime lifecycle watching is adapter-driven. Each inspected session reports a
229
+ `watcher` object with adapter id, detection mode, support level, fallback
230
+ behavior, and the reason a native callback is unavailable. `codex-cli`,
231
+ `claude-cli`, and `cursor-cli` currently reconcile completion through explicit
232
+ parent lifecycle events and then fall back to bounded artifact inspection.
233
+ `generic-runtime`, unknown runtime ids, and runtimes without declared callbacks
234
+ use the same artifact fallback directly. Event-driven callbacks should only be
235
+ used when the selected watcher adapter declares native support; otherwise
236
+ `runtime watch` performs bounded inspection of the expected handoff artifact.
237
+
238
+ ## Claude Adapter Support Level
239
+
240
+ Claude support is currently a parent-runtime dispatch and lifecycle contract,
241
+ not proof that Orchestra can invoke Claude Code or Anthropic APIs by itself.
242
+ The tested local behavior covers:
243
+
244
+ - Dispatch support: eligible `claude-agent-request` actions for `claude-cli`
245
+ with `tool=claude-code-agent` can be consumed by
246
+ `runtime parent-actions --dispatch --runtime claude-cli`. The dispatch path
247
+ records `spawned` and `active` lifecycle state with a stable child identifier
248
+ or deterministic `claude-code-agent:<session>` fallback label.
249
+ - Alias policy: `claude-code-agent` is the only auto-dispatchable Claude tool
250
+ name in the tested contract. `Task` is a legacy/manual alias and is skipped
251
+ as `tool-mismatch`; accepting it in auto-dispatch requires new tests and
252
+ documentation.
253
+ - Fallback behavior: skipped, unsupported, unsafe, stale, queued, suspended,
254
+ terminal, mismatched, or unavailable actions return structured eligibility
255
+ metadata, fallback guidance, prompt artifact, expected result artifact, and
256
+ manual lifecycle commands. Fallback never runs the phase in the parent agent
257
+ silently and never switches to direct provider APIs.
258
+ - Guardrails: dispatch is bounded by runtime guardrails, runtime filters,
259
+ session status, safety state, action kind, tool name, and stale-session
260
+ checks. It preserves `directProviderApiAllowed=false` for runtime-native
261
+ delegation artifacts.
262
+ - Completion reconciliation: current tested support relies on explicit
263
+ lifecycle events and bounded expected-artifact inspection. GH-434 tracks
264
+ stricter validation of task id, phase, role, runtime, session id, and safe
265
+ expected artifact path before a Claude session is marked complete.
266
+ - Gate preservation: auto-dispatch must not approve or skip human gates. GH-435
267
+ tracks the dedicated regression suite for safe workflow resume across
268
+ `gates=none`, `gates=phase`, `gates=all`, multi-phase dispatch, and manual
269
+ fallback recovery.
270
+
271
+ Manual recovery for a skipped or unavailable Claude action:
272
+
273
+ ```bash
274
+ orchestra runtime parent-actions --task <id> --json
275
+ orchestra runtime spawn-request --task <id> --role <role> --runtime claude-cli --json
276
+ orchestra runtime spawn-lifecycle --session <session-id> --status spawned --agent-id <claude-child-id-or-label> --json
277
+ orchestra runtime spawn-lifecycle --session <session-id> --status active --agent-id <claude-child-id-or-label> --json
278
+ orchestra runtime watch --task <id> --once --json
279
+ orchestra workflow run --task <id> --resume <run-id>
280
+ ```
281
+
282
+ Only run the lifecycle commands after the parent Claude Code session has
283
+ actually launched or taken ownership of the rendered prompt artifact. If no
284
+ child id is returned by the runtime, use a stable operator label and keep the
285
+ expected handoff artifact path from the spawn request.
207
286
 
208
287
  ## Native Background Agent Notes
209
288
 
210
289
  Claude Code and Cursor do not need Orchestra to call vendor APIs directly.
211
290
  They need a precise packet and lifecycle hooks:
212
291
 
213
- - Claude Code: render `runtime spawn-request`, then launch the packet from the
214
- parent Claude session with the native Agent/Subagent tool. If the local
215
- Claude runtime exposes `Task` as the tool name, treat it as the compatible
216
- legacy alias. Record the returned child id or role label through
217
- `runtime spawn-lifecycle`.
292
+ - Claude Code: render `runtime spawn-request`, then manually launch the packet
293
+ from the parent Claude session with the native Agent/Subagent tool. The
294
+ primary tested tool name is `claude-code-agent`. `Task` is deferred as a
295
+ legacy/manual alias and is not auto-dispatchable in GH-432; auto-dispatch
296
+ reports it as `tool-mismatch`. Record the returned child id or role label
297
+ through `runtime spawn-lifecycle`.
218
298
  - Codex: render `runtime spawn-request`, read `parentRuntimeAction`, and call
219
299
  the parent `spawn_agent` tool with the prompt artifact as the role-scoped
220
300
  assignment. In workflow auto-consumer mode, use
@@ -62,6 +62,35 @@ gate status. If the scanner can upload analysis but the wait step fails with
62
62
  `Project not found`, update the `SONAR_TOKEN` permissions or keep
63
63
  `SONAR_QUALITY_GATE_WAIT` unset until the token can read the project.
64
64
 
65
+ Before scanner execution, CI runs:
66
+
67
+ ```bash
68
+ node bin/orchestra.js sonar preflight \
69
+ --provider "$SONAR_PROVIDER_RESOLVED" \
70
+ --project-key jterrats_open-orchestra \
71
+ --organization jterrats \
72
+ --host-url "$SONAR_HOST_URL_RESOLVED" \
73
+ --branch "$BRANCH_NAME"
74
+ ```
75
+
76
+ The preflight validates token authentication, project visibility, quality gate
77
+ API access, issue API access, and security hotspot API access. It redacts the
78
+ token, host URL, and Cloudflare Access service token values from diagnostic
79
+ output. `hotspots` is a warning when unavailable because some Sonar tokens can
80
+ analyze and read issues while hotspot review permissions are managed separately.
81
+
82
+ Common remediation:
83
+
84
+ - `auth-invalid`: regenerate `SONAR_TOKEN`; do not paste header names or
85
+ prefixes into the secret value.
86
+ - `project-not-found`: verify the project key and organization, then grant the
87
+ token user Browse access on the project.
88
+ - `permission-denied`: grant Execute Analysis for scanner upload and Browse/API
89
+ access for evidence import. Use a user token when hotspot APIs must be read.
90
+ - `cloudflare-challenge`: use the Cloudflare Access service token proxy, a
91
+ self-hosted runner with local `SONAR_LOCAL_HOST_URL`, or an Access policy that
92
+ explicitly allows the CI service token without an interactive challenge.
93
+
65
94
  ## Local SonarQube
66
95
 
67
96
  Open Orchestra does not own the long-lived local SonarQube containers. The
@@ -179,6 +208,35 @@ For the current laptop setup, use the macOS ARM64 runner package and configure
179
208
  the runner with `--labels sonar,local-sonar`. GitHub automatically adds the
180
209
  platform labels such as `self-hosted`, `macOS`, and `ARM64`.
181
210
 
211
+ Current macOS ARM64 bootstrap:
212
+
213
+ ```bash
214
+ mkdir -p ~/dev/actions-runner-open-orchestra-sonar
215
+ cd ~/dev/actions-runner-open-orchestra-sonar
216
+ curl -L -o actions-runner-osx-arm64.tar.gz <github-runner-osx-arm64-download-url>
217
+ tar xzf actions-runner-osx-arm64.tar.gz
218
+ ./config.sh --url https://github.com/jterratsdev/open-orchestra --labels sonar,local-sonar --name open-orchestra-sonar-macos-arm64
219
+ ./run.sh
220
+ ```
221
+
222
+ Future Linux runner bootstrap should use the Linux package that matches the host
223
+ architecture, the same `sonar,local-sonar` labels, and a dedicated service
224
+ account. Do not reuse a broad organization runner for Sonar unless the runner
225
+ already has least-privilege filesystem, Docker, and network access.
226
+
227
+ Service lifecycle:
228
+
229
+ ```bash
230
+ cd ~/dev/actions-runner-open-orchestra-sonar
231
+ ./svc.sh install
232
+ ./svc.sh start
233
+ ./svc.sh status
234
+ ./svc.sh stop
235
+ ```
236
+
237
+ Use `./run.sh` for interactive local troubleshooting. Use `svc.sh` only after
238
+ the runner can start, claim a Sonar workflow job, and reach SonarQube locally.
239
+
182
240
  Keep the shared SonarQube stack running locally:
183
241
 
184
242
  ```bash
@@ -201,6 +259,44 @@ container. In that case either run the runner process on the host, attach the
201
259
  runner container to the SonarQube Docker network, or set `SONAR_LOCAL_HOST_URL`
202
260
  to the host/network address that reaches SonarQube without Cloudflare.
203
261
 
262
+ ### Self-Hosted Runner Health Check
263
+
264
+ Before relying on CI, validate the local runner and SonarQube path from the same
265
+ machine that runs the GitHub Actions runner:
266
+
267
+ ```bash
268
+ gh variable list --repo jterratsdev/open-orchestra
269
+ gh api repos/jterratsdev/open-orchestra/actions/runners --jq '.runners[] | {name, status, busy, labels: [.labels[].name]}'
270
+ npm run sonar:preflight:local
271
+ ```
272
+
273
+ Expected result:
274
+
275
+ - `SONAR_RUNNER` is `self-hosted`.
276
+ - A runner is `online` with `self-hosted`, `sonar`, and `local-sonar` labels.
277
+ - Sonar authentication returns `{"valid":true}`.
278
+ - `npm run sonar:preflight:local` passes `auth`, `project`, `qualityGate`, and
279
+ `issues`; `hotspots` may warn when the token lacks hotspot read access.
280
+
281
+ If the runner is online but jobs stay queued, verify the workflow labels match
282
+ the runner labels exactly. If Sonar preflight fails, fix the token/project
283
+ permissions before rerunning the workflow.
284
+
285
+ ### Current Workflow Warning Triage
286
+
287
+ - Node 20 action warning: non-blocking today. Track upstream action upgrades and
288
+ update actions when GitHub publishes Node 24-compatible major versions.
289
+ - GPG keyserver warning from the Sonar scanner action: non-blocking when scanner
290
+ setup and analysis complete. Prefer self-hosted runner network allowlisting or
291
+ a pinned scanner cache before treating it as release-blocking.
292
+ - Cache or tar warnings: non-blocking unless scanner dependencies fail to
293
+ restore and analysis cannot start. Rebuild the runner cache or rerun the job
294
+ before changing project code.
295
+
296
+ These warnings should be captured as CI annotations, but they do not override a
297
+ passing Sonar workflow unless the scanner, import, or final quality gate step
298
+ fails.
299
+
204
300
  Sonar reads TypeScript through `tsconfig.sonar.json`, a standalone analyzer
205
301
  config that mirrors the build compiler options but lowers only the analyzer
206
302
  target to `ES2022`. Keep the main build target unchanged unless runtime support
@@ -239,6 +335,17 @@ Recommended minimum quality gate for new code:
239
335
  - Coverage reported from `coverage/lcov.info` for source files on every Sonar
240
336
  run.
241
337
 
338
+ The Orchestra Sonar import stores unresolved issues and Sonar security hotspots
339
+ in the uploaded `sonar-insights` artifact. When the gate fails only on
340
+ `new_security_hotspots_reviewed`, review the hotspot list in SonarQube, mark
341
+ each hotspot as safe, fixed, or accepted with rationale, then rerun the Sonar
342
+ workflow. Do not bypass this gate from code unless the Product Owner explicitly
343
+ accepts the security risk.
344
+ If the artifact includes `securityHotspotsUnavailableReason`, the configured
345
+ `SONAR_TOKEN` can read the quality gate and issues but cannot read the hotspots
346
+ API. Grant the token Browse plus security hotspot review/read permissions in
347
+ SonarQube before using the artifact as release evidence.
348
+
242
349
  ## Coverage Publishing
243
350
 
244
351
  The Sonar workflow runs `npm run test:coverage` before analysis. That command
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jterrats/open-orchestra",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  "extensions/vscode-open-orchestra",
@@ -30,6 +30,7 @@
30
30
  "performance:bench": "npm run build && node scripts/performance-benchmark.js",
31
31
  "precommit": "npm run lint && npm run typecheck && npm run secret-scan && npm run security:audit && npm test && npm run validate:workflow",
32
32
  "prepack": "npm run build",
33
+ "sonar:preflight:local": "node bin/orchestra.js sonar preflight --provider sonarqube-local --project-key jterrats_open-orchestra --host-url ${SONAR_HOST_URL:-http://localhost:9001}",
33
34
  "sonar:scan:local": "sonar-scanner -Dsonar.host.url=${SONAR_HOST_URL:-http://localhost:9001}",
34
35
  "hooks:install": "git config core.hooksPath .githooks",
35
36
  "build:web": "npm run build:web:legacy && npm run build:web:react",
@@ -18,6 +18,8 @@ Development work is not complete when code compiles. Every implementation must m
18
18
  ## QA Gate
19
19
 
20
20
  - QA receives the Developer handoff before release approval.
21
+ - Workflow gate approval is not a status shortcut. `po→architect` can be approved only when the issue/task has user-validated scope, non-goals, assumptions, priority, acceptance criteria, and sizing context. `qa→release` can be approved only after real implementation evidence, QA findings, BA/PO acceptance, and Architect review when technical contracts changed.
22
+ - Generated handoffs with `Acceptance Criteria: none` are incomplete for release purposes. Pull the criteria from the linked GitHub issue or Orchestra task, record a review finding, and block release until the criteria/evidence gap is fixed or explicitly risk-accepted by the Product Owner.
21
23
  - QA must produce a test plan covering acceptance criteria, regression areas, edge cases, data setup, and environment assumptions.
22
24
  - QA must block test planning when acceptance criteria are fragmented, non-verifiable, or only role/phase headings. Return those findings to PO/BA before release evidence is generated.
23
25
  - QA plans must include an AC-to-evidence matrix with expected observable result, actual result, artifact/command, and pass/fail/deferred status for each acceptance criterion.