@sandrinio/vbounce 1.9.0 → 2.1.0
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/README.md +303 -19
- package/bin/vbounce.mjs +44 -0
- package/brains/AGENTS.md +51 -120
- package/brains/CHANGELOG.md +135 -0
- package/brains/CLAUDE.md +58 -133
- package/brains/GEMINI.md +68 -149
- package/brains/claude-agents/developer.md +6 -4
- package/brains/copilot/copilot-instructions.md +5 -0
- package/brains/cursor-rules/vbounce-process.mdc +3 -0
- package/brains/windsurf/.windsurfrules +5 -0
- package/package.json +1 -1
- package/scripts/close_sprint.mjs +41 -1
- package/scripts/complete_story.mjs +8 -0
- package/scripts/init_sprint.mjs +8 -0
- package/scripts/post_sprint_improve.mjs +486 -0
- package/scripts/product_graph.mjs +387 -0
- package/scripts/product_impact.mjs +167 -0
- package/scripts/suggest_improvements.mjs +206 -43
- package/skills/agent-team/SKILL.md +63 -28
- package/skills/agent-team/references/discovery.md +97 -0
- package/skills/agent-team/references/mid-sprint-triage.md +40 -26
- package/skills/doc-manager/SKILL.md +172 -19
- package/skills/improve/SKILL.md +151 -60
- package/skills/lesson/SKILL.md +14 -0
- package/skills/product-graph/SKILL.md +102 -0
- package/templates/bug.md +90 -0
- package/templates/change_request.md +105 -0
- package/templates/epic.md +19 -16
- package/templates/spike.md +143 -0
- package/templates/sprint.md +51 -17
- package/templates/sprint_report.md +6 -4
- package/templates/story.md +23 -8
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* suggest_improvements.mjs
|
|
5
|
-
* Generates improvement suggestions from
|
|
5
|
+
* Generates human-readable improvement suggestions from:
|
|
6
|
+
* 1. Improvement manifest (post_sprint_improve.mjs output)
|
|
7
|
+
* 2. Sprint trends
|
|
8
|
+
* 3. LESSONS.md
|
|
9
|
+
*
|
|
6
10
|
* Overwrites (not appends) to prevent stale suggestion accumulation.
|
|
7
11
|
*
|
|
8
12
|
* Usage:
|
|
@@ -14,6 +18,7 @@
|
|
|
14
18
|
import fs from 'fs';
|
|
15
19
|
import path from 'path';
|
|
16
20
|
import { fileURLToPath } from 'url';
|
|
21
|
+
import { spawnSync } from 'child_process';
|
|
17
22
|
|
|
18
23
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
24
|
const ROOT = path.resolve(__dirname, '..');
|
|
@@ -26,41 +31,76 @@ if (!sprintId) {
|
|
|
26
31
|
|
|
27
32
|
const today = new Date().toISOString().split('T')[0];
|
|
28
33
|
|
|
29
|
-
//
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// 0. Run post_sprint_improve.mjs to generate fresh manifest
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
const analyzerScript = path.join(__dirname, 'post_sprint_improve.mjs');
|
|
39
|
+
if (fs.existsSync(analyzerScript)) {
|
|
40
|
+
console.log('Running post-sprint improvement analyzer...');
|
|
41
|
+
const result = spawnSync(process.execPath, [analyzerScript, sprintId], {
|
|
42
|
+
stdio: 'inherit',
|
|
43
|
+
cwd: process.cwd(),
|
|
44
|
+
});
|
|
45
|
+
if (result.status !== 0) {
|
|
46
|
+
console.warn('⚠ Analyzer returned non-zero — continuing with available data.');
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// 1. Read improvement manifest (from post_sprint_improve.mjs)
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
const manifestPath = path.join(ROOT, '.bounce', 'improvement-manifest.json');
|
|
56
|
+
let manifest = null;
|
|
57
|
+
if (fs.existsSync(manifestPath)) {
|
|
58
|
+
try {
|
|
59
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
60
|
+
} catch {
|
|
61
|
+
console.warn('⚠ Could not parse improvement-manifest.json');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// 2. Read trends if available
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
30
69
|
const trendsFile = path.join(ROOT, '.bounce', 'trends.md');
|
|
31
70
|
let trendsContent = null;
|
|
32
71
|
if (fs.existsSync(trendsFile)) {
|
|
33
72
|
trendsContent = fs.readFileSync(trendsFile, 'utf8');
|
|
34
73
|
}
|
|
35
74
|
|
|
36
|
-
//
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// 3. Read LESSONS.md
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
37
79
|
const lessonsFile = path.join(ROOT, 'LESSONS.md');
|
|
38
80
|
let lessonCount = 0;
|
|
39
81
|
let oldLessons = [];
|
|
40
82
|
if (fs.existsSync(lessonsFile)) {
|
|
41
83
|
const lines = fs.readFileSync(lessonsFile, 'utf8').split('\n');
|
|
42
|
-
// Count lessons by counting ### entries
|
|
43
84
|
const lessonEntries = lines.filter(l => /^###\s+\[\d{4}-\d{2}-\d{2}\]/.test(l));
|
|
44
85
|
lessonCount = lessonEntries.length;
|
|
45
86
|
|
|
46
|
-
// Flag lessons older than 90 days
|
|
47
87
|
const cutoff = new Date();
|
|
48
88
|
cutoff.setDate(cutoff.getDate() - 90);
|
|
49
89
|
oldLessons = lessonEntries.filter(entry => {
|
|
50
90
|
const dateMatch = entry.match(/\[(\d{4}-\d{2}-\d{2})\]/);
|
|
51
|
-
if (dateMatch)
|
|
52
|
-
return new Date(dateMatch[1]) < cutoff;
|
|
53
|
-
}
|
|
91
|
+
if (dateMatch) return new Date(dateMatch[1]) < cutoff;
|
|
54
92
|
return false;
|
|
55
93
|
});
|
|
56
94
|
}
|
|
57
95
|
|
|
58
|
-
//
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// 4. Read improvement-log for rejected items
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
59
100
|
const improvementLog = path.join(ROOT, '.bounce', 'improvement-log.md');
|
|
60
101
|
let rejectedItems = [];
|
|
61
102
|
if (fs.existsSync(improvementLog)) {
|
|
62
103
|
const logContent = fs.readFileSync(improvementLog, 'utf8');
|
|
63
|
-
// Simple extraction: look for table rows in "Rejected" section
|
|
64
104
|
const rejectedMatch = logContent.match(/## Rejected\n[\s\S]*?(?=\n## |$)/);
|
|
65
105
|
if (rejectedMatch) {
|
|
66
106
|
rejectedItems = rejectedMatch[0].split('\n')
|
|
@@ -70,7 +110,10 @@ if (fs.existsSync(improvementLog)) {
|
|
|
70
110
|
}
|
|
71
111
|
}
|
|
72
112
|
|
|
73
|
-
//
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// 5. Parse sprint stats from trends
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
74
117
|
let lastSprintStats = null;
|
|
75
118
|
if (trendsContent) {
|
|
76
119
|
const rows = trendsContent.split('\n').filter(l => l.match(/^\| S-\d{2} \|/));
|
|
@@ -86,18 +129,90 @@ if (trendsContent) {
|
|
|
86
129
|
}
|
|
87
130
|
}
|
|
88
131
|
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// 6. Build suggestions
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
89
136
|
const suggestions = [];
|
|
90
137
|
let itemNum = 1;
|
|
91
138
|
|
|
92
|
-
//
|
|
139
|
+
// Impact level badge
|
|
140
|
+
function badge(impact) {
|
|
141
|
+
const badges = {
|
|
142
|
+
P0: '🔴 P0 Critical',
|
|
143
|
+
P1: '🟠 P1 High',
|
|
144
|
+
P2: '🟡 P2 Medium',
|
|
145
|
+
P3: '⚪ P3 Low',
|
|
146
|
+
};
|
|
147
|
+
return badges[impact?.level] || '⚪ Unrated';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// --- Manifest-driven suggestions (retro + lessons + effectiveness) ---
|
|
151
|
+
if (manifest && manifest.proposals) {
|
|
152
|
+
for (const proposal of manifest.proposals) {
|
|
153
|
+
// Skip previously rejected
|
|
154
|
+
if (rejectedItems.some(r => proposal.title.includes(r))) continue;
|
|
155
|
+
|
|
156
|
+
if (proposal.source === 'retro') {
|
|
157
|
+
suggestions.push({
|
|
158
|
+
num: itemNum++,
|
|
159
|
+
category: 'Retro',
|
|
160
|
+
impact: proposal.impact,
|
|
161
|
+
title: proposal.title,
|
|
162
|
+
detail: [
|
|
163
|
+
`**Area:** ${proposal.area}`,
|
|
164
|
+
`**Source Agent:** ${proposal.sourceAgent}`,
|
|
165
|
+
`**Severity:** ${proposal.severity}`,
|
|
166
|
+
proposal.recurring ? `**Recurring:** Yes — found in ${proposal.recurrenceSprints.join(', ')} (${proposal.recurrenceCount}x)` : null,
|
|
167
|
+
`**Suggested Fix:** ${proposal.suggestedFix}`,
|
|
168
|
+
].filter(Boolean).join('\n'),
|
|
169
|
+
target: mapAreaToTarget(proposal.area),
|
|
170
|
+
effort: proposal.severity === 'Blocker' ? 'Medium' : 'Low',
|
|
171
|
+
});
|
|
172
|
+
} else if (proposal.source === 'lesson') {
|
|
173
|
+
suggestions.push({
|
|
174
|
+
num: itemNum++,
|
|
175
|
+
category: 'Lesson → Automation',
|
|
176
|
+
impact: proposal.impact,
|
|
177
|
+
title: proposal.title,
|
|
178
|
+
detail: [
|
|
179
|
+
`**Rule:** ${proposal.rule}`,
|
|
180
|
+
`**What happened:** ${proposal.whatHappened}`,
|
|
181
|
+
`**Active for:** ${proposal.ageSprints} sprint(s) (since ${proposal.lessonDate})`,
|
|
182
|
+
`**Automation type:** ${proposal.automationType}`,
|
|
183
|
+
`**Action:** ${proposal.automationDetail?.action}`,
|
|
184
|
+
`**Rationale:** ${proposal.automationDetail?.rationale}`,
|
|
185
|
+
].filter(Boolean).join('\n'),
|
|
186
|
+
target: mapAutomationTypeToTarget(proposal.automationType),
|
|
187
|
+
effort: proposal.automationDetail?.effort || 'Low',
|
|
188
|
+
});
|
|
189
|
+
} else if (proposal.source === 'effectiveness_check') {
|
|
190
|
+
suggestions.push({
|
|
191
|
+
num: itemNum++,
|
|
192
|
+
category: 'Effectiveness',
|
|
193
|
+
impact: proposal.impact,
|
|
194
|
+
title: proposal.title,
|
|
195
|
+
detail: [
|
|
196
|
+
`**Status:** ${proposal.detail}`,
|
|
197
|
+
`**Originally applied in:** ${proposal.appliedInSprint}`,
|
|
198
|
+
'**Action:** Re-examine the original fix — it did not resolve the underlying issue.',
|
|
199
|
+
].join('\n'),
|
|
200
|
+
target: 'Review original improvement in .bounce/improvement-log.md',
|
|
201
|
+
effort: 'Medium',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// --- Metric-driven suggestions (from trends) ---
|
|
93
208
|
if (lastSprintStats) {
|
|
94
209
|
if (lastSprintStats.firstPassRate < 80) {
|
|
95
210
|
suggestions.push({
|
|
96
211
|
num: itemNum++,
|
|
97
|
-
category: '
|
|
212
|
+
category: 'Metrics',
|
|
213
|
+
impact: { level: 'P1', label: 'High' },
|
|
98
214
|
title: `Low first-pass rate (${lastSprintStats.firstPassRate}%)`,
|
|
99
215
|
detail: `First-pass rate was below 80% in ${lastSprintStats.sprintId}. This suggests spec ambiguity or insufficient context packs.`,
|
|
100
|
-
recommendation: 'Add spec quality gate to `validate_bounce_readiness.mjs`: check Story §1 word count > 50 and §2 has ≥ 2 Gherkin scenarios.',
|
|
101
216
|
target: 'scripts/validate_bounce_readiness.mjs',
|
|
102
217
|
effort: 'Low',
|
|
103
218
|
});
|
|
@@ -106,10 +221,10 @@ if (lastSprintStats) {
|
|
|
106
221
|
if (lastSprintStats.avgTax > 10) {
|
|
107
222
|
suggestions.push({
|
|
108
223
|
num: itemNum++,
|
|
109
|
-
category: '
|
|
224
|
+
category: 'Metrics',
|
|
225
|
+
impact: { level: 'P1', label: 'High' },
|
|
110
226
|
title: `High correction tax (${lastSprintStats.avgTax}% average)`,
|
|
111
|
-
detail: 'Average correction tax exceeded 10%, indicating significant human intervention
|
|
112
|
-
recommendation: 'Auto-flag stories with more than 3 files expected in Sprint Plan §2 Risk Flags. Consider splitting before bouncing.',
|
|
227
|
+
detail: 'Average correction tax exceeded 10%, indicating significant human intervention.',
|
|
113
228
|
target: 'skills/agent-team/SKILL.md Step 1',
|
|
114
229
|
effort: 'Low',
|
|
115
230
|
});
|
|
@@ -118,70 +233,117 @@ if (lastSprintStats) {
|
|
|
118
233
|
if (lastSprintStats.avgBounces > 0.5) {
|
|
119
234
|
suggestions.push({
|
|
120
235
|
num: itemNum++,
|
|
121
|
-
category: '
|
|
236
|
+
category: 'Metrics',
|
|
237
|
+
impact: { level: 'P2', label: 'Medium' },
|
|
122
238
|
title: `High bounce rate (${lastSprintStats.avgBounces} avg per story)`,
|
|
123
|
-
detail: 'Run `vbounce trends` to see root cause breakdown
|
|
124
|
-
recommendation: 'Review root_cause field in archived QA/Arch FAIL reports to identify systemic issues.',
|
|
239
|
+
detail: 'Run `vbounce trends` to see root cause breakdown.',
|
|
125
240
|
target: 'scripts/sprint_trends.mjs',
|
|
126
241
|
effort: 'Low',
|
|
127
242
|
});
|
|
128
243
|
}
|
|
129
244
|
}
|
|
130
245
|
|
|
131
|
-
//
|
|
246
|
+
// --- Lesson graduation ---
|
|
132
247
|
if (oldLessons.length > 0) {
|
|
133
248
|
const notRejected = oldLessons.filter(l => !rejectedItems.some(r => l.includes(r)));
|
|
134
249
|
if (notRejected.length > 0) {
|
|
135
250
|
suggestions.push({
|
|
136
251
|
num: itemNum++,
|
|
137
|
-
category: '
|
|
138
|
-
|
|
252
|
+
category: 'Graduation',
|
|
253
|
+
impact: { level: 'P2', label: 'Medium' },
|
|
254
|
+
title: `${notRejected.length} lesson(s) older than 90 days — graduation candidates`,
|
|
139
255
|
detail: notRejected.map(l => ` - ${l}`).join('\n'),
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
effort: 'Trivial',
|
|
256
|
+
target: 'LESSONS.md → brains/claude-agents/',
|
|
257
|
+
effort: 'Low',
|
|
143
258
|
});
|
|
144
259
|
}
|
|
145
260
|
}
|
|
146
261
|
|
|
147
|
-
//
|
|
148
|
-
suggestions.push({
|
|
149
|
-
num: itemNum++,
|
|
150
|
-
category: 'Framework',
|
|
151
|
-
title: 'Review lesson graduation candidates',
|
|
152
|
-
detail: `You have ${lessonCount} lessons in LESSONS.md. Lessons proven over 3+ sprints should graduate to permanent agent config rules.`,
|
|
153
|
-
recommendation: 'Run a review: which lessons have prevented recurrences for 3+ sprints? Graduate those to `.claude/agents/*.md` or `brains/claude-agents/*.md`.',
|
|
154
|
-
target: 'LESSONS.md + brains/claude-agents/',
|
|
155
|
-
effort: 'Low',
|
|
156
|
-
});
|
|
157
|
-
|
|
262
|
+
// --- Health check ---
|
|
158
263
|
suggestions.push({
|
|
159
264
|
num: itemNum++,
|
|
160
265
|
category: 'Health',
|
|
266
|
+
impact: { level: 'P3', label: 'Low' },
|
|
161
267
|
title: 'Run vbounce doctor',
|
|
162
268
|
detail: 'Verify the V-Bounce Engine installation is healthy after this sprint.',
|
|
163
|
-
recommendation: 'Run: `vbounce doctor` — checks brain files, templates, scripts, state.json validity.',
|
|
164
269
|
target: 'scripts/doctor.mjs',
|
|
165
270
|
effort: 'Trivial',
|
|
166
271
|
});
|
|
167
272
|
|
|
168
|
-
//
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
// 7. Format output
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
function mapAreaToTarget(area) {
|
|
278
|
+
const map = {
|
|
279
|
+
'Templates': 'templates/*.md',
|
|
280
|
+
'Agent Handoffs': 'brains/claude-agents/*.md',
|
|
281
|
+
'RAG Pipeline': 'scripts/prep_*.mjs',
|
|
282
|
+
'Skills': 'skills/*/SKILL.md',
|
|
283
|
+
'Process Flow': 'skills/agent-team/SKILL.md',
|
|
284
|
+
'Tooling & Scripts': 'scripts/*',
|
|
285
|
+
};
|
|
286
|
+
return map[area] || area;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function mapAutomationTypeToTarget(type) {
|
|
290
|
+
const map = {
|
|
291
|
+
'gate_check': '.bounce/gate-checks.json OR scripts/pre_gate_runner.sh',
|
|
292
|
+
'script': 'scripts/',
|
|
293
|
+
'template_field': 'templates/*.md',
|
|
294
|
+
'agent_config': 'brains/claude-agents/*.md',
|
|
295
|
+
};
|
|
296
|
+
return map[type] || type;
|
|
297
|
+
}
|
|
298
|
+
|
|
169
299
|
const suggestionBlocks = suggestions.map(s => {
|
|
170
|
-
|
|
171
|
-
return `### ${s.num}. [${s.category}] ${s.title}${rejectedNote}
|
|
300
|
+
return `### ${s.num}. [${badge(s.impact)}] [${s.category}] ${s.title}
|
|
172
301
|
${s.detail}
|
|
173
302
|
|
|
174
|
-
**Recommendation:** ${s.recommendation}
|
|
175
303
|
**Target:** \`${s.target}\`
|
|
176
304
|
**Effort:** ${s.effort}`;
|
|
177
305
|
}).join('\n\n---\n\n');
|
|
178
306
|
|
|
307
|
+
// Impact level reference
|
|
308
|
+
const impactRef = `## Impact Levels
|
|
309
|
+
|
|
310
|
+
| Level | Label | Meaning | Timeline |
|
|
311
|
+
|-------|-------|---------|----------|
|
|
312
|
+
| **P0** | 🔴 Critical | Blocks agent work or causes incorrect output | Fix before next sprint |
|
|
313
|
+
| **P1** | 🟠 High | Causes rework — bounces, wasted tokens, repeated manual steps | Fix this improvement cycle |
|
|
314
|
+
| **P2** | 🟡 Medium | Friction that slows agents but does not block | Fix within 2 sprints |
|
|
315
|
+
| **P3** | ⚪ Low | Polish — nice-to-have, batch with other improvements | Batch when convenient |`;
|
|
316
|
+
|
|
317
|
+
// Summary stats
|
|
318
|
+
const summarySection = manifest ? `## Summary
|
|
319
|
+
|
|
320
|
+
| Source | Count |
|
|
321
|
+
|--------|-------|
|
|
322
|
+
| Retro (§5 findings) | ${manifest.summary.bySource.retro} |
|
|
323
|
+
| Lesson → Automation | ${manifest.summary.bySource.lesson} |
|
|
324
|
+
| Effectiveness checks | ${manifest.summary.bySource.effectiveness_check} |
|
|
325
|
+
| Metric-driven | ${suggestions.filter(s => s.category === 'Metrics').length} |
|
|
326
|
+
| **Total** | **${suggestions.length}** |
|
|
327
|
+
|
|
328
|
+
| Impact | Count |
|
|
329
|
+
|--------|-------|
|
|
330
|
+
| 🔴 P0 Critical | ${manifest.summary.byImpact.P0} |
|
|
331
|
+
| 🟠 P1 High | ${manifest.summary.byImpact.P1 + suggestions.filter(s => s.category === 'Metrics' && s.impact.level === 'P1').length} |
|
|
332
|
+
| 🟡 P2 Medium | ${manifest.summary.byImpact.P2 + suggestions.filter(s => s.category === 'Metrics' && s.impact.level === 'P2').length} |
|
|
333
|
+
| ⚪ P3 Low | ${manifest.summary.byImpact.P3 + suggestions.filter(s => s.category === 'Health').length} |` : '';
|
|
334
|
+
|
|
179
335
|
const output = [
|
|
180
336
|
`# Improvement Suggestions (post ${sprintId})`,
|
|
181
337
|
`> Generated: ${today}. Review each item. Approved items are applied by the Lead at sprint boundary.`,
|
|
182
338
|
`> Rejected items go to \`.bounce/improvement-log.md\` with reason.`,
|
|
183
339
|
`> Applied items go to \`.bounce/improvement-log.md\` under Applied.`,
|
|
184
340
|
'',
|
|
341
|
+
impactRef,
|
|
342
|
+
'',
|
|
343
|
+
summarySection,
|
|
344
|
+
'',
|
|
345
|
+
'---',
|
|
346
|
+
'',
|
|
185
347
|
suggestionBlocks || '_No suggestions generated — all metrics look healthy!_',
|
|
186
348
|
'',
|
|
187
349
|
'---',
|
|
@@ -192,9 +354,10 @@ const output = [
|
|
|
192
354
|
`- **Defer** → Record in \`.bounce/improvement-log.md\` under Deferred`,
|
|
193
355
|
'',
|
|
194
356
|
`> Framework changes (brains/, skills/, templates/) are applied at sprint boundaries only — never mid-sprint.`,
|
|
357
|
+
`> Use \`/improve\` skill to have the Team Lead apply approved changes with brain-file sync.`,
|
|
195
358
|
].join('\n');
|
|
196
359
|
|
|
197
360
|
const outputFile = path.join(ROOT, '.bounce', 'improvement-suggestions.md');
|
|
198
|
-
fs.writeFileSync(outputFile, output);
|
|
361
|
+
fs.writeFileSync(outputFile, output);
|
|
199
362
|
console.log(`✓ Improvement suggestions written to .bounce/improvement-suggestions.md`);
|
|
200
363
|
console.log(` ${suggestions.length} suggestion(s) generated`);
|
|
@@ -176,24 +176,25 @@ Examples:
|
|
|
176
176
|
## The Bounce Sequence
|
|
177
177
|
|
|
178
178
|
### Step 0: Sprint Setup
|
|
179
|
+
|
|
180
|
+
**Prerequisite:** Sprint Planning (Phase 2) must be complete. The Sprint Plan must be in "Confirmed" status with human approval before proceeding.
|
|
181
|
+
|
|
179
182
|
```
|
|
180
183
|
1. Cut sprint branch from main:
|
|
181
184
|
git checkout -b sprint/S-01 main
|
|
182
185
|
mkdir -p .bounce/archive
|
|
183
186
|
|
|
184
|
-
2.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
3
|
|
188
|
-
If
|
|
189
|
-
Do NOT start bouncing stories with unresolved blocking questions.
|
|
187
|
+
2. Verify Sprint Plan:
|
|
188
|
+
- Sprint Plan status must be "Confirmed" (human-approved in Phase 2)
|
|
189
|
+
- §0 Sprint Readiness Gate must be fully checked
|
|
190
|
+
- §3 Sprint Open Questions must have no unresolved blocking items
|
|
191
|
+
If any check fails, return to Phase 2 (Sprint Planning).
|
|
190
192
|
|
|
191
|
-
|
|
193
|
+
3. If vdocs/_manifest.json exists, read it.
|
|
192
194
|
Understand what's already documented — this informs which stories
|
|
193
195
|
may require doc updates after the sprint.
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
use the **Hotfix Path**:
|
|
197
|
+
4. **Hotfix Path** (L1 Trivial tasks only — triaged during Phase 1):
|
|
197
198
|
a. Create `HOTFIX-{Date}-{Name}.md` using the template.
|
|
198
199
|
b. Delegate to Developer (no worktree needed if acting on active branch).
|
|
199
200
|
c. Developer runs `hotfix_manager.sh ledger "{Title}" "{Description}"` after implementation.
|
|
@@ -201,26 +202,35 @@ Examples:
|
|
|
201
202
|
e. DevOps runs `hotfix_manager.sh sync` to update any active story worktrees.
|
|
202
203
|
f. Update Delivery Plan Status to "Done".
|
|
203
204
|
|
|
204
|
-
|
|
205
|
+
5. **Gate Config Check**:
|
|
205
206
|
- If `.bounce/gate-checks.json` does not exist, run `./scripts/init_gate_config.sh` to auto-detect the project stack and generate default gate checks.
|
|
206
207
|
- If it exists, verify it's current (stack detection may have changed).
|
|
207
208
|
|
|
208
|
-
|
|
209
|
+
6. **Parallel Readiness Check** (before bouncing multiple stories simultaneously):
|
|
209
210
|
- Verify test runner config excludes `.worktrees/` (vitest, jest, pytest, etc.)
|
|
210
211
|
- Verify no shared mutable state between worktrees (e.g., shared temp files, singletons writing to same path)
|
|
211
212
|
- Verify `.gitignore` includes `.worktrees/`
|
|
212
213
|
If any check fails, fix before spawning parallel stories. Intermittent test failures from worktree cross-contamination erode trust in the test suite fast.
|
|
213
214
|
|
|
214
|
-
|
|
215
|
-
- For each story, check the `Depends On:` field in its template.
|
|
216
|
-
- If Story B depends on Story A, you MUST execute them sequentially. Do not create Story B's worktree or spawn its Developer until Story A has successfully passed the DevOps merge step.
|
|
217
|
-
- Determine Execution Mode:
|
|
218
|
-
- **Full Bounce (Default)**: Normal L2-L4 stories go through full Dev → QA → Architect → DevOps flow.
|
|
219
|
-
- **Fast Track (L1/L2 Minor)**: For cosmetic UI tweaks or isolated refactors, execute Dev → DevOps only. Skip QA and Architect loops to save overhead. Validate manually during Sprint Review.
|
|
220
|
-
|
|
221
|
-
9. Update sprint-{XX}.md: Status → "Active"
|
|
215
|
+
7. Update sprint-{XX}.md: Status → "Active"
|
|
222
216
|
```
|
|
223
217
|
|
|
218
|
+
**Note:** Risk assessment, dependency checks, scope selection, and execution mode decisions all happen during Sprint Planning (Phase 2), not here. Step 0 executes the confirmed plan.
|
|
219
|
+
|
|
220
|
+
### Step 0.5: Discovery Check (L4 / 🔴 Stories Only)
|
|
221
|
+
|
|
222
|
+
Before moving any story to Ready to Bounce:
|
|
223
|
+
|
|
224
|
+
1. For each story with `complexity_label: L4` or `ambiguity: 🔴 High`:
|
|
225
|
+
- Check for linked spikes in `product_plans/backlog/EPIC-{NNN}_{name}/SPIKE-*.md`
|
|
226
|
+
- If no spikes exist → create them (invoke doc-manager ambiguity rubric)
|
|
227
|
+
- If spikes exist but are not Validated/Closed → execute discovery sub-flow
|
|
228
|
+
- See `skills/agent-team/references/discovery.md`
|
|
229
|
+
|
|
230
|
+
2. Once all spikes are Validated/Closed:
|
|
231
|
+
- Update story `ambiguity` frontmatter (should now be 🟡 or 🟢)
|
|
232
|
+
- Transition: Probing/Spiking → Refinement → Ready to Bounce
|
|
233
|
+
|
|
224
234
|
### Step 1: Story Initialization
|
|
225
235
|
For each story with V-Bounce State "Ready to Bounce":
|
|
226
236
|
```bash
|
|
@@ -253,6 +263,8 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.bounce/{tasks,reports}
|
|
|
253
263
|
./scripts/pre_gate_runner.sh qa .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
254
264
|
- If scan FAILS on trivial issues (debug statements, missing JSDoc, TODOs):
|
|
255
265
|
Return to Developer for quick fix. Do NOT spawn QA for mechanical failures.
|
|
266
|
+
If pre-gate scan fails 3+ times → Escalate: present failures to human with options:
|
|
267
|
+
a) Human fixes manually, b) Descope the story, c) Re-assign to a different approach.
|
|
256
268
|
- If scan PASSES: Include scan output path in the QA task file.
|
|
257
269
|
1. Spawn qa subagent in .worktrees/STORY-{ID}-{StoryName}/ with:
|
|
258
270
|
- Developer Implementation Report
|
|
@@ -277,6 +289,7 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.bounce/{tasks,reports}
|
|
|
277
289
|
./scripts/pre_gate_runner.sh arch .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
278
290
|
- If scan reveals new dependencies or structural violations:
|
|
279
291
|
Return to Developer for resolution. Do NOT spawn Architect for mechanical failures.
|
|
292
|
+
If pre-gate scan fails 3+ times → Escalate to human (same options as pre-QA escalation).
|
|
280
293
|
- If scan PASSES: Include scan output path in the Architect task file.
|
|
281
294
|
1. Spawn architect subagent in .worktrees/STORY-{ID}-{StoryName}/ with:
|
|
282
295
|
- All reports for this story
|
|
@@ -309,10 +322,27 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.bounce/{tasks,reports}
|
|
|
309
322
|
4. If merge conflicts:
|
|
310
323
|
- Simple (imports, whitespace): DevOps resolves directly
|
|
311
324
|
- Complex (logic): DevOps writes Conflict Report, Lead creates fix story
|
|
312
|
-
5. If post-merge tests fail:
|
|
325
|
+
5. If post-merge tests fail:
|
|
326
|
+
- DevOps reverts the merge and writes a Post-Merge Failure Report (what failed, which tests, suspected cause)
|
|
327
|
+
- Lead returns story to Developer with the failure report as input
|
|
328
|
+
- Developer fixes in the original worktree (which is preserved until merge succeeds)
|
|
329
|
+
- Story re-enters the bounce at Step 2 (Dev pass). QA/Arch bounce counts are NOT reset — this is a merge issue, not a gate failure.
|
|
330
|
+
- If post-merge fails 3+ times → Escalate to human
|
|
313
331
|
```
|
|
314
332
|
Update sprint-{XX}.md: V-Bounce State → "Done"
|
|
315
333
|
|
|
334
|
+
### Step 5.5: Immediate Lesson Recording
|
|
335
|
+
After each story merge, before proceeding to the next story:
|
|
336
|
+
```
|
|
337
|
+
1. Read Dev report — check `lessons_flagged` field
|
|
338
|
+
2. Read QA report — check for lessons flagged during validation
|
|
339
|
+
3. For each flagged lesson:
|
|
340
|
+
- Present to the human for approval
|
|
341
|
+
- If approved → record to LESSONS.md immediately (follow lesson skill format)
|
|
342
|
+
- If rejected → note as "No" in Sprint Report §4
|
|
343
|
+
4. Do NOT defer this to Step 7 — context decays fast
|
|
344
|
+
```
|
|
345
|
+
|
|
316
346
|
### Step 6: Sprint Integration Audit
|
|
317
347
|
After ALL stories are merged into `sprint/S-01`:
|
|
318
348
|
```
|
|
@@ -320,7 +350,11 @@ After ALL stories are merged into `sprint/S-01`:
|
|
|
320
350
|
2. First, Architect runs `./scripts/hotfix_manager.sh audit` to check for hotfix drift. If it fails, perform deep audit on flagged files.
|
|
321
351
|
3. Run Sprint Integration Audit — Deep Audit on combined changes
|
|
322
352
|
4. Check for: duplicate routes, competing state, overlapping migrations
|
|
323
|
-
5. If issues found
|
|
353
|
+
5. If issues found:
|
|
354
|
+
- Present findings to human with severity assessment
|
|
355
|
+
- AI suggests which epic the fix story should belong to
|
|
356
|
+
- Fix stories are added to the BACKLOG (not the current sprint) — they enter the next sprint through normal planning
|
|
357
|
+
- Exception: if the issue blocks the sprint release (e.g., broken build), fix inline on the sprint branch without creating a story
|
|
324
358
|
```
|
|
325
359
|
|
|
326
360
|
### Step 7: Sprint Consolidation
|
|
@@ -336,12 +370,12 @@ After ALL stories are merged into `sprint/S-01`:
|
|
|
336
370
|
```
|
|
337
371
|
4. V-Bounce State → "Sprint Review" for all stories
|
|
338
372
|
4. Present Sprint Report to human
|
|
339
|
-
5. **
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
6. After
|
|
373
|
+
5. **Lesson Review (non-blocking):**
|
|
374
|
+
Most lessons should already be recorded to LESSONS.md during Step 5.5.
|
|
375
|
+
Review §4 of the Sprint Report — confirm all flagged lessons have a status.
|
|
376
|
+
If any lessons were missed during Step 5.5, present them now and record approved ones.
|
|
377
|
+
This is a review step, not a first-time approval gate.
|
|
378
|
+
6. After review → Spawn devops subagent for Sprint Release:
|
|
345
379
|
- Merge sprint/S-01 → main (--no-ff)
|
|
346
380
|
- Tag release: v{VERSION}
|
|
347
381
|
- Run full test suite + build + lint on main
|
|
@@ -435,7 +469,7 @@ The Team Lead MUST update the active `sprint-{XX}.md` at every state transition.
|
|
|
435
469
|
| Architect passes | §1: V-Bounce State → "Architect Passed" | **Nothing** |
|
|
436
470
|
| DevOps merges story | §1: V-Bounce State → "Done". §4: Add Execution Log row (via `vbounce story complete`) | **Nothing** |
|
|
437
471
|
| Escalated | §1: Move story to Escalated section | **Nothing** |
|
|
438
|
-
| Sprint CLOSES | Status → "Completed" in frontmatter | §2: sprint → Completed. §4: add summary. §3: remove delivered stories |
|
|
472
|
+
| Sprint CLOSES | Status → "Completed" in frontmatter | §2: sprint → Completed. §4: add summary. §3: remove delivered stories. **This is the ONLY time Delivery Plan updates.** |
|
|
439
473
|
|
|
440
474
|
> **Key rule**: The Delivery Plan is updated ONLY at sprint close, never during active bouncing.
|
|
441
475
|
> See `skills/agent-team/references/delivery-sync.md` for full sync rules.
|
|
@@ -501,6 +535,7 @@ If merging story branch into sprint branch creates conflicts:
|
|
|
501
535
|
- **Check risks before bouncing.** Read RISK_REGISTRY.md at sprint start. Flag high-severity risks that affect planned stories.
|
|
502
536
|
- **Resolve open questions first.** Read the active `sprint-{XX}.md` §2 Sprint Open Questions at sprint start. Do not bounce stories with unresolved blocking questions.
|
|
503
537
|
- **Know what's documented.** If `vdocs/_manifest.json` exists, read it at sprint start. Pass relevant doc references to agents. Offer documentation updates after sprints that deliver new features.
|
|
538
|
+
- **Resolve discovery before bouncing.** L4 stories and 🔴 ambiguity stories MUST complete spikes before entering the bounce sequence. See `skills/agent-team/references/discovery.md`.
|
|
504
539
|
|
|
505
540
|
## Keywords
|
|
506
541
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Discovery Phase — Spike Execution Protocol
|
|
2
|
+
|
|
3
|
+
> On-demand reference from agent-team/SKILL.md. When and how to run discovery spikes for ambiguous work.
|
|
4
|
+
|
|
5
|
+
## When Discovery Triggers
|
|
6
|
+
|
|
7
|
+
1. **Epic-level 🔴 ambiguity** — detected during Epic creation or review via the doc-manager ambiguity assessment rubric.
|
|
8
|
+
2. **Story labeled L4** — transitioning to Probing/Spiking state. L4 stories MUST have at least one linked spike before they can progress.
|
|
9
|
+
3. **Blocking Open Questions** — Epic §8 has items marked "Blocking" with no ADR or prior decision.
|
|
10
|
+
|
|
11
|
+
## Spike Lifecycle
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Open → Investigating → Findings Ready → Validated → Closed
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Status | Who Acts | What Happens |
|
|
18
|
+
|--------|----------|-------------|
|
|
19
|
+
| **Open** | Team Lead | Spike created from `templates/spike.md`, linked in Epic §9 |
|
|
20
|
+
| **Investigating** | Developer | Code exploration, prototyping, benchmarks. Fills §4 Findings and §5 Decision |
|
|
21
|
+
| **Findings Ready** | Developer → Architect | Developer marks complete. Awaiting Architect validation |
|
|
22
|
+
| **Validated** | Architect | Confirms findings against Safe Zone and ADRs. PASS → Validated. FAIL → back to Investigating |
|
|
23
|
+
| **Closed** | Team Lead | All §7 Affected Documents checked off. Findings propagated to Epic, Roadmap, Risk Registry |
|
|
24
|
+
|
|
25
|
+
## Execution Protocol
|
|
26
|
+
|
|
27
|
+
### Step 1: Create Spike (Team Lead)
|
|
28
|
+
|
|
29
|
+
1. Identify the blocking unknown (from Epic §8 Open Questions or 🔴 ambiguity signals)
|
|
30
|
+
2. Create spike document from `templates/spike.md`
|
|
31
|
+
3. Fill §1 Question, §2 Constraints, §3 Approach
|
|
32
|
+
4. Set status → Open
|
|
33
|
+
5. Link spike in parent Epic §9 Artifact Links
|
|
34
|
+
6. Set time box (default: 4 hours for focused questions, 1 day for broader exploration)
|
|
35
|
+
|
|
36
|
+
### Step 2: Investigate (Developer)
|
|
37
|
+
|
|
38
|
+
1. Read the spike §1 Question, §2 Constraints, §3 Approach
|
|
39
|
+
2. Read parent Epic §4 Technical Context for existing knowledge
|
|
40
|
+
3. Investigate using the specified approach (code exploration, prototyping, benchmarks, doc research)
|
|
41
|
+
4. Fill §4 Findings with evidence and data
|
|
42
|
+
5. Fill §5 Decision with chosen approach, rationale, and rejected alternatives
|
|
43
|
+
6. Mark §5 ADR Required if the decision is architectural
|
|
44
|
+
7. Fill §6 Residual Risk if unknowns remain
|
|
45
|
+
8. Set status → Findings Ready
|
|
46
|
+
|
|
47
|
+
### Step 3: Validate (Architect)
|
|
48
|
+
|
|
49
|
+
1. Read the spike §4 Findings and §5 Decision
|
|
50
|
+
2. Validate against:
|
|
51
|
+
- Safe Zone compliance (no unauthorized patterns or libraries)
|
|
52
|
+
- Existing ADRs in Roadmap §3 (no contradictions)
|
|
53
|
+
- Risk profile (§6 Residual Risk is acceptable)
|
|
54
|
+
3. If **PASS** → status → Validated
|
|
55
|
+
4. If **FAIL** → provide specific feedback, status remains Findings Ready, Developer re-investigates
|
|
56
|
+
|
|
57
|
+
### Step 4: Close & Propagate (Team Lead)
|
|
58
|
+
|
|
59
|
+
1. Walk through §7 Affected Documents checklist:
|
|
60
|
+
- Update Epic §4 Technical Context with findings
|
|
61
|
+
- Mark Epic §8 Open Questions as resolved
|
|
62
|
+
- Add spike reference to Epic §9 Artifact Links
|
|
63
|
+
- If §5 ADR Required → create new ADR row in Roadmap §3
|
|
64
|
+
- If §6 Residual Risk has entries → add to Risk Registry §1
|
|
65
|
+
- If story-level spike → update Story §3 Implementation Guide
|
|
66
|
+
2. Check off all items in §7
|
|
67
|
+
3. Set status → Closed
|
|
68
|
+
4. Parent story transitions: Probing/Spiking → Refinement
|
|
69
|
+
|
|
70
|
+
## Timing Rules
|
|
71
|
+
|
|
72
|
+
- Spikes happen during **planning/refinement**, NOT during sprint execution
|
|
73
|
+
- No worktrees needed — spikes produce documents, not code
|
|
74
|
+
- Time box is enforced — if the time box expires without findings, the spike is escalated to the human with a status report
|
|
75
|
+
- Prototypes created during spikes are **throwaway** — they are NOT committed to any branch
|
|
76
|
+
|
|
77
|
+
## What Spikes Are NOT
|
|
78
|
+
|
|
79
|
+
- **Not production code.** Spikes produce findings and decisions, not shippable code.
|
|
80
|
+
- **Not QA/DevOps passes.** No bounce sequence, no gate reports, no merge operations.
|
|
81
|
+
- **Not a worktree activity.** Spikes are document-level work, not branch-level work.
|
|
82
|
+
- **Not open-ended research.** Every spike has a time box and a specific question. If the question is too broad, split into multiple spikes.
|
|
83
|
+
|
|
84
|
+
## Integration with Bounce Sequence
|
|
85
|
+
|
|
86
|
+
Spikes gate the transition from Probing/Spiking → Refinement → Ready to Bounce:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Story (L4 / 🔴) → Probing/Spiking
|
|
90
|
+
└── Spike(s) created
|
|
91
|
+
└── Developer investigates → Architect validates → Team Lead propagates
|
|
92
|
+
└── All spikes Validated/Closed
|
|
93
|
+
└── Story ambiguity updated (should now be 🟡 or 🟢)
|
|
94
|
+
└── Story → Refinement → Ready to Bounce
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
No story may enter Ready to Bounce while it has linked spikes in Open, Investigating, or Findings Ready status.
|