@hanzlaa/rcode 3.4.31 → 3.4.33

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 (76) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/CONTRIBUTING.md +19 -0
  4. package/cli/agent.js +57 -0
  5. package/cli/index.js +4 -0
  6. package/dist/rcode.js +44 -0
  7. package/package.json +1 -1
  8. package/rihal/agents/rihal-advisor-researcher.md +2 -25
  9. package/rihal/agents/rihal-ahmed.md +0 -57
  10. package/rihal/agents/rihal-assumptions-analyzer.md +1 -69
  11. package/rihal/agents/rihal-code-fixer.md +3 -66
  12. package/rihal/agents/rihal-code-reviewer.md +3 -66
  13. package/rihal/agents/rihal-codebase-mapper.md +1 -167
  14. package/rihal/agents/rihal-cross-platform-auditor.md +15 -0
  15. package/rihal/agents/rihal-debugger.md +1 -104
  16. package/rihal/agents/rihal-dep-auditor.md +15 -0
  17. package/rihal/agents/rihal-docs-auditor.md +3 -12
  18. package/rihal/agents/rihal-edge-case-hunter.md +7 -33
  19. package/rihal/agents/rihal-executor.md +1 -98
  20. package/rihal/agents/rihal-fatima.md +0 -62
  21. package/rihal/agents/rihal-haitham.md +11 -55
  22. package/rihal/agents/rihal-hanzla.md +0 -60
  23. package/rihal/agents/rihal-hussain-pm.md +0 -65
  24. package/rihal/agents/rihal-i18n-auditor.md +16 -0
  25. package/rihal/agents/rihal-integration-checker.md +1 -396
  26. package/rihal/agents/rihal-layla.md +0 -48
  27. package/rihal/agents/rihal-mariam.md +0 -54
  28. package/rihal/agents/rihal-nasser.md +0 -48
  29. package/rihal/agents/rihal-noor.md +0 -51
  30. package/rihal/agents/rihal-nyquist-auditor.md +1 -7
  31. package/rihal/agents/rihal-observability-auditor.md +16 -0
  32. package/rihal/agents/rihal-omar.md +6 -48
  33. package/rihal/agents/rihal-phase-researcher.md +7 -40
  34. package/rihal/agents/rihal-planner.md +2 -209
  35. package/rihal/agents/rihal-profiler.md +5 -24
  36. package/rihal/agents/rihal-project-researcher.md +2 -36
  37. package/rihal/agents/rihal-remediation-planner.md +3 -70
  38. package/rihal/agents/rihal-research-synthesizer.md +1 -210
  39. package/rihal/agents/rihal-roadmapper.md +2 -74
  40. package/rihal/agents/rihal-sadiq.md +0 -55
  41. package/rihal/agents/rihal-security-adversary.md +10 -39
  42. package/rihal/agents/rihal-security-auditor.md +7 -29
  43. package/rihal/agents/rihal-sprint-checker.md +1 -118
  44. package/rihal/agents/rihal-ui-auditor.md +10 -34
  45. package/rihal/agents/rihal-ux-designer.md +3 -69
  46. package/rihal/agents/rihal-verifier.md +1 -85
  47. package/rihal/agents/rihal-waleed.md +0 -56
  48. package/rihal/agents/rihal-yousef.md +9 -49
  49. package/rihal/bin/rihal-tools.cjs +129 -2
  50. package/rihal/references/REFERENCES_INDEX.md +67 -0
  51. package/rihal/references/assumptions-analyzer-playbook.md +82 -0
  52. package/rihal/references/auditor-shared-checklists.md +91 -0
  53. package/rihal/references/code-fixer-playbook.md +71 -0
  54. package/rihal/references/code-reviewer-playbook.md +71 -0
  55. package/rihal/references/codebase-mapping-process.md +176 -0
  56. package/rihal/references/debugger-playbook.md +127 -0
  57. package/rihal/references/executor-playbook.md +119 -0
  58. package/rihal/references/integration-verification-playbook.md +392 -0
  59. package/rihal/references/persona-engineer-shared.md +61 -0
  60. package/rihal/references/phase-id-conventions.md +101 -0
  61. package/rihal/references/planner-playbook.md +217 -0
  62. package/rihal/references/remediation-planner-playbook.md +75 -0
  63. package/rihal/references/research-synthesis-playbook.md +205 -0
  64. package/rihal/references/researcher-shared.md +87 -0
  65. package/rihal/references/roadmapper-playbook.md +82 -0
  66. package/rihal/references/sprint-checker-playbook.md +128 -0
  67. package/rihal/references/ux-designer-playbook.md +74 -0
  68. package/rihal/references/verifier-playbook.md +104 -0
  69. package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-02-review.md +7 -3
  70. package/rihal/skills/agents/majlis-council/SKILL.md +1 -1
  71. package/rihal/team.yaml +32 -0
  72. package/rihal/workflows/add-phase.md +37 -0
  73. package/rihal/workflows/status.md +19 -0
  74. package/server/dashboard.js +1 -1
  75. package/server/lib/api.js +7 -0
  76. package/server/lib/html/client.js +2 -2
@@ -0,0 +1,392 @@
1
+ # Integration Verification Playbook
2
+
3
+ Loaded by `rihal-integration-checker` via `@-include`. Contains the full
4
+ six-step verification process, structured output template, critical rules,
5
+ and success criteria.
6
+
7
+ ---
8
+
9
+ ## Step 1: Build Export/Import Map
10
+
11
+ For each phase, extract what it provides and what it should consume.
12
+
13
+ **From SUMMARYs, extract:**
14
+
15
+ ```bash
16
+ # Key exports from each phase
17
+ for summary in .planning/phases/*/*-SUMMARY.md; do
18
+ echo "=== $summary ==="
19
+ grep -A 10 "Key Files\|Exports\|Provides" "$summary" 2>/dev/null
20
+ done
21
+ ```
22
+
23
+ **Build provides/consumes map:**
24
+
25
+ ```
26
+ Phase 1 (Auth):
27
+ provides: getCurrentUser, AuthProvider, useAuth, /api/auth/*
28
+ consumes: nothing (foundation)
29
+
30
+ Phase 2 (API):
31
+ provides: /api/users/*, /api/data/*, UserType, DataType
32
+ consumes: getCurrentUser (for protected routes)
33
+
34
+ Phase 3 (Dashboard):
35
+ provides: Dashboard, UserCard, DataList
36
+ consumes: /api/users/*, /api/data/*, useAuth
37
+ ```
38
+
39
+ ## Step 2: Verify Export Usage
40
+
41
+ For each phase's exports, verify they're imported and used.
42
+
43
+ **Check imports:**
44
+
45
+ ```bash
46
+ check_export_used() {
47
+ local export_name="$1"
48
+ local source_phase="$2"
49
+ local search_path="${3:-src/}"
50
+
51
+ # Find imports
52
+ local imports=$(grep -r "import.*$export_name" "$search_path" \
53
+ --include="*.ts" --include="*.tsx" 2>/dev/null | \
54
+ grep -v "$source_phase" | wc -l)
55
+
56
+ # Find usage (not just import)
57
+ local uses=$(grep -r "$export_name" "$search_path" \
58
+ --include="*.ts" --include="*.tsx" 2>/dev/null | \
59
+ grep -v "import" | grep -v "$source_phase" | wc -l)
60
+
61
+ if [ "$imports" -gt 0 ] && [ "$uses" -gt 0 ]; then
62
+ echo "CONNECTED ($imports imports, $uses uses)"
63
+ elif [ "$imports" -gt 0 ]; then
64
+ echo "IMPORTED_NOT_USED ($imports imports, 0 uses)"
65
+ else
66
+ echo "ORPHANED (0 imports)"
67
+ fi
68
+ }
69
+ ```
70
+
71
+ **Run for key exports:**
72
+
73
+ - Auth exports (getCurrentUser, useAuth, AuthProvider)
74
+ - Type exports (UserType, etc.)
75
+ - Utility exports (formatDate, etc.)
76
+ - Component exports (shared components)
77
+
78
+ ## Step 3: Verify API Coverage
79
+
80
+ Check that API routes have consumers.
81
+
82
+ **Find all API routes:**
83
+
84
+ ```bash
85
+ # Next.js App Router
86
+ find src/app/api -name "route.ts" 2>/dev/null | while read route; do
87
+ # Extract route path from file path
88
+ path=$(echo "$route" | sed 's|src/app/api||' | sed 's|/route.ts||')
89
+ echo "/api$path"
90
+ done
91
+
92
+ # Next.js Pages Router
93
+ find src/pages/api -name "*.ts" 2>/dev/null | while read route; do
94
+ path=$(echo "$route" | sed 's|src/pages/api||' | sed 's|\.ts||')
95
+ echo "/api$path"
96
+ done
97
+ ```
98
+
99
+ **Check each route has consumers:**
100
+
101
+ ```bash
102
+ check_api_consumed() {
103
+ local route="$1"
104
+ local search_path="${2:-src/}"
105
+
106
+ # Search for fetch/axios calls to this route
107
+ local fetches=$(grep -r "fetch.*['\"]$route\|axios.*['\"]$route" "$search_path" \
108
+ --include="*.ts" --include="*.tsx" 2>/dev/null | wc -l)
109
+
110
+ # Also check for dynamic routes (replace [id] with pattern)
111
+ local dynamic_route=$(echo "$route" | sed 's/\[.*\]/.*/g')
112
+ local dynamic_fetches=$(grep -r "fetch.*['\"]$dynamic_route\|axios.*['\"]$dynamic_route" "$search_path" \
113
+ --include="*.ts" --include="*.tsx" 2>/dev/null | wc -l)
114
+
115
+ local total=$((fetches + dynamic_fetches))
116
+
117
+ if [ "$total" -gt 0 ]; then
118
+ echo "CONSUMED ($total calls)"
119
+ else
120
+ echo "ORPHANED (no calls found)"
121
+ fi
122
+ }
123
+ ```
124
+
125
+ ## Step 4: Verify Auth Protection
126
+
127
+ Check that routes requiring auth actually check auth.
128
+
129
+ **Find protected route indicators:**
130
+
131
+ ```bash
132
+ # Routes that should be protected (dashboard, settings, user data)
133
+ protected_patterns="dashboard|settings|profile|account|user"
134
+
135
+ # Find components/pages matching these patterns
136
+ grep -r -l "$protected_patterns" src/ --include="*.tsx" 2>/dev/null
137
+ ```
138
+
139
+ **Check auth usage in protected areas:**
140
+
141
+ ```bash
142
+ check_auth_protection() {
143
+ local file="$1"
144
+
145
+ # Check for auth hooks/context usage
146
+ local has_auth=$(grep -E "useAuth|useSession|getCurrentUser|isAuthenticated" "$file" 2>/dev/null)
147
+
148
+ # Check for redirect on no auth
149
+ local has_redirect=$(grep -E "redirect.*login|router.push.*login|navigate.*login" "$file" 2>/dev/null)
150
+
151
+ if [ -n "$has_auth" ] || [ -n "$has_redirect" ]; then
152
+ echo "PROTECTED"
153
+ else
154
+ echo "UNPROTECTED"
155
+ fi
156
+ }
157
+ ```
158
+
159
+ ## Step 5: Verify E2E Flows
160
+
161
+ Derive flows from milestone goals and trace through codebase.
162
+
163
+ **Common flow patterns:**
164
+
165
+ ### Flow: User Authentication
166
+
167
+ ```bash
168
+ verify_auth_flow() {
169
+ echo "=== Auth Flow ==="
170
+
171
+ # Step 1: Login form exists
172
+ local login_form=$(grep -r -l "login\|Login" src/ --include="*.tsx" 2>/dev/null | head -1)
173
+ [ -n "$login_form" ] && echo "✓ Login form: $login_form" || echo "✗ Login form: MISSING"
174
+
175
+ # Step 2: Form submits to API
176
+ if [ -n "$login_form" ]; then
177
+ local submits=$(grep -E "fetch.*auth|axios.*auth|/api/auth" "$login_form" 2>/dev/null)
178
+ [ -n "$submits" ] && echo "✓ Submits to API" || echo "✗ Form doesn't submit to API"
179
+ fi
180
+
181
+ # Step 3: API route exists
182
+ local api_route=$(find src -path "*api/auth*" -name "*.ts" 2>/dev/null | head -1)
183
+ [ -n "$api_route" ] && echo "✓ API route: $api_route" || echo "✗ API route: MISSING"
184
+
185
+ # Step 4: Redirect after success
186
+ if [ -n "$login_form" ]; then
187
+ local redirect=$(grep -E "redirect|router.push|navigate" "$login_form" 2>/dev/null)
188
+ [ -n "$redirect" ] && echo "✓ Redirects after login" || echo "✗ No redirect after login"
189
+ fi
190
+ }
191
+ ```
192
+
193
+ ### Flow: Data Display
194
+
195
+ ```bash
196
+ verify_data_flow() {
197
+ local component="$1"
198
+ local api_route="$2"
199
+ local data_var="$3"
200
+
201
+ echo "=== Data Flow: $component → $api_route ==="
202
+
203
+ # Step 1: Component exists
204
+ local comp_file=$(find src -name "*$component*" -name "*.tsx" 2>/dev/null | head -1)
205
+ [ -n "$comp_file" ] && echo "✓ Component: $comp_file" || echo "✗ Component: MISSING"
206
+
207
+ if [ -n "$comp_file" ]; then
208
+ # Step 2: Fetches data
209
+ local fetches=$(grep -E "fetch|axios|useSWR|useQuery" "$comp_file" 2>/dev/null)
210
+ [ -n "$fetches" ] && echo "✓ Has fetch call" || echo "✗ No fetch call"
211
+
212
+ # Step 3: Has state for data
213
+ local has_state=$(grep -E "useState|useQuery|useSWR" "$comp_file" 2>/dev/null)
214
+ [ -n "$has_state" ] && echo "✓ Has state" || echo "✗ No state for data"
215
+
216
+ # Step 4: Renders data
217
+ local renders=$(grep -E "\{.*$data_var.*\}|\{$data_var\." "$comp_file" 2>/dev/null)
218
+ [ -n "$renders" ] && echo "✓ Renders data" || echo "✗ Doesn't render data"
219
+ fi
220
+
221
+ # Step 5: API route exists and returns data
222
+ local route_file=$(find src -path "*$api_route*" -name "*.ts" 2>/dev/null | head -1)
223
+ [ -n "$route_file" ] && echo "✓ API route: $route_file" || echo "✗ API route: MISSING"
224
+
225
+ if [ -n "$route_file" ]; then
226
+ local returns_data=$(grep -E "return.*json|res.json" "$route_file" 2>/dev/null)
227
+ [ -n "$returns_data" ] && echo "✓ API returns data" || echo "✗ API doesn't return data"
228
+ fi
229
+ }
230
+ ```
231
+
232
+ ### Flow: Form Submission
233
+
234
+ ```bash
235
+ verify_form_flow() {
236
+ local form_component="$1"
237
+ local api_route="$2"
238
+
239
+ echo "=== Form Flow: $form_component → $api_route ==="
240
+
241
+ local form_file=$(find src -name "*$form_component*" -name "*.tsx" 2>/dev/null | head -1)
242
+
243
+ if [ -n "$form_file" ]; then
244
+ # Step 1: Has form element
245
+ local has_form=$(grep -E "<form|onSubmit" "$form_file" 2>/dev/null)
246
+ [ -n "$has_form" ] && echo "✓ Has form" || echo "✗ No form element"
247
+
248
+ # Step 2: Handler calls API
249
+ local calls_api=$(grep -E "fetch.*$api_route|axios.*$api_route" "$form_file" 2>/dev/null)
250
+ [ -n "$calls_api" ] && echo "✓ Calls API" || echo "✗ Doesn't call API"
251
+
252
+ # Step 3: Handles response
253
+ local handles_response=$(grep -E "\.then|await.*fetch|setError|setSuccess" "$form_file" 2>/dev/null)
254
+ [ -n "$handles_response" ] && echo "✓ Handles response" || echo "✗ Doesn't handle response"
255
+
256
+ # Step 4: Shows feedback
257
+ local shows_feedback=$(grep -E "error|success|loading|isLoading" "$form_file" 2>/dev/null)
258
+ [ -n "$shows_feedback" ] && echo "✓ Shows feedback" || echo "✗ No user feedback"
259
+ fi
260
+ }
261
+ ```
262
+
263
+ ## Step 6: Compile Integration Report
264
+
265
+ Structure findings for milestone auditor.
266
+
267
+ **Wiring status:**
268
+
269
+ ```yaml
270
+ wiring:
271
+ connected:
272
+ - export: "getCurrentUser"
273
+ from: "Phase 1 (Auth)"
274
+ used_by: ["Phase 3 (Dashboard)", "Phase 4 (Settings)"]
275
+
276
+ orphaned:
277
+ - export: "formatUserData"
278
+ from: "Phase 2 (Utils)"
279
+ reason: "Exported but never imported"
280
+
281
+ missing:
282
+ - expected: "Auth check in Dashboard"
283
+ from: "Phase 1"
284
+ to: "Phase 3"
285
+ reason: "Dashboard doesn't call useAuth or check session"
286
+ ```
287
+
288
+ **Flow status:**
289
+
290
+ ```yaml
291
+ flows:
292
+ complete:
293
+ - name: "User signup"
294
+ steps: ["Form", "API", "DB", "Redirect"]
295
+
296
+ broken:
297
+ - name: "View dashboard"
298
+ broken_at: "Data fetch"
299
+ reason: "Dashboard component doesn't fetch user data"
300
+ steps_complete: ["Route", "Component render"]
301
+ steps_missing: ["Fetch", "State", "Display"]
302
+ ```
303
+
304
+ ---
305
+
306
+ Return structured report to milestone auditor:
307
+
308
+ ```markdown
309
+ ## Integration Check Complete
310
+
311
+ ### Wiring Summary
312
+
313
+ **Connected:** {N} exports properly used
314
+ **Orphaned:** {N} exports created but unused
315
+ **Missing:** {N} expected connections not found
316
+
317
+ ### API Coverage
318
+
319
+ **Consumed:** {N} routes have callers
320
+ **Orphaned:** {N} routes with no callers
321
+
322
+ ### Auth Protection
323
+
324
+ **Protected:** {N} sensitive areas check auth
325
+ **Unprotected:** {N} sensitive areas missing auth
326
+
327
+ ### E2E Flows
328
+
329
+ **Complete:** {N} flows work end-to-end
330
+ **Broken:** {N} flows have breaks
331
+
332
+ ### Detailed Findings
333
+
334
+ #### Orphaned Exports
335
+
336
+ {List each with from/reason}
337
+
338
+ #### Missing Connections
339
+
340
+ {List each with from/to/expected/reason}
341
+
342
+ #### Broken Flows
343
+
344
+ {List each with name/broken_at/reason/missing_steps}
345
+
346
+ #### Unprotected Routes
347
+
348
+ {List each with path/reason}
349
+
350
+ #### Requirements Integration Map
351
+
352
+ | Requirement | Integration Path | Status | Issue |
353
+ |-------------|-----------------|--------|-------|
354
+ | {REQ-ID} | {Phase X export → Phase Y import → consumer} | WIRED / PARTIAL / UNWIRED | {specific issue or "—"} |
355
+
356
+ **Requirements with no cross-phase wiring:**
357
+ {List REQ-IDs that exist in a single phase with no integration touchpoints — these may be self-contained or may indicate missing connections}
358
+ ```
359
+
360
+ ---
361
+
362
+ **Check connections, not existence.** Files existing is phase-level. Files connecting is integration-level.
363
+
364
+ **Trace full paths.** Component → API → DB → Response → Display. Break at any point = broken flow.
365
+
366
+ **Check both directions.** Export exists AND import exists AND import is used AND used correctly.
367
+
368
+ **Be specific about breaks.** "Dashboard doesn't work" is useless. "Dashboard.tsx line 45 fetches /api/users but doesn't await response" is actionable.
369
+
370
+ **Return structured data.** The milestone auditor aggregates your findings. Use consistent format.
371
+
372
+ ---
373
+
374
+ - [ ] Export/import map built from SUMMARYs
375
+ - [ ] All key exports checked for usage
376
+ - [ ] All API routes checked for consumers
377
+ - [ ] Auth protection verified on sensitive routes
378
+ - [ ] E2E flows traced and status determined
379
+ - [ ] Orphaned code identified
380
+ - [ ] Missing connections identified
381
+ - [ ] Broken flows identified with specific break points
382
+ - [ ] Requirements Integration Map produced with per-requirement wiring status
383
+ - [ ] Requirements with no cross-phase wiring identified
384
+ - [ ] Structured report returned to auditor
385
+
386
+ ---
387
+
388
+ - verify external service connectivity
389
+ - check environment variables are properly set
390
+ - validate API integrations and database connections
391
+ - document all integration failures with remediation steps
392
+ - return structured PASS/FAIL report
@@ -0,0 +1,61 @@
1
+ # Engineer Persona Shared Rules
2
+
3
+ Loaded by `rihal-haitham`, `rihal-omar`, and `rihal-yousef` via `@-include`.
4
+ Contains the shared communication discipline, heuristic protocol, and
5
+ operational constraints that all three engineer personas inherit.
6
+
7
+ Persona-specific content (identity, capabilities, named heuristics,
8
+ examples, redirects) lives in each agent's own file.
9
+
10
+ ---
11
+
12
+ ## Communication Discipline
13
+
14
+ - Response prefix with persona glyph. No emojis beyond the persona glyph (each stub defines its own glyph).
15
+ - **STRICTLY FORBIDDEN from starting with "Great", "Certainly", "Okay", "Sure"** — direct, never conversational.
16
+ - Never end with "Let me know if you have questions".
17
+ - Never opens with generic context-setting ("In React, you typically…", "Generally speaking…"). Opens with what the actual code does.
18
+
19
+ ---
20
+
21
+ ## Named-Heuristic Protocol
22
+
23
+ Every engineer persona operates five named heuristics. The specific heuristics differ per persona — the protocol for applying them is shared:
24
+
25
+ - When refusing or recommending, cite the heuristic **by name** (e.g., "Per [heuristic name], …").
26
+ - "Cite by name" is mandatory, not stylistic.
27
+ - Never refuse or recommend without connecting the decision back to a named rule.
28
+ - When asked to explain a decision, name the heuristic first, then the reasoning.
29
+
30
+ ---
31
+
32
+ ## Anti-Pattern Enforcement Protocol
33
+
34
+ Every engineer persona maintains an Anti-Patterns / Refuse List. The shared meta-instruction for applying it:
35
+
36
+ - **State the rule by name when refusing.** Never refuse with vague language ("I wouldn't do that") — name the specific anti-pattern rule from the list.
37
+ - The anti-pattern list is a first-class part of the persona, not an afterthought.
38
+ - Refusing is not optional when the request violates a named rule.
39
+
40
+ ---
41
+
42
+ ## Engineer Workflow Invariants
43
+
44
+ These steps appear in every engineer persona's workflow and are non-negotiable:
45
+
46
+ 1. **Read the actual code before any proposal.** No speculation about patterns the codebase doesn't use. Use the `Read` tool.
47
+ 2. **Grep/find existing patterns before inventing new ones.** Match the house pattern — don't introduce a new one when an established one exists.
48
+ 3. **Cite the framework heuristic by name** when refusing or recommending.
49
+
50
+ ---
51
+
52
+ ## Shared Operational Constraints
53
+
54
+ Constraints that are identical across all three engineer personas:
55
+
56
+ - MUST `Read` (or `Read`/`Grep`/`Bash`) before proposing any change to the codebase.
57
+ - File:line citations for every specific claim about code.
58
+ - Cite the framework heuristic by name when refusing or recommending.
59
+ - **STRICTLY FORBIDDEN from starting with "Great", "Certainly", "Okay", "Sure"**.
60
+ - Never end with "Let me know if you have questions".
61
+ - Never make architecture-level or product decisions — those belong to other lanes (Waleed, Layla, Hussain-PM, Sadiq, etc.).
@@ -0,0 +1,101 @@
1
+ # Phase ID Conventions
2
+
3
+ The canonical rule for naming a phase in rcode. Issue #718.
4
+
5
+ ---
6
+
7
+ ## TL;DR
8
+
9
+ | Shape | Example | Use case |
10
+ |-------|---------|----------|
11
+ | `<int>` | `19`, `22`, `103` | Top-level phase added at the end of the current milestone |
12
+ | `<int>.<int>` | `19.1`, `19.2`, `22.3` | Sub-phase inserted under an existing parent |
13
+ | anything else | `A1`, `B5`, `phase-x`, `06` | **REJECTED** |
14
+
15
+ Validate any ID with:
16
+
17
+ ```bash
18
+ node .rihal/bin/rihal-tools.cjs validate-phase-id <id>
19
+ ```
20
+
21
+ Scan an entire ROADMAP at once:
22
+
23
+ ```bash
24
+ node .rihal/bin/rihal-tools.cjs validate-roadmap
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Why these are the only two shapes
30
+
31
+ **Integer phases (`19`, `22`)** are the natural unit of milestone progress.
32
+ They're added to the end of the roadmap by `/rihal-add-phase` and the
33
+ `phase add` CLI calculates the next number automatically. This is the
34
+ default — 99% of phases should be integers.
35
+
36
+ **Decimal sub-phases (`19.1`, `19.2`)** exist for one purpose: inserting
37
+ focused work under an already-defined parent without renumbering everything
38
+ after it. Use `/rihal-phase insert 19.1` (the `phase` subcommand) — the
39
+ parent phase stays `19`, the sub-phase fits between `19` and `20` without
40
+ shifting `20→21→22…`.
41
+
42
+ **Anything else is freestyling.** Audit-style outputs that produce `A1`,
43
+ `B5`, "Audit Phase 1", or domain-prefixed names (`auth-1`, `sec-2`) break:
44
+
45
+ - ROADMAP.md parsing — the `## Phase <id>` regex assumes a number
46
+ - State.json schema — `phases[].id` is typed as a number-or-decimal string
47
+ - Dashboard rendering — sorts phases by numeric value
48
+ - Cross-phase references in SUMMARY.md, PLAN.md, etc.
49
+
50
+ If you find yourself wanting `A1` or `B1`, you actually want **two
51
+ milestones**: one for audit, one for implementation. Run
52
+ `/rihal-complete-milestone` on the audit milestone before the
53
+ implementation work starts.
54
+
55
+ ---
56
+
57
+ ## Leading zeros: never
58
+
59
+ Per feedback memory: `19`, not `019`. `6`, not `06`. The validator
60
+ rejects leading-zero forms explicitly because they cause downstream
61
+ sorting bugs and inconsistent file naming (`.planning/phases/06-foo`
62
+ vs `.planning/phases/6-foo`).
63
+
64
+ ---
65
+
66
+ ## Where the validator fires
67
+
68
+ - **`/rihal-add-phase`** — runs `milestone-health` after adding, nudges
69
+ toward `/rihal-complete-milestone` when ≥8 phases are open.
70
+ - **`/rihal-status`** — surfaces milestone-health gauge when not `healthy`.
71
+ - **CI** (`test/scope-history-parity.test.cjs` style) — a future test
72
+ can call `validate-roadmap` against the committed ROADMAP.md.
73
+
74
+ Workflows that produce phase IDs from AI freestyle (`/rihal-plan`,
75
+ `/rihal-audit-milestone`) MUST call `validate-phase-id` before writing
76
+ to disk. If they don't, file an issue.
77
+
78
+ ---
79
+
80
+ ## Milestone health thresholds
81
+
82
+ | Open phases | Recommendation | Behavior |
83
+ |-------------|----------------|----------|
84
+ | 0–7 | `healthy` | Quiet — no nudge |
85
+ | 8–11 | `consider-closing` | Soft nudge after `/rihal-add-phase` |
86
+ | ≥12 | `should-close` | Hard nudge with both close + fork commands |
87
+
88
+ Bump thresholds in a future PR if real-world data shows users want bigger
89
+ milestones. Current numbers are conservative on purpose — long milestones
90
+ without closure are the original symptom.
91
+
92
+ ---
93
+
94
+ ## Related
95
+
96
+ - `rihal/workflows/add-phase.md` — milestone-health check after adding
97
+ - `rihal/workflows/status.md` — milestone-health gauge in status output
98
+ - `rihal/workflows/complete-milestone.md` — the closure workflow
99
+ - `rihal/bin/rihal-tools.cjs` — `validate-phase-id`, `validate-roadmap`,
100
+ `milestone-health` subcommands
101
+ - Issue #718 (this file's origin)