@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/mcp-server.js +1405 -684
- package/package.json +6 -4
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +16 -5
- package/resources/claude-customizations/.claude/agents/orchestrator.md +21 -7
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +37 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +396 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +153 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +7 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +171 -5
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +6 -15
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -11
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +7 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -16
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +97 -19
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/claude-customizations/pack-manifests/core.json +25 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +13 -3
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +16 -6
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +43 -11
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +19 -4
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
- package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
- package/resources/powershell/PoshQC/README.md +8 -2
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -315
package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1
CHANGED
|
@@ -6,53 +6,36 @@
|
|
|
6
6
|
Dot-sourced by enforce-epic-merge-gate.ps1 immediately after the authorization sibling.
|
|
7
7
|
Holds:
|
|
8
8
|
|
|
9
|
-
- The import
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
- The import guards for WorktreeRunResolution.psm1 and, after it,
|
|
10
|
+
WorktreeItemResolution.psm1 (issue #850). A failed import is recorded in
|
|
11
|
+
$script:HookDependencyFailures, and the gate's call to
|
|
12
|
+
Get-HookDependencyFailureDecision turns it into a deny, so a missing module
|
|
12
13
|
cannot make the gate exit non-zero and fail open.
|
|
13
14
|
- The three checkpoint read seams, relocated from the gate file with their names kept.
|
|
14
15
|
Each takes a mandatory absolute path composed beneath a resolved worktree root.
|
|
15
|
-
- The session worktree root, used for
|
|
16
|
+
- The session worktree root, used for a bare command.
|
|
16
17
|
- The resolution seam Resolve-EpicMergeGateRunTarget, which locates the epic or
|
|
17
18
|
parallel checkpoint that records the command's pull request number.
|
|
19
|
+
- The item seam Resolve-EpicMergeGateItemTarget (issue #850), which locates the live
|
|
20
|
+
worktree whose per-feature checkpoint records the command's pull request number in
|
|
21
|
+
pr_gate.pr_number or a standalone_merge_authorizations entry.
|
|
18
22
|
- Test-ChildCheckpointPrGateBinding, which binds the command's pull request number to
|
|
19
|
-
the per-feature checkpoint
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
the per-feature checkpoint: pr_gate.pr_number must equal it when recorded, and
|
|
24
|
+
otherwise a positive-integer standalone record must name it (issue #788).
|
|
25
|
+
- Get-EpicMergeGateUnresolvedReason, the reason prefix used when neither the item
|
|
26
|
+
target nor either run branch resolves.
|
|
27
|
+
- Test-EpicMergeGateNoRecordingTarget, the precondition of the docs-only merge branch:
|
|
28
|
+
the item, epic, and parallel targets all resolve NoTarget (issue #927).
|
|
22
29
|
|
|
23
30
|
.NOTES
|
|
24
|
-
PowerShell 7+. Depends on Get-EpicMergeGateBlockDecision
|
|
25
|
-
sibling, dot-sourced by the
|
|
31
|
+
PowerShell 7+. Depends on Get-EpicMergeGateBlockDecision and
|
|
32
|
+
Test-StandalonePositiveJsonInteger from the authorization sibling, dot-sourced by the
|
|
33
|
+
gate before this file. Mirrored byte-identically under
|
|
26
34
|
extensions/drm-copilot/resources/claude-customizations/.
|
|
27
35
|
#>
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
$
|
|
31
|
-
try {
|
|
32
|
-
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunResolution.psm1') -Force -ErrorAction Stop
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
$script:EpicMergeGateResolutionImportFailure = 'WorktreeRunResolution.psm1'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function Get-EpicMergeGateImportFailureDecision {
|
|
39
|
-
<#
|
|
40
|
-
.SYNOPSIS
|
|
41
|
-
Returns the deny for a failed worktree-resolution import, or $null.
|
|
42
|
-
.OUTPUTS
|
|
43
|
-
System.Collections.Specialized.OrderedDictionary, or $null when the import succeeded.
|
|
44
|
-
#>
|
|
45
|
-
[CmdletBinding()]
|
|
46
|
-
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
47
|
-
param()
|
|
48
|
-
|
|
49
|
-
if (-not $script:EpicMergeGateResolutionImportFailure) {
|
|
50
|
-
return $null
|
|
51
|
-
}
|
|
52
|
-
return Get-EpicMergeGateBlockDecision -Reason (
|
|
53
|
-
"EPIC_MERGE_GATE_BLOCKED: the worktree-resolution module '$($script:EpicMergeGateResolutionImportFailure)' " +
|
|
54
|
-
'failed to import, so the run checkpoint that governs this merge cannot be located; the gate fails closed.')
|
|
55
|
-
}
|
|
37
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunResolution.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunResolution.psm1' -ErrorRecord $_ }
|
|
38
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeItemResolution.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeItemResolution.psm1' -ErrorRecord $_ }
|
|
56
39
|
|
|
57
40
|
function Get-ChildOrchestratorCheckpointContent {
|
|
58
41
|
<#
|
|
@@ -60,7 +43,7 @@ function Get-ChildOrchestratorCheckpointContent {
|
|
|
60
43
|
Read the raw JSON text of the per-feature orchestrator checkpoint. Tests mock
|
|
61
44
|
this function (read seam).
|
|
62
45
|
.PARAMETER Path
|
|
63
|
-
The absolute checkpoint path composed beneath the session worktree root.
|
|
46
|
+
The absolute checkpoint path composed beneath the item or session worktree root.
|
|
64
47
|
.OUTPUTS
|
|
65
48
|
System.String or $null
|
|
66
49
|
#>
|
|
@@ -117,7 +100,7 @@ function Get-ParallelOrchestratorCheckpointContent {
|
|
|
117
100
|
function Get-EpicMergeGateSessionWorktreeRoot {
|
|
118
101
|
<#
|
|
119
102
|
.SYNOPSIS
|
|
120
|
-
Return the worktree root the session runs in (the
|
|
103
|
+
Return the worktree root the session runs in (the bare-command root).
|
|
121
104
|
.OUTPUTS
|
|
122
105
|
System.String
|
|
123
106
|
#>
|
|
@@ -149,14 +132,35 @@ function Resolve-EpicMergeGateRunTarget {
|
|
|
149
132
|
return Resolve-WorktreeRunTargetByRecord -Kind $Kind -RecordField pr_number -Value ([string]$PrNumber) -SessionRoot (Get-Location).Path
|
|
150
133
|
}
|
|
151
134
|
|
|
135
|
+
function Resolve-EpicMergeGateItemTarget {
|
|
136
|
+
<#
|
|
137
|
+
.SYNOPSIS
|
|
138
|
+
Resolve the worktree whose per-feature checkpoint records a pull request number (issue #850 seam).
|
|
139
|
+
.PARAMETER PrNumber
|
|
140
|
+
The explicit pull request number the command names.
|
|
141
|
+
.OUTPUTS
|
|
142
|
+
System.Management.Automation.PSCustomObject (the worktree-resolution target result).
|
|
143
|
+
#>
|
|
144
|
+
[CmdletBinding()]
|
|
145
|
+
[OutputType([pscustomobject])]
|
|
146
|
+
param(
|
|
147
|
+
[Parameter(Mandatory)][int] $PrNumber
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return Resolve-WorktreeItemTargetByPrNumber -PrNumber $PrNumber -SessionRoot (Get-Location).Path
|
|
151
|
+
}
|
|
152
|
+
|
|
152
153
|
function Test-ChildCheckpointPrGateBinding {
|
|
153
154
|
<#
|
|
154
155
|
.SYNOPSIS
|
|
155
|
-
True
|
|
156
|
+
True when the per-feature checkpoint binds the command's pull request number (issue #788).
|
|
156
157
|
.DESCRIPTION
|
|
157
|
-
A bare command
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
Pure. A bare command is unbound and returns $true. An explicit number requires a
|
|
159
|
+
checkpoint: when it records pr_gate.pr_number, that value must parse as an integer
|
|
160
|
+
equal to the number; otherwise a standalone_merge_authorizations entry whose
|
|
161
|
+
pr_number is a positive JSON integer equal to the number must exist. Every other
|
|
162
|
+
case returns $false, so a checkpoint that names neither field cannot authorize an
|
|
163
|
+
explicit-number merge through the child branch.
|
|
160
164
|
.PARAMETER Checkpoint
|
|
161
165
|
Parsed per-feature checkpoint, or $null.
|
|
162
166
|
.PARAMETER CommandPrNumber
|
|
@@ -171,30 +175,45 @@ function Test-ChildCheckpointPrGateBinding {
|
|
|
171
175
|
[AllowNull()][Nullable[int]] $CommandPrNumber
|
|
172
176
|
)
|
|
173
177
|
|
|
174
|
-
if ($null -eq $CommandPrNumber
|
|
178
|
+
if ($null -eq $CommandPrNumber) {
|
|
175
179
|
return $true
|
|
176
180
|
}
|
|
177
|
-
if (
|
|
178
|
-
return $
|
|
181
|
+
if ($null -eq $Checkpoint) {
|
|
182
|
+
return $false
|
|
179
183
|
}
|
|
180
|
-
$
|
|
181
|
-
if (
|
|
182
|
-
|
|
184
|
+
$props = @($Checkpoint.PSObject.Properties.Name)
|
|
185
|
+
if ($props -contains 'pr_gate' -and $null -ne $Checkpoint.pr_gate -and
|
|
186
|
+
@($Checkpoint.pr_gate.PSObject.Properties.Name) -contains 'pr_number' -and $null -ne $Checkpoint.pr_gate.pr_number) {
|
|
187
|
+
$recorded = 0
|
|
188
|
+
if (-not [int]::TryParse([string]$Checkpoint.pr_gate.pr_number, [ref] $recorded)) {
|
|
189
|
+
return $false
|
|
190
|
+
}
|
|
191
|
+
return ($recorded -eq $CommandPrNumber)
|
|
183
192
|
}
|
|
184
|
-
$
|
|
185
|
-
if (-not [int]::TryParse([string]$prGate.pr_number, [ref] $recorded)) {
|
|
193
|
+
if ($props -notcontains 'standalone_merge_authorizations') {
|
|
186
194
|
return $false
|
|
187
195
|
}
|
|
188
|
-
|
|
196
|
+
foreach ($entry in @($Checkpoint.standalone_merge_authorizations)) {
|
|
197
|
+
if ($null -eq $entry -or @($entry.PSObject.Properties.Name) -notcontains 'pr_number') {
|
|
198
|
+
continue
|
|
199
|
+
}
|
|
200
|
+
if ((Test-StandalonePositiveJsonInteger -Value $entry.pr_number) -and [long]$entry.pr_number -eq $CommandPrNumber) {
|
|
201
|
+
return $true
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return $false
|
|
189
205
|
}
|
|
190
206
|
|
|
191
207
|
function Get-EpicMergeGateUnresolvedReason {
|
|
192
208
|
<#
|
|
193
209
|
.SYNOPSIS
|
|
194
|
-
Returns '<code>: <epic detail>; <parallel detail>' when
|
|
210
|
+
Returns '<code>: <item detail>; <epic detail>; <parallel detail>' when no target resolved, or $null.
|
|
195
211
|
.DESCRIPTION
|
|
196
|
-
The ambiguity code
|
|
197
|
-
target is
|
|
212
|
+
The ambiguity code of the first Ambiguous target among item, epic, and parallel
|
|
213
|
+
wins; otherwise the item target's code is used. Returns $null when any target is
|
|
214
|
+
absent (a bare command) or any target resolved.
|
|
215
|
+
.PARAMETER ItemTarget
|
|
216
|
+
The item target, or $null.
|
|
198
217
|
.PARAMETER EpicTarget
|
|
199
218
|
The epic run target, or $null.
|
|
200
219
|
.PARAMETER ParallelTarget
|
|
@@ -205,17 +224,55 @@ function Get-EpicMergeGateUnresolvedReason {
|
|
|
205
224
|
[CmdletBinding()]
|
|
206
225
|
[OutputType([string])]
|
|
207
226
|
param(
|
|
227
|
+
[AllowNull()] $ItemTarget,
|
|
208
228
|
[AllowNull()] $EpicTarget,
|
|
209
229
|
[AllowNull()] $ParallelTarget
|
|
210
230
|
)
|
|
211
231
|
|
|
212
|
-
if ($null -eq $EpicTarget -or $null -eq $ParallelTarget) {
|
|
232
|
+
if ($null -eq $ItemTarget -or $null -eq $EpicTarget -or $null -eq $ParallelTarget) {
|
|
213
233
|
return $null
|
|
214
234
|
}
|
|
235
|
+
$targets = @($ItemTarget, $EpicTarget, $ParallelTarget)
|
|
215
236
|
$unresolved = @('NoTarget', 'Ambiguous')
|
|
216
|
-
|
|
217
|
-
|
|
237
|
+
foreach ($target in $targets) {
|
|
238
|
+
if ($unresolved -notcontains $target.Status) {
|
|
239
|
+
return $null
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
$ambiguous = @($targets | Where-Object { $_.Status -eq 'Ambiguous' })
|
|
243
|
+
$code = if ($ambiguous.Count -gt 0) { $ambiguous[0].ReasonCode } else { $ItemTarget.ReasonCode }
|
|
244
|
+
return ('{0}: {1}; {2}; {3}' -f $code, $ItemTarget.Detail, $EpicTarget.Detail, $ParallelTarget.Detail)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function Test-EpicMergeGateNoRecordingTarget {
|
|
248
|
+
<#
|
|
249
|
+
.SYNOPSIS
|
|
250
|
+
True only when the item, epic, and parallel targets all have status NoTarget (issue #927).
|
|
251
|
+
.DESCRIPTION
|
|
252
|
+
Pure. That combination means no checkpoint records the command's pull request number,
|
|
253
|
+
which is the only case the docs-only merge branch evaluates. A $null target (a bare
|
|
254
|
+
command), an Ambiguous target, and any resolved target return $false.
|
|
255
|
+
.PARAMETER ItemTarget
|
|
256
|
+
The item target, or $null.
|
|
257
|
+
.PARAMETER EpicTarget
|
|
258
|
+
The epic run target, or $null.
|
|
259
|
+
.PARAMETER ParallelTarget
|
|
260
|
+
The parallel run target, or $null.
|
|
261
|
+
.OUTPUTS
|
|
262
|
+
System.Boolean
|
|
263
|
+
#>
|
|
264
|
+
[CmdletBinding()]
|
|
265
|
+
[OutputType([bool])]
|
|
266
|
+
param(
|
|
267
|
+
[AllowNull()] $ItemTarget,
|
|
268
|
+
[AllowNull()] $EpicTarget,
|
|
269
|
+
[AllowNull()] $ParallelTarget
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
foreach ($target in @($ItemTarget, $EpicTarget, $ParallelTarget)) {
|
|
273
|
+
if ($null -eq $target -or [string]$target.Status -cne 'NoTarget') {
|
|
274
|
+
return $false
|
|
275
|
+
}
|
|
218
276
|
}
|
|
219
|
-
|
|
220
|
-
return ('{0}: {1}; {2}' -f $code, $EpicTarget.Detail, $ParallelTarget.Detail)
|
|
277
|
+
return $true
|
|
221
278
|
}
|
|
@@ -33,15 +33,25 @@
|
|
|
33
33
|
PR number never satisfies condition 4, and a blanket flag is rejected rather than read.
|
|
34
34
|
Trigger scope: --squash is out of scope for this gate and is allowed on both runtimes.
|
|
35
35
|
|
|
36
|
-
Design decision:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
Design decision: branches 1-4 trust the on-disk checkpoint and never call gh. Issue #927
|
|
37
|
+
adds a docs-only branch after branch 4 fails, only for an explicit PR number whose item,
|
|
38
|
+
epic, and parallel targets are all NoTarget (no checkpoint records the PR): it calls
|
|
39
|
+
Get-DocsOnlyMergeExemption (hook-docs-only-diff.ps1), which runs gh pr view and git in the
|
|
40
|
+
session worktree and allows the merge when conditions M1-M9 of that file hold. Otherwise
|
|
41
|
+
the deny gains " (docs-only exemption not applied: <Reason>)", where the reason may be
|
|
42
|
+
DOCS_ONLY_EXEMPTION_PR_UNRESOLVED. The hook never fetches; --match-head-commit, when
|
|
43
|
+
present, must equal headRefOid (OD-2). Residual limits: an ambient GH_REPO or GH_HOST is
|
|
44
|
+
not visible in the command text; gh and git run in the session worktree root, so a cd
|
|
45
|
+
made by an earlier Bash call is not visible either; and a push after the lookup can
|
|
46
|
+
change the head unless --match-head-commit is passed. Like the receipt mechanism of
|
|
47
|
+
enforce-pr-author-skill.ps1, this is a policy-level control, not a cryptographic one.
|
|
40
48
|
|
|
41
49
|
Issue #690: with an explicit PR number, the epic and parallel checkpoints are read
|
|
42
|
-
beneath the live worktree whose run checkpoint records that number
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
beneath the live worktree whose run checkpoint records that number. Issue #850: with
|
|
51
|
+
an explicit PR number, the per-feature checkpoint is read beneath the live worktree
|
|
52
|
+
whose checkpoint records the number in pr_gate.pr_number or a standalone record, and
|
|
53
|
+
the child branch requires that checkpoint to bind the number (issue #788). A bare
|
|
54
|
+
command reads every checkpoint beneath the session worktree.
|
|
45
55
|
|
|
46
56
|
.NOTES
|
|
47
57
|
Compatible with PowerShell 7+. Depends on WorktreeRunResolution.psm1 through the
|
|
@@ -57,16 +67,19 @@
|
|
|
57
67
|
#>
|
|
58
68
|
[CmdletBinding()]
|
|
59
69
|
param()
|
|
70
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
60
71
|
|
|
61
|
-
Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force
|
|
72
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
62
73
|
# Shared command-line parser (issue #545), consumed by the scope filter in
|
|
63
74
|
# Invoke-EpicMergeGateDecision and by Get-EpicMergeGateCommandPrNumber.
|
|
64
|
-
. (Join-Path $PSScriptRoot 'hook-command-scanner.ps1')
|
|
65
|
-
. (Join-Path $PSScriptRoot 'hook-command-invocation.ps1')
|
|
75
|
+
try { . (Join-Path $PSScriptRoot 'hook-command-scanner.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-scanner.ps1' -ErrorRecord $_ }
|
|
76
|
+
try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-invocation.ps1' -ErrorRecord $_ }
|
|
66
77
|
# Standalone-merge authorization predicates and the two decision-envelope factories (issue #670).
|
|
67
|
-
. (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-authorization.ps1')
|
|
78
|
+
try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-authorization.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-authorization.ps1' -ErrorRecord $_ }
|
|
68
79
|
# Checkpoint read seams, the import guard, and run-target resolution (issue #690).
|
|
69
|
-
. (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-resolution.ps1')
|
|
80
|
+
try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-resolution.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-resolution.ps1' -ErrorRecord $_ }
|
|
81
|
+
# Shared docs-only diff classification and the merge-side docs-only exemption (issue #927).
|
|
82
|
+
try { . (Join-Path $PSScriptRoot 'hook-docs-only-diff.ps1') } catch { Add-HookDependencyFailure -Name 'hook-docs-only-diff.ps1' -ErrorRecord $_ }
|
|
70
83
|
|
|
71
84
|
function ConvertFrom-EpicMergeGateJson {
|
|
72
85
|
<#
|
|
@@ -312,10 +325,8 @@ function Invoke-EpicMergeGateDecision {
|
|
|
312
325
|
)
|
|
313
326
|
|
|
314
327
|
# A failed worktree-resolution import denies before any other logic (issue #690).
|
|
315
|
-
$
|
|
316
|
-
if ($null -ne $
|
|
317
|
-
return $importFailure
|
|
318
|
-
}
|
|
328
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'EPIC_MERGE_GATE_BLOCKED:'
|
|
329
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
319
330
|
|
|
320
331
|
$payload = Resolve-ClaudeHookToolInput -Raw $ToolInputRaw
|
|
321
332
|
if (-not $payload.IsValid) {
|
|
@@ -357,9 +368,17 @@ function Invoke-EpicMergeGateDecision {
|
|
|
357
368
|
$commandPrNumber = Get-EpicMergeGateCommandPrNumber -CommandText $commandText
|
|
358
369
|
$sessionRoot = Get-EpicMergeGateSessionWorktreeRoot
|
|
359
370
|
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
|
|
371
|
+
# With an explicit PR number, the per-feature checkpoint is read beneath the live
|
|
372
|
+
# worktree whose checkpoint records the number in pr_gate.pr_number or a standalone
|
|
373
|
+
# record (issue #850); an unresolved item target reads none. A bare command reads the
|
|
374
|
+
# session worktree. The checkpoint read must still bind the number (issue #788).
|
|
375
|
+
$itemTarget = $null
|
|
376
|
+
$childRoot = $sessionRoot
|
|
377
|
+
if ($null -ne $commandPrNumber) {
|
|
378
|
+
$itemTarget = Resolve-EpicMergeGateItemTarget -PrNumber $commandPrNumber
|
|
379
|
+
$childRoot = if (@('SessionRoot', 'OtherWorktree') -contains $itemTarget.Status) { $itemTarget.WorktreeRoot } else { $null }
|
|
380
|
+
}
|
|
381
|
+
$childCheckpoint = if ($childRoot) { ConvertFrom-EpicMergeGateJson -Raw (Get-ChildOrchestratorCheckpointContent -Path (Get-WorktreeRunCheckpointPath -Kind item -WorktreeRoot $childRoot)) } else { $null }
|
|
363
382
|
if ((Test-ChildCheckpointAllowsEpicMerge -Checkpoint $childCheckpoint) -and
|
|
364
383
|
(Test-ChildCheckpointPrGateBinding -Checkpoint $childCheckpoint -CommandPrNumber $commandPrNumber)) {
|
|
365
384
|
return Get-EpicMergeGateAllowDecision
|
|
@@ -396,10 +415,20 @@ function Invoke-EpicMergeGateDecision {
|
|
|
396
415
|
if ($standalone.Allowed) {
|
|
397
416
|
return Get-EpicMergeGateAllowDecision
|
|
398
417
|
}
|
|
399
|
-
#
|
|
400
|
-
$
|
|
418
|
+
# Docs-only branch (issue #927): evaluated only when no checkpoint records the PR.
|
|
419
|
+
$docsOnlySuffix = ''
|
|
420
|
+
if (Test-EpicMergeGateNoRecordingTarget -ItemTarget $itemTarget -EpicTarget $epicTarget -ParallelTarget $parallelTarget) {
|
|
421
|
+
$docsOnly = Get-DocsOnlyMergeExemption -CommandText $commandText -PrNumber $commandPrNumber -WorktreeRoot $sessionRoot
|
|
422
|
+
if ($docsOnly.Exempt) {
|
|
423
|
+
return Get-EpicMergeGateAllowDecision
|
|
424
|
+
}
|
|
425
|
+
$docsOnlySuffix = ' (docs-only exemption not applied: ' + $docsOnly.Reason + ')'
|
|
426
|
+
}
|
|
427
|
+
# When neither the item target nor a run branch resolved, the reason code and the
|
|
428
|
+
# three details precede the standalone reason (issue #850).
|
|
429
|
+
$unresolved = Get-EpicMergeGateUnresolvedReason -ItemTarget $itemTarget -EpicTarget $epicTarget -ParallelTarget $parallelTarget
|
|
401
430
|
$prefix = if ($unresolved) { $unresolved + '; ' } else { '' }
|
|
402
|
-
return Get-EpicMergeGateBlockDecision -Reason ('EPIC_MERGE_GATE_BLOCKED: ' + $prefix + $standalone.ReasonCode + ': ' + $standalone.Message)
|
|
431
|
+
return Get-EpicMergeGateBlockDecision -Reason ('EPIC_MERGE_GATE_BLOCKED: ' + $prefix + $standalone.ReasonCode + ': ' + $standalone.Message + $docsOnlySuffix)
|
|
403
432
|
}
|
|
404
433
|
|
|
405
434
|
return Get-EpicMergeGateBlockDecision -Reason 'EPIC_MERGE_GATE_BLOCKED: gh pr merge --merge requires either a per-feature checkpoint with epic_mode == true and step9_status == "passed", an epic checkpoint with epic_merge_pr.ci_gate.conclusion == "success" and a matching pr_number, or a parallel-orchestrator checkpoint with route_id == "parallel" whose target item (matched by pr_number) has merge_status == "ci_green". No checkpoint satisfied this gate.'
|
|
@@ -447,6 +476,9 @@ function Invoke-EpicMergeGateEntryPoint {
|
|
|
447
476
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
448
477
|
return
|
|
449
478
|
}
|
|
479
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('EPIC_MERGE_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
480
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'EPIC_MERGE_GATE_BLOCKED:'
|
|
481
|
+
if ($null -ne $dependencyDecision) { $dependencyDecision | ConvertTo-Json -Compress -Depth 5 | Write-Output; exit 0 }
|
|
450
482
|
|
|
451
483
|
# The entry point returns its [int] exit code as the last pipeline element and the
|
|
452
484
|
# decision JSON before it. `exit (<call>)` would capture BOTH into the exit
|
|
@@ -456,4 +488,4 @@ if ($entryPointResult.Count -gt 1) {
|
|
|
456
488
|
$entryPointResult[0..($entryPointResult.Count - 2)] | Write-Output
|
|
457
489
|
}
|
|
458
490
|
|
|
459
|
-
exit ([int]$entryPointResult[-1])
|
|
491
|
+
exit ([int]$entryPointResult[-1])
|
|
@@ -8,45 +8,59 @@
|
|
|
8
8
|
and the serialized prompt contains the epic-mode kickoff marker "Epic mode: true".
|
|
9
9
|
|
|
10
10
|
Resolution and decision procedure:
|
|
11
|
-
1. Resolve the
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
4.
|
|
11
|
+
1. Resolve the worktree whose epic checkpoint records the prompt's
|
|
12
|
+
integration_branch: value (issue #690) and deny an unresolved or ambiguous target.
|
|
13
|
+
2. Collect the cited feature-folder candidates with the shared resolver
|
|
14
|
+
(feature-folder-resolution.ps1, issue #565): every docs/features/active/<token>
|
|
15
|
+
path is truncated to its feature-folder segment, so a nested research/ or
|
|
16
|
+
evidence/ citation names its own folder. No candidate denies.
|
|
17
|
+
3. Read artifacts/orchestration/epic-orchestrator-state.json beneath that worktree
|
|
18
|
+
and select the target among the candidates with Select-FeatureFolderTarget
|
|
19
|
+
-DependencyAware: a cited upstream dependency of another cited candidate is
|
|
20
|
+
pruned, and two or more remaining candidates deny as ambiguous. Neither string
|
|
21
|
+
length nor prompt position takes part in the selection.
|
|
22
|
+
4. Locate the target's features[] record and, for every depends_on entry, its own
|
|
23
|
+
record. An entry resolves through the union index, so an issue number matches
|
|
24
|
+
issue_num and a folder value matches the normalized feature_folder.
|
|
25
|
+
5. Deny with reason EPIC_WAVE_BARRIER_BLOCKED unless every dependency's merge_status
|
|
23
26
|
is merged or worktree_removed. A missing/unreadable checkpoint, an unresolved
|
|
24
27
|
target feature_folder, or a missing dependency record also denies (fail-closed).
|
|
25
28
|
|
|
26
|
-
This is the per-call deterrent (Layer 1) of the two-layer wave-barrier design
|
|
27
|
-
retrospective backstop (Layer 2) is the wave-barrier ordering invariant
|
|
28
|
-
validate_epic_orchestrator_state_text,
|
|
29
|
-
|
|
29
|
+
This is the per-call deterrent (Layer 1) of the two-layer wave-barrier design. The
|
|
30
|
+
retrospective backstop (Layer 2) is the wave-barrier ordering invariant of
|
|
31
|
+
validate_epic_orchestrator_state_text, run at epic-orchestrator SubagentStop time by
|
|
32
|
+
validate-orchestrator-output.ps1 through its PowerShell port
|
|
33
|
+
OrchestratorStateEpicWaveBarrier.psm1, with parity pinned by tests/fixtures/epic_wave_barrier/.
|
|
34
|
+
The SubagentStop transport and exit-code defect that hook depended on was resolved by epic #904
|
|
35
|
+
and issue #928: a violation blocks the stop with exit 2 and a stderr reason.
|
|
36
|
+
The two layers share no code.
|
|
30
37
|
|
|
31
38
|
.NOTES
|
|
32
|
-
Compatible with PowerShell 7+. Depends on WorktreeRunResolution.psm1 (issue #690)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
mock the boundary without
|
|
39
|
+
Compatible with PowerShell 7+. Depends on WorktreeRunResolution.psm1 (issue #690) and
|
|
40
|
+
the pure sibling feature-folder-resolution.ps1 (issue #565), each loaded inside a
|
|
41
|
+
guard: a failure is recorded and the decision denies naming the dependency. Filesystem
|
|
42
|
+
reads go through an injectable wrapper function so tests can mock the boundary without
|
|
43
|
+
writing temporary files.
|
|
36
44
|
#>
|
|
37
45
|
[CmdletBinding()]
|
|
38
46
|
param()
|
|
47
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
39
48
|
|
|
40
49
|
|
|
41
|
-
Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force
|
|
50
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunResolution.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunResolution.psm1' -ErrorRecord $_ }
|
|
44
53
|
$script:EpicWaveBarrierResolutionImportFailure = $null
|
|
54
|
+
|
|
55
|
+
# Shared feature-folder resolution (issue #565). Guarded so a failed dot-source denies
|
|
56
|
+
# rather than failing open; an earlier recorded failure is kept.
|
|
45
57
|
try {
|
|
46
|
-
|
|
58
|
+
. (Join-Path $PSScriptRoot 'feature-folder-resolution.ps1')
|
|
47
59
|
}
|
|
48
60
|
catch {
|
|
49
|
-
$script:EpicWaveBarrierResolutionImportFailure
|
|
61
|
+
if (-not $script:EpicWaveBarrierResolutionImportFailure) {
|
|
62
|
+
$script:EpicWaveBarrierResolutionImportFailure = 'feature-folder-resolution.ps1'
|
|
63
|
+
}
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
$script:AllowedMergeStatuses = @('merged', 'worktree_removed')
|
|
@@ -95,56 +109,35 @@ function Resolve-EpicWaveBarrierTarget {
|
|
|
95
109
|
function Find-EpicWaveBarrierFeatureFolderFromPrompt {
|
|
96
110
|
<#
|
|
97
111
|
.SYNOPSIS
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
Returns the distinct feature-folder basenames cited in a prompt, in first-occurrence
|
|
113
|
+
order. Returns no output when no folder is cited.
|
|
100
114
|
.DESCRIPTION
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
Delegates to Find-FeatureFolderCandidate in the shared resolver (issue #565): each
|
|
116
|
+
docs/features/active/<token> path, in either separator style, is truncated to its
|
|
117
|
+
feature-folder segment, so a nested research/ or evidence/ citation names its own
|
|
118
|
+
folder. Selection among several candidates is made by Select-FeatureFolderTarget.
|
|
105
119
|
.PARAMETER Prompt
|
|
106
120
|
The delegation prompt text under evaluation.
|
|
107
121
|
.OUTPUTS
|
|
108
|
-
System.String
|
|
122
|
+
System.String[]
|
|
109
123
|
#>
|
|
110
124
|
[CmdletBinding()]
|
|
111
|
-
[OutputType([string])]
|
|
125
|
+
[OutputType([string[]])]
|
|
112
126
|
param(
|
|
113
127
|
[Parameter(Mandatory)]
|
|
114
128
|
[AllowEmptyString()]
|
|
115
129
|
[string] $Prompt
|
|
116
130
|
)
|
|
117
131
|
|
|
118
|
-
|
|
119
|
-
return $null
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
$pattern = 'docs[\\/]+features[\\/]+active[\\/]+[^\s"''`]+'
|
|
123
|
-
$matchList = [regex]::Matches($Prompt, $pattern)
|
|
124
|
-
if ($matchList.Count -eq 0) {
|
|
125
|
-
return $null
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
$unique = @{}
|
|
129
|
-
foreach ($m in $matchList) {
|
|
130
|
-
$normalized = ($m.Value -replace '\\', '/').TrimEnd('/')
|
|
131
|
-
$unique[$normalized] = $true
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
$candidates = @(@($unique.Keys) | Sort-Object -Property Length -Descending)
|
|
135
|
-
$best = $candidates[0]
|
|
136
|
-
|
|
137
|
-
if ($best -match '\.md$') {
|
|
138
|
-
$best = $best -replace '/[^/]+\.md$', ''
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return ($best -split '/')[-1]
|
|
132
|
+
return [string[]]@(Find-FeatureFolderCandidate -Text $Prompt)
|
|
142
133
|
}
|
|
143
134
|
|
|
144
135
|
function Find-EpicWaveBarrierFeatureRecord {
|
|
145
136
|
<#
|
|
146
137
|
.SYNOPSIS
|
|
147
|
-
Locate the features[] record
|
|
138
|
+
Locate the features[] record the target basename identifies, through the shared
|
|
139
|
+
union index (Find-FeatureFolderRecord). A lifecycle-prefixed feature_folder value
|
|
140
|
+
such as active/<folder> matches its basename; zero or several matches return $null.
|
|
148
141
|
.PARAMETER Checkpoint
|
|
149
142
|
Parsed epic checkpoint, or $null when absent/unreadable.
|
|
150
143
|
.PARAMETER FeatureFolder
|
|
@@ -169,17 +162,7 @@ function Find-EpicWaveBarrierFeatureRecord {
|
|
|
169
162
|
return $null
|
|
170
163
|
}
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
foreach ($feature in @($Checkpoint.features)) {
|
|
174
|
-
$featureProps = @($feature.PSObject.Properties.Name)
|
|
175
|
-
if ($featureProps -notcontains 'feature_folder') {
|
|
176
|
-
continue
|
|
177
|
-
}
|
|
178
|
-
if (([string]$feature.feature_folder) -eq $FeatureFolder) {
|
|
179
|
-
return $feature
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return $null
|
|
165
|
+
return Find-FeatureFolderRecord -Records @($Checkpoint.features) -Reference $FeatureFolder
|
|
183
166
|
}
|
|
184
167
|
|
|
185
168
|
function Test-EpicWaveBarrierDependenciesMerged {
|
|
@@ -219,9 +202,11 @@ function Test-EpicWaveBarrierDependenciesMerged {
|
|
|
219
202
|
}
|
|
220
203
|
|
|
221
204
|
# Every dependency edge must be durably confirmed merged or worktree_removed before
|
|
222
|
-
# this wave's feature is allowed to start.
|
|
223
|
-
|
|
224
|
-
|
|
205
|
+
# this wave's feature is allowed to start. Each raw entry resolves through the union
|
|
206
|
+
# index, so an issue-number edge matches issue_num (issue #565).
|
|
207
|
+
$features = if (@($Checkpoint.PSObject.Properties.Name) -contains 'features') { @($Checkpoint.features) } else { @() }
|
|
208
|
+
foreach ($dependency in $dependsOn) {
|
|
209
|
+
$dependencyRecord = Find-FeatureFolderRecord -Records $features -Reference $dependency
|
|
225
210
|
if ($null -eq $dependencyRecord) {
|
|
226
211
|
return $false
|
|
227
212
|
}
|
|
@@ -280,11 +265,13 @@ function Invoke-EpicWaveBarrierDecision {
|
|
|
280
265
|
param(
|
|
281
266
|
[string] $ToolInputRaw
|
|
282
267
|
)
|
|
268
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'EPIC_WAVE_BARRIER_BLOCKED:'
|
|
269
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
283
270
|
|
|
284
|
-
# A failed
|
|
271
|
+
# A failed dependency import denies before any other logic (issue #565).
|
|
285
272
|
if ($script:EpicWaveBarrierResolutionImportFailure) {
|
|
286
273
|
return Get-EpicWaveBarrierBlockDecision -Reason (
|
|
287
|
-
"EPIC_WAVE_BARRIER_BLOCKED: the
|
|
274
|
+
"EPIC_WAVE_BARRIER_BLOCKED: the dependency '$($script:EpicWaveBarrierResolutionImportFailure)' " +
|
|
288
275
|
'failed to import, so the epic checkpoint that governs this delegation cannot be located; the gate fails closed.')
|
|
289
276
|
}
|
|
290
277
|
|
|
@@ -312,8 +299,8 @@ function Invoke-EpicWaveBarrierDecision {
|
|
|
312
299
|
return Get-EpicWaveBarrierBlockDecision -Reason "EPIC_WAVE_BARRIER_BLOCKED: $($target.ReasonCode): $($target.Detail)"
|
|
313
300
|
}
|
|
314
301
|
|
|
315
|
-
$
|
|
316
|
-
if (-
|
|
302
|
+
$candidates = @(Find-EpicWaveBarrierFeatureFolderFromPrompt -Prompt $prompt)
|
|
303
|
+
if ($candidates.Count -eq 0) {
|
|
317
304
|
return Get-EpicWaveBarrierBlockDecision -Reason 'EPIC_WAVE_BARRIER_BLOCKED: an epic-mode orchestrator delegation must reference the target feature folder in the prompt so its dependency edges can be verified.'
|
|
318
305
|
}
|
|
319
306
|
|
|
@@ -327,6 +314,15 @@ function Invoke-EpicWaveBarrierDecision {
|
|
|
327
314
|
}
|
|
328
315
|
}
|
|
329
316
|
|
|
317
|
+
# The target is selected among the cited candidates (issue #565): a cited upstream
|
|
318
|
+
# dependency of another candidate is pruned, and an unresolved tie denies.
|
|
319
|
+
$records = if ($null -ne $checkpoint -and @($checkpoint.PSObject.Properties.Name) -contains 'features') { @($checkpoint.features) } else { @() }
|
|
320
|
+
$selection = Select-FeatureFolderTarget -Records $records -Candidate $candidates -DependencyAware
|
|
321
|
+
if ($selection.Status -eq 'Ambiguous') {
|
|
322
|
+
return Get-EpicWaveBarrierBlockDecision -Reason "EPIC_WAVE_BARRIER_BLOCKED: $($selection.Detail)."
|
|
323
|
+
}
|
|
324
|
+
$featureFolder = $selection.Basename
|
|
325
|
+
|
|
330
326
|
$featureRecord = Find-EpicWaveBarrierFeatureRecord -Checkpoint $checkpoint -FeatureFolder $featureFolder
|
|
331
327
|
if (Test-EpicWaveBarrierDependenciesMerged -Checkpoint $checkpoint -FeatureRecord $featureRecord) {
|
|
332
328
|
return Get-EpicWaveBarrierAllowDecision
|
|
@@ -377,5 +373,8 @@ function Invoke-EpicWaveBarrierEntryPoint {
|
|
|
377
373
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
378
374
|
return
|
|
379
375
|
}
|
|
376
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('EPIC_WAVE_BARRIER_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
377
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'EPIC_WAVE_BARRIER_BLOCKED:'
|
|
378
|
+
if ($null -ne $dependencyDecision) { $dependencyDecision | ConvertTo-Json -Compress -Depth 5 | Write-Output; exit 0 }
|
|
380
379
|
|
|
381
380
|
exit (Invoke-EpicWaveBarrierEntryPoint)
|