@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24

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 (261) hide show
  1. package/out/mcp-server.js +18758 -12030
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
  5. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
  6. package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
  7. package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
  8. package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
  9. package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
  10. package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
  11. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
  12. package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
  13. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  14. package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
  15. package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
  17. package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
  18. package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
  20. package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
  21. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
  23. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
  24. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
  25. package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
  26. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
  27. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
  28. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
  29. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
  30. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
  31. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
  32. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
  33. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
  34. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
  35. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
  36. package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
  37. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
  38. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
  39. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
  40. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
  41. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
  42. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
  43. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
  44. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
  45. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
  46. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
  47. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
  48. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
  49. package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
  50. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
  51. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  52. package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
  53. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  54. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  55. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  56. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  57. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  58. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  59. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  60. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  61. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  62. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  63. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  64. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  65. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  66. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  67. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
  68. package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
  69. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
  70. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
  71. package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
  72. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
  73. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
  74. package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
  75. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
  76. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
  77. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  78. package/resources/claude-customizations/.claude/rules/shell.md +1 -1
  79. package/resources/claude-customizations/.claude/settings.json +36 -3
  80. package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  81. package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
  82. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
  83. package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
  84. package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
  85. package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
  86. package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
  87. package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
  88. package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
  89. package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
  90. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
  91. package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
  92. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
  93. package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  94. package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
  95. package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
  96. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
  97. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
  98. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
  99. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
  100. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
  101. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
  102. package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
  103. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
  104. package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
  105. package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
  106. package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
  107. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
  108. package/resources/claude-customizations/config/blast-radius.json +6 -5
  109. package/resources/claude-customizations/config/orchestration-routing.json +61 -1
  110. package/resources/claude-customizations/pack-manifests/core.json +40 -1
  111. package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  112. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
  113. package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
  114. package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  115. package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
  116. package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
  117. package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
  118. package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
  119. package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
  120. package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
  122. package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
  123. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  124. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
  125. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
  126. package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  127. package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
  128. package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
  129. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
  130. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
  131. package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
  132. package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
  133. package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
  134. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
  135. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
  136. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
  137. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
  138. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
  139. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
  140. package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
  141. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
  142. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
  143. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
  144. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
  145. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
  146. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
  147. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
  148. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
  149. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
  150. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
  151. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
  152. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
  153. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
  154. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
  155. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
  156. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
  157. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
  158. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
  159. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  160. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
  161. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
  162. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
  163. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
  164. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
  165. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
  166. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
  167. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
  168. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
  169. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
  170. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
  171. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
  172. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
  173. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
  174. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
  175. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
  176. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
  177. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
  178. package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
  179. package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
  180. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
  181. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
  182. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
  183. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
  184. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
  185. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
  186. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
  187. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
  188. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
  189. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
  190. package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
  191. package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
  192. package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
  193. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
  194. package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
  195. package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
  196. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
  197. package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
  198. package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
  199. package/resources/config/orchestration-routing.json +61 -1
  200. package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
  201. package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
  202. package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
  203. package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
  204. package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
  205. package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
  206. package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
  207. package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
  208. package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
  209. package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
  210. package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
  211. package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
  212. package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
  213. package/resources/customizations/.github/hooks/discovery.json +35 -0
  214. package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
  215. package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
  216. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
  217. package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
  218. package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
  219. package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  220. package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
  221. package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  222. package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
  223. package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
  224. package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
  225. package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
  226. package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
  227. package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
  228. package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
  229. package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
  230. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
  231. package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  232. package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
  233. package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
  234. package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
  235. package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
  236. package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
  237. package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
  238. package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  239. package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
  240. package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  241. package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  242. package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  243. package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  244. package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  245. package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  246. package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  247. package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  248. package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  249. package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  250. package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  251. package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  252. package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  253. package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  254. package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
  255. package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
  256. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
  257. package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
  258. package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
  259. package/resources/powershell/PoshQC/README.md +20 -1
  260. package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
  261. package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
@@ -1,61 +1,41 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Portable discovery-artifact validation for the Claude enforcement hooks (#475).
3
+ Bounded compatibility surface of the retired PowerShell discovery-artifact validator (#475, #980).
4
4
  .DESCRIPTION
5
- Validates the domain-profile document and the seven schema-governed discovery
6
- artifact types WITHOUT invoking a Python interpreter. Both discovery hooks
7
- previously shelled out to `python -m scripts.dev_tools.validate_discovery_artifacts`;
8
- the `.claude/**` payload ships to destinations with no guaranteed Python, Poetry,
9
- or `scripts/dev_tools`, where that call fails obscurely or blocks everything.
10
-
11
- REQUIRES POWERSHELL 7.4 OR LATER. Schema validation uses `Test-Json -SchemaFile`,
12
- whose JSON Schema Draft 2020-12 support was added in PowerShell 7.4. All seven
13
- schemas under `schemas/discovery/v1/` declare Draft 2020-12 (verified 7 of 7), so
14
- the floor is unavoidable. Verified present in PowerShell 7.6.3 in this environment.
15
- DESTINATION RISK: on PowerShell 7.0-7.3 every entry point fails CLOSED with an
16
- explicit, actionable message naming the required version, the `Test-Json -SchemaFile`
17
- Draft 2020-12 reason, and issue #475. It never degrades silently and never fails
18
- open. The repo standard in `.claude/rules/powershell.md` is "PowerShell 7+", which
19
- is below this floor; that rule file is NOT modified by this change.
20
-
21
- This help is the destination-visible statement of that requirement: the module ships
22
- inside `.claude/**`, and the pushed-down pack holds only `config/` and
23
- `pack-manifests/` beside it, with no pack README to carry the statement.
5
+ Until issue #980 this module evaluated discovery artifacts itself: a placeholder
6
+ profile contract and `Test-Json -SchemaFile` checks against the v1 schemas. One
7
+ Python engine now owns artifact meaning, the installed TypeScript gateway is the
8
+ only writer of protected validation receipts, and the native hooks under
9
+ `.claude/hooks`, `.codex/hooks` and `.github/hooks` verify protected current
10
+ authority through the sibling Discovery* modules. This module therefore keeps
11
+ its exported names for compatibility and directs every semantic question to
12
+ the authoritative service:
13
+
14
+ - the artifact-type table and the destination PowerShell floor are retained
15
+ (the floor is still the hook runtime requirement, and an unsupported host
16
+ fails closed with the same actionable message);
17
+ - every former validation entry returns a validation-required result naming
18
+ `validate_discovery_artifacts`; none parses a profile or a schema, none
19
+ returns an empty error list, and `Invoke-DiscoveryArtifactValidation` never
20
+ returns `ExitCode = 0`, so an old entry name cannot mint a passing gate;
21
+ - `Get-DiscoveryValidationAuthority` reports whether the workspace holds a
22
+ protected activation on a supported host, which is the only authority a
23
+ native hook consults.
24
+
25
+ No Python interpreter or other process is invoked anywhere in this module.
24
26
  .NOTES
25
- Issue #475.
26
-
27
- RESULT CONTRACT (defect D-2 avoidance). Success is SILENT: a passing validation
28
- returns `ExitCode = 0` with EMPTY `Output`. Both hooks deny on a non-zero exit code
29
- OR on non-empty output, so the previous Python CLI's success line
30
- ("<type> validation passed: <path>") turned a PASSING validation into a DENY.
31
-
32
- PARITY with `validate_discovery_profile.py` / `validate_discovery_schema_artifacts.py`. Error
33
- families are preserved: `invalid JSON (...)`, `JSON root must be an object for validation`,
34
- `schema resolution failed (...)`, `Profile document is empty.`,
35
- `Profile document root must be a mapping.`, `Missing required field: <field>.` Schema
36
- location resolves solely from each artifact's own `$schema`, as in the reference; the
37
- type-to-file table below is documentation and artifact-type validation only. Deliberate
38
- divergences: an `http(s)://` `$schema` is NOT fetched (no guaranteed destination network,
39
- so a non-`file` scheme is reported fail-closed in the `schema resolution failed (...)`
40
- family), and `file://` resolves through `[uri]::LocalPath` rather than the reference's
41
- `Path(parsed.path)`, which mishandles a Windows `file:///C:/...` path. Unavoidable
42
- divergence: per-violation wording comes from `Test-Json`, not `jsonschema`, so violation
43
- strings differ while family and verdict match. The profile check reproduces the
44
- placeholder contract without a YAML parser (PowerShell ships none); see
45
- `Get-DiscoveryProfileValidationError` for what is and is not detected.
46
- .EXAMPLE
47
- Invoke-DiscoveryArtifactValidation -ValidatorArgs @('evidence-reference', $path)
48
-
49
- Returns @{ ExitCode = 0; Output = '' } when the artifact conforms.
27
+ Issues #475 and #980. Requires PowerShell 7.4 or later on a destination host.
50
28
  CONVENTION: this module fails fast at module scope and imports its siblings with -ErrorAction Stop.
51
29
  #>
52
30
 
53
31
  Set-StrictMode -Version Latest
54
32
  $ErrorActionPreference = 'Stop'
55
33
 
34
+ Import-Module (Join-Path $PSScriptRoot 'DiscoveryEncoding.psm1') -ErrorAction Stop
35
+ Import-Module (Join-Path $PSScriptRoot 'DiscoveryAuthority.psm1') -ErrorAction Stop
36
+
56
37
  # Schema-governed artifact types mapped to their filenames under `schemas/discovery/v1/`.
57
- # Verified against `validate_discovery_artifacts.py`: `runtime-scenario`,
58
- # `product-decision`, and `unspecified-behavior` do NOT share their token's stem.
38
+ # Retained as documentation and artifact-type recognition only; no schema is evaluated here.
59
39
  $script:DiscoverySchemaArtifactFile = [ordered]@{
60
40
  'feature-contract' = 'feature-contract.schema.json'
61
41
  'coverage-ledger' = 'coverage-ledger.schema.json'
@@ -65,47 +45,25 @@ $script:DiscoverySchemaArtifactFile = [ordered]@{
65
45
  'product-decision' = 'product-decision-record.schema.json'
66
46
  'evidence-reference' = 'evidence-reference.schema.json'
67
47
  }
68
-
69
- # `Test-Json -SchemaFile` gained Draft 2020-12 support in PowerShell 7.4 and all seven
70
- # schemas declare Draft 2020-12, so this floor is unavoidable. Verified on 7.6.3 here.
71
48
  $script:MinimumPowerShellVersion = [version]'7.4'
72
-
73
- # TODO(#9001): replace with the finalized field contract once #9001 ships. Mirrors
74
- # `_PLACEHOLDER_REQUIRED_FIELDS` in `validate_discovery_profile.py`, whose own
75
- # TODO(#9001) marks it as the single seam that changes when #9001 lands.
76
- $script:ProfileRequiredField = @('legacy_source_path')
49
+ $script:ValidationRequiredPrefix = 'DISCOVERY_VALIDATION_REQUIRED:'
50
+ $script:ServiceOperation = 'validate_discovery_artifacts'
77
51
 
78
52
  function Get-DiscoveryRuntimeVersionError {
79
53
  <#
80
54
  .SYNOPSIS
81
- Returns the fail-closed message when the host PowerShell is below 7.4, or
82
- $null when the host meets the floor.
55
+ Returns the fail-closed message when the host PowerShell is below 7.4, or $null when the host meets the floor.
83
56
  .DESCRIPTION
84
- The destination version floor (issue #475). `Test-Json -SchemaFile` gained
85
- JSON Schema Draft 2020-12 support in PowerShell 7.4, and all seven discovery
86
- schemas declare Draft 2020-12, so an older host cannot validate them.
87
-
88
- This runs BEFORE any schema validation so an unsupported host fails with one
89
- explicit, actionable message instead of a raw `Test-Json` parameter error. It
90
- never degrades silently: no partial validation, no fail-open path.
91
-
92
- `PowerShellVersion` is the injectable seam, defaulting to the real
93
- `$PSVersionTable.PSVersion` and only ever READ; nothing here writes
94
- `$PSVersionTable`, so tests pass a version rather than mutating host state.
95
- .OUTPUTS
96
- [string] The fail-closed message, or $null when the host is supported.
57
+ The destination version floor (issue #475) is unchanged: the native hooks
58
+ and this module require PowerShell 7.4 or later. `PowerShellVersion` is the
59
+ injectable seam, defaulting to the real `$PSVersionTable.PSVersion` and only
60
+ ever read.
97
61
  #>
98
62
  [CmdletBinding()]
99
63
  [OutputType([string])]
100
- param(
101
- [Parameter(Mandatory = $false)]
102
- [version]$PowerShellVersion = $PSVersionTable.PSVersion
103
- )
104
-
105
- if ($PowerShellVersion -ge $script:MinimumPowerShellVersion) {
106
- return $null
107
- }
64
+ param([Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion)
108
65
 
66
+ if ($PowerShellVersion -ge $script:MinimumPowerShellVersion) { return $null }
109
67
  return (
110
68
  "Discovery-artifact validation requires PowerShell $($script:MinimumPowerShellVersion) or later " +
111
69
  "(this host is PowerShell $PowerShellVersion). Reason: schema validation uses " +
@@ -118,302 +76,167 @@ function Get-DiscoveryRuntimeVersionError {
118
76
  function Get-DiscoverySchemaArtifactType {
119
77
  <#
120
78
  .SYNOPSIS
121
- Returns the seven schema-governed artifact-type tokens, in dispatch order.
79
+ Returns the seven schema-governed artifact-type tokens.
122
80
  #>
123
81
  [CmdletBinding()]
124
- [OutputType([object[]])]
82
+ [OutputType([string[]])]
125
83
  param()
126
84
 
127
- return , @($script:DiscoverySchemaArtifactFile.Keys)
85
+ return [string[]]@($script:DiscoverySchemaArtifactFile.Keys)
128
86
  }
129
87
 
130
88
  function Get-DiscoverySchemaFileName {
131
89
  <#
132
90
  .SYNOPSIS
133
- Returns the schema filename an artifact-type token corresponds to, or $null
134
- when the token is not a schema-governed type. Documentation and artifact-type
135
- validation only: schema RESOLUTION is driven by the artifact's `$schema`.
91
+ Returns the v1 schema filename of a schema-governed artifact type, or $null for any other token.
136
92
  #>
137
93
  [CmdletBinding()]
138
94
  [OutputType([string])]
139
- param(
140
- [Parameter(Mandatory = $true)]
141
- [AllowEmptyString()]
142
- [string]$ArtifactType
143
- )
95
+ param([Parameter(Mandatory = $true)][AllowEmptyString()][string]$ArtifactType)
144
96
 
145
- if ($script:DiscoverySchemaArtifactFile.Contains($ArtifactType)) {
146
- return [string]$script:DiscoverySchemaArtifactFile[$ArtifactType]
147
- }
97
+ if ($script:DiscoverySchemaArtifactFile.Contains($ArtifactType)) { return [string]$script:DiscoverySchemaArtifactFile[$ArtifactType] }
148
98
  return $null
149
99
  }
150
100
 
151
- function Get-DiscoveryProfileTopLevelKey {
101
+ function Resolve-DiscoverySchemaFilePath {
152
102
  <#
153
103
  .SYNOPSIS
154
- Extracts the top-level mapping keys of a YAML profile document by line
155
- inspection, without a YAML parser.
104
+ Returns the repository path of a schema-governed artifact type's v1 schema file, or $null.
156
105
  .DESCRIPTION
157
- A top-level key is an unindented `key:` line. Blank lines, comment lines, and
158
- the `---`/`...` document markers are skipped. Nested keys are indented and are
159
- therefore ignored, which is exactly the scope the placeholder contract needs.
160
- Returns $null when the document presents no top-level mapping key, which the
161
- caller reports as a non-mapping root.
106
+ Documentation lookup only; the schema is never evaluated here. Artifact
107
+ `$schema` references are not resolved or fetched by this module any more.
162
108
  #>
163
109
  [CmdletBinding()]
164
- [OutputType([object[]])]
110
+ [OutputType([string])]
165
111
  param(
166
- [Parameter(Mandatory = $true)]
167
- [AllowEmptyString()]
168
- [string]$Text
112
+ [Parameter(Mandatory = $true)][AllowEmptyString()][string]$ArtifactType,
113
+ [Parameter(Mandatory = $true)][string]$RepositoryRoot
169
114
  )
170
115
 
171
- $keys = [System.Collections.Generic.List[string]]::new()
172
- $sawContent = $false
173
-
174
- foreach ($line in ($Text -split '\r?\n')) {
175
- $trimmed = $line.Trim()
176
- if ($trimmed.Length -eq 0 -or $trimmed.StartsWith('#')) {
177
- continue
178
- }
179
- if ($trimmed -eq '---' -or $trimmed -eq '...') {
180
- continue
181
- }
182
- $sawContent = $true
183
-
184
- # Only unindented lines can carry a top-level key.
185
- if ($line -match '^(?<key>[A-Za-z_][A-Za-z0-9_.-]*)\s*:(\s|$)') {
186
- $keys.Add($Matches['key'])
187
- }
188
- }
189
-
190
- # Content that never presented an unindented `key:` is not a mapping root
191
- # (a sequence root, a bare scalar, or a flow document).
192
- if (-not $sawContent -or $keys.Count -eq 0) {
193
- return $null
194
- }
195
- return , $keys.ToArray()
116
+ $fileName = Get-DiscoverySchemaFileName -ArtifactType $ArtifactType
117
+ if ($null -eq $fileName) { return $null }
118
+ return "$($RepositoryRoot.TrimEnd('/', '\'))/schemas/discovery/v1/$fileName"
196
119
  }
197
120
 
198
- function Get-DiscoveryProfileValidationError {
121
+ function Get-DiscoveryValidationRequiredMessage {
199
122
  <#
200
123
  .SYNOPSIS
201
- Validates domain-profile document text against the placeholder contract,
202
- mirroring `validate_profile_text` in `validate_discovery_profile.py`.
203
- .DESCRIPTION
204
- Reproduced checks: empty/whitespace-only document; non-mapping root; and the
205
- placeholder required-field set (`legacy_source_path`), reported one error per
206
- absent field.
207
-
208
- NOT reproduced: detection of arbitrary YAML syntax errors. PowerShell ships no
209
- YAML parser and this module must not add a dependency, so the reference's
210
- `Profile document is not valid YAML: <exc>` branch has no direct analogue. The
211
- substitute is fail-CLOSED: any document not presenting an unindented `key:`
212
- line is reported as a non-mapping root rather than accepted, so a malformed
213
- document is still rejected and only the diagnostic wording differs.
214
- .OUTPUTS
215
- [object[]] Zero or more error strings; empty when the document conforms.
124
+ Returns the validation-required message that directs an artifact question to the authoritative service.
216
125
  #>
217
126
  [CmdletBinding()]
218
- [OutputType([object[]])]
127
+ [OutputType([string])]
219
128
  param(
220
- [Parameter(Mandatory = $true)]
221
- [AllowEmptyString()]
222
- [string]$Text,
223
-
224
- [Parameter(Mandatory = $false)]
225
- [version]$PowerShellVersion = $PSVersionTable.PSVersion
129
+ [Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$ArtifactType = $null,
130
+ [Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$Path = $null
226
131
  )
227
132
 
228
- $errors = [System.Collections.Generic.List[string]]::new()
229
-
230
- # The floor is enforced at EVERY validation entry point, not only the schema path,
231
- # so an unsupported host can never receive a partial pass from this module.
232
- $versionError = Get-DiscoveryRuntimeVersionError -PowerShellVersion $PowerShellVersion
233
- if ($null -ne $versionError) {
234
- $errors.Add($versionError)
235
- return , $errors.ToArray()
236
- }
237
-
238
- if ([string]::IsNullOrWhiteSpace($Text)) {
239
- $errors.Add('Profile document is empty.')
240
- return , $errors.ToArray()
241
- }
242
-
243
- $keys = Get-DiscoveryProfileTopLevelKey -Text $Text
244
- if ($null -eq $keys) {
245
- $errors.Add('Profile document root must be a mapping.')
246
- return , $errors.ToArray()
247
- }
248
-
249
- # Report every absent field so a maintainer can fix the document in one pass.
250
- foreach ($field in $script:ProfileRequiredField) {
251
- if ($keys -notcontains $field) {
252
- $errors.Add("Missing required field: $field.")
253
- }
254
- }
255
-
256
- return , $errors.ToArray()
133
+ $subject = $(if ([string]::IsNullOrWhiteSpace($ArtifactType)) { 'the artifact' } else { "the $ArtifactType artifact" })
134
+ if (-not [string]::IsNullOrWhiteSpace($Path)) { $subject = "$subject at $Path" }
135
+ return "$($script:ValidationRequiredPrefix) $subject is validated only by the installed discovery service ($($script:ServiceOperation)); " +
136
+ 'this compatibility module no longer evaluates profile or schema semantics and cannot authorize a gate. ' +
137
+ 'Native hooks verify the protected validation receipt the gateway writes.'
257
138
  }
258
139
 
259
- function Resolve-DiscoverySchemaFilePath {
140
+ function Add-DiscoveryCompatibilityError {
260
141
  <#
261
142
  .SYNOPSIS
262
- Resolves an artifact's `$schema` URI to a local schema file path.
143
+ Appends the never-empty compatibility errors shared by the retired validation entries to a caller's list.
263
144
  .DESCRIPTION
264
- Mirrors the Python reference's resolution rules for the cases a destination
265
- can service: only a `file://` URI resolves. A scheme-less or non-`file` URI is
266
- rejected, and an `http(s)://` URI is deliberately NOT fetched.
267
- .OUTPUTS
268
- [hashtable] `@{ Path = <string>; Error = <string> }`; exactly one is non-null.
145
+ The version floor is appended alone when the host is below it. Otherwise an
146
+ unrecognized artifact type is appended first (when requested) and the
147
+ validation-required message always follows, so the list is never left empty.
269
148
  #>
270
149
  [CmdletBinding()]
271
- [OutputType([hashtable])]
150
+ [OutputType([void])]
272
151
  param(
273
- [Parameter(Mandatory = $true)]
274
- [AllowNull()]
275
- [object]$SchemaUri
152
+ [Parameter(Mandatory = $true)][AllowEmptyCollection()][System.Collections.Generic.List[string]]$ErrorList,
153
+ [Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$ArtifactType = $null,
154
+ [Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion,
155
+ [Parameter(Mandatory = $false)][switch]$ReportUnrecognizedType
276
156
  )
277
157
 
278
- if ($SchemaUri -isnot [string] -or [string]::IsNullOrEmpty([string]$SchemaUri)) {
279
- return @{ Path = $null; Error = 'schema resolution failed (missing $schema)' }
158
+ $floor = Get-DiscoveryRuntimeVersionError -PowerShellVersion $PowerShellVersion
159
+ if ($null -ne $floor) {
160
+ $ErrorList.Add($floor)
161
+ return
280
162
  }
163
+ if ($ReportUnrecognizedType) { $ErrorList.Add("Unrecognized discovery artifact type '$ArtifactType'.") }
164
+ $ErrorList.Add((Get-DiscoveryValidationRequiredMessage -ArtifactType $ArtifactType))
165
+ }
281
166
 
282
- $uri = $null
283
- if (-not [System.Uri]::TryCreate([string]$SchemaUri, [System.UriKind]::Absolute, [ref]$uri)) {
284
- # A scheme-less value cannot resolve: these pure text validators receive no
285
- # document path to resolve a relative reference against.
286
- return @{ Path = $null; Error = 'schema resolution failed (Unsupported schema URI scheme: missing)' }
287
- }
167
+ function Get-DiscoveryProfileTopLevelKey {
168
+ <#
169
+ .SYNOPSIS
170
+ Compatibility export: profile parsing is retired, so no top-level key is ever reported.
171
+ #>
172
+ [CmdletBinding()]
173
+ [OutputType([string[]])]
174
+ param([Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text)
288
175
 
289
- if ($uri.Scheme -ine 'file') {
290
- $message = "schema resolution failed (Unsupported schema URI scheme: $($uri.Scheme))"
291
- return @{ Path = $null; Error = $message }
292
- }
176
+ # The text is deliberately not read; the service owns profile semantics.
177
+ $null = $Text
178
+ return [string[]]@()
179
+ }
293
180
 
294
- # LocalPath, not the raw URI path, so a Windows `file:///C:/...` URI resolves.
295
- $localPath = $uri.LocalPath
296
- if (-not (Test-Path -LiteralPath $localPath -PathType Leaf)) {
297
- return @{ Path = $null; Error = "schema resolution failed (Schema file not found: $localPath)" }
298
- }
181
+ function Get-DiscoveryProfileValidationError {
182
+ <#
183
+ .SYNOPSIS
184
+ Returns the version-floor error below PowerShell 7.4, otherwise the validation-required message for the profile.
185
+ #>
186
+ [CmdletBinding()]
187
+ [OutputType([object[]])]
188
+ param(
189
+ [Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text,
190
+ [Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion
191
+ )
299
192
 
300
- return @{ Path = $localPath; Error = $null }
193
+ $null = $Text
194
+ $errors = [System.Collections.Generic.List[string]]::new()
195
+ Add-DiscoveryCompatibilityError -ErrorList $errors -ArtifactType 'profile' -PowerShellVersion $PowerShellVersion
196
+ return , $errors.ToArray()
301
197
  }
302
198
 
303
199
  function Get-DiscoverySchemaArtifactValidationError {
304
200
  <#
305
201
  .SYNOPSIS
306
- Validates a schema-governed discovery artifact against its declared `$schema`,
307
- mirroring `_validate_against_schema` in `validate_discovery_schema_artifacts.py`.
308
- .DESCRIPTION
309
- Order of checks, matching the reference: JSON parse, object-root check,
310
- `$schema` extraction and resolution, then Draft 2020-12 schema validation via
311
- `Test-Json -SchemaFile`.
312
- .OUTPUTS
313
- [object[]] Zero or more error strings; empty when the artifact conforms.
202
+ Returns the version-floor error below PowerShell 7.4, otherwise the validation-required message for a schema-governed artifact.
314
203
  #>
315
204
  [CmdletBinding()]
316
205
  [OutputType([object[]])]
317
206
  param(
318
- [Parameter(Mandatory = $true)]
319
- [AllowEmptyString()]
320
- [string]$Text,
321
-
322
- [Parameter(Mandatory = $false)]
323
- [version]$PowerShellVersion = $PSVersionTable.PSVersion
207
+ [Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text,
208
+ [Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$ArtifactType = $null,
209
+ [Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion
324
210
  )
325
211
 
212
+ $null = $Text
326
213
  $errors = [System.Collections.Generic.List[string]]::new()
327
-
328
- # Fail closed before any schema work: on an unsupported host `Test-Json -SchemaFile`
329
- # would otherwise fail with an opaque parameter error.
330
- $versionError = Get-DiscoveryRuntimeVersionError -PowerShellVersion $PowerShellVersion
331
- if ($null -ne $versionError) {
332
- $errors.Add($versionError)
333
- return , $errors.ToArray()
334
- }
335
-
336
- $parsed = $null
337
- try {
338
- $parsed = ConvertFrom-Json -InputObject $Text -Depth 100 -ErrorAction Stop
339
- }
340
- catch {
341
- $errors.Add("invalid JSON ($($_.Exception.Message))")
342
- return , $errors.ToArray()
343
- }
344
-
345
- if ($parsed -isnot [System.Management.Automation.PSCustomObject]) {
346
- $errors.Add('JSON root must be an object for validation')
347
- return , $errors.ToArray()
348
- }
349
-
350
- $schemaProperty = $parsed.PSObject.Properties['$schema']
351
- $schemaUri = if ($null -eq $schemaProperty) { $null } else { $schemaProperty.Value }
352
-
353
- $resolution = Resolve-DiscoverySchemaFilePath -SchemaUri $schemaUri
354
- if ($null -ne $resolution.Error) {
355
- $errors.Add([string]$resolution.Error)
356
- return , $errors.ToArray()
357
- }
358
-
359
- # Test-Json emits one non-terminating error per schema violation; collect them
360
- # all rather than stopping at the first, matching the reference's behavior.
361
- $schemaErrors = $null
362
- $isValid = Test-Json -Json $Text -SchemaFile ([string]$resolution.Path) `
363
- -ErrorAction SilentlyContinue -ErrorVariable schemaErrors
364
- if (-not $isValid) {
365
- foreach ($schemaError in @($schemaErrors)) {
366
- $errors.Add([string]$schemaError.Exception.Message)
367
- }
368
- # Guarantee a non-empty result so a failure is never reported as a pass.
369
- if ($errors.Count -eq 0) {
370
- $errors.Add('JSON is not valid with the schema')
371
- }
372
- }
373
-
214
+ Add-DiscoveryCompatibilityError -ErrorList $errors -ArtifactType $ArtifactType -PowerShellVersion $PowerShellVersion
374
215
  return , $errors.ToArray()
375
216
  }
376
217
 
377
218
  function Get-DiscoveryArtifactValidationError {
378
219
  <#
379
220
  .SYNOPSIS
380
- Validates artifact text of any supported type, dispatching on the type token.
221
+ Returns the compatibility error list for an artifact: the floor, an unrecognized type, and always the validation-required message.
381
222
  .DESCRIPTION
382
- Dispatches `profile` to the placeholder-contract check and each of the seven
383
- schema-governed types to the `$schema`-driven check. An unrecognized token is
384
- reported rather than silently accepted.
385
- .OUTPUTS
386
- [object[]] Zero or more error strings; empty when the artifact conforms.
223
+ The list is never empty. The version floor is reported alone when the host is
224
+ below it; otherwise an unrecognized artifact type is reported before the
225
+ validation-required message so the caller sees both defects.
387
226
  #>
388
227
  [CmdletBinding()]
389
228
  [OutputType([object[]])]
390
229
  param(
391
- [Parameter(Mandatory = $true)]
392
- [AllowEmptyString()]
393
- [string]$ArtifactType,
394
-
395
- [Parameter(Mandatory = $true)]
396
- [AllowEmptyString()]
397
- [string]$Text,
398
-
399
- [Parameter(Mandatory = $false)]
400
- [version]$PowerShellVersion = $PSVersionTable.PSVersion
230
+ [Parameter(Mandatory = $true)][AllowEmptyString()][string]$ArtifactType,
231
+ [Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text,
232
+ [Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion
401
233
  )
402
234
 
403
- # Assign before returning, never `@(Get-...)`. These helpers emit their array as
404
- # a SINGLE object (the unary-comma no-enumerate idiom), so wrapping the call in
405
- # `@()` collects that one object into a nested one-element array.
406
- if ($ArtifactType -ieq 'profile') {
407
- $profileErrors = Get-DiscoveryProfileValidationError -Text $Text -PowerShellVersion $PowerShellVersion
408
- return , $profileErrors
409
- }
410
-
411
- if ($script:DiscoverySchemaArtifactFile.Contains($ArtifactType)) {
412
- $schemaErrors = Get-DiscoverySchemaArtifactValidationError -Text $Text -PowerShellVersion $PowerShellVersion
413
- return , $schemaErrors
414
- }
415
-
416
- return , @("Unsupported artifact type: $ArtifactType")
235
+ $null = $Text
236
+ $unrecognized = ($ArtifactType -ne 'profile' -and $null -eq (Get-DiscoverySchemaFileName -ArtifactType $ArtifactType))
237
+ $errors = [System.Collections.Generic.List[string]]::new()
238
+ Add-DiscoveryCompatibilityError -ErrorList $errors -ArtifactType $ArtifactType -PowerShellVersion $PowerShellVersion -ReportUnrecognizedType:$unrecognized
239
+ return , $errors.ToArray()
417
240
  }
418
241
 
419
242
  function ConvertTo-DiscoveryValidationResult {
@@ -421,69 +244,91 @@ function ConvertTo-DiscoveryValidationResult {
421
244
  .SYNOPSIS
422
245
  Shapes an error list into the hook seam's `@{ ExitCode; Output }` result.
423
246
  .DESCRIPTION
424
- The defect D-2 contract in one place: an EMPTY error list yields `ExitCode = 0`
425
- with an EMPTY `Output`. Both hooks deny on a non-zero exit code OR on non-empty
426
- output, so success chatter here would turn a passing validation into a deny.
427
- Kept separate from the on-disk entry point so the contract is unit-testable
428
- without touching the filesystem.
429
- .OUTPUTS
430
- [hashtable] `@{ ExitCode = <int>; Output = <string> }`.
247
+ The defect D-2 contract in one place: an empty list yields `ExitCode = 0` with
248
+ empty `Output`. No entry of this module produces an empty list any more; the
249
+ shape is kept for callers that assemble their own lists.
431
250
  #>
432
251
  [CmdletBinding()]
433
252
  [OutputType([hashtable])]
434
- param(
435
- [Parameter(Mandatory = $true)]
436
- [AllowEmptyCollection()]
437
- [string[]]$ValidationError
438
- )
253
+ param([Parameter(Mandatory = $true)][AllowEmptyCollection()][string[]]$ValidationError)
439
254
 
440
- if (@($ValidationError).Count -eq 0) {
441
- return @{ ExitCode = 0; Output = '' }
442
- }
255
+ if (@($ValidationError).Count -eq 0) { return @{ ExitCode = 0; Output = '' } }
443
256
  return @{ ExitCode = 1; Output = ($ValidationError -join [System.Environment]::NewLine) }
444
257
  }
445
258
 
446
259
  function Invoke-DiscoveryArtifactValidation {
447
260
  <#
448
261
  .SYNOPSIS
449
- Validates a discovery artifact on disk and returns the hook seam's result shape.
262
+ Compatibility entry of the retired validator: reports the floor, a missing artifact or the validation-required result, never a pass.
450
263
  .DESCRIPTION
451
- The entry point both discovery hooks call from `Invoke-DiscoveryValidatorExe`.
452
- `ValidatorArgs` keeps the CLI-style shape the seam already passed:
453
- `@(<artifact-type>, <path>)`. Success returns `ExitCode = 0` with EMPTY
454
- `Output` (defect D-2 avoidance); see `ConvertTo-DiscoveryValidationResult`.
455
- .OUTPUTS
456
- [hashtable] `@{ ExitCode = <int>; Output = <string> }`.
264
+ `ValidatorArgs` keeps the CLI shape `@(<artifact-type>, <path>)`. The result
265
+ always carries `ExitCode = 1`: the version floor first, then too few
266
+ arguments, then a missing artifact file (actionable), then the
267
+ validation-required message naming the authoritative service.
457
268
  #>
458
269
  [CmdletBinding()]
459
270
  [OutputType([hashtable])]
460
271
  param(
461
- [Parameter(Mandatory = $true)]
462
- [string[]]$ValidatorArgs,
463
-
464
- [Parameter(Mandatory = $false)]
465
- [version]$PowerShellVersion = $PSVersionTable.PSVersion
272
+ [Parameter(Mandatory = $true)][AllowEmptyCollection()][string[]]$ValidatorArgs,
273
+ [Parameter(Mandatory = $false)][version]$PowerShellVersion = $PSVersionTable.PSVersion,
274
+ [Parameter(Mandatory = $false)][scriptblock]$TestArtifactPath = { param([string]$Candidate) Test-Path -LiteralPath $Candidate -PathType Leaf }
466
275
  )
467
276
 
277
+ $floor = Get-DiscoveryRuntimeVersionError -PowerShellVersion $PowerShellVersion
278
+ if ($null -ne $floor) { return ConvertTo-DiscoveryValidationResult -ValidationError @($floor) }
468
279
  if (@($ValidatorArgs).Count -lt 2) {
469
- return @{ ExitCode = 1; Output = 'Discovery validation requires an artifact type and a path.' }
280
+ return ConvertTo-DiscoveryValidationResult -ValidationError @('Discovery validation requires an artifact type and a path.')
470
281
  }
471
-
472
282
  $artifactType = [string]$ValidatorArgs[0]
473
283
  $path = [string]$ValidatorArgs[1]
474
-
475
- if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
476
- return @{ ExitCode = 1; Output = "Artifact not found: $path" }
284
+ if (-not (& $TestArtifactPath $path)) {
285
+ return ConvertTo-DiscoveryValidationResult -ValidationError @("Artifact not found: $path")
477
286
  }
287
+ return ConvertTo-DiscoveryValidationResult -ValidationError @((Get-DiscoveryValidationRequiredMessage -ArtifactType $artifactType -Path $path))
288
+ }
478
289
 
479
- $text = Get-Content -LiteralPath $path -Raw -ErrorAction Stop
480
- if ($null -eq $text) {
481
- $text = ''
482
- }
290
+ function Get-DiscoveryValidationAuthority {
291
+ <#
292
+ .SYNOPSIS
293
+ Reports the only authority a native hook consults: the protected activation of the workspace on a supported host.
294
+ .DESCRIPTION
295
+ Status is `active`, `missing`, `inactive`, `invalid` or `unsupported-host`;
296
+ Supported is true only for `active`. The message is actionable in every case
297
+ and names the authoritative service. No artifact is read.
298
+ .OUTPUTS
299
+ [pscustomobject] Status, Supported, Message, Service, Directory.
300
+ #>
301
+ [CmdletBinding()]
302
+ [OutputType([pscustomobject])]
303
+ param(
304
+ [Parameter(Mandatory = $true)][string]$WorkspaceRoot,
305
+ [Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
306
+ [Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadText = $null
307
+ )
483
308
 
484
- $errors = Get-DiscoveryArtifactValidationError -ArtifactType $artifactType -Text $text `
485
- -PowerShellVersion $PowerShellVersion
486
- return ConvertTo-DiscoveryValidationResult -ValidationError $errors
309
+ try {
310
+ if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
311
+ $location = Resolve-DiscoveryAuthorityLocation -WorkspaceRoot $WorkspaceRoot -Platform $HostEnvironment.Platform `
312
+ -UserHome $HostEnvironment.UserHome -LocalAppData $HostEnvironment.LocalAppData -XdgStateHome $HostEnvironment.XdgStateHome
313
+ } catch {
314
+ return [pscustomobject]@{ Status = 'unsupported-host'; Supported = $false; Service = $script:ServiceOperation; Directory = $null; Message = "$($script:ValidationRequiredPrefix) this host cannot resolve the protected discovery authority ($($_.Exception.Message)); discovery agents are fail-closed here and no artifact can be validated locally." }
315
+ }
316
+ $parameters = @{ Location = $location }
317
+ if ($null -ne $ReadText) { $parameters['ReadText'] = $ReadText }
318
+ $activation = Read-DiscoveryActivationState @parameters
319
+ $message = switch ($activation.Status) {
320
+ 'active' { "the workspace holds an active protected activation; run $($script:ServiceOperation) through the installed service to validate artifacts and let the native hooks verify the protected receipt." }
321
+ 'missing' { "no protected activation exists for this workspace; initialize or configure discovery through the installed service before any artifact gate can pass." }
322
+ 'inactive' { 'discovery was deliberately deactivated for this workspace; only a root-owned activation can restore artifact gates.' }
323
+ default { "the protected activation record is unreadable ($($activation.Reason)); the gate fails closed until the service rewrites it." }
324
+ }
325
+ return [pscustomobject]@{
326
+ Status = $activation.Status
327
+ Supported = ($activation.Status -eq 'active')
328
+ Service = $script:ServiceOperation
329
+ Directory = $location.Directory
330
+ Message = "$($script:ValidationRequiredPrefix) $message"
331
+ }
487
332
  }
488
333
 
489
334
  Export-ModuleMember -Function @(
@@ -496,5 +341,7 @@ Export-ModuleMember -Function @(
496
341
  'Get-DiscoverySchemaArtifactValidationError',
497
342
  'Get-DiscoveryArtifactValidationError',
498
343
  'ConvertTo-DiscoveryValidationResult',
499
- 'Invoke-DiscoveryArtifactValidation'
344
+ 'Invoke-DiscoveryArtifactValidation',
345
+ 'Get-DiscoveryValidationRequiredMessage',
346
+ 'Get-DiscoveryValidationAuthority'
500
347
  )