@seanyao/roll 0.5.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.
Files changed (50) hide show
  1. package/README.md +201 -0
  2. package/bin/roll +1375 -0
  3. package/conventions/config.yaml +15 -0
  4. package/conventions/global/.cursor-rules +31 -0
  5. package/conventions/global/AGENTS.md +100 -0
  6. package/conventions/global/CLAUDE.md +32 -0
  7. package/conventions/global/GEMINI.md +28 -0
  8. package/conventions/templates/backend-service/.cursor-rules +17 -0
  9. package/conventions/templates/backend-service/AGENTS.md +88 -0
  10. package/conventions/templates/backend-service/CLAUDE.md +18 -0
  11. package/conventions/templates/backend-service/GEMINI.md +16 -0
  12. package/conventions/templates/cli/.cursor-rules +17 -0
  13. package/conventions/templates/cli/AGENTS.md +66 -0
  14. package/conventions/templates/cli/CLAUDE.md +18 -0
  15. package/conventions/templates/cli/GEMINI.md +16 -0
  16. package/conventions/templates/frontend-only/.cursor-rules +16 -0
  17. package/conventions/templates/frontend-only/AGENTS.md +71 -0
  18. package/conventions/templates/frontend-only/CLAUDE.md +16 -0
  19. package/conventions/templates/frontend-only/GEMINI.md +14 -0
  20. package/conventions/templates/fullstack/.cursor-rules +17 -0
  21. package/conventions/templates/fullstack/AGENTS.md +87 -0
  22. package/conventions/templates/fullstack/CLAUDE.md +17 -0
  23. package/conventions/templates/fullstack/GEMINI.md +15 -0
  24. package/package.json +33 -0
  25. package/skills/roll-.changelog/SKILL.md +79 -0
  26. package/skills/roll-.clarify/SKILL.md +59 -0
  27. package/skills/roll-.echo/SKILL.md +113 -0
  28. package/skills/roll-.qa/SKILL.md +204 -0
  29. package/skills/roll-.review/SKILL.md +105 -0
  30. package/skills/roll-build/SKILL.md +559 -0
  31. package/skills/roll-debug/SKILL.md +428 -0
  32. package/skills/roll-design/ENGINEERING_CHECKLIST.md +256 -0
  33. package/skills/roll-design/SKILL.md +276 -0
  34. package/skills/roll-fix/SKILL.md +442 -0
  35. package/skills/roll-jot/SKILL.md +50 -0
  36. package/skills/roll-research/SKILL.md +307 -0
  37. package/skills/roll-research/references/schema.json +162 -0
  38. package/skills/roll-research/scripts/md_to_pdf.py +289 -0
  39. package/skills/roll-sentinel/SKILL.md +355 -0
  40. package/skills/roll-spar/SKILL.md +287 -0
  41. package/template/.env.example +47 -0
  42. package/template/.github/workflows/ci.yml +32 -0
  43. package/template/.github/workflows/sentinel.yml +26 -0
  44. package/template/AGENTS.md +80 -0
  45. package/template/BACKLOG.md +42 -0
  46. package/template/package.json +43 -0
  47. package/tools/roll-fetch/SKILL.md +182 -0
  48. package/tools/roll-fetch/package.json +15 -0
  49. package/tools/roll-fetch/smart-web-fetch.js +558 -0
  50. package/tools/roll-probe/SKILL.md +84 -0
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Deep Research Report: Markdown to PDF converter (WeasyPrint)
4
+ Usage: python md_to_pdf.py input.md output.pdf [--title "Report Title"] [--author "Author"]
5
+
6
+ Dependencies: pip install weasyprint markdown --break-system-packages
7
+ """
8
+
9
+ import sys
10
+ import os
11
+ import re
12
+ import argparse
13
+ import markdown
14
+
15
+ # ── CSS Styles ──
16
+ CSS_TEMPLATE = """
17
+ @page {
18
+ size: A4;
19
+ margin: 25mm 20mm 20mm 20mm;
20
+
21
+ @top-center {
22
+ content: "HEADER_TEXT";
23
+ font-family: "Droid Sans Fallback", Helvetica, Arial, sans-serif;
24
+ font-size: 8pt;
25
+ color: #95a5a6;
26
+ border-bottom: 0.5pt solid #ecf0f1;
27
+ padding-bottom: 3mm;
28
+ }
29
+
30
+ @bottom-center {
31
+ content: "Page " counter(page);
32
+ font-family: "Droid Sans Fallback", Helvetica, Arial, sans-serif;
33
+ font-size: 8pt;
34
+ color: #95a5a6;
35
+ border-top: 0.8pt solid #1a5276;
36
+ padding-top: 2mm;
37
+ }
38
+ }
39
+
40
+ @page :first {
41
+ @top-center { content: none; }
42
+ @bottom-center { content: none; }
43
+ }
44
+
45
+ body {
46
+ font-family: "Droid Sans Fallback", Helvetica, Arial, sans-serif;
47
+ font-size: 10.5pt;
48
+ line-height: 1.75;
49
+ color: #2c3e50;
50
+ text-align: justify;
51
+ }
52
+
53
+ /* Cover page */
54
+ .cover {
55
+ page-break-after: always;
56
+ text-align: center;
57
+ padding-top: 45%;
58
+ }
59
+ .cover h1 {
60
+ font-size: 28pt;
61
+ color: #1a5276;
62
+ margin-bottom: 8mm;
63
+ font-weight: bold;
64
+ letter-spacing: 2pt;
65
+ }
66
+ .cover .subtitle {
67
+ font-size: 14pt;
68
+ color: #95a5a6;
69
+ margin-bottom: 6mm;
70
+ }
71
+ .cover .meta {
72
+ font-size: 11pt;
73
+ color: #95a5a6;
74
+ margin-bottom: 4mm;
75
+ }
76
+ .cover .divider {
77
+ width: 60%;
78
+ margin: 8mm auto;
79
+ border: none;
80
+ border-top: 1.5pt solid #1a5276;
81
+ }
82
+
83
+ /* H1 */
84
+ h1 {
85
+ font-size: 20pt;
86
+ color: #1a5276;
87
+ margin-top: 16mm;
88
+ margin-bottom: 6mm;
89
+ padding-bottom: 3mm;
90
+ border-bottom: 2pt solid #1a5276;
91
+ page-break-before: always;
92
+ font-weight: bold;
93
+ }
94
+
95
+ /* H2 */
96
+ h2 {
97
+ font-size: 14pt;
98
+ color: #1e8449;
99
+ margin-top: 10mm;
100
+ margin-bottom: 5mm;
101
+ font-weight: bold;
102
+ }
103
+
104
+ /* H3 */
105
+ h3 {
106
+ font-size: 12pt;
107
+ color: #2e86c1;
108
+ margin-top: 6mm;
109
+ margin-bottom: 3mm;
110
+ font-weight: bold;
111
+ }
112
+
113
+ h4 {
114
+ font-size: 11pt;
115
+ color: #5b2c6f;
116
+ margin-top: 5mm;
117
+ margin-bottom: 2mm;
118
+ font-weight: bold;
119
+ }
120
+
121
+ /* Paragraphs */
122
+ p {
123
+ margin-top: 1.5mm;
124
+ margin-bottom: 1.5mm;
125
+ orphans: 3;
126
+ widows: 3;
127
+ }
128
+
129
+ /* Blockquotes */
130
+ blockquote {
131
+ margin: 4mm 0;
132
+ padding: 4mm 4mm 4mm 10mm;
133
+ background: #f8f9fa;
134
+ border-left: 3pt solid #1a5276;
135
+ color: #5d6d7e;
136
+ font-size: 10pt;
137
+ }
138
+ blockquote p {
139
+ margin: 1mm 0;
140
+ }
141
+
142
+ /* Bold */
143
+ strong, b {
144
+ font-weight: bold;
145
+ color: #1a252f;
146
+ }
147
+
148
+ /* Inline code */
149
+ code {
150
+ font-family: "Courier New", Courier, monospace;
151
+ background: #fdf2e9;
152
+ color: #c0392b;
153
+ padding: 0.5mm 1.5mm;
154
+ border-radius: 2pt;
155
+ font-size: 9.5pt;
156
+ }
157
+
158
+ /* Tables */
159
+ table {
160
+ width: 100%;
161
+ border-collapse: collapse;
162
+ margin: 4mm 0;
163
+ font-size: 9.5pt;
164
+ }
165
+ thead th {
166
+ background: #1a5276;
167
+ color: white;
168
+ padding: 3mm;
169
+ text-align: left;
170
+ font-weight: bold;
171
+ }
172
+ tbody td {
173
+ padding: 2.5mm 3mm;
174
+ border-bottom: 0.5pt solid #bdc3c7;
175
+ }
176
+ tbody tr:nth-child(even) {
177
+ background: #f8f9fa;
178
+ }
179
+
180
+ /* Horizontal rule */
181
+ hr {
182
+ border: none;
183
+ border-top: 0.5pt solid #bdc3c7;
184
+ margin: 4mm 0;
185
+ }
186
+
187
+ /* Lists */
188
+ ul, ol {
189
+ margin: 2mm 0;
190
+ padding-left: 8mm;
191
+ }
192
+ li {
193
+ margin-bottom: 1mm;
194
+ }
195
+
196
+ /* Links */
197
+ a {
198
+ color: #2e86c1;
199
+ text-decoration: none;
200
+ }
201
+ """
202
+
203
+
204
+ def md_to_html(md_text, title="Deep Research Report", subtitle="Let's roll",
205
+ meta_line="", author="roll"):
206
+ """Convert Markdown to HTML with cover page"""
207
+
208
+ # Convert body with markdown library
209
+ html_body = markdown.markdown(
210
+ md_text,
211
+ extensions=['tables', 'fenced_code', 'nl2br'],
212
+ output_format='html5'
213
+ )
214
+
215
+ # Extract first H1 for cover (remove from body)
216
+ first_h1_match = re.search(r'<h1>(.*?)</h1>', html_body)
217
+ if first_h1_match:
218
+ extracted_title = first_h1_match.group(1)
219
+ if not title or title == "Deep Research Report":
220
+ title = extracted_title
221
+ html_body = html_body.replace(first_h1_match.group(0), '', 1)
222
+
223
+ # Replace header placeholder in CSS
224
+ css = CSS_TEMPLATE.replace("HEADER_TEXT", f"{title} | Deep Research Report")
225
+
226
+ # Build cover page
227
+ cover_html = f"""
228
+ <div class="cover">
229
+ <h1 style="page-break-before: avoid; border: none;">{title}</h1>
230
+ <div class="subtitle">{subtitle}</div>
231
+ {"<div class='meta'>" + meta_line + "</div>" if meta_line else ""}
232
+ <hr class="divider">
233
+ <div class="meta">Author: {author}</div>
234
+ </div>
235
+ """
236
+
237
+ full_html = f"""<!DOCTYPE html>
238
+ <html lang="en">
239
+ <head>
240
+ <meta charset="UTF-8">
241
+ <style>{css}</style>
242
+ </head>
243
+ <body>
244
+ {cover_html}
245
+ {html_body}
246
+ </body>
247
+ </html>"""
248
+
249
+ return full_html
250
+
251
+
252
+ def main():
253
+ parser = argparse.ArgumentParser(description="Deep Research Report: Markdown to PDF")
254
+ parser.add_argument("input", help="Input Markdown file path")
255
+ parser.add_argument("output", help="Output PDF file path")
256
+ parser.add_argument("--title", default=None, help="Report title")
257
+ parser.add_argument("--author", default="roll", help="Author name")
258
+ parser.add_argument("--subtitle", default="Let's roll", help="Report subtitle")
259
+ args = parser.parse_args()
260
+
261
+ with open(args.input, "r", encoding="utf-8") as f:
262
+ md_text = f.read()
263
+
264
+ # Extract metadata line
265
+ meta_line = ""
266
+ for line in md_text.split("\n"):
267
+ stripped = line.strip().lstrip(">").strip()
268
+ if "research date" in stripped.lower() or "field:" in stripped.lower() or "subject type" in stripped.lower():
269
+ meta_line = stripped
270
+ break
271
+
272
+ html = md_to_html(md_text, title=args.title or "Deep Research Report",
273
+ subtitle=args.subtitle, meta_line=meta_line, author=args.author)
274
+
275
+ # Save intermediate HTML (for debugging)
276
+ html_path = args.output.replace('.pdf', '.html')
277
+ with open(html_path, 'w', encoding='utf-8') as f:
278
+ f.write(html)
279
+ print(f"[OK] HTML generated: {html_path}")
280
+
281
+ # Convert to PDF
282
+ from weasyprint import HTML
283
+ HTML(string=html).write_pdf(args.output)
284
+ size_kb = os.path.getsize(args.output) / 1024
285
+ print(f"[OK] PDF generated: {args.output} ({size_kb:.1f} KB)")
286
+
287
+
288
+ if __name__ == "__main__":
289
+ main()
@@ -0,0 +1,355 @@
1
+ ---
2
+ name: roll-sentinel
3
+ description: Smart patrol inspector for production systems. Scheduled randomized sampling checks based on BACKLOG requirements. Cost-controlled AI validation with intelligent spot-checking logic.
4
+ ---
5
+
6
+ # Sentinel
7
+
8
+ **Smart Patrol Inspector** - Scheduled, randomized, cost-controlled patrol and acceptance checks for production systems.
9
+
10
+ ## Core Principle
11
+
12
+ ```
13
+ ┌─────────────────────────────────────────────────────────────┐
14
+ │ Smart Patrol Logic │
15
+ ├─────────────────────────────────────────────────────────────┤
16
+ │ │
17
+ │ Not full-coverage checks! Think of it like a security │
18
+ │ guard on patrol: │
19
+ │ │
20
+ │ 🕐 Scheduled Triggers - Auto-patrol on schedule │
21
+ │ └── "Patrol once every 6 hours" │
22
+ │ │
23
+ │ 🎲 Random Sampling - Different samples each time │
24
+ │ └── "Check Stories 1-10 this time, 50-60 next time" │
25
+ │ │
26
+ │ 💰 Cost Control - AI checks are expensive, use sparingly │
27
+ │ └── "Only check 10 each time, not all 100" │
28
+ │ │
29
+ │ 🎯 BACKLOG-Based - Validate against requirements │
30
+ │ └── "US-001 says login works, so verify login" │
31
+ │ │
32
+ └─────────────────────────────────────────────────────────────┘
33
+ ```
34
+
35
+ ## Patrol Strategy
36
+
37
+ ### Sampling Logic
38
+
39
+ ```javascript
40
+ // Sampling logic for each patrol
41
+ function selectSamples(backlog, strategy = 'smart') {
42
+ const completedStories = backlog.filter(s => s.status === '✅');
43
+
44
+ switch(strategy) {
45
+ case 'random':
46
+ // Fully random: randomly select N from all completed Stories
47
+ return shuffle(completedStories).slice(0, 10);
48
+
49
+ case 'weighted':
50
+ // Weighted random: prioritize recently modified and frequently used
51
+ return completedStories
52
+ .sort((a, b) => b.lastModified - a.lastModified)
53
+ .slice(0, 5) // 5 most recent
54
+ .concat(shuffle(completedStories).slice(0, 5)); // + 5 random
55
+
56
+ case 'coverage':
57
+ // Coverage sampling: ensure different modules are all covered
58
+ const byModule = groupBy(completedStories, 'module');
59
+ return Object.values(byModule).map(
60
+ stories => randomPick(stories)
61
+ );
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### Cost Control
67
+
68
+ | Strategy | Sample Size | Frequency | Use Case |
69
+ |----------|-------------|-----------|----------|
70
+ | **Light** | 5 Stories | Once daily | Stable period |
71
+ | **Normal** | 10 Stories | Every 6 hours | General monitoring |
72
+ | **Intensive** | 20 Stories | Every hour | Post-release period |
73
+ | **Full** | All | Once weekly | Weekly patrol |
74
+
75
+ ```yaml
76
+ # sentinel.config.yml
77
+ cost_control:
78
+ daily_budget: 100 # AI call budget
79
+
80
+ light_patrol:
81
+ samples: 5
82
+ schedule: "0 9 * * *" # Daily at 9am
83
+
84
+ normal_patrol:
85
+ samples: 10
86
+ schedule: "0 */6 * * *" # Every 6 hours
87
+
88
+ # Intensive patrol after deployment
89
+ post_deploy:
90
+ trigger: "after_deploy"
91
+ samples: 20
92
+ duration: "2h" # Lasts 2 hours
93
+ ```
94
+
95
+ ### Uncertainty Handling
96
+
97
+ ```javascript
98
+ // Systems have uncertainty; a single check may be inaccurate.
99
+ // Use multiple random checks to increase confidence.
100
+
101
+ class UncertaintyHandler {
102
+ // Track check result history
103
+ history = new Map(); // storyId -> [check1, check2, ...]
104
+
105
+ // Determine if an issue is real
106
+ isRealIssue(storyId, currentResult) {
107
+ const pastResults = this.history.get(storyId) || [];
108
+ pastResults.push(currentResult);
109
+
110
+ // Only consider it a real issue if it fails 3 times consecutively
111
+ const recent3 = pastResults.slice(-3);
112
+ if (recent3.every(r => r.status === 'FAIL')) {
113
+ return true; // Real issue
114
+ }
115
+
116
+ // If it fails occasionally, it may be intermittent; keep observing
117
+ if (recent3.filter(r => r.status === 'FAIL').length === 1) {
118
+ return false; // Likely intermittent, don't alert yet
119
+ }
120
+
121
+ return false;
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## When to Patrol
127
+
128
+ ### Scheduled Patrols
129
+
130
+ ```bash
131
+ # Daily patrol - randomly check a few each day
132
+ $roll-sentinel patrol --mode=normal
133
+
134
+ # Late-night patrol - full check during off-peak hours
135
+ $roll-sentinel patrol --mode=full --schedule="0 3 * * *"
136
+
137
+ # Weekend walkthrough - check the week's accumulation on Sunday
138
+ $roll-sentinel patrol --mode=weekly --schedule="0 10 * * 0"
139
+ ```
140
+
141
+ ### Event-Triggered
142
+
143
+ ```bash
144
+ # Intensive patrol for 2 hours after deployment
145
+ $roll-sentinel patrol --mode=intensive --duration=2h --after-deploy
146
+
147
+ # Emergency check after an alert
148
+ $roll-sentinel patrol --mode=focus --target=US-XXX
149
+ ```
150
+
151
+ ## Patrol Report
152
+
153
+ ```markdown
154
+ ## 🛡️ Sentinel Patrol Report #247
155
+ **Time**: 2024-01-15 14:00 UTC
156
+ **Patrol ID**: patrol-20240115-1400
157
+ **Mode**: Normal (Random Sampling)
158
+
159
+ ### 📊 Sampling Info
160
+ | Metric | Value |
161
+ |--------|-------|
162
+ | Total Stories | 150 |
163
+ | Sample Size | 10 |
164
+ | Sampling Rate | 6.7% |
165
+ | Cost Estimate | $0.07 |
166
+
167
+ ### 🎲 Random Sample
168
+ | # | Story | Module | Last Checked | Result |
169
+ |---|-------|--------|--------------|--------|
170
+ | 1 | US-LOGIN-001 | Auth | 6h ago | ✅ |
171
+ | 2 | US-STORY-042 | Content | 12h ago | ✅ |
172
+ | 3 | US-AUDIO-015 | Player | 2h ago | 🟡* |
173
+ | 4 | US-SEARCH-003 | Search | 18h ago | ✅ |
174
+ | 5 | ... | ... | ... | ... |
175
+
176
+ \* US-AUDIO-015: Occasional playback stuttering (2nd occurrence, under observation)
177
+
178
+ ### 🔴 Issues Found
179
+ None (no confirmed issues found in this sample)
180
+
181
+ ### 📈 Patrol Statistics (7 days)
182
+ | Metric | Value |
183
+ |--------|-------|
184
+ | Total Patrols | 28 |
185
+ | Stories Checked | 280 |
186
+ | Issues Found | 3 |
187
+ | False Positives | 1 |
188
+ | Coverage | 85% of all stories |
189
+
190
+ ### 💰 Cost Report
191
+ | Item | Usage |
192
+ |------|-------|
193
+ | AI Checks | 280 calls |
194
+ | Playwright Runs | 28 sessions |
195
+ | Total Cost | $2 |
196
+ | Budget Used | 15% of monthly |
197
+ ```
198
+
199
+ ## Smart Detection Logic
200
+
201
+ ### Pattern 1: Intermittent vs Real Issue
202
+
203
+ ```javascript
204
+ // Don't alert on the first failure; look at the trend
205
+ const checks = [
206
+ { time: 'T-6h', status: 'PASS' },
207
+ { time: 'T-12h', status: 'FAIL' }, // Intermittent?
208
+ { time: 'T-18h', status: 'PASS' },
209
+ { time: 'Now', status: 'FAIL' }, // Failed again!
210
+ ];
211
+
212
+ // 2 consecutive failures → Create Issue
213
+ if (lastN(checks, 2).all(c => c.status === 'FAIL')) {
214
+ createBacklogItem('FIX-XXX');
215
+ }
216
+ // Occasional failure → Log for observation
217
+ else if (checks.filter(c => c.status === 'FAIL').length <= 1) {
218
+ logForObservation('Might be flaky, continue monitoring');
219
+ }
220
+ ```
221
+
222
+ ### Pattern 2: Hotspot Detection
223
+
224
+ ```javascript
225
+ // Some Stories frequently show issues when sampled.
226
+ // Automatically increase their check frequency.
227
+
228
+ const hotSpots = analyzeHistory();
229
+ // hotSpots = [
230
+ // { story: 'US-AUDIO-015', failRate: 0.3 }, // 30% failure rate
231
+ // { story: 'US-SEARCH-003', failRate: 0.1 },
232
+ // ]
233
+
234
+ // Increase weight for hotspots
235
+ if (hotSpots.some(h => h.story === selectedStory)) {
236
+ // If it's a hotspot, even if not randomly selected, add extra check probability
237
+ if (Math.random() < 0.3) {
238
+ extraCheck(story);
239
+ }
240
+ }
241
+ ```
242
+
243
+ ## Cost Optimization
244
+
245
+ ### Tiered Checking
246
+
247
+ ```
248
+ Level 1: Lightweight Check (cheap)
249
+ └── HTTP ping / API health check
250
+ └── Cost: $0.001 per check
251
+
252
+ Level 2: Functional Check (moderate)
253
+ └── Playwright critical path
254
+ └── Cost: $0.01 per check
255
+
256
+ Level 3: AI Deep Check (expensive)
257
+ └── AI-powered content quality analysis
258
+ └── Cost: $0.07 per check
259
+
260
+ Strategy:
261
+ - Each patrol: 90% Level 1 + 10% Level 2
262
+ - Once weekly: Level 3 deep inspection
263
+ ```
264
+
265
+ ### Smart Batching
266
+
267
+ ```javascript
268
+ // Batch checks to reduce cost.
269
+ // Instead of 10 separate checks, open one browser for all 10.
270
+
271
+ async function batchCheck(stories) {
272
+ const browser = await chromium.launch();
273
+ const context = await browser.newContext();
274
+
275
+ // Reuse browser session to check multiple Stories
276
+ for (const story of stories) {
277
+ const page = await context.newPage();
278
+ await checkStory(page, story);
279
+ await page.close();
280
+ }
281
+
282
+ await browser.close();
283
+ // Cost: 1 session for 10 checks
284
+ }
285
+ ```
286
+
287
+ ## Workflow: Find Issue → Backlog
288
+
289
+ ```
290
+ ┌─────────────────────────────────────────────────────────────┐
291
+ │ Issue Discovery Workflow via Patrol │
292
+ ├─────────────────────────────────────────────────────────────┤
293
+ │ │
294
+ │ 1. Sentinel Patrol (scheduled random sampling) │
295
+ │ └── Sample: US-AUDIO-015 │
296
+ │ │
297
+ │ 2. Check Result │
298
+ │ └── Status: FAIL (playback stuttering) │
299
+ │ │
300
+ │ 3. Uncertainty Check │
301
+ │ └── Check history: this is the 2nd failure │
302
+ │ └── 1st was 6h ago (possibly intermittent) │
303
+ │ └── Decision: continue observing, don't create Issue │
304
+ │ │
305
+ │ 4. Next Patrol │
306
+ │ └── US-AUDIO-015 sampled again (hotspot weighting) │
307
+ │ └── Status: FAIL (failed again!) │
308
+ │ └── Check history: 2 consecutive failures │
309
+ │ └── Decision: create FIX-AUDIO-015 │
310
+ │ │
311
+ │ 5. Create Backlog Item │
312
+ │ └── Add FIX-AUDIO-015 to BACKLOG.md │
313
+ │ └── Status: 📋 Todo │
314
+ │ └── Awaiting human fix │
315
+ │ │
316
+ │ 6. Human Fix │
317
+ │ └── User: "Fix FIX-AUDIO-015" │
318
+ │ └── $roll-fix FIX-AUDIO-015 │
319
+ │ │
320
+ │ 7. Verification │
321
+ │ └── Next patrol will prioritize verifying this FIX │
322
+ │ └── Status: ✅ Fixed │
323
+ │ │
324
+ └─────────────────────────────────────────────────────────────┘
325
+ ```
326
+
327
+ ## Integration with Other Skills
328
+
329
+ ```
330
+ ┌─────────────────────────────────────────────────────────────┐
331
+ │ Complete Monitoring System │
332
+ ├─────────────────────────────────────────────────────────────┤
333
+ │ │
334
+ │ $roll-sentinel patrol Scheduled random patrol (main) │
335
+ │ ↓ │
336
+ │ Issue found? ──┬── Yes ──→ Create BACKLOG item │
337
+ │ │ Await $roll-fix │
338
+ │ │ │
339
+ │ └── No ──→ Continue patrolling │
340
+ │ │
341
+ │ $roll-debug On-demand deep diagnosis (aux) │
342
+ │ (When Sentinel finds an issue, manually trigger deep dive) │
343
+ │ │
344
+ │ $roll-story Post-fix regression verify │
345
+ │ │
346
+ └─────────────────────────────────────────────────────────────┘
347
+ ```
348
+
349
+ ## Best Practices
350
+
351
+ 1. **Don't do full-coverage checks** - Expensive and unnecessary
352
+ 2. **Random + Hotspots** - Balance coverage and cost
353
+ 3. **Multi-check confirmation** - Avoid false positives from intermittent failures
354
+ 4. **Budget control** - Set daily/monthly AI call limits
355
+ 5. **Progressive intensity** - Light during stable periods, Intensive after releases