@geraldmaron/construct 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (556) hide show
  1. package/.env.example +36 -0
  2. package/README.md +41 -7
  3. package/bin/construct +1029 -65
  4. package/bin/construct-postinstall.mjs +27 -2
  5. package/config/tag-vocabulary.json +264 -0
  6. package/examples/distribution/sources/deck-one-pager.md +1 -1
  7. package/lib/acp/server.mjs +21 -7
  8. package/lib/adapters-sync.mjs +2 -1
  9. package/lib/audit-trail.mjs +185 -2
  10. package/lib/beads/auto-close.mjs +2 -1
  11. package/lib/beads/drift.mjs +2 -1
  12. package/lib/bridges/copilot-proxy.mjs +20 -5
  13. package/lib/certification/skill-inventory.mjs +10 -1
  14. package/lib/cli/approvals.mjs +147 -0
  15. package/lib/cli-commands.mjs +105 -14
  16. package/lib/comment-lint.mjs +127 -8
  17. package/lib/config/schema.mjs +7 -30
  18. package/lib/config/source-target-registry.mjs +70 -0
  19. package/lib/config/source-targets.mjs +179 -205
  20. package/lib/contracts/coverage.mjs +77 -0
  21. package/lib/contracts/validate.mjs +102 -13
  22. package/lib/contracts/violation-log.mjs +50 -4
  23. package/lib/db/migrate.mjs +69 -0
  24. package/lib/db/migrations/001_orchestration_runs.sql +9 -0
  25. package/lib/db/migrations/002_queue_provider.sql +50 -0
  26. package/lib/db/migrations/003_worker_registry.sql +17 -0
  27. package/lib/db/migrations/004_trace_events.sql +16 -0
  28. package/lib/db/migrations/005_shared_memory.sql +15 -0
  29. package/lib/db/migrations/006_orchestration_runs_tenant.sql +5 -0
  30. package/lib/decisions/enforced-baseline.json +0 -2
  31. package/lib/decisions/registry.mjs +3 -2
  32. package/lib/deployment/parity-contract.mjs +1 -1
  33. package/lib/deployment-mode.mjs +78 -2
  34. package/lib/diagram-export.mjs +10 -1
  35. package/lib/distill.mjs +5 -2
  36. package/lib/docs-verify.mjs +2 -1
  37. package/lib/doctor/cli.mjs +1 -0
  38. package/lib/doctor/command-on-path.mjs +24 -0
  39. package/lib/doctor/diagnosis.mjs +109 -0
  40. package/lib/doctor/embedding-health.mjs +50 -0
  41. package/lib/doctor/engine-health.mjs +93 -0
  42. package/lib/doctor/graph-validate.mjs +47 -0
  43. package/lib/doctor/index.mjs +23 -4
  44. package/lib/doctor/sidecar-providers.mjs +56 -0
  45. package/lib/doctor/watchers/consistency.mjs +93 -1
  46. package/lib/doctor/watchers/cx-budget.mjs +1 -1
  47. package/lib/doctor/watchers/graph-staleness.mjs +1 -1
  48. package/lib/doctor/watchers/mcp-protocol.mjs +17 -0
  49. package/lib/doctor/watchers/oracle-liveness.mjs +92 -0
  50. package/lib/doctor/watchers/orchestration-runs.mjs +108 -0
  51. package/lib/doctor/watchers/provider-breaker.mjs +78 -0
  52. package/lib/document-export.mjs +52 -27
  53. package/lib/document-extract/docling-client.mjs +9 -5
  54. package/lib/document-extract/docling-sidecar.py +30 -0
  55. package/lib/document-extract.mjs +1 -1
  56. package/lib/document-ingest.mjs +9 -0
  57. package/lib/embed/approval-queue.mjs +184 -88
  58. package/lib/embed/authority-guard.mjs +65 -2
  59. package/lib/embed/capability-jobs.mjs +365 -0
  60. package/lib/embed/capability-lifecycle.mjs +219 -0
  61. package/lib/embed/capability-loader.mjs +303 -0
  62. package/lib/embed/capability-runtime.mjs +58 -0
  63. package/lib/embed/cli.mjs +185 -8
  64. package/lib/embed/config.mjs +4 -0
  65. package/lib/embed/daemon.mjs +125 -6
  66. package/lib/embed/demand-fetch.mjs +190 -54
  67. package/lib/embed/inbox.mjs +12 -10
  68. package/lib/embed/presets/ops-triage.mjs +236 -0
  69. package/lib/embed/presets/pm-feedback.mjs +341 -0
  70. package/lib/embed/presets/tpm.mjs +401 -0
  71. package/lib/embed/providers/jira.mjs +72 -1
  72. package/lib/embed/providers/registry.mjs +140 -33
  73. package/lib/embed/worker.mjs +5 -0
  74. package/lib/embedded-contract/capability.mjs +4 -0
  75. package/lib/embedded-contract/execution.mjs +1 -1
  76. package/lib/embedded-contract/model-resolve.mjs +53 -3
  77. package/lib/embedded-contract/workflow-defs.mjs +48 -73
  78. package/lib/embedded-contract/workflow-invoke.mjs +144 -4
  79. package/lib/embedded-contract/workflows/architecture-review.manifest.json +15 -0
  80. package/lib/embedded-contract/workflows/data-structure.manifest.json +14 -0
  81. package/lib/embedded-contract/workflows/evidence-ingest.manifest.json +14 -0
  82. package/lib/embedded-contract/workflows/memo-draft.manifest.json +14 -0
  83. package/lib/embedded-contract/workflows/operations-triage.manifest.json +18 -0
  84. package/lib/embedded-contract/workflows/operations.manifest.json +18 -0
  85. package/lib/embedded-contract/workflows/pm-feedback.manifest.json +18 -0
  86. package/lib/embedded-contract/workflows/prd-draft.manifest.json +15 -0
  87. package/lib/embedded-contract/workflows/proposal-review.manifest.json +15 -0
  88. package/lib/embedded-contract/workflows/research-synthesis.manifest.json +14 -0
  89. package/lib/embedded-contract/workflows/risk-review.manifest.json +15 -0
  90. package/lib/embedded-contract/workflows/structure-notes.manifest.json +14 -0
  91. package/lib/embedded-contract/workflows/transcript-process.manifest.json +14 -0
  92. package/lib/embedded-contract/workflows/triage.manifest.json +14 -0
  93. package/lib/env-config.mjs +60 -11
  94. package/lib/export-validate.mjs +34 -2
  95. package/lib/extensions/index.mjs +27 -0
  96. package/lib/extensions/loader.mjs +120 -0
  97. package/lib/extensions/manifest-schema.mjs +141 -0
  98. package/lib/extensions/manifests/anthropic.manifest.json +12 -0
  99. package/lib/extensions/manifests/atlassian-confluence.manifest.json +12 -0
  100. package/lib/extensions/manifests/atlassian-jira.manifest.json +53 -0
  101. package/lib/extensions/manifests/directory.manifest.json +12 -0
  102. package/lib/extensions/manifests/docling.manifest.json +37 -0
  103. package/lib/extensions/manifests/echo.manifest.json +8 -0
  104. package/lib/extensions/manifests/feedback.manifest.json +12 -0
  105. package/lib/extensions/manifests/github-copilot.manifest.json +12 -0
  106. package/lib/extensions/manifests/github.manifest.json +52 -0
  107. package/lib/extensions/manifests/linear.manifest.json +50 -0
  108. package/lib/extensions/manifests/local.manifest.json +12 -0
  109. package/lib/extensions/manifests/ollama.manifest.json +12 -0
  110. package/lib/extensions/manifests/openai.manifest.json +12 -0
  111. package/lib/extensions/manifests/openrouter-anthropic.manifest.json +12 -0
  112. package/lib/extensions/manifests/openrouter-deepseek.manifest.json +12 -0
  113. package/lib/extensions/manifests/openrouter-google.manifest.json +12 -0
  114. package/lib/extensions/manifests/openrouter-llama.manifest.json +12 -0
  115. package/lib/extensions/manifests/openrouter-qwen.manifest.json +12 -0
  116. package/lib/extensions/manifests/openrouter.manifest.json +12 -0
  117. package/lib/extensions/manifests/postgres.manifest.json +12 -0
  118. package/lib/extensions/manifests/salesforce.manifest.json +12 -0
  119. package/lib/extensions/manifests/slack.manifest.json +58 -0
  120. package/lib/extensions/manifests/whisper.manifest.json +36 -0
  121. package/lib/extensions/validate.mjs +175 -0
  122. package/lib/features.mjs +13 -9
  123. package/lib/flows/checkpoint.mjs +184 -0
  124. package/lib/flows/constants.mjs +27 -0
  125. package/lib/flows/define.mjs +146 -0
  126. package/lib/flows/engine.mjs +249 -0
  127. package/lib/flows/errors.mjs +19 -0
  128. package/lib/flows/index.mjs +27 -0
  129. package/lib/flows/joins.mjs +18 -0
  130. package/lib/flows/schema.mjs +90 -0
  131. package/lib/flows/state.mjs +31 -0
  132. package/lib/frameworks/loader.mjs +99 -0
  133. package/lib/frameworks/schema.mjs +157 -0
  134. package/lib/graph/build-from-corpus.mjs +67 -0
  135. package/lib/graph/build-from-embed.mjs +82 -0
  136. package/lib/graph/build-from-registry.mjs +164 -3
  137. package/lib/graph/cli.mjs +456 -12
  138. package/lib/graph/gap-queries.mjs +156 -0
  139. package/lib/graph/gaps.mjs +41 -0
  140. package/lib/graph/impacted.mjs +129 -0
  141. package/lib/graph/runtime-evidence.mjs +177 -0
  142. package/lib/graph/security-coverage.mjs +113 -0
  143. package/lib/graph/staleness.mjs +241 -10
  144. package/lib/graph/store.mjs +24 -7
  145. package/lib/graph/validate.mjs +161 -0
  146. package/lib/headhunt.mjs +9 -8
  147. package/lib/health-check.mjs +15 -7
  148. package/lib/hook-health.mjs +1 -1
  149. package/lib/hooks/agent-tracker.mjs +10 -4
  150. package/lib/hooks/edit-guard.mjs +3 -3
  151. package/lib/hooks/graph-impact-advisory.mjs +2 -2
  152. package/lib/hooks/guard-bash.mjs +41 -15
  153. package/lib/hooks/mcp-health-check.mjs +11 -4
  154. package/lib/hooks/model-fallback.mjs +50 -6
  155. package/lib/hooks/orchestration-dispatch-guard.mjs +14 -3
  156. package/lib/hooks/pre-compact.mjs +181 -173
  157. package/lib/hooks/rule-verifier.mjs +2 -1
  158. package/lib/hooks/session-reflect.mjs +2 -1
  159. package/lib/hooks/session-start.mjs +3 -3
  160. package/lib/host/readiness.mjs +109 -0
  161. package/lib/host-capabilities.mjs +13 -2
  162. package/lib/host-disposition.mjs +29 -8
  163. package/lib/identity.mjs +92 -0
  164. package/lib/ingest/degraded-extract.mjs +96 -0
  165. package/lib/ingest/docling-remote.mjs +2 -1
  166. package/lib/ingest/provider-extract.mjs +7 -19
  167. package/lib/ingest/sidecar-providers.mjs +196 -0
  168. package/lib/ingest-tooling.mjs +11 -5
  169. package/lib/init-unified.mjs +55 -38
  170. package/lib/init-update.mjs +2 -1
  171. package/lib/install/legacy-global-cleanup.mjs +25 -0
  172. package/lib/install/stage-project.mjs +41 -4
  173. package/lib/intake/daemon.mjs +99 -8
  174. package/lib/intake/git-queue.mjs +110 -38
  175. package/lib/intake/prepare.mjs +2 -0
  176. package/lib/intake/queue-registry.mjs +50 -0
  177. package/lib/intake/queue.mjs +133 -17
  178. package/lib/intake/session-prelude.mjs +57 -8
  179. package/lib/integrations/intake-integrations.mjs +61 -111
  180. package/lib/intent-classifier.mjs +43 -5
  181. package/lib/libreoffice-export.mjs +8 -8
  182. package/lib/logging/rotate.mjs +5 -4
  183. package/lib/mcp/broker.mjs +332 -17
  184. package/lib/mcp/denied-store.mjs +95 -0
  185. package/lib/mcp/destructive-approval.mjs +57 -0
  186. package/lib/mcp/destructive-gate.mjs +30 -0
  187. package/lib/mcp/dispatch-envelope.mjs +199 -0
  188. package/lib/mcp/memory-bridge.mjs +2 -1
  189. package/lib/mcp/server.mjs +185 -1268
  190. package/lib/mcp/tool-definitions-memory.mjs +376 -0
  191. package/lib/mcp/tool-definitions-project.mjs +271 -0
  192. package/lib/mcp/tool-definitions-skills.mjs +311 -0
  193. package/lib/mcp/tool-definitions-workflow.mjs +398 -0
  194. package/lib/mcp/tool-definitions.mjs +25 -0
  195. package/lib/mcp/tool-rate-limit.mjs +47 -0
  196. package/lib/mcp/tool-registry.mjs +107 -0
  197. package/lib/mcp/tool-safety.mjs +95 -0
  198. package/lib/mcp/tool-surface-parity.mjs +60 -0
  199. package/lib/mcp/tools/orchestration-delegation-next.tool.mjs +68 -0
  200. package/lib/mcp/tools/orchestration-run.mjs +197 -19
  201. package/lib/mcp/tools/orchestration-task-result.tool.mjs +77 -0
  202. package/lib/mcp/tools/project.mjs +25 -8
  203. package/lib/mcp/tools/provider-write.mjs +187 -0
  204. package/lib/mcp/tools/scope.mjs +0 -3
  205. package/lib/mcp/tools/skills.mjs +1 -1
  206. package/lib/mcp/tools/storage.mjs +2 -2
  207. package/lib/mcp/tools/web-search-governance.mjs +96 -0
  208. package/lib/mcp/tools/web-search.mjs +5 -76
  209. package/lib/mcp/transport/auth.mjs +238 -0
  210. package/lib/mcp/transport/http.mjs +136 -0
  211. package/lib/mcp/transport/mode.mjs +31 -0
  212. package/lib/mcp/transport/stdio.mjs +22 -0
  213. package/lib/mcp-catalog.json +4 -4
  214. package/lib/mcp-manager.mjs +34 -23
  215. package/lib/mcp-platform-config.mjs +53 -20
  216. package/lib/mode-capabilities.mjs +109 -0
  217. package/lib/model-router.mjs +42 -9
  218. package/lib/models/catalog.mjs +40 -1
  219. package/lib/net-guard.mjs +247 -0
  220. package/lib/observation-store.mjs +6 -2
  221. package/lib/ollama/provision-context.mjs +2 -1
  222. package/lib/opencode-config.mjs +22 -3
  223. package/lib/opencode-runtime-plugin.mjs +120 -2
  224. package/lib/oracle/actions.mjs +204 -10
  225. package/lib/oracle/cli.mjs +24 -3
  226. package/lib/oracle/daemon-entry.mjs +6 -0
  227. package/lib/oracle/dispatch.mjs +2 -1
  228. package/lib/oracle/execute.mjs +2 -2
  229. package/lib/oracle/gaps.mjs +3 -3
  230. package/lib/oracle/heartbeat.mjs +53 -0
  231. package/lib/oracle/read-model.mjs +69 -13
  232. package/lib/oracle/reconcile.mjs +3 -46
  233. package/lib/oracle/routing.mjs +37 -31
  234. package/lib/oracle/synthesize.mjs +1 -1
  235. package/lib/orchestration/classification.mjs +434 -0
  236. package/lib/orchestration/delegation-flow.mjs +132 -0
  237. package/lib/orchestration/flow-selection.mjs +418 -0
  238. package/lib/orchestration/gates.mjs +244 -0
  239. package/lib/orchestration/host-sampling.mjs +121 -0
  240. package/lib/orchestration/policy-constants.mjs +48 -0
  241. package/lib/orchestration/provider-outcome.mjs +197 -0
  242. package/lib/orchestration/readiness.mjs +114 -13
  243. package/lib/orchestration/run-store-postgres.mjs +32 -26
  244. package/lib/orchestration/run-store-sqlite.mjs +8 -14
  245. package/lib/orchestration/run-store.mjs +25 -12
  246. package/lib/orchestration/runtime.mjs +508 -62
  247. package/lib/orchestration/store.mjs +87 -12
  248. package/lib/orchestration/trace-store.mjs +125 -0
  249. package/lib/orchestration/web-capability.mjs +60 -0
  250. package/lib/orchestration/worker-runtime.mjs +162 -0
  251. package/lib/orchestration/worker.mjs +763 -80
  252. package/lib/orchestration-policy.mjs +67 -1111
  253. package/lib/output-quality.mjs +61 -2
  254. package/lib/packs/cli.mjs +144 -0
  255. package/lib/packs/core-pack.mjs +112 -0
  256. package/lib/packs/enablement.mjs +187 -0
  257. package/lib/packs/index.mjs +23 -0
  258. package/lib/packs/loader.mjs +176 -0
  259. package/lib/packs/manifest-schema.mjs +58 -0
  260. package/lib/packs/prompts.mjs +120 -0
  261. package/lib/packs/validate.mjs +208 -0
  262. package/lib/path-policy.mjs +56 -0
  263. package/lib/plugin-registry.mjs +4 -5
  264. package/lib/policy/audit-gate.mjs +42 -0
  265. package/lib/policy/consumption-budget.mjs +149 -0
  266. package/lib/policy/engine.mjs +81 -6
  267. package/lib/policy/role-authority.mjs +89 -0
  268. package/lib/prompt-composer.js +19 -3
  269. package/lib/providers/contract/adapters/confluence/governed-write.mjs +215 -0
  270. package/lib/providers/contract/adapters/confluence/manifest.json +17 -0
  271. package/lib/providers/contract/adapters/confluence/transport.mjs +135 -0
  272. package/lib/providers/contract/adapters/github/governed-write.mjs +121 -0
  273. package/lib/providers/contract/adapters/github/index.mjs +38 -3
  274. package/lib/providers/contract/adapters/jira/adf.mjs +151 -0
  275. package/lib/providers/contract/adapters/jira/createmeta.mjs +143 -0
  276. package/lib/providers/contract/adapters/jira/governed-write.mjs +182 -0
  277. package/lib/providers/contract/adapters/jira/manifest.json +17 -0
  278. package/lib/providers/contract/adapters/jira/transport.mjs +119 -0
  279. package/lib/providers/contract.mjs +207 -0
  280. package/lib/providers/credential-bootstrap.mjs +7 -4
  281. package/lib/providers/credential-sources.mjs +14 -2
  282. package/lib/providers/directory/index.mjs +261 -0
  283. package/lib/providers/feedback/index.mjs +392 -0
  284. package/lib/providers/filter-audit.mjs +68 -0
  285. package/lib/providers/filter-schema.mjs +54 -0
  286. package/lib/providers/github/index.mjs +31 -0
  287. package/lib/providers/instance-config.mjs +215 -0
  288. package/lib/providers/op-locate.mjs +96 -0
  289. package/lib/providers/op-run.mjs +64 -9
  290. package/lib/providers/registry.mjs +26 -3
  291. package/lib/providers/secret-audit-wiring.mjs +41 -18
  292. package/lib/providers/secret-resolver.mjs +263 -31
  293. package/lib/publish-template.mjs +6 -3
  294. package/lib/publish-tooling.mjs +4 -0
  295. package/lib/publish.mjs +32 -4
  296. package/lib/queue/pg-queue.mjs +395 -0
  297. package/lib/reflect.mjs +2 -1
  298. package/lib/registry/assemble.mjs +28 -2
  299. package/lib/registry/catalog.mjs +6 -0
  300. package/lib/registry/consolidation.mjs +8 -1
  301. package/lib/registry/custom-scaffold.mjs +200 -0
  302. package/lib/registry/custom-schema.mjs +137 -0
  303. package/lib/registry/loader.mjs +15 -4
  304. package/lib/registry/manifests/format-engines.default.json +15 -0
  305. package/lib/registry/manifests/surface-map.default.json +46 -0
  306. package/lib/registry/retired-paths.mjs +1 -0
  307. package/lib/registry/surface-map.mjs +100 -50
  308. package/lib/registry/validate.mjs +3 -3
  309. package/lib/render-visual-check.mjs +240 -0
  310. package/lib/resources/budget.mjs +40 -17
  311. package/lib/roles/flavor-bindings.mjs +36 -14
  312. package/lib/roles/gateway.mjs +15 -8
  313. package/lib/roots.mjs +107 -0
  314. package/lib/runtime/uv-bootstrap.mjs +32 -6
  315. package/lib/runtime/whisper-bootstrap.mjs +11 -3
  316. package/lib/runtime-env.mjs +5 -2
  317. package/lib/sandbox.mjs +1 -1
  318. package/lib/scheduler/index.mjs +8 -20
  319. package/lib/schema-infer.mjs +31 -2
  320. package/lib/scopes/lifecycle.mjs +29 -25
  321. package/lib/scopes/loader.mjs +49 -12
  322. package/lib/scopes/teams.mjs +1 -1
  323. package/lib/security/ingest-boundary.mjs +80 -0
  324. package/lib/security/recall-wrapper.mjs +99 -0
  325. package/lib/security/trust.mjs +132 -0
  326. package/lib/service-manager.mjs +93 -24
  327. package/lib/setup.mjs +41 -23
  328. package/lib/skills-apply.mjs +4 -2
  329. package/lib/specialists/postconditions.mjs +2 -2
  330. package/lib/state-root.mjs +147 -0
  331. package/lib/status.mjs +597 -6
  332. package/lib/storage/admin.mjs +84 -7
  333. package/lib/storage/backend-registry.mjs +73 -0
  334. package/lib/storage/backend.mjs +63 -9
  335. package/lib/storage/embeddings-openai.mjs +12 -2
  336. package/lib/storage/hybrid-query.mjs +11 -3
  337. package/lib/storage/retrieval-hardening.mjs +384 -0
  338. package/lib/storage/shared-memory.mjs +158 -0
  339. package/lib/storage/vector-client.mjs +69 -2
  340. package/lib/team/health.mjs +72 -0
  341. package/lib/telemetry/backends/local.mjs +9 -3
  342. package/lib/telemetry/client.mjs +3 -7
  343. package/lib/template-registry.mjs +10 -12
  344. package/lib/tenant/context.mjs +82 -0
  345. package/lib/tenant/isolation.mjs +129 -0
  346. package/lib/test-corpus-inventory.mjs +103 -2
  347. package/lib/uninstall/uninstall.mjs +78 -12
  348. package/lib/validator.mjs +4 -6
  349. package/lib/worker/entrypoint.mjs +2 -1
  350. package/lib/worker/run.mjs +2 -2
  351. package/lib/worker/trace.mjs +5 -11
  352. package/lib/workflow-state.mjs +52 -8
  353. package/lib/workflows/liveness.mjs +203 -0
  354. package/lib/workflows/loader.mjs +177 -0
  355. package/lib/workflows/manifest-schema.mjs +71 -0
  356. package/lib/workflows/surface-parity.mjs +118 -0
  357. package/lib/workflows/validate.mjs +127 -0
  358. package/lib/writes/control-plane.mjs +140 -0
  359. package/lib/writes/envelope.mjs +206 -0
  360. package/lib/writes/sent-log.mjs +86 -0
  361. package/lib/writes/write-intent.mjs +109 -0
  362. package/package.json +20 -7
  363. package/personas/construct.md +12 -3
  364. package/registry/agent-manifest.json +117 -0
  365. package/registry/capabilities.json +1987 -0
  366. package/rules/common/comments.md +1 -0
  367. package/schemas/brand-voice.schema.json +24 -0
  368. package/schemas/capability-registry.schema.json +72 -0
  369. package/schemas/certification-run.schema.json +130 -0
  370. package/schemas/demo-recording.schema.json +46 -0
  371. package/schemas/eval-dataset.schema.json +79 -0
  372. package/schemas/execution-capability-profile.schema.json +46 -0
  373. package/schemas/execution-policy.schema.json +114 -0
  374. package/schemas/improvement-proposal.schema.json +65 -0
  375. package/schemas/mcp-tool-output.schema.json +61 -0
  376. package/schemas/platform-capabilities.schema.json +83 -0
  377. package/schemas/project-config.schema.json +215 -0
  378. package/schemas/project-demo.schema.json +60 -0
  379. package/schemas/provider-behavior-matrix.schema.json +91 -0
  380. package/schemas/scope.schema.json +197 -0
  381. package/schemas/specialist-trace.schema.json +107 -0
  382. package/schemas/team.schema.json +99 -0
  383. package/schemas/unified-registry.schema.json +546 -0
  384. package/scripts/sync-specialists.mjs +336 -106
  385. package/skills/docs/adr-workflow.md +1 -1
  386. package/skills/docs/codebase-research-workflow.md +3 -3
  387. package/skills/docs/prd-workflow.md +5 -6
  388. package/skills/docs/runbook-workflow.md +2 -2
  389. package/skills/docs/user-research-workflow.md +3 -3
  390. package/skills/operating/fleet-health-routing.md +77 -0
  391. package/skills/roles/ai-engineer.md +1 -1
  392. package/skills/roles/architect.md +0 -1
  393. package/skills/roles/business-strategist.md +1 -1
  394. package/skills/roles/data-analyst.telemetry.md +1 -1
  395. package/skills/roles/data-engineer.md +1 -1
  396. package/skills/roles/data-engineer.pipeline.md +1 -1
  397. package/skills/roles/data-engineer.vector-retrieval.md +1 -2
  398. package/skills/roles/data-engineer.warehouse.md +1 -1
  399. package/skills/roles/designer.accessibility.md +1 -1
  400. package/skills/roles/designer.md +0 -1
  401. package/skills/roles/devil-advocate.md +1 -1
  402. package/skills/roles/docs-keeper.md +1 -1
  403. package/skills/roles/evaluator.md +1 -1
  404. package/skills/roles/explorer.md +1 -1
  405. package/skills/roles/platform-engineer.md +1 -1
  406. package/skills/roles/qa.ai-eval.md +1 -2
  407. package/skills/roles/qa.api-contract.md +0 -1
  408. package/skills/roles/qa.data-pipeline.md +0 -1
  409. package/skills/roles/qa.md +0 -1
  410. package/skills/roles/qa.web-ui.md +0 -1
  411. package/skills/roles/release-manager.md +1 -1
  412. package/skills/roles/researcher.md +0 -2
  413. package/skills/roles/reviewer.md +0 -3
  414. package/skills/roles/security.ai.md +1 -1
  415. package/skills/roles/security.legal-compliance.md +1 -1
  416. package/skills/roles/security.md +0 -1
  417. package/skills/roles/security.privacy.md +0 -1
  418. package/skills/roles/security.supply-chain.md +1 -1
  419. package/skills/roles/sre.md +1 -1
  420. package/skills/roles/test-automation.md +1 -1
  421. package/skills/roles/trace-reviewer.md +1 -1
  422. package/skills/roles/ux-researcher.md +1 -1
  423. package/specialists/artifact-manifest.json +36 -36
  424. package/specialists/org/contracts/accessibility-to-qa.json +11 -3
  425. package/specialists/org/contracts/any-to-business-strategist.json +19 -7
  426. package/specialists/org/contracts/any-to-debugger.json +7 -1
  427. package/specialists/org/contracts/any-to-designer.json +7 -1
  428. package/specialists/org/contracts/any-to-docs-keeper.json +18 -4
  429. package/specialists/org/contracts/any-to-explorer.json +13 -4
  430. package/specialists/org/contracts/any-to-sre-incident.json +6 -2
  431. package/specialists/org/contracts/any-to-trace-reviewer.json +16 -4
  432. package/specialists/org/contracts/architect-to-ai-engineer.json +6 -2
  433. package/specialists/org/contracts/architect-to-data-engineer.json +17 -5
  434. package/specialists/org/contracts/architect-to-devil-advocate.json +11 -3
  435. package/specialists/org/contracts/architect-to-engineer.json +20 -4
  436. package/specialists/org/contracts/architect-to-evaluator.json +15 -5
  437. package/specialists/org/contracts/architect-to-legal-compliance.json +15 -5
  438. package/specialists/org/contracts/architect-to-operations.json +17 -4
  439. package/specialists/org/contracts/architect-to-platform-engineer.json +20 -4
  440. package/specialists/org/contracts/construct-to-orchestrator.json +10 -2
  441. package/specialists/org/contracts/data-analyst-to-product-manager.json +11 -2
  442. package/specialists/org/contracts/engineer-to-qa.json +20 -4
  443. package/specialists/org/contracts/engineer-to-reviewer.json +29 -5
  444. package/specialists/org/contracts/explorer-to-engineer.json +11 -3
  445. package/specialists/org/contracts/legal-compliance-to-release-manager.json +12 -4
  446. package/specialists/org/contracts/operations-to-user.json +53 -0
  447. package/specialists/org/contracts/operations-triage-output.json +53 -0
  448. package/specialists/org/contracts/pm-requirements-candidates.json +53 -0
  449. package/specialists/org/contracts/product-manager-to-architect.json +30 -10
  450. package/specialists/org/contracts/product-manager-to-data-analyst.json +13 -3
  451. package/specialists/org/contracts/product-manager-to-ux-researcher.json +15 -5
  452. package/specialists/org/contracts/qa-to-release-manager.json +11 -3
  453. package/specialists/org/contracts/researcher-to-architect.json +10 -2
  454. package/specialists/org/contracts/researcher-to-product-manager.json +16 -5
  455. package/specialists/org/contracts/reviewer-to-security.json +17 -3
  456. package/specialists/org/contracts/test-automation-to-engineer.json +11 -3
  457. package/specialists/org/contracts/trace-reviewer-to-sre.json +12 -4
  458. package/specialists/org/contracts/user-to-construct.json +11 -4
  459. package/specialists/org/frameworks/cx-architect-constraint-option-failure.md +66 -0
  460. package/specialists/org/frameworks/cx-engineer-feasibility-blast-radius.md +66 -0
  461. package/specialists/org/frameworks/cx-ops-dependency-sequencing.md +74 -0
  462. package/specialists/org/frameworks/cx-pm-value-tradeoff.md +66 -0
  463. package/specialists/org/frameworks/cx-qa-risk-based-coverage.md +69 -0
  464. package/specialists/org/groups/engineering-group.json +2 -6
  465. package/specialists/org/groups/governance-group.json +2 -3
  466. package/specialists/org/groups/operations-group.json +5 -8
  467. package/specialists/org/groups/product-group.json +4 -8
  468. package/specialists/org/groups/quality-group.json +3 -7
  469. package/specialists/org/groups/strategy-group.json +6 -9
  470. package/specialists/org/models.json.example +8 -0
  471. package/specialists/org/scopes/creative.json +6 -1
  472. package/specialists/org/scopes/operations.json +7 -1
  473. package/specialists/org/scopes/research.json +6 -1
  474. package/specialists/org/scopes/rnd.json +7 -1
  475. package/specialists/org/specialists/cx-architect.json +27 -8
  476. package/specialists/org/specialists/cx-designer.json +22 -8
  477. package/specialists/org/specialists/cx-engineer.json +71 -7
  478. package/specialists/org/specialists/cx-operations.json +89 -15
  479. package/specialists/org/specialists/cx-orchestrator.json +16 -4
  480. package/specialists/org/specialists/cx-product-manager.json +28 -9
  481. package/specialists/org/specialists/cx-qa.json +16 -6
  482. package/specialists/org/specialists/cx-researcher.json +41 -7
  483. package/specialists/org/specialists/cx-reviewer.json +61 -11
  484. package/specialists/org/specialists/cx-security.json +30 -10
  485. package/specialists/org/teams/design-team.json +3 -4
  486. package/specialists/org/teams/engineering-team.json +3 -10
  487. package/specialists/org/teams/governance-team.json +3 -5
  488. package/specialists/org/teams/operations-team.json +6 -12
  489. package/specialists/org/teams/product-management-team.json +2 -3
  490. package/specialists/org/teams/quality-team.json +4 -12
  491. package/specialists/org/teams/research-team.json +3 -3
  492. package/specialists/org/teams/strategy-team.json +7 -14
  493. package/specialists/prompts/cx-architect.md +20 -1
  494. package/specialists/prompts/cx-data-analyst.md +1 -1
  495. package/specialists/prompts/cx-designer.md +12 -4
  496. package/specialists/prompts/cx-engineer.md +15 -1
  497. package/specialists/prompts/cx-operations.md +14 -2
  498. package/specialists/prompts/cx-orchestrator.md +9 -5
  499. package/specialists/prompts/cx-product-manager.md +5 -1
  500. package/specialists/prompts/cx-qa.md +6 -2
  501. package/specialists/prompts/cx-researcher.md +27 -31
  502. package/specialists/prompts/cx-reviewer.md +19 -1
  503. package/specialists/prompts/cx-security.md +5 -1
  504. package/templates/distribution/construct-brand.typ +123 -59
  505. package/templates/distribution/construct-decision.typ +6 -3
  506. package/templates/distribution/construct-pdf.typ +11 -4
  507. package/templates/distribution/construct-prd.typ +6 -3
  508. package/templates/distribution/construct-research.typ +7 -4
  509. package/vendor/pandoc-ext/README.md +3 -0
  510. package/vendor/pandoc-ext/diagram.lua +687 -0
  511. package/lib/providers/contract/adapters/git/index.mjs +0 -115
  512. package/lib/providers/contract/adapters/slack/index.mjs +0 -175
  513. package/specialists/org/contracts/business-strategist-to-product-manager.json +0 -39
  514. package/specialists/org/contracts/construct-to-rd-lead.json +0 -53
  515. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +0 -36
  516. package/specialists/org/contracts/designer-to-accessibility.json +0 -36
  517. package/specialists/org/contracts/platform-engineer-to-engineer.json +0 -31
  518. package/specialists/org/contracts/qa-to-test-automation.json +0 -42
  519. package/specialists/org/contracts/rd-lead-to-architect.json +0 -38
  520. package/specialists/org/contracts/sre-to-release-manager.json +0 -36
  521. package/specialists/org/specialists/cx-accessibility.json +0 -69
  522. package/specialists/org/specialists/cx-ai-engineer.json +0 -75
  523. package/specialists/org/specialists/cx-business-strategist.json +0 -72
  524. package/specialists/org/specialists/cx-data-engineer.json +0 -71
  525. package/specialists/org/specialists/cx-devil-advocate.json +0 -71
  526. package/specialists/org/specialists/cx-docs-keeper.json +0 -82
  527. package/specialists/org/specialists/cx-evaluator.json +0 -69
  528. package/specialists/org/specialists/cx-explorer.json +0 -69
  529. package/specialists/org/specialists/cx-legal-compliance.json +0 -74
  530. package/specialists/org/specialists/cx-oracle.json +0 -46
  531. package/specialists/org/specialists/cx-platform-engineer.json +0 -80
  532. package/specialists/org/specialists/cx-rd-lead.json +0 -73
  533. package/specialists/org/specialists/cx-release-manager.json +0 -77
  534. package/specialists/org/specialists/cx-sre.json +0 -94
  535. package/specialists/org/specialists/cx-test-automation.json +0 -69
  536. package/specialists/org/specialists/cx-trace-reviewer.json +0 -69
  537. package/specialists/org/specialists/cx-ux-researcher.json +0 -68
  538. package/specialists/org/teams/accessibility-team.json +0 -39
  539. package/specialists/org/teams/ux-research-team.json +0 -39
  540. package/specialists/prompts/cx-accessibility.md +0 -55
  541. package/specialists/prompts/cx-ai-engineer.md +0 -124
  542. package/specialists/prompts/cx-business-strategist.md +0 -58
  543. package/specialists/prompts/cx-data-engineer.md +0 -55
  544. package/specialists/prompts/cx-devil-advocate.md +0 -59
  545. package/specialists/prompts/cx-docs-keeper.md +0 -164
  546. package/specialists/prompts/cx-evaluator.md +0 -49
  547. package/specialists/prompts/cx-explorer.md +0 -71
  548. package/specialists/prompts/cx-legal-compliance.md +0 -58
  549. package/specialists/prompts/cx-oracle.md +0 -98
  550. package/specialists/prompts/cx-platform-engineer.md +0 -97
  551. package/specialists/prompts/cx-rd-lead.md +0 -59
  552. package/specialists/prompts/cx-release-manager.md +0 -54
  553. package/specialists/prompts/cx-sre.md +0 -111
  554. package/specialists/prompts/cx-test-automation.md +0 -55
  555. package/specialists/prompts/cx-trace-reviewer.md +0 -101
  556. package/specialists/prompts/cx-ux-researcher.md +0 -53
@@ -0,0 +1,53 @@
1
+ /**
2
+ * lib/oracle/heartbeat.mjs — oracle producer liveness from the last-tick record.
3
+ *
4
+ * The oracle daemon records last-tick.json when a tick completes and idles itself
5
+ * out after a few no-work ticks, so a stale tick on its own is not death — it is a
6
+ * dead-producer signal only when oracle work is actually waiting (pending approvals
7
+ * or unaddressed gaps). Consumers therefore pair heartbeatFreshness with a pending
8
+ * count; this module owns only the age check. It is deliberately distinct from
9
+ * verdictFreshness in lib/intake/session-prelude.mjs, which ages the verdict's own
10
+ * `at` (is the answer current) rather than the producer's tick `at` (is anything
11
+ * still generating answers). formatAge is shared with the verdict path.
12
+ */
13
+
14
+ import { readLastTick } from './index.mjs';
15
+
16
+ // Six missed 5-minute intervals clears the daemon's idle-shutdown window before a
17
+ // stale tick is treated as a stalled producer, so a briefly-quiet daemon is never
18
+ // mislabelled dead.
19
+ export const ORACLE_TICK_INTERVAL_MS = 5 * 60_000;
20
+ export const HEARTBEAT_STALE_MS = ORACLE_TICK_INTERVAL_MS * 6;
21
+
22
+ export function formatAge(ageMs) {
23
+ if (!Number.isFinite(ageMs)) return 'unknown';
24
+ const hours = Math.floor(ageMs / (60 * 60 * 1000));
25
+ if (hours < 1) return '<1h';
26
+ if (hours < 24) return `${hours}h`;
27
+ return `${Math.floor(hours / 24)}d`;
28
+ }
29
+
30
+ // Missing or unparseable `at` resolves to Infinity — stale, never fresh — so an
31
+ // absent tick record reads as a stalled producer rather than a healthy one.
32
+
33
+ export function heartbeatFreshness(lastTick, now = Date.now()) {
34
+ const at = lastTick?.at;
35
+ const parsed = at ? Date.parse(at) : NaN;
36
+ const ageMs = Number.isFinite(parsed) ? now - parsed : Infinity;
37
+ return {
38
+ ageMs,
39
+ stale: !Number.isFinite(ageMs) || ageMs > HEARTBEAT_STALE_MS,
40
+ asOf: Number.isFinite(parsed) ? new Date(parsed).toISOString() : null,
41
+ };
42
+ }
43
+
44
+ // Honors the oracle off-switch so a deliberately disabled daemon is never flagged.
45
+
46
+ export function readHeartbeatStatus({ homeDir, env = process.env } = {}) {
47
+ if (env?.CONSTRUCT_ORACLE === 'off' || env?.CONSTRUCT_ORACLE === '0') {
48
+ return { enabled: false, lastTick: null, ageMs: null, stale: false, asOf: null };
49
+ }
50
+ const lastTick = readLastTick(homeDir);
51
+ const { ageMs, stale, asOf } = heartbeatFreshness(lastTick);
52
+ return { enabled: true, lastTick, ageMs, stale, asOf };
53
+ }
@@ -22,7 +22,7 @@ import { collectArtifactGateSignals } from './artifact-gate.mjs';
22
22
  import { loadGraph, nodesByType, dependentsOf } from '../graph/store.mjs';
23
23
  import { hashFiles } from '../graph/build-from-registry.mjs';
24
24
  import { GRAPH_SEED_FILES } from '../graph/staleness.mjs';
25
- import { readViolationSupersedeCutoff } from '../contracts/violation-log.mjs';
25
+ import { recentViolations } from '../contracts/violation-log.mjs';
26
26
  import { doctorRoot } from '../config/xdg.mjs';
27
27
 
28
28
  const RECENT_MS = 24 * 60 * 60 * 1000;
@@ -109,14 +109,12 @@ function collectOutcomesSummary(projectDir) {
109
109
 
110
110
  function collectContractViolations(projectDir) {
111
111
  const file = path.join(projectDir, '.cx', 'contract-violations.jsonl');
112
- const since = Date.now() - RECENT_MS;
113
- const supersedeCutoff = readViolationSupersedeCutoff(projectDir);
114
- const recent = readRecentJsonl(file, { since, limit: VIOLATION_LIMIT })
115
- .filter((row) => {
116
- if (!row?.ts) return false;
117
- if (supersedeCutoff != null && new Date(row.ts).getTime() <= supersedeCutoff) return false;
118
- return true;
119
- });
112
+ const recent = recentViolations({
113
+ windowMs: RECENT_MS,
114
+ repoRoot: projectDir,
115
+ excludeDevNoise: true,
116
+ limit: VIOLATION_LIMIT,
117
+ });
120
118
  return {
121
119
  present: fs.existsSync(file),
122
120
  recentCount: recent.length,
@@ -243,7 +241,57 @@ function collectStructureSprawl(projectDir) {
243
241
  // edge), and freshness (a capability whose realizing files changed after its
244
242
  // lastValidated stamp). Never throws; an absent graph yields present:false.
245
243
 
246
- function collectDependencyGraph(rootDir, projectDir) {
244
+ // Freshness needs content identity, not mtime: any checkout, rebase, or touch
245
+ // rewrites file mtimes repo-wide without changing a single byte, so a pure
246
+ // mtime > stamp comparison flags every capability on every fresh clone. A
247
+ // file only "changed since lastValidated" if its working-tree bytes differ
248
+ // from HEAD (dirty edit) or a commit touching it landed after the stamp
249
+ // (`git log --since`). Both checks are batched into one spawnSync each so
250
+ // the cost stays O(1) per capability rather than O(realizers).
251
+
252
+ function gitDirtyFiles(rootDir) {
253
+ try {
254
+ const res = spawnSync('git', ['diff', '--name-only', 'HEAD'], { cwd: rootDir, encoding: 'utf8' });
255
+ if (res.status !== 0) return null;
256
+ return new Set(res.stdout.split('\n').map((l) => l.trim()).filter(Boolean));
257
+ } catch {
258
+ return null;
259
+ }
260
+ }
261
+
262
+ function gitFilesChangedSince(rootDir, sinceIso, rels) {
263
+ if (rels.length === 0) return new Set();
264
+ try {
265
+ const res = spawnSync(
266
+ 'git',
267
+ ['log', `--since=${sinceIso}`, '--name-only', '--pretty=format:', '--', ...rels],
268
+ { cwd: rootDir, encoding: 'utf8' },
269
+ );
270
+ if (res.status !== 0) return null;
271
+ return new Set(res.stdout.split('\n').map((l) => l.trim()).filter(Boolean));
272
+ } catch {
273
+ return null;
274
+ }
275
+ }
276
+
277
+ // Validation-grade freshness must not reuse the advisory `realizes` closure:
278
+ // build-import-graph.mjs deliberately widens that edge set for impact tracing
279
+ // (a broad edge only widens advisory reach, which is safe there). Reused
280
+ // here it would treat all 300+ files transitively reachable from a
281
+ // capability's tests as realizers, guaranteeing false positives. The
282
+ // freshness gate instead only trusts direct, declaration-sourced realizes
283
+ // edges (source: 'registry') — the curated implFiles list a capability
284
+ // actually declares — leaving the wide closure untouched for `construct
285
+ // trace`/`impact`.
286
+
287
+ function directRealizers(graph, capId) {
288
+ const edges = graph.in.get(capId) || [];
289
+ return edges
290
+ .filter((e) => e.rel === 'realizes' && (e.sources || []).includes('registry'))
291
+ .map((e) => e.from.slice('file:'.length));
292
+ }
293
+
294
+ export function collectDependencyGraph(rootDir, projectDir) {
247
295
  const graph = loadGraph(projectDir);
248
296
  if (!graph.exists) {
249
297
  return { present: false, applicable: isConstructPackageRepo(projectDir) };
@@ -271,18 +319,26 @@ function collectDependencyGraph(rootDir, projectDir) {
271
319
  const orphanFileCount = nodesByType(graph, 'file')
272
320
  .filter((f) => (graph.out.get(f.id) || []).every((e) => e.rel !== 'realizes')).length;
273
321
 
322
+ const dirtyFiles = gitDirtyFiles(rootDir);
274
323
  const untested = [];
275
324
  for (const cap of nodesByType(graph, 'capability')) {
276
325
  const lastValidated = cap.attrs?.lastValidated;
277
326
  if (!lastValidated) continue;
278
327
  const stamp = Date.parse(lastValidated);
279
328
  if (!Number.isFinite(stamp)) continue;
280
- const realizers = dependentsOf(graph, cap.id, 'realizes').map((id) => id.slice('file:'.length));
329
+ const realizers = directRealizers(graph, cap.id);
330
+ if (realizers.length === 0) continue;
331
+ const committedChanged = gitFilesChangedSince(rootDir, lastValidated, realizers);
281
332
  let changed = 0;
282
333
  for (const rel of realizers) {
283
334
  try {
284
- if (fs.statSync(path.join(rootDir, rel)).mtimeMs > stamp) changed++;
285
- } catch { /* file gone — coverage handles it */ }
335
+ fs.statSync(path.join(rootDir, rel));
336
+ } catch {
337
+ continue;
338
+ }
339
+ const dirty = dirtyFiles?.has(rel) ?? false;
340
+ const committed = committedChanged?.has(rel) ?? false;
341
+ if (dirty || committed) changed++;
286
342
  }
287
343
  if (changed > 0) untested.push({ capability: cap.id.slice('capability:'.length), changedFiles: changed, lastValidated });
288
344
  }
@@ -9,7 +9,7 @@ import fs from 'node:fs';
9
9
  import path from 'node:path';
10
10
 
11
11
  import { runBd } from '../beads-client.mjs';
12
- import { markContractViolationsSuperseded, recentViolations } from '../contracts/violation-log.mjs';
12
+ import { isDevSessionContractNoise, markContractViolationsSuperseded, recentViolations } from '../contracts/violation-log.mjs';
13
13
  import { VERDICT_ONLY_GAP_IDS } from './policy.mjs';
14
14
  import { oracleBeadTitlePrefix } from './issues.mjs';
15
15
 
@@ -91,55 +91,12 @@ function pruneRaisedIssues(projectDir, { dryRun = false } = {}) {
91
91
  return { pruned };
92
92
  }
93
93
 
94
- const BARE_GOAL_FIELD_LABELS = ['intent', 'workCategory', 'riskFlags', 'acceptanceCriteria'];
95
-
96
- const RESEARCHER_PROBE_MISSING = [
97
- 'artifact missing required field: question',
98
- 'artifact missing required field: method',
99
- 'artifact missing required field: sources',
100
- 'artifact missing required field: findings',
101
- 'artifact missing required field: confidence',
102
- ];
103
-
104
- const A11Y_PROBE_MISSING = [
105
- 'artifact missing required field: findings',
106
- 'artifact missing required field: wcagCriterion',
107
- 'artifact missing required field: userImpact',
108
- ];
109
-
110
- function missingBareGoalConstructFields(missing) {
111
- if (!Array.isArray(missing) || missing.length !== BARE_GOAL_FIELD_LABELS.length) return false;
112
- return BARE_GOAL_FIELD_LABELS.every((field) =>
113
- missing.some((entry) => String(entry).includes(field)),
114
- );
115
- }
116
-
117
- function isBareGoalConstructViolation(row) {
118
- if (row?.contractId !== 'construct-to-orchestrator') return false;
119
- if (!missingBareGoalConstructFields(row.missing)) return false;
120
- const keys = row.packet_keys ?? row.packetKeys;
121
- return Array.isArray(keys) && keys.length === 1 && keys[0] === 'goal';
122
- }
123
-
124
- function isEmptyProbeViolation(row, contractId, expectedMissing) {
125
- if (row?.contractId !== contractId) return false;
126
- const keys = row.packet_keys ?? row.packetKeys;
127
- if (!Array.isArray(keys) || keys.length !== 0) return false;
128
- return JSON.stringify(row.missing) === JSON.stringify(expectedMissing);
129
- }
130
-
131
- function isDevSessionContractNoise(row) {
132
- return isBareGoalConstructViolation(row)
133
- || isEmptyProbeViolation(row, 'researcher-to-architect', RESEARCHER_PROBE_MISSING)
134
- || isEmptyProbeViolation(row, 'accessibility-to-qa', A11Y_PROBE_MISSING);
135
- }
136
-
137
94
  /**
138
95
  * @param {string} projectDir
139
96
  * @returns {{ shouldSupersede: boolean, recentCount: number, reason: string }}
140
97
  */
141
- export function planContractViolationSupersede(projectDir) {
142
- const recent = recentViolations({ repoRoot: projectDir });
98
+ export function planContractViolationSupersede(projectDir, { now = Date.now() } = {}) {
99
+ const recent = recentViolations({ repoRoot: projectDir, now });
143
100
  if (!recent.length) {
144
101
  return { shouldSupersede: false, recentCount: 0, reason: 'no recent contract violations' };
145
102
  }
@@ -1,54 +1,60 @@
1
1
  /**
2
2
  * lib/oracle/routing.mjs — deterministic gap → specialist routing table.
3
3
  *
4
- * Mirrors cx-oracle.md routing without LLM involvement. Issue raising,
5
- * approve execution, and routing artifact generation consume these mappings.
4
+ * Mirrors skills/operating/fleet-health-routing.md (the fleet-health duty
5
+ * cx-oracle's retirement folded into cx-orchestrator, construct-rf26.11)
6
+ * without LLM involvement. Issue raising, approve execution, and routing
7
+ * artifact generation consume these mappings. Specialist ids reflect the
8
+ * post-consolidation 12-role roster; team-governance signals route to
9
+ * cx-operations (owns dependency/ownership mapping) rather than the retired
10
+ * cx-rd-lead.
6
11
  */
7
12
 
8
13
  const GAP_ROUTES = {
9
- 'parity-drift': { primary: 'cx-platform-engineer', secondary: 'cx-docs-keeper' },
14
+ 'parity-drift': { primary: 'cx-engineer', secondary: 'cx-operations' },
10
15
  'contract-violations': { primary: 'cx-reviewer', secondary: 'cx-engineer' },
11
- 'doctor-escalation': { primary: 'cx-sre', secondary: 'cx-operations' },
12
- 'outcomes-degradation': { primary: 'cx-trace-reviewer', secondary: null },
13
- 'census-stale': { primary: 'cx-architect', secondary: 'cx-docs-keeper' },
14
- 'alignment-regression': { primary: 'cx-architect', secondary: 'cx-docs-keeper' },
15
- 'true-skill-orphan': { primary: 'cx-architect', secondary: 'cx-docs-keeper' },
16
- 'observations-empty': { primary: 'cx-explorer', secondary: 'cx-data-engineer' },
16
+ 'doctor-escalation': { primary: 'cx-operations', secondary: 'cx-operations' },
17
+ 'outcomes-degradation': { primary: 'cx-reviewer', secondary: null },
18
+ 'census-stale': { primary: 'cx-architect', secondary: 'cx-operations' },
19
+ 'alignment-regression': { primary: 'cx-architect', secondary: 'cx-operations' },
20
+ 'true-skill-orphan': { primary: 'cx-architect', secondary: 'cx-operations' },
21
+ 'observations-empty': { primary: 'cx-researcher', secondary: 'cx-engineer' },
17
22
  'beads-hygiene': { primary: 'cx-operations', secondary: null },
18
- 'hook-failures': { primary: 'cx-sre', secondary: null },
19
- 'registry-warn': { primary: 'cx-platform-engineer', secondary: null },
20
- 'consistency-drift': { primary: 'cx-platform-engineer', secondary: null },
21
- 'propagation-stale': { primary: 'cx-platform-engineer', secondary: 'cx-docs-keeper' },
23
+ 'hook-failures': { primary: 'cx-operations', secondary: null },
24
+ 'registry-warn': { primary: 'cx-engineer', secondary: null },
25
+ 'consistency-drift': { primary: 'cx-engineer', secondary: null },
26
+ 'propagation-stale': { primary: 'cx-engineer', secondary: 'cx-operations' },
22
27
  'policy-coverage-gap': { primary: 'cx-architect', secondary: null },
23
28
  'workflow-misaligned': { primary: 'cx-product-manager', secondary: null },
24
- 'legal-review-pending': { primary: 'cx-legal-compliance', secondary: null },
25
- 'capability-unvalidated': { primary: 'cx-platform-engineer', secondary: null },
29
+ 'legal-review-pending': { primary: 'cx-security', secondary: null },
30
+ 'capability-unvalidated': { primary: 'cx-engineer', secondary: null },
26
31
  'dead-code-regression': { primary: 'cx-architect', secondary: null },
27
32
  'structure-sprawl': { primary: 'cx-architect', secondary: null },
28
33
  'init-duplicate-lanes': { primary: 'cx-architect', secondary: null },
29
- 'outcomes-missing': { primary: 'cx-data-engineer', secondary: null },
30
- 'repo-layout-legacy': { primary: 'cx-platform-engineer', secondary: 'cx-architect' },
31
- 'specialist-audit-drift': { primary: 'cx-architect', secondary: 'cx-docs-keeper' },
32
- 'artifact-gate-bypass': { primary: 'cx-reviewer', secondary: 'cx-docs-keeper' },
34
+ 'outcomes-missing': { primary: 'cx-engineer', secondary: null },
35
+ 'repo-layout-legacy': { primary: 'cx-engineer', secondary: 'cx-architect' },
36
+ 'specialist-audit-drift': { primary: 'cx-architect', secondary: 'cx-operations' },
37
+ 'artifact-gate-bypass': { primary: 'cx-reviewer', secondary: 'cx-operations' },
33
38
  'artifact-reviewer-gap': { primary: 'cx-reviewer', secondary: null },
34
- 'dependency-graph-stale': { primary: 'cx-platform-engineer', secondary: null },
39
+ 'dependency-graph-stale': { primary: 'cx-engineer', secondary: null },
35
40
  'matrix-coverage-gap': { primary: 'cx-architect', secondary: 'cx-qa' },
36
41
  'impact-untested': { primary: 'cx-qa', secondary: 'cx-engineer' },
37
- // Team governance signals — route to rd-lead for strategic resolution
38
- 'team-understaffed': { primary: 'cx-rd-lead', secondary: 'cx-orchestrator' },
39
- 'escalation-path-broken': { primary: 'cx-rd-lead', secondary: 'cx-architect' },
40
- 'team-decision-violation': { primary: 'cx-rd-lead', secondary: 'cx-orchestrator' },
41
- 'cross-team-handoff-blocked': { primary: 'cx-rd-lead', secondary: null },
42
+ // Team governance signals — rd-lead retired (construct-rf26.11); route to
43
+ // cx-operations (owns dependency/ownership mapping) for resolution.
44
+ 'team-understaffed': { primary: 'cx-operations', secondary: 'cx-orchestrator' },
45
+ 'escalation-path-broken': { primary: 'cx-operations', secondary: 'cx-architect' },
46
+ 'team-decision-violation': { primary: 'cx-operations', secondary: 'cx-orchestrator' },
47
+ 'cross-team-handoff-blocked': { primary: 'cx-operations', secondary: null },
42
48
  };
43
49
 
44
50
  const ACTION_ROUTES = {
45
51
  'specialist-review': { primary: 'cx-reviewer', gateType: 'specialist-dispatch' },
46
- 'doctor-followup': { primary: 'cx-sre', gateType: 'operational-followup' },
47
- 'trace-review': { primary: 'cx-trace-reviewer', gateType: 'specialist-dispatch' },
48
- 'outcomes-aggregate': { primary: 'cx-data-engineer', gateType: 'maintenance' },
52
+ 'doctor-followup': { primary: 'cx-operations', gateType: 'operational-followup' },
53
+ 'trace-review': { primary: 'cx-reviewer', gateType: 'specialist-dispatch' },
54
+ 'outcomes-aggregate': { primary: 'cx-engineer', gateType: 'maintenance' },
49
55
  'executive-signoff-required': { primary: 'cx-product-manager', gateType: 'executive-gate' },
50
56
  'structure-cleanup-proposal': { primary: 'cx-architect', gateType: 'human-approval' },
51
- 'graph-rebuild': { primary: 'cx-platform-engineer', gateType: 'maintenance' },
57
+ 'graph-rebuild': { primary: 'cx-engineer', gateType: 'maintenance' },
52
58
  };
53
59
 
54
60
  /**
@@ -59,14 +65,14 @@ export function routeGap(gap) {
59
65
  const id = gap?.id ?? gap?.signal ?? '';
60
66
  const row = GAP_ROUTES[id];
61
67
  if (row) return { ...row, gateType: signOffGateForGap(id) };
62
- return { primary: 'cx-oracle', secondary: null, gateType: 'human-approval' };
68
+ return { primary: 'cx-orchestrator', secondary: null, gateType: 'human-approval' };
63
69
  }
64
70
 
65
71
  /**
66
72
  * @param {string} actionKind
67
73
  */
68
74
  export function routeAction(actionKind) {
69
- return ACTION_ROUTES[actionKind] ?? { primary: 'cx-oracle', gateType: 'human-approval' };
75
+ return ACTION_ROUTES[actionKind] ?? { primary: 'cx-orchestrator', gateType: 'human-approval' };
70
76
  }
71
77
 
72
78
  function signOffGateForGap(gapId) {
@@ -94,7 +94,7 @@ export function synthesizeVerdict(readModel) {
94
94
  ));
95
95
  recommendedActions.push(action(
96
96
  'trace-review',
97
- 'Dispatch cx-trace-reviewer to inspect degraded specialist outcomes',
97
+ 'Dispatch cx-reviewer to inspect degraded specialist outcomes',
98
98
  { roles: degradedRoles, signOff: signOffMetadata({ id: 'outcomes-degradation' }, readModel.projectDir) },
99
99
  ));
100
100
  }