@danmoisan/drm-copilot-mcp 0.0.1 → 0.0.6

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 (183) hide show
  1. package/out/mcp-server.js +98 -21
  2. package/package.json +21 -5
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +15 -3
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_branch_base_check_unmerged_pr_deps.md +16 -0
  5. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_every_change_through_lifecycle.md +15 -0
  6. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_policy_compliance_not_optional.md +18 -0
  7. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_potential_to_issue_creates_github_issue.md +13 -0
  8. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_remediation_plan_em_dash_required.md +13 -0
  9. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_small_bug_uses_minor_audit.md +13 -0
  10. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +13 -0
  11. package/resources/claude-customizations/.claude/agents/atomic-executor.md +7 -7
  12. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +4 -5
  13. package/resources/claude-customizations/.claude/agents/feature-review.md +7 -3
  14. package/resources/claude-customizations/.claude/agents/orchestrator.md +22 -3
  15. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/agents/pr-author.md +78 -0
  17. package/resources/claude-customizations/.claude/agents/task-researcher.md +10 -6
  18. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +303 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +300 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +40 -14
  21. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +148 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +210 -0
  23. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +333 -0
  24. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +216 -0
  25. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +84 -15
  26. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +1 -1
  27. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +75 -5
  28. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +93 -0
  29. package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +136 -0
  30. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +90 -6
  31. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +46 -0
  32. package/resources/claude-customizations/.claude/rules/benchmark-baselines.md +35 -0
  33. package/resources/claude-customizations/.claude/rules/ci-workflows.md +36 -0
  34. package/resources/claude-customizations/.claude/rules/csharp.md +62 -16
  35. package/resources/claude-customizations/.claude/rules/general-code-change.md +12 -3
  36. package/resources/claude-customizations/.claude/rules/general-unit-test.md +47 -2
  37. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +39 -0
  38. package/resources/claude-customizations/.claude/rules/powershell.md +5 -5
  39. package/resources/claude-customizations/.claude/rules/python.md +4 -3
  40. package/resources/claude-customizations/.claude/rules/quality-tiers.md +51 -0
  41. package/resources/claude-customizations/.claude/rules/typescript.md +37 -8
  42. package/resources/claude-customizations/.claude/settings.json +59 -12
  43. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -2
  44. package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +25 -10
  45. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +0 -1
  46. package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +6 -6
  47. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +8 -8
  48. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +17 -6
  49. package/resources/claude-customizations/.claude/skills/human-exception-runbook/SKILL.md +52 -0
  50. package/resources/claude-customizations/.claude/skills/human-exception-runbook/example.runbook.md +36 -0
  51. package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -4
  52. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +172 -5
  53. package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +3 -3
  54. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +4 -4
  55. package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +3 -3
  56. package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +1 -1
  57. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +90 -17
  58. package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +5 -3
  59. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +69 -0
  60. package/resources/claude-customizations/.claude-variants/csharp-legacy/rules/csharp.md +96 -0
  61. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +77 -0
  62. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +64 -0
  63. package/resources/claude-customizations/pack-manifests/core.json +65 -0
  64. package/resources/claude-customizations/pack-manifests/csharp-legacy.json +11 -0
  65. package/resources/claude-customizations/pack-manifests/csharp-modern.json +12 -0
  66. package/resources/claude-customizations/pack-manifests/powershell.json +14 -0
  67. package/resources/claude-customizations/pack-manifests/python.json +14 -0
  68. package/resources/claude-customizations/pack-manifests/typescript.json +9 -0
  69. package/resources/claude-dir-customizations/.mcp.json +3 -3
  70. package/resources/codex-and-agents-customizations/.agents/README.md +1 -1
  71. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +0 -5
  72. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +52 -0
  73. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +16 -8
  74. package/resources/codex-and-agents-customizations/.agents/skills/benchmark-baselines/SKILL.md +44 -0
  75. package/resources/codex-and-agents-customizations/.agents/skills/ci-workflows/SKILL.md +45 -0
  76. package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +3 -11
  77. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +1 -5
  78. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -6
  79. package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +0 -5
  80. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +0 -5
  81. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +0 -5
  82. package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +8 -17
  83. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +41 -25
  84. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +1 -6
  85. package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +0 -5
  86. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +86 -0
  87. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +111 -0
  88. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/SKILL.md +57 -0
  89. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/example.runbook.md +36 -0
  90. package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +0 -9
  91. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -9
  92. package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +0 -9
  93. package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +0 -5
  94. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +206 -18
  95. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +48 -0
  96. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +94 -10
  97. package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +3 -8
  98. package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +0 -10
  99. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +4 -8
  100. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -6
  101. package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +0 -5
  102. package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +3 -9
  103. package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +1 -9
  104. package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +4 -9
  105. package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +0 -5
  106. package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +1 -5
  107. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -6
  108. package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +0 -5
  109. package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +2 -6
  110. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +57 -0
  111. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +0 -5
  112. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +96 -72
  113. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +1 -1
  114. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +0 -10
  115. package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +0 -5
  116. package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +0 -5
  117. package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +0 -5
  118. package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +2 -6
  119. package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +0 -5
  120. package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +86 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +297 -0
  122. package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +0 -22
  123. package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +1 -5
  124. package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +2 -6
  125. package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +0 -5
  126. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +5 -5
  127. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +91 -63
  128. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +1 -1
  129. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  130. package/resources/codex-and-agents-customizations/.codex/config.toml +111 -137
  131. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +303 -0
  132. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +300 -0
  133. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +148 -0
  134. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-pr-author-skill.ps1 +336 -0
  135. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +84 -18
  136. package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +4 -3
  137. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +5 -0
  138. package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +68 -0
  139. package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +15 -0
  140. package/resources/config/orchestration-routing.json +76 -0
  141. package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +1 -1
  142. package/resources/customizations/.github/agents/atomic_executor.agent.md +1 -1
  143. package/resources/customizations/.github/agents/atomic_planning.agent.md +10 -10
  144. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +6 -2
  145. package/resources/customizations/.github/agents/feature-review.agent.md +2 -2
  146. package/resources/customizations/.github/agents/orchestrator.agent.md +6 -2
  147. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +4 -4
  148. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +10 -10
  149. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -2
  150. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +2 -2
  151. package/resources/customizations/.github/agents/pr-author.agent.md +25 -0
  152. package/resources/customizations/.github/agents/python-orchestrator.agent.md +6 -2
  153. package/resources/customizations/.github/agents/staged-review.agent.md +1 -1
  154. package/resources/customizations/.github/agents/task-researcher.agent.md +4 -4
  155. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +6 -6
  156. package/resources/customizations/.github/prompts/fillout-prd-feature.prompt.md +1 -1
  157. package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +1 -1
  158. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +5 -3
  159. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +5 -3
  160. package/resources/customizations/.github/prompts/research-issue.prompt.md +4 -3
  161. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +14 -1
  162. package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +11 -7
  163. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +10 -1
  164. package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +2 -2
  165. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +5 -0
  166. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +7 -0
  167. package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +127 -0
  168. package/resources/scripts/dev_tools/_orchestrator_state_routing.py +216 -0
  169. package/resources/scripts/dev_tools/push_down_claude_customizations.py +276 -61
  170. package/resources/scripts/dev_tools/push_down_claude_filesystem.py +472 -0
  171. package/resources/scripts/dev_tools/push_down_claude_pack_selection.py +401 -0
  172. package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +103 -411
  173. package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +107 -0
  174. package/resources/scripts/dev_tools/validate_orchestrator_state.py +505 -0
  175. package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +472 -0
  176. package/resources/templates/push_down_claude_customizations.py +162 -117
  177. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +0 -11
  178. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +0 -19
  179. package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +0 -11
  180. package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +0 -1
  181. package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +0 -13
  182. package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +0 -3
  183. package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +0 -11
@@ -0,0 +1,136 @@
1
+ <#
2
+ .SYNOPSIS
3
+ SubagentStop hook that verifies the pr-author agent reported a created or updated PR.
4
+
5
+ .DESCRIPTION
6
+ Invoked by the Claude Code SubagentStop hook for the pr-author matcher. Reads the agent
7
+ transcript JSON from the CLAUDE_HOOK_INPUT environment variable, extracts the .output field,
8
+ and confirms the output reports that a pull request was created or updated. The hook allows
9
+ (exit 0) when the output contains:
10
+ - a GitHub PR URL (github.com/<owner>/<repo>/pull/<n>), or
11
+ - a PR reference of the form "PR #<n>", or
12
+ - a "gh pr create"/"gh pr edit" confirmation that includes a PR number.
13
+ The hook blocks (exit 1) when:
14
+ - CLAUDE_HOOK_INPUT is empty,
15
+ - the input is not valid JSON,
16
+ - the .output field is empty, or
17
+ - the output contains no PR URL or PR number.
18
+
19
+ .NOTES
20
+ Compatible with PowerShell 7+. No external module dependencies.
21
+
22
+ Enforcement strength: this validator is a policy guardrail, not a cryptographic or security
23
+ control. It confirms that the pr-author agent's final output references a PR; it cannot verify
24
+ that the referenced PR actually exists on GitHub, and the output text is forgeable by any actor
25
+ that controls the agent transcript. It MUST NOT be described as tamper-proof or as a security
26
+ boundary.
27
+ #>
28
+ [CmdletBinding()]
29
+ param()
30
+
31
+ function Test-PrAuthorOutputReportsPr {
32
+ <#
33
+ .SYNOPSIS
34
+ Return $true when the supplied output text reports a created or updated PR.
35
+ .DESCRIPTION
36
+ Detection helper (injectable boundary for tests). Matches a GitHub PR URL, a "PR #<n>"
37
+ reference, or a "gh pr create"/"gh pr edit" confirmation that contains a PR number.
38
+ .PARAMETER OutputText
39
+ The pr-author agent's final output text extracted from CLAUDE_HOOK_INPUT.output.
40
+ .OUTPUTS
41
+ System.Boolean
42
+ #>
43
+ [CmdletBinding()]
44
+ [OutputType([bool])]
45
+ param(
46
+ [string] $OutputText
47
+ )
48
+
49
+ if ([string]::IsNullOrWhiteSpace($OutputText)) {
50
+ return $false
51
+ }
52
+
53
+ # GitHub PR URL, e.g. https://github.com/owner/repo/pull/123
54
+ if ($OutputText -match '(?i)github\.com/[^\s/]+/[^\s/]+/pull/\d+') {
55
+ return $true
56
+ }
57
+
58
+ # Explicit PR number reference, e.g. "PR #123".
59
+ if ($OutputText -match '(?i)\bPR\s*#\d+') {
60
+ return $true
61
+ }
62
+
63
+ # gh pr create / gh pr edit confirmation that includes a PR number anywhere in the output.
64
+ if (($OutputText -match '(?i)\bgh\s+pr\s+(create|edit)\b') -and ($OutputText -match '#\d+')) {
65
+ return $true
66
+ }
67
+
68
+ return $false
69
+ }
70
+
71
+ function Get-PrAuthorOutputDecision {
72
+ <#
73
+ .SYNOPSIS
74
+ Parse CLAUDE_HOOK_INPUT and return an allow-or-block decision with exit code semantics.
75
+ .DESCRIPTION
76
+ Returns an ordered dictionary with 'allowed' (bool) and 'reason' (string). Allowed is $true
77
+ only when the parsed .output reports a PR per Test-PrAuthorOutputReportsPr. Empty input,
78
+ malformed JSON, empty output, and PR-less output all yield allowed = $false.
79
+ .PARAMETER HookInputRaw
80
+ The raw JSON transcript payload supplied by Claude Code via CLAUDE_HOOK_INPUT.
81
+ .OUTPUTS
82
+ System.Collections.Specialized.OrderedDictionary
83
+ #>
84
+ [CmdletBinding()]
85
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
86
+ param(
87
+ [string] $HookInputRaw
88
+ )
89
+
90
+ if ([string]::IsNullOrWhiteSpace($HookInputRaw)) {
91
+ return [ordered]@{
92
+ allowed = $false
93
+ reason = 'PR_AUTHOR_OUTPUT_MISSING: CLAUDE_HOOK_INPUT is empty; the pr-author agent produced no transcript to validate.'
94
+ }
95
+ }
96
+
97
+ try {
98
+ $parsed = $HookInputRaw | ConvertFrom-Json -ErrorAction Stop
99
+ } catch {
100
+ return [ordered]@{
101
+ allowed = $false
102
+ reason = 'PR_AUTHOR_OUTPUT_MALFORMED: CLAUDE_HOOK_INPUT is not valid JSON.'
103
+ }
104
+ }
105
+
106
+ $outputText = [string]$parsed.output
107
+ if ([string]::IsNullOrWhiteSpace($outputText)) {
108
+ return [ordered]@{
109
+ allowed = $false
110
+ reason = 'PR_AUTHOR_OUTPUT_EMPTY: the pr-author agent output is empty; it must report the created or updated PR URL or number.'
111
+ }
112
+ }
113
+
114
+ if (Test-PrAuthorOutputReportsPr -OutputText $outputText) {
115
+ return [ordered]@{ allowed = $true }
116
+ }
117
+
118
+ return [ordered]@{
119
+ allowed = $false
120
+ reason = 'PR_AUTHOR_OUTPUT_NO_PR: the pr-author agent output does not reference a PR URL or PR number; it must report the created or updated pull request.'
121
+ }
122
+ }
123
+
124
+ # Allow dot-sourcing in tests without executing the entrypoint.
125
+ if ($MyInvocation.InvocationName -eq '.') {
126
+ return
127
+ }
128
+
129
+ $decision = Get-PrAuthorOutputDecision -HookInputRaw $env:CLAUDE_HOOK_INPUT
130
+
131
+ if (-not $decision['allowed']) {
132
+ Write-Error $decision['reason']
133
+ exit 1
134
+ }
135
+
136
+ exit 0
@@ -5,8 +5,10 @@
5
5
  .DESCRIPTION
6
6
  Blocks termination of the task-researcher subagent unless the agent's
7
7
  final output advertises a `research-path` token, the path is rooted
8
- under artifacts/research/, matches the documented filename convention,
9
- and the file exists on disk.
8
+ under one of the two tracked research roots
9
+ (docs/features/<feature>/research/ for feature-associated research, or
10
+ docs/research/ for one-off research), matches the documented filename
11
+ convention, and the file exists on disk.
10
12
 
11
13
  .NOTES
12
14
  Reads the hook payload from CLAUDE_HOOK_INPUT as JSON. Exits 0 to allow
@@ -64,7 +66,20 @@ function Test-IsUnderResearchRoot {
64
66
  )
65
67
 
66
68
  $normalized = $Path -replace '\\', '/'
67
- return $normalized.StartsWith('artifacts/research/', [System.StringComparison]::OrdinalIgnoreCase)
69
+
70
+ # Accept either of the two tracked research roots:
71
+ # - feature-associated research: docs/features/<...>/research/<file>
72
+ # (a feature-folder path that contains a /research/ segment), or
73
+ # - one-off research: docs/research/<file>.
74
+ # The /research/ segment requirement distinguishes feature research from
75
+ # other files under docs/features/ (for example spec.md or plan files).
76
+ $isFeatureResearch =
77
+ $normalized.StartsWith('docs/features/', [System.StringComparison]::OrdinalIgnoreCase) -and
78
+ $normalized.IndexOf('/research/', [System.StringComparison]::OrdinalIgnoreCase) -ge 0
79
+ $isOneOffResearch =
80
+ $normalized.StartsWith('docs/research/', [System.StringComparison]::OrdinalIgnoreCase)
81
+
82
+ return ($isFeatureResearch -or $isOneOffResearch)
68
83
  }
69
84
 
70
85
  function Test-IsValidResearchFileName {
@@ -83,6 +98,69 @@ function Test-IsValidResearchFileName {
83
98
  )
84
99
  }
85
100
 
101
+ function Test-AutomationFeasibilitySection {
102
+ <#
103
+ .SYNOPSIS
104
+ Enforces the '## Automation Feasibility' section for applicable
105
+ autonomous-execution research artifacts.
106
+ .DESCRIPTION
107
+ Returns a hashtable with keys:
108
+ - Ok: $true when the artifact is not applicable, or it is
109
+ applicable and contains the '## Automation Feasibility'
110
+ section.
111
+ - Message: rejection message; $null on success.
112
+
113
+ Detection is narrow (OD-45-7): the section is required only when the
114
+ research filename or the agent output contains an autonomous-execution
115
+ token (for example 'autonomous-execution' or 'human-interaction').
116
+ Non-matching research artifacts pass unaffected.
117
+
118
+ ReadFileContent is an injectable scriptblock so tests can supply the
119
+ research file body without writing temporary files. It defaults to
120
+ Get-Content -Raw.
121
+ #>
122
+ [CmdletBinding()]
123
+ [OutputType([hashtable])]
124
+ param(
125
+ [Parameter(Mandatory = $true)]
126
+ [string] $ResearchFilePath,
127
+
128
+ [Parameter(Mandatory = $true)]
129
+ [AllowEmptyString()]
130
+ [string] $AgentOutput,
131
+
132
+ [Parameter(Mandatory = $false)]
133
+ [scriptblock] $ReadFileContent = { param($Path) Get-Content -LiteralPath $Path -Raw -ErrorAction Stop }
134
+ )
135
+
136
+ $detectionPattern = 'autonomous-execution|human-interaction'
137
+ $fileName = [System.IO.Path]::GetFileName(($ResearchFilePath -replace '\\', '/'))
138
+
139
+ $isApplicable = ([regex]::IsMatch($fileName, $detectionPattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)) -or
140
+ ([regex]::IsMatch($AgentOutput, $detectionPattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase))
141
+
142
+ if (-not $isApplicable) {
143
+ return @{ Ok = $true; Message = $null }
144
+ }
145
+
146
+ $content = & $ReadFileContent $ResearchFilePath
147
+ if ([string]::IsNullOrWhiteSpace($content)) {
148
+ return @{ Ok = $false; Message = "task-researcher hook: autonomous-execution research artifact '$ResearchFilePath' is empty; it must include an '## Automation Feasibility' section." }
149
+ }
150
+
151
+ $hasSection = [regex]::IsMatch(
152
+ $content,
153
+ '(?m)^\s{0,3}#{2,}\s+Automation\s+Feasibility\s*$',
154
+ [System.Text.RegularExpressions.RegexOptions]::IgnoreCase
155
+ )
156
+
157
+ if (-not $hasSection) {
158
+ return @{ Ok = $false; Message = "task-researcher hook: autonomous-execution research artifact '$ResearchFilePath' is missing the required '## Automation Feasibility' section." }
159
+ }
160
+
161
+ return @{ Ok = $true; Message = $null }
162
+ }
163
+
86
164
  function Invoke-TaskResearcherOutputValidation {
87
165
  [CmdletBinding()]
88
166
  [OutputType([hashtable])]
@@ -111,21 +189,26 @@ function Invoke-TaskResearcherOutputValidation {
111
189
 
112
190
  $researchPath = Get-ResearchPathFromOutput -AgentOutput $agentOutput
113
191
  if ($null -eq $researchPath) {
114
- return @{ Ok = $false; Message = 'task-researcher hook: agent output does not advertise a research-path. Researcher must report `research-path: <path>` pointing to artifacts/research/.' }
192
+ return @{ Ok = $false; Message = 'task-researcher hook: agent output does not advertise a research-path. Researcher must report `research-path: <path>` pointing to docs/features/<feature>/research/ (feature-associated) or docs/research/ (one-off).' }
115
193
  }
116
194
 
117
195
  if (-not (Test-IsUnderResearchRoot -Path $researchPath)) {
118
- return @{ Ok = $false; Message = "task-researcher hook: research-path '$researchPath' is not under artifacts/research/. All research artifacts must be written to artifacts/research/." }
196
+ return @{ Ok = $false; Message = "task-researcher hook: research-path '$researchPath' is not under a tracked research root. All research artifacts must be written to docs/features/<feature>/research/ (feature-associated) or docs/research/ (one-off)." }
119
197
  }
120
198
 
121
199
  if (-not (Test-IsValidResearchFileName -Path $researchPath)) {
122
- return @{ Ok = $false; Message = "task-researcher hook: research-path '$researchPath' does not match the required filename convention `artifacts/research/<timestamp>-<short-name>-research.md`." }
200
+ return @{ Ok = $false; Message = "task-researcher hook: research-path '$researchPath' does not match the required filename convention `<timestamp>-<short-name>-research.md` under docs/features/<feature>/research/ or docs/research/." }
123
201
  }
124
202
 
125
203
  if (-not (Test-ResearchFile -Path $researchPath)) {
126
204
  return @{ Ok = $false; Message = "task-researcher hook: researcher advertised research-path '$researchPath' but no file exists at that location." }
127
205
  }
128
206
 
207
+ $feasibilityResult = Test-AutomationFeasibilitySection -ResearchFilePath $researchPath -AgentOutput $agentOutput
208
+ if (-not $feasibilityResult.Ok) {
209
+ return @{ Ok = $false; Message = $feasibilityResult.Message }
210
+ }
211
+
129
212
  return @{ Ok = $true; Message = $null }
130
213
  }
131
214
 
@@ -140,3 +223,4 @@ if (-not $result.Ok) {
140
223
  }
141
224
 
142
225
  exit 0
226
+
@@ -0,0 +1,46 @@
1
+ ---
2
+ paths:
3
+ - "**/*.ts"
4
+ - "**/*.cs"
5
+ description: Architecture boundary enforcement rules for the No-COM architecture.
6
+ ---
7
+
8
+ # Architecture Boundaries
9
+
10
+ Architecture boundary enforcement is a uniform gate across all tiers (T1–T4). Violations block PRs.
11
+
12
+ ## Enforcement Tools
13
+
14
+ - **TypeScript:** `dependency-cruiser`. Configuration file pattern: `.dependency-cruiser.cjs`.
15
+ - **.NET (when the backend exists):** `NetArchTest.Rules`. Test project naming pattern: `*.ArchitectureTests`.
16
+
17
+ ## No-COM Architecture Rules (enforceable assertions)
18
+
19
+ Production code in this repository must satisfy each of the following assertions. Each assertion is enforced by `dependency-cruiser` (TypeScript) or `NetArchTest.Rules` (.NET) where applicable; legacy import utilities, when added, must satisfy the same assertions.
20
+
21
+ 1. New runtime code must not reference VSTO APIs (`Microsoft.Office.Tools.*`).
22
+ 2. New runtime code must not reference Outlook desktop automation APIs (`Microsoft.Office.Interop.Outlook`).
23
+ 3. New runtime code must not expose COM-visible interfaces (`[ComVisible(true)]` attribute is banned in production code).
24
+ 4. New runtime code must not use Ribbon extensibility callbacks tied to the desktop object model.
25
+ 5. New runtime code must not depend on local Outlook event streams.
26
+ 6. New runtime code must not depend on Outlook user-defined fields as the primary state store.
27
+ 7. Mailbox data must be accessed only through Office.js or Microsoft Graph.
28
+ 8. Business behavior must be implemented in the backend or in host-neutral domain or application modules.
29
+ 9. Client UI must be implemented as web UI.
30
+ 10. Legacy integration, when required, must be limited to offline data import from files or exported data.
31
+
32
+ ## Layer Boundary Assertions (TypeScript)
33
+
34
+ - `src/taskpane/` and `src/commands/` must not import from backend internals.
35
+ - Domain modules must not import from Office.js, Microsoft Graph SDK, or any infrastructure adapter.
36
+ - Adapters may import from domain; domain must not import from adapters.
37
+
38
+ ## Layer Boundary Assertions (.NET, applies once the backend exists)
39
+
40
+ - `TaskMaster.Domain` must have zero references to Outlook PIA, VSTO, or Office.js types.
41
+ - `TaskMaster.Application` may depend on `TaskMaster.Domain` only.
42
+ - Adapter projects may depend on `TaskMaster.Domain` and `TaskMaster.Application`; domain may not depend on adapters.
43
+
44
+ ## Enforcement Outcome
45
+
46
+ Violations of any rule above are PR-blocking findings. CI runs the architecture-boundary stage on every PR; a non-zero violation count fails the stage and prevents merge.
@@ -0,0 +1,35 @@
1
+ # Benchmark Baseline Provenance
2
+
3
+ This rule governs performance baselines used by benchmark regression gates. It exists because a baseline captured on a developer workstation was compared against a `windows-latest` runner, producing deterministic latency regressions that the benchmark gate could not survive (issue #26, PR #30).
4
+
5
+ ## Runner-Environment Parity (Required)
6
+
7
+ Performance baselines must be captured in the same runner environment class against which they are compared. A baseline captured on a developer workstation must not be committed for comparison against a CI runner.
8
+
9
+ ## Prohibited: Unknown Processor
10
+
11
+ A baseline whose `HostEnvironmentInfo.ProcessorName` is the literal string `"Unknown processor"` is rejected. This value indicates the baseline was captured in an environment where the processor could not be identified (typically a virtualized or developer workstation), which violates runner-environment parity.
12
+
13
+ - Tooling MUST reject any baseline JSON where `HostEnvironmentInfo.ProcessorName == "Unknown processor"`.
14
+ - The rejection is a Blocking finding; the baseline must be recaptured on the target runner class.
15
+
16
+ ## Required: Sibling Provenance File
17
+
18
+ Every committed baseline file MUST have a sibling `baseline.provenance.json` in the same directory. The provenance file records, at minimum:
19
+
20
+ - `runner_class` — the runner environment class that produced the baseline (for example `windows-latest`).
21
+ - `host_signature` — a stable signature of the host (for example a hashed or labeled description of the CPU/core configuration).
22
+ - `workflow_run_url` — the URL of the workflow run that produced the baseline.
23
+
24
+ - Tooling MUST reject a baseline that has no sibling `baseline.provenance.json`.
25
+ - The rejection is a Blocking finding; the baseline must be recaptured with provenance recorded.
26
+
27
+ ## Enforcement
28
+
29
+ - The validator `scripts/benchmarks/Test-BaselineProvenance.ps1` enforces both rejection conditions above and accepts a runner-captured baseline whose `ProcessorName` is a real processor and whose sibling `baseline.provenance.json` is present.
30
+ - The feature-review policy rule `modified-workflow-needs-green-run` (see `.claude/skills/feature-review-workflow/SKILL.md`) provides a second line of defense: a diff under `scripts/benchmarks/**` is Blocking unless a green workflow run against the branch head is present in remediation inputs.
31
+
32
+ ## Scope
33
+
34
+ - This rule applies to any baseline consumed by a benchmark regression gate.
35
+ - It does not change which checks are required by branch protection; it constrains the provenance of the data those checks consume.
@@ -0,0 +1,36 @@
1
+ # CI Workflow Authoring
2
+
3
+ This rule governs GitHub Actions workflow steps that run PowerShell (`pwsh`). It exists because a `pwsh` step that intentionally invoked a failing nested command left `$LASTEXITCODE == 1` after its verification logic had already succeeded, leaking a failure to GitHub Actions even though the step's intent was satisfied (issue #26, PR #30).
4
+
5
+ ## Deliberately-Failing Nested Command Pattern (Required)
6
+
7
+ A workflow step whose `run:` block intentionally invokes a command expected to fail — for example a negative-path self-validation that asserts a gate catches a synthetic regression — MUST not allow the residual non-zero exit code to propagate to GitHub Actions.
8
+
9
+ For any such step, the `run:` block MUST do one of the following:
10
+
11
+ 1. Reset the exit code explicitly after the expected failure:
12
+ ```powershell
13
+ & ./some-tool --expect-failure
14
+ $LASTEXITCODE = 0
15
+ ```
16
+ 2. Or terminate the success path with an explicit zero exit:
17
+ ```powershell
18
+ if ($verificationSucceeded) { exit 0 } else { exit 1 }
19
+ ```
20
+
21
+ A `pwsh` step terminates with the exit code of the last external command unless the script explicitly resets it or calls `exit`. Negative-path verification steps therefore require an explicit reset or explicit `exit 0`.
22
+
23
+ ## Rationale
24
+
25
+ - GitHub Actions interprets a step's process exit code as the step result. A leaked `$LASTEXITCODE` from an intentionally-failing nested command causes a passing verification to report failure.
26
+ - No local toolchain stage executes a workflow's `run:` block, so this defect is invisible to local feature-review. This textual rule is the artifact local review cites when reading workflow YAML.
27
+
28
+ ## Enforcement
29
+
30
+ - Local feature-review cites this rule when reviewing diffs that add or modify `pwsh` steps with deliberately-failing nested commands.
31
+ - The feature-review policy rule `modified-workflow-needs-green-run` (see `.claude/skills/feature-review-workflow/SKILL.md`) requires a green workflow run against the branch head before a workflow change can merge, which exercises the exit-code path on the runner.
32
+
33
+ ## Scope
34
+
35
+ - This rule applies to any workflow step whose `run:` block uses `shell: pwsh` (or the repo default `pwsh`) and intentionally invokes a failing nested command.
36
+ - It does not change required-check configuration or branch protection.
@@ -2,43 +2,83 @@
2
2
  paths:
3
3
  - "**/*.cs"
4
4
  - "**/*.csproj"
5
- description: C#-specific toolchain and coding standards.
5
+ description: C#-specific toolchain and coding standards (No-COM, xUnit).
6
6
  ---
7
7
 
8
8
  # C# Code Standards
9
9
 
10
- This rule file summarizes the C#-specific policies for this repository.
10
+ This rule file summarizes the C#-specific policies for this repository. It targets the No-COM .NET foundation: xUnit, NSubstitute, FluentAssertions, `dotnet build`, the analyzer stack, `TimeProvider`, and uniform coverage thresholds.
11
11
 
12
12
  ## Toolchain
13
13
 
14
- 1. **Formatting — CSharpier**: All C# source files must be formatted with CSharpier. Do not use `dotnet format`. Command: `dotnet tool run csharpier .` or `csharpier .`
15
- 2. **Linting — .NET Analyzers**: C# code must pass Roslyn/.NET analyzer diagnostics. Command: `msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true`
16
- 3. **Type Checking — Nullable Analysis**: Enable nullable reference types and fail on warnings. Command: `msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:Nullable=enable /p:TreatWarningsAsErrors=true`
17
- 4. **Testing — MSTest + Moq + FluentAssertions**: Run tests with: `vstest.console.exe <test-assembly-paths> /EnableCodeCoverage`
14
+ 1. **Formatting — CSharpier**: All C# source files must be formatted with CSharpier. Do not use `dotnet format`. Command: `dotnet tool restore` followed by `dotnet csharpier check .` (or `dotnet csharpier .` to auto-format).
15
+ 2. **Linting — .NET Analyzers**: C# code must pass Roslyn/.NET analyzer diagnostics. Analyzer enforcement is centralized in `Directory.Build.props` (`AnalysisLevel=latest-all`, `AnalysisMode=All`, `TreatWarningsAsErrors=true`). Command: `dotnet build` runs analyzers as part of the build.
16
+ 3. **Type Checking — Nullable Analysis**: Nullable reference types are enabled solution-wide via `Directory.Build.props` (`Nullable=enable`, `TreatWarningsAsErrors=true`). Command: `dotnet build` enforces nullable warnings as errors.
17
+ 4. **Testing — xUnit + NSubstitute + FluentAssertions**: Run tests with: `dotnet test --collect:"XPlat Code Coverage"`.
18
18
 
19
- Run the toolchain in order: format → lint → type-check → test. Restart from step 1 if any step fails or changes files.
19
+ Run the toolchain in order: format → lint → type-check → architecture → test. Restart from step 1 if any step fails or changes files.
20
20
 
21
21
  ## Coding Standards
22
22
 
23
- - **Naming**: `PascalCase` for types and public members. `camelCase` for locals and private fields/parameters.
23
+ - **Naming**: `PascalCase` for types and public members. `camelCase` for locals and private fields/parameters. Private fields use `_camelCase`. Interfaces use the `I` prefix. Async methods carry the `Async` suffix.
24
24
  - **Null safety**: Keep nullable reference types enabled. Model optional values with nullable annotations and guard clauses.
25
25
  - **Composition over inheritance**: Keep classes cohesive and scoped to one responsibility. Favor composition unless polymorphism is a clear requirement.
26
26
  - **Async/await**: Use `async`/`await` for I/O-bound operations. Prefer `using`/`await using` for disposable resources.
27
27
  - **Exceptions**: Fail fast with explicit exceptions. Avoid broad `catch (Exception)` unless at a defined boundary with added context.
28
28
  - **Public surface**: Keep public API surface intentional and minimal. Prefer `internal` for non-public APIs.
29
29
  - **XML docs**: Public APIs should include XML documentation comments when behavior or contract is non-obvious.
30
+ - **File-scoped namespaces**: Required (`csharp_style_namespace_declarations = file_scoped:error` in `.editorconfig`).
30
31
 
31
32
  ## Testing Standards
32
33
 
33
- - Use **MSTest** (`Microsoft.VisualStudio.TestTools.UnitTesting`) as the test framework.
34
- - Use **Moq** for mocking.
35
- - Prefer **FluentAssertions** for assertions; use MSTest `Assert` only when FluentAssertions is not practical.
36
- - Use `[TestClass]` and `[TestMethod]` attributes.
34
+ - Use **xUnit** as the test framework with `[Fact]` and `[Theory]` attributes.
35
+ - Use **`[Theory]` + `[InlineData]`** for parameterized tests.
36
+ - Use **`IClassFixture<T>`** to share expensive setup across tests within a class.
37
+ - Use **NSubstitute** for test doubles. Example: `var sut = Substitute.For<IService>(); sut.Get().Returns(value);`.
38
+ - Prefer **FluentAssertions** for assertions; use xUnit `Assert` only when FluentAssertions is not practical.
37
39
  - Follow Arrange–Act–Assert structure.
38
40
  - No external dependencies in unit tests.
39
- - Repository-wide line coverage must remain >= 80%.
40
- - Any new module, class, or method must reach >= 90% coverage.
41
+
42
+ ### Coverage
43
+
44
+ - Line coverage line >= 85% and branch coverage branch >= 75% uniform across all tiers (T1–T4). No tier-specific lower floor is used.
45
+ - Mutation score mutation >= 75% on T1 modules (via Stryker.NET).
41
46
  - Coverage regression on changed lines is a blocking finding.
47
+ - Interface-only files with no executable behavior — files consisting solely of `interface` declarations or abstract contracts — may be omitted from coverage measurement. Such files legitimately report 0% executable coverage. This is a clarification only; it does not lower any coverage threshold.
48
+
49
+ ### Property-Based and Mutation Testing
50
+
51
+ - **CsCheck**: at least one property-based test per pure function on T1 and T2 modules.
52
+ - **Stryker.NET**: mutation testing required on T1 modules with a mutation score mutation >= 75%. Runs in pre-merge or nightly pipelines.
53
+
54
+ ### Golden Tests
55
+
56
+ - **Verify.Xunit**: required for T1 classifier-output modules, tested against a versioned corpus.
57
+
58
+ ## Analyzer Stack
59
+
60
+ All projects reference the following analyzer packages via `<PackageReference>` with `PrivateAssets="all"` (versions pinned centrally in `Directory.Packages.props`):
61
+
62
+ - `Meziantou.Analyzer` — `PrivateAssets="all"`
63
+ - `SonarAnalyzer.CSharp` — `PrivateAssets="all"`
64
+ - `Roslynator.Analyzers` — `PrivateAssets="all"`
65
+ - `AsyncFixer` — `PrivateAssets="all"`
66
+ - `SecurityCodeScan.VS2019` — `PrivateAssets="all"`
67
+ - `Microsoft.CodeAnalysis.BannedApiAnalyzers` — `PrivateAssets="all"`
68
+
69
+ The shared `<ItemGroup>` lives in `Directory.Build.props` so the stack applies to every project automatically.
70
+
71
+ ## Banned APIs
72
+
73
+ The following APIs are banned outside an explicit allowlist; enforcement is via `Microsoft.CodeAnalysis.BannedApiAnalyzers` against `BannedSymbols.txt` (at solution root, wired through `Directory.Build.props` as an `<AdditionalFiles>` entry):
74
+
75
+ - `DateTime.Now` (use `TimeProvider.GetLocalNow()` on an injected `TimeProvider`).
76
+ - `DateTime.UtcNow` (use `TimeProvider.GetUtcNow()` on an injected `TimeProvider`).
77
+ - `Random.Shared` (inject a seeded `Random` or use a deterministic seam).
78
+ - `Thread.Sleep` (banned; use cooperative awaits and fake-time advancement).
79
+ - `Task.Delay` (banned in production paths; tests must use `FakeTimeProvider`).
80
+
81
+ Tests inject `TimeProvider` via `Microsoft.Extensions.TimeProvider.Testing`'s `FakeTimeProvider` rather than calling `DateTime.UtcNow` or `Task.Delay` directly.
42
82
 
43
83
  ## Deterministic Test Rules
44
84
 
@@ -48,9 +88,15 @@ Unit tests must not depend on network, mutable machine PATH or profile state, im
48
88
 
49
89
  Introduce the smallest seam that enables reliable unit testing. Apply in this order of preference:
50
90
 
51
- 1. **Interface seam (preferred)** — extract boundary calls into narrow purpose-specific interfaces (for example, `IProcessRunner`, `IFileSystem`, `IClock`). Keep interfaces minimal.
91
+ 1. **Interface seam (preferred)** — extract boundary calls into narrow purpose-specific interfaces (for example, `IProcessRunner`, `IFileSystem`). Keep interfaces minimal.
52
92
  2. **Injectable delegate seam** — use a narrow `Func<>`/`Action<>` delegate for a single call path when a full interface is excessive. Default behavior must remain safe and deterministic.
53
- 3. **Adapter seam for static or third-party APIs** — wrap the static or third-party call behind a small adapter so tests can mock the adapter with Moq.
93
+ 3. **Adapter seam for static or third-party APIs** — wrap the static or third-party call behind a small adapter so tests can substitute the adapter with NSubstitute.
94
+
95
+ ### Clock Seam
96
+
97
+ - **`TimeProvider` is preferred** for new code (since .NET 8). Inject `TimeProvider` and use `GetUtcNow()` / `GetLocalNow()` / `CreateTimer()`.
98
+ - Test code injects `FakeTimeProvider` from **`Microsoft.Extensions.TimeProvider.Testing`** to advance simulated time deterministically.
99
+ - `IClock` legacy: acceptable only in legacy or pre-.NET 8 contexts that have not yet been migrated. New code must use `TimeProvider`.
54
100
 
55
101
  ## Prohibited Behaviors
56
102
 
@@ -24,16 +24,25 @@ Apply these priorities in order when designing or changing code:
24
24
  - Keep methods small and focused. Avoid god objects.
25
25
  - Use interfaces/abstract types/protocols when multiple implementations are likely.
26
26
 
27
+ ## Module Rigor Tiers
28
+
29
+ Module rigor tiers (T1–T4) and the uniform-versus-tier-dependent gate matrix are defined in `.claude/rules/quality-tiers.md`. Every project must be classified in `quality-tiers.yml` at repo root.
30
+
27
31
  ## Mandatory Toolchain Loop
28
32
 
29
- Run the full toolchain in this exact order and repeat until all steps pass in a single pass:
33
+ Run the full seven-stage toolchain in this exact order and repeat until all stages pass in a single pass:
30
34
 
31
35
  1. **Formatting** (e.g., Black, Prettier, CSharpier, Invoke-Formatter)
32
36
  2. **Linting** (e.g., Ruff, ESLint, PSScriptAnalyzer, .NET analyzers)
33
37
  3. **Type checking** (e.g., Pyright, TSC, nullable analysis; skip for PowerShell)
34
- 4. **Testing** (e.g., Pytest, Jest, MSTest, Pester)
38
+ 4. **Architecture-boundary tests** (e.g., dependency-cruiser, NetArchTest.Rules)
39
+ 5. **Unit tests** (e.g., Pytest, Vitest, MSTest, Pester) including property-based tests where applicable per `quality-tiers.md`
40
+ 6. **Contract / schema compatibility checks** (e.g., oasdiff, schema-snapshot diff)
41
+ 7. **Integration tests**
42
+
43
+ **Restart from step 1** if any stage fails or auto-fixes any files. Do not stop the loop until all seven stages complete without errors in a single pass.
35
44
 
36
- **Restart from step 1** if any step fails or auto-fixes any files. Do not stop the loop until all four steps complete without errors in a single pass.
45
+ Mutation testing and golden tests run in pre-merge or nightly pipelines, not the per-commit loop.
37
46
 
38
47
  ## File Size Limit
39
48
 
@@ -20,11 +20,30 @@ Every unit test must satisfy all five of these properties:
20
20
 
21
21
  ## Coverage Requirements
22
22
 
23
- - **Repository-wide line coverage must remain >= 80%.**
24
- - **Any new module, class, or method must target >= 90% coverage.**
23
+ - **Line coverage must remain >= 85% across all tiers (T1–T4).**
24
+ - **Branch coverage must remain >= 75% across all tiers (T1–T4).**
25
25
  - Code changes or refactors must not reduce coverage for the lines that were changed.
26
+ - Tier-specific lower coverage thresholds are not used in this repository. See `.claude/rules/quality-tiers.md` for the full tier system.
26
27
  - Coverage is a supporting metric, not the sole quality gate. Untested critical behavior is not acceptable even if the overall percentage looks good.
27
28
  - Configure coverage tooling to exclude test files (e.g., `tests/`) so metrics reflect application code, not tests.
29
+ - Type-only / interface-only modules with no executable behavior may be omitted from coverage measurement. Examples: Python `Protocol`-only modules consumed only under `TYPE_CHECKING`, TypeScript interface/type-only files, and C# interface-only files. Such modules legitimately report 0% executable coverage and may be excluded from measurement. This is a clarification only; it does not lower any coverage threshold.
30
+
31
+ ## Coverage Exclusion Policy
32
+
33
+ No production file may be excluded from coverage measurement. Every production source file is in the denominator of the coverage metric, regardless of whether its lines are reachable in the test environment.
34
+
35
+ The correct response to a file that contains untestable lines is to refactor it — extract all logic into host-neutral, testable modules and leave only the thinnest possible wiring in the host-bound entry point. The entry point's uncovered lines then represent a real and visible cost in the coverage metric, which creates ongoing pressure to keep those files minimal.
36
+
37
+ **Permitted `exclude` entries** (non-production paths only):
38
+ - Build output directories: `dist/**`, `lib/**`, `lib-amd/**`.
39
+ - Test files and test infrastructure: `**/*.test.ts`, `tests/**`, `src/test-support/**`.
40
+ - Config files that are not production code: `vitest.config.ts`, `eslint.config.mjs`, `.dependency-cruiser.cjs`, `webpack.config.js`.
41
+ - `node_modules/**`.
42
+
43
+ **Prohibited `exclude` entries:**
44
+ - Any path under `src/` that contains production runtime code, regardless of whether it is auto-generated, host-bound, or difficult to test.
45
+
46
+ **Enforcement:** Feature-review agents must treat any `exclude` entry that matches a production source path as a **Blocking** finding.
28
47
 
29
48
  ## Scenario Completeness
30
49
 
@@ -54,7 +73,33 @@ Assertions must produce clear, actionable failure messages.
54
73
  - **Creation and use of temporary files in tests is strictly prohibited.**
55
74
  - Tests must not rely on mutable global state or external configuration that can change between runs.
56
75
 
76
+ ## Test File Location
77
+
78
+ Test files must live in a `tests/` directory tree that mirrors the production source structure. The test for `src/foo/bar.ts` belongs at `tests/foo/bar.test.ts`; the test for `scripts/powershell/Foo.ps1` belongs at `tests/scripts/powershell/Foo.Tests.ps1`. Language-specific rules may add further naming conventions (framework suffix, file extension) on top of this universal layout requirement.
79
+
80
+ Colocation — placing test files alongside production source files in `src/` or equivalent — is not permitted. An agent that creates or moves a test file into the production source tree has violated this rule.
81
+
57
82
  ## Documentation
58
83
 
59
84
  - Each test must clearly communicate its purpose via a descriptive name and/or a short docstring or comment summarizing the scenario and expected outcome.
60
85
  - Group related tests logically within the same file or test class.
86
+
87
+ ## Test Categories
88
+
89
+ The following test categories apply across the repository, with tier-dependent obligations per `.claude/rules/quality-tiers.md`:
90
+
91
+ - **Unit tests** — required for all tiers (T1–T4). Cover single units of behavior in isolation.
92
+ - **Property-based tests** — required for T1 and T2 modules: at least one property test per pure function. Use `fast-check` (TypeScript) or `hypothesis` (Python) where applicable.
93
+ - **Golden / snapshot tests** — required only for T1 classifier-output modules, tested against a versioned corpus. Snapshot tests are otherwise discouraged unless stable and intentional.
94
+ - **Contract / schema tests** — required at every host-service boundary (e.g., Office.js, Microsoft Graph, internal API contracts).
95
+ - **Mutation tests** — required for T1 modules: mutation score >= 75%. Run in pre-merge or nightly pipelines.
96
+ - **Integration tests** — required where adapters interact with external systems; scoped per tier in the gate matrix.
97
+
98
+ ## Determinism Infrastructure
99
+
100
+ All test code must be deterministic. The following infrastructure requirements apply uniformly:
101
+
102
+ - **Controllable clock** — use a `Clock` interface (TypeScript) or `TimeProvider` (.NET) injected into code under test. Do not read wall-clock time directly in production code under test.
103
+ - **Seeded RNG** — randomness must be supplied via a seedable interface; on test failure the seed must be printed so the failure is reproducible.
104
+ - **Banned APIs in test code** — `setTimeout`, `Thread.Sleep`, `Task.Delay`, real wall-clock waits, and `Date.now()` outside the clock interface are prohibited in tests.
105
+ - **Virtual scheduler / fake timers / `FakeTimeProvider`** — async tests must use the framework's fake-timer facility (`vi.useFakeTimers()` for Vitest, `FakeTimeProvider` for .NET) to advance simulated time deterministically.