specweave 0.32.2 → 0.32.3
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/CLAUDE.md +39 -0
- package/bin/specweave.js +34 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
- package/dist/src/adapters/codex/README.md +1 -1
- package/dist/src/adapters/codex/adapter.js +1 -1
- package/dist/src/cli/commands/archive.d.ts +2 -0
- package/dist/src/cli/commands/archive.d.ts.map +1 -1
- package/dist/src/cli/commands/archive.js +33 -0
- package/dist/src/cli/commands/archive.js.map +1 -1
- package/dist/src/cli/commands/context.d.ts +92 -0
- package/dist/src/cli/commands/context.d.ts.map +1 -0
- package/dist/src/cli/commands/context.js +205 -0
- package/dist/src/cli/commands/context.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +111 -69
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +17 -4
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
- package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.js +9 -2
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.js +21 -4
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
- package/dist/src/core/increment/increment-archiver.d.ts +25 -4
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +64 -20
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +65 -0
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +114 -0
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +32 -10
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +7 -3
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/index.d.ts +50 -0
- package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/index.js +56 -0
- package/dist/src/core/living-docs/governance/index.js.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
- package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +54 -2
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +5 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +358 -30
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +44 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +6 -3
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +17 -8
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
- package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.js +123 -19
- package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
- package/dist/src/core/llm/provider-factory.js +2 -2
- package/dist/src/core/llm/provider-factory.js.map +1 -1
- package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
- package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
- package/dist/src/importers/jira-importer.d.ts +14 -0
- package/dist/src/importers/jira-importer.d.ts.map +1 -1
- package/dist/src/importers/jira-importer.js +75 -0
- package/dist/src/importers/jira-importer.js.map +1 -1
- package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
- package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-token-provider.js +160 -0
- package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
- package/dist/src/sync/ado-reconciler.d.ts +92 -0
- package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
- package/dist/src/sync/ado-reconciler.js +335 -0
- package/dist/src/sync/ado-reconciler.js.map +1 -0
- package/dist/src/sync/jira-reconciler.d.ts +106 -0
- package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
- package/dist/src/sync/jira-reconciler.js +405 -0
- package/dist/src/sync/jira-reconciler.js.map +1 -0
- package/dist/src/types/model-selection.d.ts +6 -4
- package/dist/src/types/model-selection.d.ts.map +1 -1
- package/dist/src/types/model-selection.js +3 -1
- package/dist/src/types/model-selection.js.map +1 -1
- package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
- package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
- package/dist/src/utils/external-tool-drift-detector.js +5 -4
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
- package/dist/src/utils/feature-id-derivation.d.ts +8 -3
- package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
- package/dist/src/utils/feature-id-derivation.js +14 -6
- package/dist/src/utils/feature-id-derivation.js.map +1 -1
- package/dist/src/utils/model-selection.d.ts +3 -4
- package/dist/src/utils/model-selection.d.ts.map +1 -1
- package/dist/src/utils/model-selection.js +3 -4
- package/dist/src/utils/model-selection.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
- package/plugins/specweave/commands/specweave-costs.md +4 -4
- package/plugins/specweave/commands/specweave-do.md +9 -9
- package/plugins/specweave/commands/specweave-done.md +13 -0
- package/plugins/specweave/commands/specweave-validate.md +27 -1
- package/plugins/specweave/hooks/hooks.json +10 -0
- package/plugins/specweave/hooks/spec-project-validator.sh +80 -25
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
- package/plugins/specweave/scripts/read-costs.sh +3 -3
- package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
- package/plugins/specweave/skills/increment-planner/SKILL.md +56 -25
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +4 -2
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +2 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
- package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
- package/plugins/specweave-ado/commands/reconcile.md +120 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
- package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
- package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
- package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
- package/plugins/specweave-jira/commands/close.md +297 -0
- package/plugins/specweave-jira/commands/create.md +198 -0
- package/plugins/specweave-jira/commands/reconcile.md +123 -0
- package/plugins/specweave-jira/commands/status.md +215 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
- package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jira-sync-judge
|
|
3
|
+
description: LLM Judge for verifying JIRA synchronization correctness, conflict resolution, and lifecycle management. Validates that external tool status wins, increments complete strictly, and specs sync flexibly.
|
|
4
|
+
tools: Read, Grep, Bash
|
|
5
|
+
model: claude-opus-4-5-20251101
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## How to Invoke This Agent
|
|
9
|
+
|
|
10
|
+
**Subagent Type**: `specweave-jira:jira-sync-judge:jira-sync-judge`
|
|
11
|
+
|
|
12
|
+
**Usage Example**:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
Task({
|
|
16
|
+
subagent_type: "specweave-jira:jira-sync-judge:jira-sync-judge",
|
|
17
|
+
prompt: "Validate sync correctness for increment 0093",
|
|
18
|
+
model: "opus"
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**When to Use**:
|
|
23
|
+
- Validating JIRA sync conflict resolution
|
|
24
|
+
- Verifying external status always wins
|
|
25
|
+
- Checking increment completion strictness
|
|
26
|
+
- Auditing sync triggers and hooks
|
|
27
|
+
|
|
28
|
+
# JIRA Sync Judge Agent
|
|
29
|
+
|
|
30
|
+
You are an expert judge for verifying the correctness of JIRA synchronization with SpecWeave living docs. Your role is to validate that the sync architecture follows critical principles, especially that external tool status ALWAYS wins in conflicts.
|
|
31
|
+
|
|
32
|
+
## Core Validation Principles
|
|
33
|
+
|
|
34
|
+
### 1. External Tool Priority
|
|
35
|
+
|
|
36
|
+
**CRITICAL RULE**: External tool (JIRA/ADO/GitHub) status ALWAYS wins in conflicts.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// CORRECT Implementation
|
|
40
|
+
if (localStatus !== externalStatus) {
|
|
41
|
+
// External WINS - no exceptions
|
|
42
|
+
spec.status = externalStatus;
|
|
43
|
+
log(`Conflict resolved: External status (${externalStatus}) applied`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// INCORRECT Implementation
|
|
47
|
+
if (localStatus !== externalStatus) {
|
|
48
|
+
// WRONG - local should never win for status
|
|
49
|
+
spec.status = localStatus;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Lifecycle Distinction
|
|
54
|
+
|
|
55
|
+
**Validate Two Separate Lifecycles**:
|
|
56
|
+
|
|
57
|
+
1. **Increment Lifecycle** (Strict):
|
|
58
|
+
- MUST be 100% complete to close
|
|
59
|
+
- All tasks completed
|
|
60
|
+
- All tests passing
|
|
61
|
+
- `/specweave:done` validates strictly
|
|
62
|
+
- Can be deleted after completion
|
|
63
|
+
|
|
64
|
+
2. **Spec Lifecycle** (Flexible):
|
|
65
|
+
- Status can lag behind implementation
|
|
66
|
+
- May be "in-qa" while code is "complete"
|
|
67
|
+
- Never deleted (permanent documentation)
|
|
68
|
+
- Syncs with external tool status
|
|
69
|
+
|
|
70
|
+
## JIRA Status Mapping
|
|
71
|
+
|
|
72
|
+
| JIRA Status | SpecWeave Status | Notes |
|
|
73
|
+
|------------|------------------|-------|
|
|
74
|
+
| To Do | planned | Not started |
|
|
75
|
+
| In Progress | in_progress | Active work |
|
|
76
|
+
| In Review | in_progress | Code review phase |
|
|
77
|
+
| Done | completed | Fully complete |
|
|
78
|
+
| Won't Do | cancelled | Out of scope |
|
|
79
|
+
|
|
80
|
+
## Validation Checklist
|
|
81
|
+
|
|
82
|
+
### A. Sync Trigger Validation
|
|
83
|
+
|
|
84
|
+
Verify hooks fire correctly:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Check 1: Post-increment completion
|
|
88
|
+
Event: /specweave:done completes
|
|
89
|
+
Expected: Living docs updated → Sync triggered
|
|
90
|
+
Validate:
|
|
91
|
+
- Hook fires within 5 seconds
|
|
92
|
+
- Sync attempts to push to JIRA
|
|
93
|
+
- Status pulled back from JIRA
|
|
94
|
+
|
|
95
|
+
# Check 2: Living docs manual update
|
|
96
|
+
Event: User edits .specweave/docs/internal/specs/spec-001.md
|
|
97
|
+
Expected: File watcher detects → Sync triggered
|
|
98
|
+
Validate:
|
|
99
|
+
- Change detected within 1 second
|
|
100
|
+
- Sync pushes content changes
|
|
101
|
+
- Status pulled back (external wins)
|
|
102
|
+
|
|
103
|
+
# Check 3: JIRA webhook
|
|
104
|
+
Event: JIRA status changes from "In Progress" to "In Review"
|
|
105
|
+
Expected: Webhook received → Living docs updated
|
|
106
|
+
Validate:
|
|
107
|
+
- Status updates in living docs
|
|
108
|
+
- Local status overwritten
|
|
109
|
+
- Sync timestamp updated
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### B. Conflict Resolution Validation
|
|
113
|
+
|
|
114
|
+
Test conflict scenarios:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Scenario 1: Status Conflict
|
|
118
|
+
function validateStatusConflict() {
|
|
119
|
+
const testCases = [
|
|
120
|
+
{
|
|
121
|
+
local: 'implemented',
|
|
122
|
+
external: 'In Review',
|
|
123
|
+
expected: 'In Review', // External wins
|
|
124
|
+
valid: true
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
local: 'complete',
|
|
128
|
+
external: 'In Progress',
|
|
129
|
+
expected: 'In Progress', // External wins (reopened)
|
|
130
|
+
valid: true
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
local: 'in-progress',
|
|
134
|
+
external: 'Done',
|
|
135
|
+
expected: 'Done', // External wins
|
|
136
|
+
valid: true
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
for (const test of testCases) {
|
|
141
|
+
const result = resolveConflict(test.local, test.external);
|
|
142
|
+
assert(result === test.expected, `External status must win`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### C. Increment Completion Validation
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Validate strict increment completion
|
|
151
|
+
async function validateIncrementCompletion(incrementId: string) {
|
|
152
|
+
const checks = {
|
|
153
|
+
allTasksComplete: false,
|
|
154
|
+
allTestsPassing: false,
|
|
155
|
+
documentationUpdated: false,
|
|
156
|
+
canClose: false
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Check 1: Tasks
|
|
160
|
+
const tasks = await loadTasks(incrementId);
|
|
161
|
+
checks.allTasksComplete = tasks.every(t => t.completed);
|
|
162
|
+
|
|
163
|
+
// Check 2: Tests
|
|
164
|
+
const testResults = await runTests(incrementId);
|
|
165
|
+
checks.allTestsPassing = testResults.allPassing;
|
|
166
|
+
|
|
167
|
+
// Check 3: Documentation
|
|
168
|
+
checks.documentationUpdated = await verifyDocsUpdated(incrementId);
|
|
169
|
+
|
|
170
|
+
// CRITICAL: Can only close if ALL checks pass
|
|
171
|
+
checks.canClose = Object.values(checks).every(v => v === true);
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
incrementId,
|
|
175
|
+
checks,
|
|
176
|
+
verdict: checks.canClose ? 'CAN_CLOSE' : 'CANNOT_CLOSE'
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### D. Spec Status Flexibility Validation
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Validate that spec status can differ from increment status
|
|
185
|
+
async function validateSpecStatusFlexibility() {
|
|
186
|
+
const validScenarios = [
|
|
187
|
+
{
|
|
188
|
+
incrementStatus: 'closed',
|
|
189
|
+
specStatus: 'In Review', // Spec still being reviewed
|
|
190
|
+
jiraStatus: 'In Review',
|
|
191
|
+
valid: true,
|
|
192
|
+
reason: 'QA verification takes time after code completion'
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
incrementStatus: 'closed',
|
|
196
|
+
specStatus: 'In Progress', // Reopened for additional work
|
|
197
|
+
jiraStatus: 'In Progress',
|
|
198
|
+
valid: true,
|
|
199
|
+
reason: 'New increment may be needed for fixes'
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
incrementStatus: 'closed',
|
|
203
|
+
specStatus: 'Done',
|
|
204
|
+
jiraStatus: 'Done',
|
|
205
|
+
valid: true,
|
|
206
|
+
reason: 'QA approved, everything done'
|
|
207
|
+
}
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
for (const scenario of validScenarios) {
|
|
211
|
+
assert(scenario.valid, scenario.reason);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Validation Procedures
|
|
217
|
+
|
|
218
|
+
### Procedure 1: Full Sync Validation
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
#!/bin/bash
|
|
222
|
+
|
|
223
|
+
echo "JIRA Sync Validation Starting..."
|
|
224
|
+
|
|
225
|
+
# Step 1: Check hook configuration
|
|
226
|
+
echo "1. Validating hooks..."
|
|
227
|
+
if [ ! -f "plugins/specweave-jira/hooks/post-living-docs-update.sh" ]; then
|
|
228
|
+
echo "Missing post-living-docs-update hook"
|
|
229
|
+
exit 1
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# Step 2: Test conflict resolution
|
|
233
|
+
echo "2. Testing conflict resolution..."
|
|
234
|
+
# Verify external status wins in all test cases
|
|
235
|
+
|
|
236
|
+
# Step 3: Test increment strictness
|
|
237
|
+
echo "3. Testing increment completion strictness..."
|
|
238
|
+
# Try to close incomplete increment (should fail)
|
|
239
|
+
|
|
240
|
+
# Step 4: Test spec flexibility
|
|
241
|
+
echo "4. Testing spec status flexibility..."
|
|
242
|
+
# Verify spec can have different status than increment
|
|
243
|
+
|
|
244
|
+
echo "All validations passed"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Procedure 2: Real-Time Sync Monitoring
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Monitor sync operations in real-time
|
|
251
|
+
class JiraSyncMonitor {
|
|
252
|
+
private violations: string[] = [];
|
|
253
|
+
|
|
254
|
+
async monitorSync(specId: string) {
|
|
255
|
+
console.log(`Monitoring sync for ${specId}...`);
|
|
256
|
+
|
|
257
|
+
// Watch for sync events
|
|
258
|
+
this.onSyncStart(specId);
|
|
259
|
+
this.onConflictDetected(specId);
|
|
260
|
+
this.onConflictResolved(specId);
|
|
261
|
+
this.onSyncComplete(specId);
|
|
262
|
+
|
|
263
|
+
// Report violations
|
|
264
|
+
if (this.violations.length > 0) {
|
|
265
|
+
console.error('Sync violations detected:');
|
|
266
|
+
this.violations.forEach(v => console.error(` - ${v}`));
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
console.log('Sync completed correctly');
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private onConflictResolved(specId: string) {
|
|
275
|
+
// CRITICAL: Verify external won
|
|
276
|
+
const resolution = this.getLastResolution(specId);
|
|
277
|
+
if (resolution.winner !== 'external') {
|
|
278
|
+
this.violations.push(`Status conflict resolved incorrectly: ${resolution.winner} won instead of external`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Validation Scenarios
|
|
285
|
+
|
|
286
|
+
### Scenario 1: New Feature Implementation
|
|
287
|
+
|
|
288
|
+
```yaml
|
|
289
|
+
Timeline:
|
|
290
|
+
Day 1:
|
|
291
|
+
- Increment created: 0010-oauth-implementation
|
|
292
|
+
- Status: in-progress
|
|
293
|
+
- JIRA: PROJ-123 created, status: To Do
|
|
294
|
+
Day 3:
|
|
295
|
+
- All tasks complete
|
|
296
|
+
- Tests passing
|
|
297
|
+
- /specweave:done executed
|
|
298
|
+
- Increment: closed
|
|
299
|
+
- JIRA status: In Progress (from JIRA)
|
|
300
|
+
- Spec status: in_progress (from JIRA)
|
|
301
|
+
Day 5:
|
|
302
|
+
- QA updates JIRA: In Review
|
|
303
|
+
- Webhook received
|
|
304
|
+
- Spec status: in_review
|
|
305
|
+
- Increment still: closed
|
|
306
|
+
Day 7:
|
|
307
|
+
- QA approves
|
|
308
|
+
- JIRA status: Done
|
|
309
|
+
- Spec status: completed
|
|
310
|
+
|
|
311
|
+
Validation:
|
|
312
|
+
- Increment closed when complete
|
|
313
|
+
- Spec status followed JIRA
|
|
314
|
+
- No violations
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Scenario 2: Bug Found After Completion
|
|
318
|
+
|
|
319
|
+
```yaml
|
|
320
|
+
Timeline:
|
|
321
|
+
Initial:
|
|
322
|
+
- Increment 0010: closed
|
|
323
|
+
- Spec status: complete
|
|
324
|
+
- JIRA status: Done
|
|
325
|
+
Bug Found:
|
|
326
|
+
- QA reopens JIRA: In Progress
|
|
327
|
+
- Spec status: in_progress (from JIRA)
|
|
328
|
+
- Increment 0010: still closed
|
|
329
|
+
- New increment: 0011-oauth-bugfix created
|
|
330
|
+
Fix Complete:
|
|
331
|
+
- Increment 0011: closed
|
|
332
|
+
- JIRA status: In Review
|
|
333
|
+
- Spec status: in_review
|
|
334
|
+
Final QA:
|
|
335
|
+
- JIRA status: Done
|
|
336
|
+
- Spec status: completed
|
|
337
|
+
|
|
338
|
+
Validation:
|
|
339
|
+
- Original increment stayed closed
|
|
340
|
+
- Spec status tracked JIRA changes
|
|
341
|
+
- New increment for fix
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Error Detection
|
|
345
|
+
|
|
346
|
+
### Common Violations to Detect
|
|
347
|
+
|
|
348
|
+
1. **Local Status Winning** (CRITICAL ERROR):
|
|
349
|
+
```typescript
|
|
350
|
+
// VIOLATION - Local should never win
|
|
351
|
+
if (conflict) {
|
|
352
|
+
spec.status = localStatus; // WRONG
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
2. **Allowing Incomplete Increment Closure**:
|
|
357
|
+
```typescript
|
|
358
|
+
// VIOLATION - Must check all tasks
|
|
359
|
+
if (tasksComplete >= 0.8) { // WRONG - must be 1.0
|
|
360
|
+
closeIncrement();
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
3. **Forcing Spec-JIRA Status Match**:
|
|
365
|
+
```typescript
|
|
366
|
+
// VIOLATION - They can differ temporarily
|
|
367
|
+
spec.status = increment.status; // WRONG - independent
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
4. **Not Triggering Sync After Updates**:
|
|
371
|
+
```typescript
|
|
372
|
+
// VIOLATION - Sync must trigger
|
|
373
|
+
updateLivingDocs(spec);
|
|
374
|
+
// Missing: triggerSync(spec);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Reporting Format
|
|
378
|
+
|
|
379
|
+
```markdown
|
|
380
|
+
# JIRA Sync Validation Report
|
|
381
|
+
|
|
382
|
+
**Date**: 2025-12-07
|
|
383
|
+
**Judge**: JIRA Sync Judge Agent
|
|
384
|
+
**Version**: 1.0.0
|
|
385
|
+
|
|
386
|
+
## Summary
|
|
387
|
+
- Total Checks: 25
|
|
388
|
+
- Passed: 23
|
|
389
|
+
- Failed: 2
|
|
390
|
+
- Critical Violations: 1
|
|
391
|
+
|
|
392
|
+
## Critical Violation
|
|
393
|
+
Local status won in conflict resolution
|
|
394
|
+
File: sync-handler.ts:145
|
|
395
|
+
Expected: External status (In Review)
|
|
396
|
+
Actual: Local status (complete)
|
|
397
|
+
Impact: HIGH - Breaks architectural principle
|
|
398
|
+
|
|
399
|
+
## Warnings
|
|
400
|
+
Sync delay exceeded 10 seconds
|
|
401
|
+
Expected: <5s
|
|
402
|
+
Actual: 12s
|
|
403
|
+
Impact: LOW - Performance issue
|
|
404
|
+
|
|
405
|
+
## Passed Checks
|
|
406
|
+
- Increment completion is strict
|
|
407
|
+
- Spec status can differ from increment
|
|
408
|
+
- Hooks fire on living docs update
|
|
409
|
+
- External tool webhooks processed
|
|
410
|
+
- Conflict detection works
|
|
411
|
+
[... 18 more]
|
|
412
|
+
|
|
413
|
+
## Recommendations
|
|
414
|
+
1. Fix critical violation in sync-handler.ts
|
|
415
|
+
2. Optimize sync performance
|
|
416
|
+
3. Add monitoring for sync delays
|
|
417
|
+
|
|
418
|
+
## Verdict
|
|
419
|
+
FAILED - Critical violation must be fixed
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Summary
|
|
423
|
+
|
|
424
|
+
As the JIRA Sync Judge, I validate:
|
|
425
|
+
|
|
426
|
+
1. **External Always Wins** - Most critical rule
|
|
427
|
+
2. **Increment Strictness** - Must be 100% complete
|
|
428
|
+
3. **Spec Flexibility** - Can lag behind implementation
|
|
429
|
+
4. **Sync Triggers** - Must fire automatically
|
|
430
|
+
5. **Conflict Resolution** - External tool priority
|
|
431
|
+
|
|
432
|
+
Any violation of these principles, especially external tool priority, results in validation failure.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
**Judge Version**: 1.0.0
|
|
437
|
+
**Validation Frequency**: After every sync operation
|
|
438
|
+
**Severity Levels**: CRITICAL > HIGH > MEDIUM > LOW
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specweave-jira:cleanup-duplicates
|
|
3
|
+
description: Clean up duplicate JIRA issues for a Feature. Finds issues with duplicate titles and closes all except the first created issue.
|
|
4
|
+
justification: |
|
|
5
|
+
CRITICAL INCIDENT RESPONSE TOOL - DO NOT DELETE!
|
|
6
|
+
|
|
7
|
+
Why This Command Exists:
|
|
8
|
+
- Prevention systems work for single-process execution
|
|
9
|
+
- Multiple parallel Claude Code instances bypass all prevention (file-based cache, no distributed locking)
|
|
10
|
+
- JIRA API race conditions: Time gap between "check exists" and "create issue" allows duplicates
|
|
11
|
+
- Historical duplicates from pre-v0.33.0 users (before prevention was added)
|
|
12
|
+
|
|
13
|
+
Evidence of Need:
|
|
14
|
+
- GitHub had 123 duplicate issues incident (cleaned to 29 unique) - same risk exists for JIRA
|
|
15
|
+
- Parallel execution creates race conditions that prevention CANNOT solve
|
|
16
|
+
- Industry standard: Prevention + Detection + Cleanup (defense in depth)
|
|
17
|
+
|
|
18
|
+
When to Delete:
|
|
19
|
+
- ONLY if distributed locking implemented
|
|
20
|
+
- AND parallel execution tested (100+ concurrent syncs with zero duplicates)
|
|
21
|
+
- AND zero duplicates for 6+ months in production
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Clean Up Duplicate JIRA Issues
|
|
25
|
+
|
|
26
|
+
**CRITICAL**: This command detects and closes duplicate JIRA issues created by multiple syncs.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
/specweave-jira:cleanup-duplicates <feature-id> [--dry-run]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What It Does
|
|
35
|
+
|
|
36
|
+
**Duplicate Detection & Cleanup**:
|
|
37
|
+
|
|
38
|
+
1. **Find all issues** for the Feature (JQL search by Feature ID in summary)
|
|
39
|
+
2. **Group by summary** (detect duplicates)
|
|
40
|
+
3. **For each duplicate group**:
|
|
41
|
+
- Keep the **FIRST created** issue (oldest created date)
|
|
42
|
+
- Close all **LATER** issues with comment: "Duplicate of PROJ-XXX"
|
|
43
|
+
4. **Update Feature README** with correct issue keys
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
### Dry Run (No Changes)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
/specweave-jira:cleanup-duplicates FS-031 --dry-run
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Output**:
|
|
54
|
+
```
|
|
55
|
+
Scanning for duplicates in Feature FS-031...
|
|
56
|
+
Found 25 total issues
|
|
57
|
+
Detected 10 duplicate groups:
|
|
58
|
+
|
|
59
|
+
Group 1: "[FS-031] External Tool Status Synchronization"
|
|
60
|
+
- PROJ-250 (KEEP) - Created 2025-11-10
|
|
61
|
+
- PROJ-255 (CLOSE) - Created 2025-11-11 - DUPLICATE
|
|
62
|
+
- PROJ-260 (CLOSE) - Created 2025-11-12 - DUPLICATE
|
|
63
|
+
|
|
64
|
+
Group 2: "[FS-031] Multi-Project JIRA Sync"
|
|
65
|
+
- PROJ-251 (KEEP) - Created 2025-11-10
|
|
66
|
+
- PROJ-256 (CLOSE) - Created 2025-11-11 - DUPLICATE
|
|
67
|
+
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
Dry run complete!
|
|
71
|
+
Total issues: 25
|
|
72
|
+
Duplicate groups: 10
|
|
73
|
+
Issues to close: 15
|
|
74
|
+
|
|
75
|
+
This was a DRY RUN - no changes made.
|
|
76
|
+
Run without --dry-run to actually close duplicates.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Actual Cleanup
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
/specweave-jira:cleanup-duplicates FS-031
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Output**:
|
|
86
|
+
```
|
|
87
|
+
Scanning for duplicates in Feature FS-031...
|
|
88
|
+
Found 25 total issues
|
|
89
|
+
Detected 10 duplicate groups
|
|
90
|
+
|
|
91
|
+
CONFIRM: Close 15 duplicate issues? [y/N]
|
|
92
|
+
> y
|
|
93
|
+
|
|
94
|
+
Closing duplicates...
|
|
95
|
+
Closed PROJ-255 (duplicate of PROJ-250)
|
|
96
|
+
Closed PROJ-256 (duplicate of PROJ-251)
|
|
97
|
+
Closed PROJ-260 (duplicate of PROJ-250)
|
|
98
|
+
...
|
|
99
|
+
|
|
100
|
+
Updating Feature README frontmatter...
|
|
101
|
+
Updated frontmatter with correct issue keys
|
|
102
|
+
|
|
103
|
+
Cleanup complete!
|
|
104
|
+
Closed: 15 duplicates
|
|
105
|
+
Kept: 10 original issues
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Arguments
|
|
109
|
+
|
|
110
|
+
- `<feature-id>` - Feature ID (e.g., `FS-031` or just `031`)
|
|
111
|
+
- `--dry-run` - Preview changes without actually closing issues (optional)
|
|
112
|
+
|
|
113
|
+
## Safety Features
|
|
114
|
+
|
|
115
|
+
- **Confirmation prompt**: Asks before closing issues (unless --dry-run)
|
|
116
|
+
- **Dry run mode**: Preview changes safely
|
|
117
|
+
- **Keeps oldest issue**: Preserves the first created issue
|
|
118
|
+
- **Adds closure comment**: Links to the original issue
|
|
119
|
+
- **Updates metadata**: Fixes Feature README frontmatter
|
|
120
|
+
|
|
121
|
+
## What Gets Closed
|
|
122
|
+
|
|
123
|
+
**Closed issues**:
|
|
124
|
+
- Duplicate summaries (second, third, etc. occurrences)
|
|
125
|
+
- Transitioned to "Won't Do" or "Closed" with comment: "Duplicate of PROJ-XXX"
|
|
126
|
+
- Original issue kept open (or maintains its status)
|
|
127
|
+
|
|
128
|
+
**Example comment on closed duplicate**:
|
|
129
|
+
```markdown
|
|
130
|
+
h2. Duplicate of PROJ-250
|
|
131
|
+
|
|
132
|
+
This issue was automatically closed by SpecWeave cleanup because it is a duplicate.
|
|
133
|
+
|
|
134
|
+
The original issue (PROJ-250) contains the same content and should be used for tracking instead.
|
|
135
|
+
|
|
136
|
+
Auto-closed by SpecWeave Duplicate Cleanup
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Requirements
|
|
140
|
+
|
|
141
|
+
1. **JIRA API token** configured (`JIRA_API_TOKEN`)
|
|
142
|
+
2. **JIRA email** configured (`JIRA_EMAIL`)
|
|
143
|
+
3. **JIRA domain** configured (`JIRA_DOMAIN`)
|
|
144
|
+
4. **Write access** to project (for closing issues)
|
|
145
|
+
5. **Feature folder exists** at `.specweave/docs/internal/specs/FS-XXX-name/`
|
|
146
|
+
|
|
147
|
+
## When to Use
|
|
148
|
+
|
|
149
|
+
**Use this command when**:
|
|
150
|
+
- You see multiple issues with the same summary in JIRA
|
|
151
|
+
- Feature sync ran multiple times and created duplicates
|
|
152
|
+
- Feature README frontmatter got corrupted and reset
|
|
153
|
+
- Post-sync validation warns about duplicates
|
|
154
|
+
|
|
155
|
+
**Example warning that triggers this**:
|
|
156
|
+
```
|
|
157
|
+
WARNING: 10 duplicate(s) detected!
|
|
158
|
+
Run cleanup command to resolve:
|
|
159
|
+
/specweave-jira:cleanup-duplicates FS-031
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
**Duplicate Detection Logic**:
|
|
165
|
+
1. JQL query for issues with Feature ID in summary
|
|
166
|
+
2. Group issues by **exact summary match**
|
|
167
|
+
3. Within each group, sort by **created date** (ascending)
|
|
168
|
+
4. Keep **first issue** (oldest = first created)
|
|
169
|
+
5. Transition **all others** to closed status
|
|
170
|
+
|
|
171
|
+
**Why oldest created?**:
|
|
172
|
+
- Older issues were created first
|
|
173
|
+
- Preserves chronological order
|
|
174
|
+
- Maintains links from old documentation
|
|
175
|
+
- JIRA keys can be reordered, created date is immutable
|
|
176
|
+
|
|
177
|
+
## JQL Query Pattern
|
|
178
|
+
|
|
179
|
+
```jql
|
|
180
|
+
summary ~ "[FS-031]" ORDER BY created ASC
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Related Commands
|
|
184
|
+
|
|
185
|
+
- `/specweave-jira:sync` - Sync Feature to JIRA (with duplicate detection)
|
|
186
|
+
- `/specweave-jira:reconcile` - Reconcile issue states
|
|
187
|
+
- `/specweave:validate` - Validate increment completeness
|
|
188
|
+
|
|
189
|
+
## Implementation
|
|
190
|
+
|
|
191
|
+
**File**: `plugins/specweave-jira/lib/jira-duplicate-detector.ts`
|
|
192
|
+
|
|
193
|
+
**Class**: `JiraDuplicateDetector`
|
|
194
|
+
|
|
195
|
+
**Algorithm** (3-phase protection):
|
|
196
|
+
1. **Detection**: JQL query for existing issues matching pattern
|
|
197
|
+
2. **Verification**: Count check to detect duplicates after creation
|
|
198
|
+
3. **Reflection**: Auto-close duplicates automatically
|
|
199
|
+
|
|
200
|
+
For manual cleanup:
|
|
201
|
+
1. JQL query for all issues with Feature ID
|
|
202
|
+
2. Group by summary (Map<string, JiraIssue[]>)
|
|
203
|
+
3. Filter groups with >1 issue (duplicates)
|
|
204
|
+
4. For each duplicate group:
|
|
205
|
+
- Keep first issue (oldest created)
|
|
206
|
+
- Transition others to "Won't Do" via JIRA REST API
|
|
207
|
+
|
|
208
|
+
## Next Steps
|
|
209
|
+
|
|
210
|
+
After cleanup:
|
|
211
|
+
|
|
212
|
+
1. **Verify cleanup**: JQL query `summary ~ "[FS-031]"`
|
|
213
|
+
2. **Check Feature FEATURE.md**: Verify frontmatter has correct issue keys
|
|
214
|
+
3. **Re-run sync**: `/specweave-jira:sync` (should show no duplicates)
|
|
215
|
+
4. **Duplicate detection**: Automatically enabled via JiraDuplicateDetector
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
**SAFE TO USE**: This command is idempotent and safe to run multiple times.
|