@danmoisan/drm-copilot-mcp 1.1.25 → 1.1.27
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 +170 -52
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +3 -3
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +2 -2
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +7 -7
- package/resources/claude-customizations/.claude/agents/feature-review.md +6 -3
- package/resources/claude-customizations/.claude/agents/orchestrator.md +11 -7
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +7 -3
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +6 -2
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +7 -7
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +6 -6
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-review.ps1 +699 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +16 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +41 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-cleanup.ps1 +481 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +3 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier-helpers.ps1 +69 -3
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +2 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.cleanup.ps1 +246 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +1 -0
- package/resources/claude-customizations/.claude/hooks/hook-cleanup-context.ps1 +343 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +50 -16
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -1
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +4 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +51 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +5 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +116 -4
- package/resources/claude-customizations/.claude/lib/parallel-admission/Invoke-ParallelAdmission.ps1 +626 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmission.psm1 +508 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmissionJson.psm1 +141 -0
- package/resources/claude-customizations/.claude/lib/parallel-admission/ParallelAdmissionPrecedence.psm1 +508 -0
- package/resources/claude-customizations/.claude/rules/csharp.md +8 -8
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +28 -2
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +17 -1
- package/resources/claude-customizations/.claude/rules/powershell.md +2 -2
- package/resources/claude-customizations/.claude/settings.json +1 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +9 -13
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +93 -14
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +23 -10
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +54 -46
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_merge_lib.sh +234 -0
- package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +14 -15
- package/resources/claude-customizations/.claude/skills/epic-progress-report/SKILL.md +338 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Logic.ps1 +248 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Metrics.ps1 +232 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Render.ps1 +196 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.State.ps1 +286 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 +475 -0
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +31 -16
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +21 -9
- package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +5 -5
- package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/invoke-python-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +24 -2
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +71 -7
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +34 -2
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +82 -12
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +16 -17
- package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +15 -16
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +1 -1
- package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +6 -6
- package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/pack-manifests/core.json +15 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +8 -12
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +31 -16
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +5 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +18 -5
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +24 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +16 -1
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +15 -16
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +14 -15
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-di-unit-test-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/pytest-unit-test-coding.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-execution-only-typed.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate-review.ps1 +699 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +29 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-cleanup.ps1 +481 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +4 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-cleanup-context.ps1 +343 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +51 -4
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +3 -0
- package/resources/customizations/.github/agents/5.1-Beast-adjusted.agent.md +1 -1
- package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +20 -26
- package/resources/customizations/.github/agents/atomic_executor.agent.md +4 -4
- package/resources/customizations/.github/agents/atomic_planning.agent.md +4 -4
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
- package/resources/customizations/.github/agents/commit-steward.agent.md +1 -1
- package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +14 -14
- package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +4 -4
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +19 -22
- package/resources/customizations/.github/agents/epic-review.agent.md +1 -1
- package/resources/customizations/.github/agents/gpt-5-beast-mode.agent.md +3 -3
- package/resources/customizations/.github/agents/orchestrator.agent.md +8 -8
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +12 -12
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +4 -4
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -6
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +21 -24
- package/resources/customizations/.github/agents/pytest-unit-test-coding.agent.md +13 -17
- package/resources/customizations/.github/agents/python-atomic-executor.agent.md +11 -11
- package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +14 -17
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +7 -7
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +17 -20
- package/resources/customizations/.github/agents/staged-review.agent.md +2 -2
- package/resources/customizations/.github/agents/tdd-green.agent.md +1 -1
- package/resources/customizations/.github/agents/tdd-red.agent.md +3 -3
- package/resources/customizations/.github/agents/tdd-refactor.agent.md +2 -2
- package/resources/customizations/.github/agents/typescript-engineer.agent.md +3 -3
- package/resources/customizations/.github/codex/execute-hard-lock.prompt.md +3 -3
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +1 -1
- package/resources/customizations/.github/instructions/powershell-unit-test.instructions.md +1 -1
- package/resources/customizations/.github/instructions/python-code-change.instructions.md +5 -5
- package/resources/customizations/.github/instructions/python-suppressions.instructions.md +3 -3
- package/resources/customizations/.github/instructions/python-unit-test.instructions.md +1 -1
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +2 -2
- package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +2 -2
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +2 -2
- package/resources/customizations/.github/prompts/review-feature.prompt.md +1 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +8 -12
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +31 -16
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +15 -2
- package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +4 -4
- package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +3 -3
- package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +2 -2
- package/resources/powershell/PoshQC/PoshQC.ScanConfig.psm1 +3 -1
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +14 -12
- package/resources/powershell/PoshQC/PoshQC.psm1 +3 -3
- package/resources/powershell/PoshQC/README.md +8 -8
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -2
- package/resources/templates/policy_audit/AGENTS.md +9 -10
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +19 -20
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cleanup_worktrees_preserve_merge_lib.sh: sourceable staging-decision function group for
|
|
3
|
+
# the preserve pass of the cleanup-worktrees tool. For each preserve record whose target
|
|
4
|
+
# already exists as a regular file on the consolidation branch, it decides whether the
|
|
5
|
+
# source may be copied, whether a three-way union merge may be staged instead, or whether
|
|
6
|
+
# the record must be refused with ACTION|preserve-stage|<target-path>|REFUSED-WOULD-REGRESS.
|
|
7
|
+
#
|
|
8
|
+
# Sourcing contract: this library defines functions only and runs no work at source time.
|
|
9
|
+
# It MUST be sourced before cleanup_worktrees_preserve_lib.sh, whose preserve_plan_one calls
|
|
10
|
+
# preserve_merge_check_duplicate and preserve_merge_decide. Its own git calls go through
|
|
11
|
+
# cleanup_wt_git, defined in cleanup_worktrees_enumerate_lib.sh.
|
|
12
|
+
#
|
|
13
|
+
# Phase-1 write exception. The preserve planning phase writes no index, ref, or working-tree
|
|
14
|
+
# file. The one write it performs is the creation of unreferenced blob objects in the object
|
|
15
|
+
# store: `git hash-object -w` hashes the two merge inputs and `git merge-file --object-id`
|
|
16
|
+
# records the merged result. Nothing refers to those blobs unless the writing phase stages
|
|
17
|
+
# the merged result, and an unreferenced blob is removed by the normal object pruning.
|
|
18
|
+
#
|
|
19
|
+
# Line-comparison rule. Every guard compares lines. Content is split with the
|
|
20
|
+
# `while IFS= read -r line || [[ -n $line ]]` idiom, so an unterminated final line counts as
|
|
21
|
+
# a line, and one trailing carriage return is stripped from each line before comparison, so
|
|
22
|
+
# a CRLF working-tree file and its LF-normalized blob compare equal.
|
|
23
|
+
#
|
|
24
|
+
# No git call in this library passes -f or --force, and no process substitution is passed
|
|
25
|
+
# to git as a file argument: native git on Windows cannot open an MSYS /dev/fd path.
|
|
26
|
+
|
|
27
|
+
preserve_merge_split_lines() {
|
|
28
|
+
# Split one content string into the global array PRESERVE_MERGE_LINES under the
|
|
29
|
+
# line-comparison rule stated in the header. An empty string yields no line at all.
|
|
30
|
+
#
|
|
31
|
+
# Args: $1 = the content.
|
|
32
|
+
PRESERVE_MERGE_LINES=()
|
|
33
|
+
# The carriage return is held in a variable: ANSI-C quoting nested inside a
|
|
34
|
+
# double-quoted expansion is not interpreted consistently across bash versions.
|
|
35
|
+
local line cr=$'\r'
|
|
36
|
+
while IFS= read -r line || [[ -n $line ]]; do
|
|
37
|
+
PRESERVE_MERGE_LINES+=("${line%"$cr"}")
|
|
38
|
+
done < <(printf '%s' "${1-}")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
preserve_merge_is_subsequence() {
|
|
42
|
+
# Return 0 when every line of the needle appears in the haystack in the same order, not
|
|
43
|
+
# necessarily adjacent, and 1 otherwise. An empty needle is a subsequence of anything.
|
|
44
|
+
#
|
|
45
|
+
# Args: $1 = needle content, $2 = haystack content.
|
|
46
|
+
local -a needle=() hay=()
|
|
47
|
+
preserve_merge_split_lines "${1-}"
|
|
48
|
+
needle=("${PRESERVE_MERGE_LINES[@]}")
|
|
49
|
+
preserve_merge_split_lines "${2-}"
|
|
50
|
+
hay=("${PRESERVE_MERGE_LINES[@]}")
|
|
51
|
+
local n=${#needle[@]} i=0 line
|
|
52
|
+
if ((n == 0)); then
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
for line in "${hay[@]}"; do
|
|
56
|
+
if [[ $line == "${needle[$i]}" ]]; then
|
|
57
|
+
i=$((i + 1))
|
|
58
|
+
if ((i == n)); then
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
done
|
|
63
|
+
return 1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
preserve_merge_extra_within() {
|
|
67
|
+
# Guard G3. Return 0 when multiset(merged) minus multiset(main) is contained in
|
|
68
|
+
# multiset(worktree) minus multiset(base), and 1 otherwise. A merged line that main does
|
|
69
|
+
# not carry is admitted only as one of the worktree's own additions, so a base line that
|
|
70
|
+
# main deleted and the merge re-emitted is refused. Counts are kept per line, so a line
|
|
71
|
+
# the worktree added once may appear at most once beyond main's own copies.
|
|
72
|
+
#
|
|
73
|
+
# Keys carry a fixed prefix because bash refuses an empty associative-array subscript,
|
|
74
|
+
# and a blank line is an ordinary line.
|
|
75
|
+
#
|
|
76
|
+
# Args: $1 = merged content, $2 = main content, $3 = worktree content, $4 = base content.
|
|
77
|
+
local -A extra=() added=()
|
|
78
|
+
local line key
|
|
79
|
+
preserve_merge_split_lines "${1-}"
|
|
80
|
+
for line in "${PRESERVE_MERGE_LINES[@]}"; do
|
|
81
|
+
key="k$line"
|
|
82
|
+
extra["$key"]=$((${extra["$key"]:-0} + 1))
|
|
83
|
+
done
|
|
84
|
+
preserve_merge_split_lines "${2-}"
|
|
85
|
+
for line in "${PRESERVE_MERGE_LINES[@]}"; do
|
|
86
|
+
key="k$line"
|
|
87
|
+
extra["$key"]=$((${extra["$key"]:-0} - 1))
|
|
88
|
+
done
|
|
89
|
+
preserve_merge_split_lines "${3-}"
|
|
90
|
+
for line in "${PRESERVE_MERGE_LINES[@]}"; do
|
|
91
|
+
key="k$line"
|
|
92
|
+
added["$key"]=$((${added["$key"]:-0} + 1))
|
|
93
|
+
done
|
|
94
|
+
preserve_merge_split_lines "${4-}"
|
|
95
|
+
for line in "${PRESERVE_MERGE_LINES[@]}"; do
|
|
96
|
+
key="k$line"
|
|
97
|
+
added["$key"]=$((${added["$key"]:-0} - 1))
|
|
98
|
+
done
|
|
99
|
+
for key in "${!extra[@]}"; do
|
|
100
|
+
if ((${extra["$key"]} > ${added["$key"]:-0} && ${extra["$key"]} > 0)); then
|
|
101
|
+
return 1
|
|
102
|
+
fi
|
|
103
|
+
done
|
|
104
|
+
return 0
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
preserve_merge_refuse() {
|
|
108
|
+
# Refuse one record: emit ACTION|preserve-stage|<target-path>|REFUSED-WOULD-REGRESS on
|
|
109
|
+
# stdout, a `cleanup-worktrees: refused` diagnostic naming the reason on stderr, set
|
|
110
|
+
# PRESERVE_EXIT to 1, and return 1. A refusal is not a hard stop: the remaining records
|
|
111
|
+
# are still planned and the pass exits 1.
|
|
112
|
+
#
|
|
113
|
+
# Args: $1 = target_path, $2 = the reason, which begins with the failed guard's token.
|
|
114
|
+
printf 'ACTION|preserve-stage|%s|REFUSED-WOULD-REGRESS\n' "${1-}"
|
|
115
|
+
printf 'cleanup-worktrees: refused %s: %s\n' "${1-}" "${2-}" >&2
|
|
116
|
+
# Read by preserve_plan and run_preserve across a source boundary shellcheck does not
|
|
117
|
+
# follow, so SC2034 reports it unused here; the suppression is line-scoped.
|
|
118
|
+
# shellcheck disable=SC2034
|
|
119
|
+
PRESERVE_EXIT=1
|
|
120
|
+
return 1
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
preserve_merge_check_duplicate() {
|
|
124
|
+
# Refuse a record whose target_path an earlier record of the same pass already named. A
|
|
125
|
+
# target counts as seen as soon as a record reaches this check, whatever that record's
|
|
126
|
+
# later outcome, so the first record keeps the target and every later one is refused.
|
|
127
|
+
# The seen set is the newline-delimited global PRESERVE_SEEN_TARGETS, which preserve_plan
|
|
128
|
+
# resets at the start of every pass.
|
|
129
|
+
#
|
|
130
|
+
# Args: $1 = target_path. Returns 0 when the target is new, 1 when it was refused.
|
|
131
|
+
local tgt=${1-}
|
|
132
|
+
local seen=${PRESERVE_SEEN_TARGETS:-$'\n'}
|
|
133
|
+
if [[ $seen == *$'\n'"$tgt"$'\n'* ]]; then
|
|
134
|
+
preserve_merge_refuse "$tgt" "duplicate-target: an earlier record in this pass names the same target_path"
|
|
135
|
+
return 1
|
|
136
|
+
fi
|
|
137
|
+
PRESERVE_SEEN_TARGETS="$seen$tgt"$'\n'
|
|
138
|
+
return 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
preserve_merge_resolve_base() {
|
|
142
|
+
# Echo the blob id of the source file at the merge base of the worktree HEAD and the
|
|
143
|
+
# consolidation HEAD, or return 1 when no base is available. The base is unavailable
|
|
144
|
+
# when source_path differs from target_path (no git call is made in that case), when
|
|
145
|
+
# the worktree HEAD does not resolve, when the two HEADs have no merge base, or when the
|
|
146
|
+
# file is absent at the merge base. An empty answer from git counts as unavailable.
|
|
147
|
+
#
|
|
148
|
+
# Args: $1 = worktree path, $2 = source_path, $3 = target_path, $4 = consolidation path.
|
|
149
|
+
local wt=${1-} src=${2-} tgt=${3-} cwt=${4-} head="" mb="" oid=""
|
|
150
|
+
if [[ $src != "$tgt" ]]; then
|
|
151
|
+
return 1
|
|
152
|
+
fi
|
|
153
|
+
head=$(cleanup_wt_git -C "$wt" rev-parse --verify --quiet HEAD) || return 1
|
|
154
|
+
[[ -n $head ]] || return 1
|
|
155
|
+
mb=$(cleanup_wt_git -C "$cwt" merge-base "$head" HEAD) || return 1
|
|
156
|
+
[[ -n $mb ]] || return 1
|
|
157
|
+
oid=$(cleanup_wt_git -C "$cwt" rev-parse --verify --quiet "$mb:$src") || return 1
|
|
158
|
+
[[ -n $oid ]] || return 1
|
|
159
|
+
printf '%s\n' "$oid"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
preserve_merge_guard_b() {
|
|
163
|
+
# Guard (b), the fallback when no merge base is available: admit a whole-file copy only
|
|
164
|
+
# when main's version is a line-subsequence of the source, so no main line is lost.
|
|
165
|
+
#
|
|
166
|
+
# Args: $1 = target_path, $2 = main content, $3 = source content.
|
|
167
|
+
if preserve_merge_is_subsequence "${2-}" "${3-}"; then
|
|
168
|
+
PRESERVE_STAGE_MODE="copy"
|
|
169
|
+
return 0
|
|
170
|
+
fi
|
|
171
|
+
preserve_merge_refuse "${1-}" "guard-b: the target holds lines the source lacks"
|
|
172
|
+
return 1
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# PRESERVE_STAGE_MODE and PRESERVE_STAGE_OID are read by preserve_plan_one across a source
|
|
176
|
+
# boundary shellcheck does not follow, so SC2034 reports them unused; the suppression is
|
|
177
|
+
# scoped to this one function.
|
|
178
|
+
# shellcheck disable=SC2034
|
|
179
|
+
preserve_merge_decide() {
|
|
180
|
+
# Decide how one record is staged. Sets PRESERVE_STAGE_MODE to `copy` or `merge` and
|
|
181
|
+
# PRESERVE_STAGE_OID to the merged blob id (empty for `copy`), or refuses the record.
|
|
182
|
+
#
|
|
183
|
+
# - target not a regular file: `copy`, with no git call at all;
|
|
184
|
+
# - `untracked` record, or `modified` record with no merge base: guard (b);
|
|
185
|
+
# - `modified` record with a merge base: G1 (the worktree change is insertion-only),
|
|
186
|
+
# then a `git merge-file --union --object-id` merge, then G2 (every main line
|
|
187
|
+
# survives) and G3 (no line beyond the worktree's own additions); `merge` on success.
|
|
188
|
+
#
|
|
189
|
+
# The source and target are read with plain file I/O. The base and merged contents are
|
|
190
|
+
# read from the object store with `cat-file blob`.
|
|
191
|
+
#
|
|
192
|
+
# Args: $1 = change_class, $2 = worktree path, $3 = source_path, $4 = target_path,
|
|
193
|
+
# $5 = consolidation path. Returns 0 when the record may be staged, 1 when it was refused.
|
|
194
|
+
local cls=${1-} wt=${2-} src=${3-} tgt=${4-} cwt=${5-}
|
|
195
|
+
PRESERVE_STAGE_MODE="copy"
|
|
196
|
+
PRESERVE_STAGE_OID=""
|
|
197
|
+
if [[ ! -f "$cwt/$tgt" ]]; then
|
|
198
|
+
return 0
|
|
199
|
+
fi
|
|
200
|
+
local main_c wt_c base_oid base_c main_oid wt_oid merged_oid merged_c mrc=0
|
|
201
|
+
main_c=$(<"$cwt/$tgt")
|
|
202
|
+
wt_c=$(<"$wt/$src")
|
|
203
|
+
if [[ $cls == "untracked" ]] || ! base_oid=$(preserve_merge_resolve_base "$wt" "$src" "$tgt" "$cwt"); then
|
|
204
|
+
preserve_merge_guard_b "$tgt" "$main_c" "$wt_c"
|
|
205
|
+
return
|
|
206
|
+
fi
|
|
207
|
+
base_c=$(cleanup_wt_git -C "$cwt" cat-file blob "$base_oid") ||
|
|
208
|
+
{ preserve_merge_refuse "$tgt" "G1: the base blob could not be read" || return 1; }
|
|
209
|
+
if ! preserve_merge_is_subsequence "$base_c" "$wt_c"; then
|
|
210
|
+
preserve_merge_refuse "$tgt" "G1: the worktree removed or changed a base line"
|
|
211
|
+
return 1
|
|
212
|
+
fi
|
|
213
|
+
main_oid=$(cleanup_wt_git -C "$cwt" hash-object -w --path="$tgt" -- "$tgt") || main_oid=""
|
|
214
|
+
wt_oid=$(cleanup_wt_git -C "$wt" hash-object -w --path="$tgt" -- "$src") || wt_oid=""
|
|
215
|
+
merged_oid=$(cleanup_wt_git -C "$cwt" merge-file --union --object-id "$main_oid" "$base_oid" "$wt_oid") || mrc=$?
|
|
216
|
+
if ((mrc != 0)) || [[ -z $main_oid || -z $wt_oid || -z $merged_oid ]]; then
|
|
217
|
+
preserve_merge_refuse "$tgt" "merge-file rc=$mrc: no merged blob was produced"
|
|
218
|
+
return 1
|
|
219
|
+
fi
|
|
220
|
+
merged_c=$(cleanup_wt_git -C "$cwt" cat-file blob "$merged_oid") ||
|
|
221
|
+
{ preserve_merge_refuse "$tgt" "G2: the merged blob could not be read" || return 1; }
|
|
222
|
+
if ! preserve_merge_is_subsequence "$main_c" "$merged_c"; then
|
|
223
|
+
preserve_merge_refuse "$tgt" "G2: the merged result lost a main line"
|
|
224
|
+
return 1
|
|
225
|
+
fi
|
|
226
|
+
if ! preserve_merge_extra_within "$merged_c" "$main_c" "$wt_c" "$base_c"; then
|
|
227
|
+
preserve_merge_refuse "$tgt" "G3: the merged result carries a line the worktree did not add"
|
|
228
|
+
return 1
|
|
229
|
+
fi
|
|
230
|
+
PRESERVE_STAGE_MODE="merge"
|
|
231
|
+
PRESERVE_STAGE_OID=$merged_oid
|
|
232
|
+
printf 'cleanup-worktrees: merged %s\n' "$tgt" >&2
|
|
233
|
+
return 0
|
|
234
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: csharp-qa-gate
|
|
3
|
-
description: Final QA gate for C# changes. Executes the full CSharpier -> .NET Analyzers -> Nullable Analysis ->
|
|
3
|
+
description: Final QA gate for C# changes. Executes the full CSharpier -> .NET Analyzers -> Nullable Analysis -> MSTest toolchain (with architecture tests), compares static tool results against the static baseline, reads test and coverage results from the single gate run, and produces the required reporting block before the agent declares the change complete.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# C# QA Gate
|
|
@@ -12,14 +12,14 @@ Canonical procedure for the Phase D final quality gate that every C# change must
|
|
|
12
12
|
Use this skill when:
|
|
13
13
|
|
|
14
14
|
- `csharp-typed-engineer` is about to declare a change complete.
|
|
15
|
-
- An executor has finished applying a planned batch and must verify
|
|
15
|
+
- An executor has finished applying a planned batch and must verify the static tools against the static baseline recorded in Phase A, and the tests in the single gate run.
|
|
16
16
|
- A reviewer needs to confirm the toolchain was actually run and produced a clean pass.
|
|
17
17
|
|
|
18
18
|
## Required Inputs
|
|
19
19
|
|
|
20
20
|
Before invoking this gate, the agent must have:
|
|
21
21
|
|
|
22
|
-
- a baseline record produced in Phase A, containing analyzer findings
|
|
22
|
+
- a static baseline record produced in Phase A, containing analyzer findings and compiler/nullable diagnostics for the in-scope files,
|
|
23
23
|
- the exact list of touched production and test files,
|
|
24
24
|
- a clean working tree (all planned edits committed to the working copy).
|
|
25
25
|
|
|
@@ -48,36 +48,35 @@ Analyzer settings (`AnalysisLevel`, `AnalysisMode`, `TreatWarningsAsErrors`, `Nu
|
|
|
48
48
|
|
|
49
49
|
If the environment prevents running any tool, stop and report the change as **unverified**. Do not declare completion.
|
|
50
50
|
|
|
51
|
-
##
|
|
51
|
+
## Gate Requirements (Hard Gate)
|
|
52
52
|
|
|
53
|
-
Compare the final results to the Phase A
|
|
53
|
+
Compare the final static tool results to the static baseline recorded in Phase A, and read test and coverage results from the single gate run. All of the following must hold:
|
|
54
54
|
|
|
55
55
|
- **Analyzer delta**: 0 new findings across the repository.
|
|
56
56
|
- **Compiler / nullable delta**: 0 new diagnostics across the repository.
|
|
57
|
-
- **
|
|
58
|
-
- **Architecture
|
|
59
|
-
- **Per-file coverage
|
|
60
|
-
- **Overall coverage delta** (when the repo enforces it): overall coverage is greater than or equal to the baseline.
|
|
57
|
+
- **MSTest gate**: zero failures in the single gate run.
|
|
58
|
+
- **Architecture tests**: zero failures in the `*.ArchitectureTests` project.
|
|
59
|
+
- **Per-file coverage**: every changed file meets the coverage thresholds, read from the single gate run, and new behavior is tested.
|
|
61
60
|
- **New modules, classes, or methods**: coverage >= 90% for each new unit introduced in the batch.
|
|
62
61
|
|
|
63
|
-
If any
|
|
62
|
+
If any check fails, the agent must revert or fix immediately and rerun the full toolchain. Do not proceed to reporting until all checks are clean.
|
|
64
63
|
|
|
65
64
|
## Required Reporting Block
|
|
66
65
|
|
|
67
66
|
Every completion response must include the following sections:
|
|
68
67
|
|
|
69
68
|
1. **Scope** — exact file list touched in this change.
|
|
70
|
-
2. **Baseline** — analyzer
|
|
69
|
+
2. **Baseline** — analyzer and compiler/nullable findings recorded in Phase A.
|
|
71
70
|
3. **Plan** — design and test-strategy summary, referencing the approved plan.
|
|
72
71
|
4. **Diffs** — patch-style or full-file replacements for scoped files only.
|
|
73
|
-
5. **QA Gate Results** — analyzer
|
|
72
|
+
5. **QA Gate Results** — analyzer and compiler/nullable deltas, failures in the single gate run and the architecture tests, and per-file coverage against the thresholds. If any step could not be run, mark the corresponding line **unverified** and state why.
|
|
74
73
|
|
|
75
74
|
## Evidence Storage
|
|
76
75
|
|
|
77
76
|
Persist toolchain output according to `evidence-and-timestamp-conventions`:
|
|
78
77
|
|
|
79
|
-
- store baseline outputs under `<FEATURE>/evidence/baseline/<timestamp>/`,
|
|
80
|
-
- store
|
|
78
|
+
- store static baseline outputs under `<FEATURE>/evidence/baseline/<timestamp>/`,
|
|
79
|
+
- store final gate outputs under `<FEATURE>/evidence/qa-gates/<timestamp>/`,
|
|
81
80
|
- use ISO-8601 UTC timestamps in folder names.
|
|
82
81
|
|
|
83
82
|
This location is canonical per evidence-and-timestamp-conventions and is not overridable.
|
|
@@ -89,4 +88,4 @@ The evidence paths must be referenced in the agent's completion message to satis
|
|
|
89
88
|
|
|
90
89
|
- Do not disable, skip, or narrow any step of the toolchain to reach a clean result.
|
|
91
90
|
- Do not add analyzer suppressions, `#pragma warning disable`, `#nullable disable`, or test `[Ignore]` attributes to suppress new findings introduced by the change.
|
|
92
|
-
- Do not report success based on partial or targeted runs
|
|
91
|
+
- Do not report success based on partial or targeted runs. A focused run of one test file to debug a specific failure is debugging only; it is never a gate or evidence, and the final gate is the single gate run.
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: epic-progress-report
|
|
3
|
+
description: 'Post recurring epic progress reports from the coordinator session: a four-line TL;DR every 10 minutes and an hourly full status update with a push notification. Use when an epic is running and the owner wants scheduled progress, velocity, and time-remaining reports, or when the reports must be started, reset after a pause, moved to a new cadence, stopped, or recreated after a restart.'
|
|
4
|
+
argument-hint: "[epic-folder]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Glob
|
|
8
|
+
- "Bash(pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 *)"
|
|
9
|
+
- "Bash(cswap list*)"
|
|
10
|
+
- CronCreate
|
|
11
|
+
- CronList
|
|
12
|
+
- CronDelete
|
|
13
|
+
- PushNotification
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Epic Progress Report
|
|
17
|
+
|
|
18
|
+
This skill runs the epic progress report script and schedules two recurring reports in the
|
|
19
|
+
coordinator's main session: a four-line TL;DR and an hourly full status update. The script is
|
|
20
|
+
`.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1`. It reads the epic
|
|
21
|
+
kickoff, the feature plans, the epic checkpoint, the pull-request state, and the weekly quota,
|
|
22
|
+
prints the report, and keeps its samples and baseline in a state file.
|
|
23
|
+
|
|
24
|
+
## When to Use This Skill
|
|
25
|
+
|
|
26
|
+
- An epic is running and the owner wants scheduled progress reports.
|
|
27
|
+
- The reports must be started for an epic, or recreated after the session restarted.
|
|
28
|
+
- Work resumed after a pause or an outage and the velocity baseline must be reset.
|
|
29
|
+
- The TL;DR cadence changes (for example from 5 to 10 minutes).
|
|
30
|
+
- The epic is finished and the reports must be stopped.
|
|
31
|
+
|
|
32
|
+
## Prerequisites
|
|
33
|
+
|
|
34
|
+
- PowerShell 7 and `git`. `gh` and `cswap` are optional: without `gh` the pull-request state
|
|
35
|
+
is empty, and without `cswap` (or without parseable output) the weekly quota prints `n/a`.
|
|
36
|
+
- The epic kickoff at `docs/features/epics/<epic-folder>/epic-kickoff.md` on
|
|
37
|
+
`origin/epic/<epic-folder>-integration`, with a feature-summary table (header first cell
|
|
38
|
+
`issue_num` or `Issue`) and an `Epic issue: #<n>` line. Pass `-EpicIssue` when the line
|
|
39
|
+
is missing.
|
|
40
|
+
- The epic checkpoint `artifacts/orchestration/epic-orchestrator-state.json` under the
|
|
41
|
+
repository root (optional; without it every feature is classified from its plan and PR).
|
|
42
|
+
- Run from the repository root in the coordinator's main session. An agent-isolated worktree
|
|
43
|
+
refuses command text containing `pwsh`, and the scheduled jobs and notifications belong to
|
|
44
|
+
the main session.
|
|
45
|
+
|
|
46
|
+
## Inputs
|
|
47
|
+
|
|
48
|
+
| Parameter | Default | Meaning |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `-EpicFolder` | (mandatory) | Epic folder name under `docs/features/epics/`; also the epic name in the status heading. |
|
|
51
|
+
| `-StartUtc` | stored start | Start of the measurement. Resolution: the passed value, else now with `-ResetBaseline`, else the stored start. With none of these the script stops before any git call with an error naming `-StartUtc` and `-ResetBaseline`. |
|
|
52
|
+
| `-BaselineDone` | stored value, else 0 | Tasks already complete at the start. With `-ResetBaseline` and no passed value, the current done count. |
|
|
53
|
+
| `-BaselineWeeklyPct` | stored value, else 0 | Weekly quota percentage at the start. `-ResetBaseline` does not change it. |
|
|
54
|
+
| `-EpicIssue` | the kickoff's `Epic issue: #<n>` line | Epic issue number printed in the report. |
|
|
55
|
+
| `-IntegrationBranch` | `origin/epic/<epic-folder>-integration` | Branch that holds the kickoff and the plans. |
|
|
56
|
+
| `-KickoffPath` | `docs/features/epics/<epic-folder>/epic-kickoff.md` | Kickoff path on the integration branch. |
|
|
57
|
+
| `-RepositoryRoot` | current location | Repository root in which git runs. |
|
|
58
|
+
| `-CheckpointPath` | `artifacts/orchestration/epic-orchestrator-state.json` | Epic checkpoint under the repository root. |
|
|
59
|
+
| `-StatePath` | `.claude/state/epic-progress-<epic-folder>.json` | State file under the repository root; the directory is created when missing. |
|
|
60
|
+
| `-WaveOverheadHours` | 1.25 | Review and CI hours added per open wave. |
|
|
61
|
+
| `-SampleCap` | 14 | Maximum number of samples kept. |
|
|
62
|
+
| `-Mode` | `Full` | `TLDR` prints the four TL;DR lines; `Full` prints them followed by the full report. |
|
|
63
|
+
| `-ResetBaseline` | off | Discards the stored samples and restarts the baseline now (see the reset section). |
|
|
64
|
+
| `-PairSamples` | off | One-shot: pairs the stored samples for a cadence change (see the cadence section). Cannot be combined with `-ResetBaseline`. |
|
|
65
|
+
|
|
66
|
+
A passed `-StartUtc`, `-BaselineDone`, or `-BaselineWeeklyPct` overrides the stored value and
|
|
67
|
+
is persisted with the next state write.
|
|
68
|
+
|
|
69
|
+
## Report Formats
|
|
70
|
+
|
|
71
|
+
The wording, order, and punctuation below are the script's output and do not change. Values in
|
|
72
|
+
angle brackets are placeholders; the examples use the fictional epic folder `example-epic` and
|
|
73
|
+
epic issue `42`.
|
|
74
|
+
|
|
75
|
+
TL;DR (both modes print these four lines first):
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
**TL;DR:** Epic #<issue> is at <done> of <total> tasks (<pct>%). <done-sentence> <running-sentence>
|
|
79
|
+
**Elapsed:** <H h MM min>, with about <hours> hours left on the wave-parallel estimate. **Weekly** quota is at <weekly>.
|
|
80
|
+
**Avg Velocity:** <avg> tasks / hr. **Recent Velocity:** <recent> tasks / hr since last check-in. (SD of recent velocity: <sd>, from <n> intervals)
|
|
81
|
+
**Estimated time remaining:** <range>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Variants:
|
|
85
|
+
|
|
86
|
+
- done-sentence: `None of the <N> features is done yet.` or `<K> of <N> features are done.`
|
|
87
|
+
- running-sentence: `No feature is running.`, `#<i> is running (<d> of <t>).`, or
|
|
88
|
+
`#<a> (<d> of <t>), #<b> (<d> of <t>) are running.`
|
|
89
|
+
- range: `<HH:MM> hrs (range needs 3 or more check-in intervals)`, `<HH:MM> hrs to <HH:MM> hrs`,
|
|
90
|
+
or `<HH:MM> hrs to no upper bound (average velocity minus 2.05 SD is at or below 0.5 tasks / hr)`.
|
|
91
|
+
- `<pct>`, `<avg>`, `<recent>`, and `<sd>` are rounded to one decimal and `<hours>` to zero
|
|
92
|
+
decimals, with invariant culture and default (to-even) rounding; an integral value prints
|
|
93
|
+
without a decimal (`1`, not `1.0`). `<weekly>` is `<value>%` or `n/a`.
|
|
94
|
+
- Any non-finite value prints `n/a`; no report prints `NaN` or `Infinity`.
|
|
95
|
+
|
|
96
|
+
Example (fictional):
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
**TL;DR:** Epic #42 is at 3 of 10 tasks (30%). 1 of 3 features are done. #12345 is running (1 of 5).
|
|
100
|
+
**Elapsed:** 3 h 00 min, with about 10 hours left on the wave-parallel estimate. **Weekly** quota is at 42.5%.
|
|
101
|
+
**Avg Velocity:** 1 tasks / hr. **Recent Velocity:** 1 tasks / hr since last check-in. (SD of recent velocity: 0, from 3 intervals)
|
|
102
|
+
**Estimated time remaining:** 09:22 hrs to 09:39 hrs
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Full mode prints the TL;DR lines, then these lines:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
|
|
109
|
+
## Epic #<issue> <epic-folder>: status at <HH:mm> UTC, <MMM d>
|
|
110
|
+
|
|
111
|
+
**Elapsed:** <H h MM min> since <HH:mm> UTC. **Progress:** <done> of <total> tasks complete, **<pct>%**.
|
|
112
|
+
|
|
113
|
+
| State | Features |
|
|
114
|
+
|---|---|
|
|
115
|
+
| Completed | <completed> |
|
|
116
|
+
| Running | #<i> (wave <w>, <band>): <d> of <t> tasks (<share>%).<phase><pr> |
|
|
117
|
+
| Pending, wave <w> | #<i> (<t>), #<j> (<t>) |
|
|
118
|
+
|
|
119
|
+
| Wave | Children | Tasks | Done |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| <w> | <count> | <tasks> | <done> |
|
|
122
|
+
| **Total** | **<features>** | **<total>** | **<done>** |
|
|
123
|
+
|
|
124
|
+
**Velocity:** <avg> tasks per hour (one child's pace). **Remaining:** <remaining> tasks.
|
|
125
|
+
- Straight line, no parallelism: about <H h MM min> (upper bound).
|
|
126
|
+
- Wave-parallel (longest chain <tasks> tasks plus about <overhead> h per open wave for review and CI): about **<H h MM min>**.
|
|
127
|
+
**Weekly quota (active account):** <weekly> used, <delta> points since the epic started. This pool also covers the other runs in this session, so it is not the epic's cost alone.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Full report contents:
|
|
131
|
+
|
|
132
|
+
- `<completed>` is `None yet` or the completed issues as `#<i>` joined with `, `.
|
|
133
|
+
- One `Running` row per running feature. `<phase>` is ` Now at: <phase>.` when a current
|
|
134
|
+
phase exists, else empty; `<pr>` is ` PR <state>.` when a pull request exists, else empty;
|
|
135
|
+
`<share>` is the feature percentage rounded to zero decimals.
|
|
136
|
+
- One `Pending, wave <w>` row per wave that holds pending features, in ascending wave order.
|
|
137
|
+
- One Wave-table row per wave in ascending order, then the bold Total row.
|
|
138
|
+
- `<overhead>` is `-WaveOverheadHours` unrounded. `<delta>` is the weekly percentage minus
|
|
139
|
+
the weekly baseline, with a leading `+` when it is finite and not negative, else `n/a`.
|
|
140
|
+
- Times use invariant culture and UTC.
|
|
141
|
+
|
|
142
|
+
## Calculation Rules
|
|
143
|
+
|
|
144
|
+
- Task counts: plan checkboxes `- [ ] [P#-T#]` and `- [x] [P#-T#]` of each feature, read from
|
|
145
|
+
the feature's worktree when its branch has one, otherwise from the plan on the integration
|
|
146
|
+
branch. The feature list, waves, bands, and plan paths come from the kickoff's
|
|
147
|
+
feature-summary table.
|
|
148
|
+
- Feature state: Completed when the checkpoint's `merge_status` is `merged` or
|
|
149
|
+
`worktree_removed`, or the feature PR is merged; Running when any task is done, the
|
|
150
|
+
checkpoint status is past `not_started`, or a PR exists; otherwise Pending.
|
|
151
|
+
- Elapsed: from the start instant to now, clamped at 0; printed as `H h MM min` from rounded
|
|
152
|
+
total minutes.
|
|
153
|
+
- Average velocity: (done now - baseline done) / elapsed hours; 0 when elapsed is not above 0.
|
|
154
|
+
- Straight-line estimate: remaining tasks / average velocity; `n/a` when the average is not
|
|
155
|
+
above 0.
|
|
156
|
+
- Wave-parallel estimate: the sum, over every wave with a non-completed feature, of the largest
|
|
157
|
+
remaining task count among that wave's non-completed features, divided by the average
|
|
158
|
+
velocity, plus `-WaveOverheadHours` (default 1.25 hours) per open wave; `n/a` when the
|
|
159
|
+
average is not above 0.
|
|
160
|
+
- Samples: a check-in sample (Unix epoch seconds, done count) is added when there is no
|
|
161
|
+
previous sample or the previous one is at least 90 seconds old; the newest `-SampleCap`
|
|
162
|
+
(default 14) samples are kept. Epoch seconds are used because `ConvertFrom-Json` converts ISO
|
|
163
|
+
date strings into local-time values.
|
|
164
|
+
- Interval velocity: max(0, change in done) / change in hours, for consecutive samples at
|
|
165
|
+
least 2 minutes apart; closer pairs are skipped.
|
|
166
|
+
- Recent velocity: the latest interval's value; `n/a` without intervals.
|
|
167
|
+
- SD: the sample standard deviation (n-1 denominator) of the interval velocities; `n/a` below
|
|
168
|
+
3 intervals. The report prints the interval count.
|
|
169
|
+
- Range: below 3 intervals, the wave-parallel estimate followed by
|
|
170
|
+
`(range needs 3 or more check-in intervals)`. With 3 or more intervals the range is the
|
|
171
|
+
average velocity plus and minus 2.05 SD: fast end = critical-path tasks /
|
|
172
|
+
(average + 2.05 x SD) + overhead; slow velocity = average - 2.05 x SD; when the slow
|
|
173
|
+
velocity is above 0.5 tasks per hour the slow end = critical-path tasks / slow velocity +
|
|
174
|
+
overhead, otherwise the slow end prints the no-upper-bound text. Hours print as `HH:MM`.
|
|
175
|
+
- Weekly quota: the seven-day percentage of the active account in `cswap list --json`;
|
|
176
|
+
`n/a` when `cswap` is missing or prints nothing parseable.
|
|
177
|
+
- `n/a`: every printed number passes through a formatter that returns `n/a` for NaN or
|
|
178
|
+
infinity.
|
|
179
|
+
|
|
180
|
+
## Starting the Reports
|
|
181
|
+
|
|
182
|
+
1. Run the script once from the repository root to set the baseline. Either pass the start
|
|
183
|
+
and the tasks already done at that start:
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 -EpicFolder example-epic -StartUtc 2026-01-05T09:00:00Z -BaselineDone 40 -Mode TLDR
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
or start the measurement now:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 -EpicFolder example-epic -ResetBaseline
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The start and baseline are stored in the state file, so later runs need no `-StartUtc`.
|
|
196
|
+
2. Create the two recurring jobs with `CronCreate`, using the prompts below with
|
|
197
|
+
`<epic-folder>` replaced by the epic folder name.
|
|
198
|
+
3. Confirm both jobs with `CronList`.
|
|
199
|
+
|
|
200
|
+
## Scheduling Prompts
|
|
201
|
+
|
|
202
|
+
TL;DR job: cron `*/10 * * * *`, recurring.
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
Run `pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 -EpicFolder <epic-folder> -Mode TLDR` from the repository root and post its output verbatim as the TL;DR epic update (no push notification). Do not add commentary unless a run is blocked or a child has finished and needs relaying.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Hourly job: cron `7 * * * *`, recurring.
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
Run `pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 -EpicFolder <epic-folder>` (full mode) from the repository root and post its output as the hourly epic update, then send a PushNotification with the TL;DR line (under 200 characters). Check `cswap list` for the weekly pool; stop and commit at 93%.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Notes on the prompts:
|
|
215
|
+
|
|
216
|
+
- Push-notification text: the first TL;DR output line with every `**` removed. When that text
|
|
217
|
+
is 200 characters or longer, drop the running-features sentence; the remaining text (prefix,
|
|
218
|
+
task counts, percentage, and done-sentence) is well under 200 characters.
|
|
219
|
+
- The prompts omit `-StartUtc`, `-BaselineDone`, `-ResetBaseline`, and `-PairSamples`. The
|
|
220
|
+
baseline is read from the state file, so a later reset is never overridden by a stale
|
|
221
|
+
scheduled argument, and pairing is never repeated by a recurring job.
|
|
222
|
+
- Cron times are local time, not UTC.
|
|
223
|
+
- Jitter: a 10-minute job fires up to 5 minutes late and an hourly job up to 30 minutes late,
|
|
224
|
+
by a constant delay per job.
|
|
225
|
+
|
|
226
|
+
## Resetting the Baseline After a Pause
|
|
227
|
+
|
|
228
|
+
Whenever work resumes after a pause or an outage, run the script once with `-ResetBaseline`:
|
|
229
|
+
|
|
230
|
+
```text
|
|
231
|
+
pwsh -NoProfile -File .claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 -EpicFolder example-epic -ResetBaseline
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- The stored samples are discarded, the start becomes now, and the baseline done count becomes
|
|
235
|
+
the current done count. Pass `-StartUtc` and `-BaselineDone` with `-ResetBaseline` when the
|
|
236
|
+
resume instant is in the past.
|
|
237
|
+
- The weekly-quota baseline is kept, so the Full report's points since the epic started stay
|
|
238
|
+
accurate.
|
|
239
|
+
- The scheduled prompts are not changed.
|
|
240
|
+
- The first reports after a reset show `0 h 00 min` elapsed and `n/a` estimates, and the
|
|
241
|
+
estimates are unreliable for about two hours.
|
|
242
|
+
- Reason: earlier measures include the paused time. A 9-hour outage once distorted the averages
|
|
243
|
+
until the baseline was reset.
|
|
244
|
+
|
|
245
|
+
## Changing the Cadence
|
|
246
|
+
|
|
247
|
+
To move the TL;DR job to a new interval (for example from 5 to 10 minutes):
|
|
248
|
+
|
|
249
|
+
1. Run the script once with `-PairSamples`. It keeps the newest sample and every second older
|
|
250
|
+
sample, so the stored intervals match the doubled cadence. 14 samples become 7.
|
|
251
|
+
2. Delete the TL;DR job with `CronDelete` and create it again with `CronCreate` at the new
|
|
252
|
+
interval.
|
|
253
|
+
|
|
254
|
+
`-PairSamples` is a one-shot command: each run halves the samples again. Never put it in a
|
|
255
|
+
scheduled prompt.
|
|
256
|
+
|
|
257
|
+
Worked example from recorded samples: thirteen 5-minute intervals gave mean 26.2 and SD 31.4
|
|
258
|
+
tasks per hour; after pairing, six 10-minute intervals give mean 27.3 and SD 23.2. The
|
|
259
|
+
conversation that defined the reports quoted 31.5 for the 5-minute SD; the recorded samples
|
|
260
|
+
give 31.4 (unrounded 31.4495).
|
|
261
|
+
|
|
262
|
+
## Stopping the Reports
|
|
263
|
+
|
|
264
|
+
1. Run `CronList` and note the IDs of the TL;DR and hourly jobs.
|
|
265
|
+
2. Run `CronDelete` for each report job ID.
|
|
266
|
+
3. Keep the state file for a later restart of the reports, or delete it.
|
|
267
|
+
|
|
268
|
+
## After a Restart
|
|
269
|
+
|
|
270
|
+
- `CronCreate` jobs are session-only: they fire only while the session runs and is idle, and a
|
|
271
|
+
missed run fires once when the session becomes idle again.
|
|
272
|
+
- `claude --resume` or `claude --continue` restores jobs that have not expired.
|
|
273
|
+
- Recurring jobs expire 7 days after creation; recreate both before the 7-day expiry.
|
|
274
|
+
- Run `CronList` and recreate only the missing jobs with the prompts above.
|
|
275
|
+
- If work paused during the restart, reset the baseline first.
|
|
276
|
+
- The state file survives under `.claude/state/` wherever the checkout persists, so the
|
|
277
|
+
baseline and samples are kept.
|
|
278
|
+
|
|
279
|
+
## State File
|
|
280
|
+
|
|
281
|
+
- Location: `.claude/state/epic-progress-<epic-folder>.json` under the repository root.
|
|
282
|
+
`-StatePath` overrides it.
|
|
283
|
+
- The state is never committed: `.claude/state/` is gitignored in this repository and the
|
|
284
|
+
push-down adds it to a destination's `.gitignore`.
|
|
285
|
+
- The state is per checkout: a different worktree or `-RepositoryRoot` starts a separate
|
|
286
|
+
history. Run from the same root, or pass `-StatePath`.
|
|
287
|
+
- `git clean -fdX` deletes it.
|
|
288
|
+
- A state file under the system temporary directory, written by an earlier version, is not
|
|
289
|
+
migrated: pass its path once with `-StatePath`, or reset the baseline.
|
|
290
|
+
- The legacy format (a JSON array of samples) is still read. The current document is:
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"version": 1,
|
|
295
|
+
"startUnixSeconds": 1767603600,
|
|
296
|
+
"baselineDone": 0,
|
|
297
|
+
"baselineWeeklyPct": 0,
|
|
298
|
+
"samples": [ { "ts": 1767614400, "done": 3 } ]
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
- Blank text, unparseable text, or a version other than 1 is read as empty state; a missing
|
|
303
|
+
field is absent.
|
|
304
|
+
- The state is written when a sample is added, or when `-ResetBaseline` or `-PairSamples` is
|
|
305
|
+
given. A run within 90 seconds of the last sample with neither switch writes nothing.
|
|
306
|
+
|
|
307
|
+
## Known Behaviors and Measured Rates
|
|
308
|
+
|
|
309
|
+
- Plan checkboxes tick at batch boundaries, so 5-minute interval velocity is bursty: 0 to
|
|
310
|
+
about 150 tasks per hour, with an SD of about 30 to 45 around a mean near 26.
|
|
311
|
+
- Aggregate throughput with three or four features in parallel is about 25 to 30 tasks per
|
|
312
|
+
hour. Per-feature pace is about 9 to 13 tasks per hour; a lone feature, including its review
|
|
313
|
+
and PR tail, about 4.
|
|
314
|
+
- The wave-parallel estimate is unreliable for about two hours after a baseline: it swung
|
|
315
|
+
between 35 and 110 hours in the first hour, and once estimated 26 to 30 hours for about 10
|
|
316
|
+
active hours.
|
|
317
|
+
- Task totals drift when planners revise plans, so read the percentage against the live total.
|
|
318
|
+
- Flat stretches of 20 to 60 minutes are normal during review, PR, CI, and merge.
|
|
319
|
+
- The tail from plan complete to merge is 0.8 to 4 hours per feature, and each remediation
|
|
320
|
+
cycle adds 45 to 90 minutes.
|
|
321
|
+
- Weekly quota burn is 3 to 7 points per hour (4.3 to 7.6 tasks per point).
|
|
322
|
+
- The hourly Full run also records a sample when it runs more than 90 seconds after the
|
|
323
|
+
previous one. This adds a shorter interval about once an hour and raises the SD.
|
|
324
|
+
- A negative average (done below the baseline after a plan revision) makes the straight-line
|
|
325
|
+
and wave-parallel estimates `n/a`, while the range can print negative or very large values.
|
|
326
|
+
- Integral velocities print without a decimal (`1`, not `1.0`).
|
|
327
|
+
|
|
328
|
+
## Notes
|
|
329
|
+
|
|
330
|
+
- Delivery: the push-down serves the installed extension payload, so this skill reaches a
|
|
331
|
+
destination repository only after the extension is rebuilt and reinstalled.
|
|
332
|
+
- Quota: the 93% stop in the hourly prompt is coordinator policy. The commit-before-the-wall
|
|
333
|
+
procedure is governed by `.claude/skills/quota-throttling/SKILL.md`.
|
|
334
|
+
- The script is read-only toward git and GitHub: it runs only `git fetch`, `git show`,
|
|
335
|
+
`git worktree list`, `gh pr list`, and `cswap list --json`, and the only file it writes is
|
|
336
|
+
the state file.
|
|
337
|
+
- In this repository, `scripts/dev-tools/Get-EpicProgressReport.ps1` forwards every argument
|
|
338
|
+
to the canonical script; the skill always invokes the canonical script.
|