fraim-framework 2.0.26 → 2.0.30

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 (104) hide show
  1. package/.github/workflows/deploy-fraim.yml +1 -1
  2. package/dist/registry/scripts/build-scripts-generator.js +205 -0
  3. package/dist/registry/scripts/cleanup-branch.js +258 -0
  4. package/dist/registry/scripts/evaluate-code-quality.js +66 -0
  5. package/dist/registry/scripts/exec-with-timeout.js +142 -0
  6. package/dist/registry/scripts/fraim-config.js +61 -0
  7. package/dist/registry/scripts/generate-engagement-emails.js +630 -0
  8. package/dist/registry/scripts/generic-issues-api.js +100 -0
  9. package/dist/registry/scripts/newsletter-helpers.js +731 -0
  10. package/dist/registry/scripts/openapi-generator.js +664 -0
  11. package/dist/registry/scripts/performance/profile-server.js +390 -0
  12. package/dist/registry/scripts/run-thank-you-workflow.js +92 -0
  13. package/dist/registry/scripts/send-newsletter-simple.js +85 -0
  14. package/dist/registry/scripts/send-thank-you-emails.js +54 -0
  15. package/dist/registry/scripts/validate-openapi-limits.js +311 -0
  16. package/dist/registry/scripts/validate-test-coverage.js +262 -0
  17. package/dist/registry/scripts/verify-test-coverage.js +66 -0
  18. package/dist/src/cli/commands/init.js +14 -12
  19. package/dist/src/cli/commands/sync.js +19 -2
  20. package/dist/src/cli/fraim.js +24 -22
  21. package/dist/src/cli/setup/first-run.js +13 -6
  22. package/dist/src/fraim/config-loader.js +0 -8
  23. package/dist/src/fraim/db-service.js +26 -15
  24. package/dist/src/fraim/issues.js +67 -0
  25. package/dist/src/fraim/setup-wizard.js +1 -69
  26. package/dist/src/fraim/types.js +0 -11
  27. package/dist/src/fraim-mcp-server.js +272 -18
  28. package/dist/src/utils/git-utils.js +1 -1
  29. package/dist/src/utils/version-utils.js +32 -0
  30. package/dist/tests/debug-tools.js +79 -0
  31. package/dist/tests/esm-compat.js +11 -0
  32. package/dist/tests/test-chalk-esm-issue.js +159 -0
  33. package/dist/tests/test-chalk-real-world.js +265 -0
  34. package/dist/tests/test-chalk-regression.js +327 -0
  35. package/dist/tests/test-chalk-resolution-issue.js +304 -0
  36. package/dist/tests/test-cli.js +0 -2
  37. package/dist/tests/test-fraim-install-chalk-issue.js +254 -0
  38. package/dist/tests/test-fraim-issues.js +59 -0
  39. package/dist/tests/test-genericization.js +1 -3
  40. package/dist/tests/test-mcp-connection.js +166 -0
  41. package/dist/tests/test-mcp-issue-integration.js +144 -0
  42. package/dist/tests/test-mcp-lifecycle-methods.js +312 -0
  43. package/dist/tests/test-node-compatibility.js +71 -0
  44. package/dist/tests/test-npm-install.js +66 -0
  45. package/dist/tests/test-npm-resolution-diagnostic.js +140 -0
  46. package/dist/tests/test-session-rehydration.js +145 -0
  47. package/dist/tests/test-standalone.js +2 -8
  48. package/dist/tests/test-sync-version-update.js +93 -0
  49. package/dist/tests/test-telemetry.js +190 -0
  50. package/package.json +10 -8
  51. package/registry/agent-guardrails.md +62 -54
  52. package/registry/rules/agent-success-criteria.md +52 -0
  53. package/registry/rules/agent-testing-guidelines.md +502 -502
  54. package/registry/rules/communication.md +121 -121
  55. package/registry/rules/continuous-learning.md +54 -54
  56. package/registry/rules/ephemeral-execution.md +10 -5
  57. package/registry/rules/hitl-ppe-record-analysis.md +302 -302
  58. package/registry/rules/local-development.md +251 -251
  59. package/registry/rules/software-development-lifecycle.md +104 -104
  60. package/registry/rules/successful-debugging-patterns.md +482 -478
  61. package/registry/rules/telemetry.md +67 -0
  62. package/registry/scripts/build-scripts-generator.ts +216 -215
  63. package/registry/scripts/cleanup-branch.ts +303 -284
  64. package/registry/scripts/code-quality-check.sh +559 -559
  65. package/registry/scripts/detect-tautological-tests.sh +38 -38
  66. package/registry/scripts/evaluate-code-quality.ts +1 -1
  67. package/registry/scripts/generate-engagement-emails.ts +744 -744
  68. package/registry/scripts/generic-issues-api.ts +110 -150
  69. package/registry/scripts/newsletter-helpers.ts +874 -874
  70. package/registry/scripts/openapi-generator.ts +695 -693
  71. package/registry/scripts/performance/profile-server.ts +5 -3
  72. package/registry/scripts/prep-issue.sh +468 -455
  73. package/registry/scripts/validate-openapi-limits.ts +366 -365
  74. package/registry/scripts/validate-test-coverage.ts +280 -280
  75. package/registry/scripts/verify-pr-comments.sh +70 -70
  76. package/registry/scripts/verify-test-coverage.ts +1 -1
  77. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +53 -53
  78. package/registry/templates/evidence/Implementation-BugEvidence.md +85 -85
  79. package/registry/templates/evidence/Implementation-FeatureEvidence.md +120 -120
  80. package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +66 -0
  81. package/registry/workflows/bootstrap/create-architecture.md +2 -2
  82. package/registry/workflows/bootstrap/evaluate-code-quality.md +3 -3
  83. package/registry/workflows/bootstrap/verify-test-coverage.md +2 -2
  84. package/registry/workflows/customer-development/insight-analysis.md +156 -156
  85. package/registry/workflows/customer-development/interview-preparation.md +421 -421
  86. package/registry/workflows/customer-development/strategic-brainstorming.md +146 -146
  87. package/registry/workflows/customer-development/thank-customers.md +193 -191
  88. package/registry/workflows/customer-development/weekly-newsletter.md +362 -352
  89. package/registry/workflows/improve-fraim/contribute.md +32 -0
  90. package/registry/workflows/improve-fraim/file-issue.md +32 -0
  91. package/registry/workflows/marketing/hbr-article.md +73 -0
  92. package/registry/workflows/performance/analyze-performance.md +63 -59
  93. package/registry/workflows/product-building/design.md +3 -2
  94. package/registry/workflows/product-building/implement.md +4 -3
  95. package/registry/workflows/product-building/prep-issue.md +28 -17
  96. package/registry/workflows/product-building/resolve.md +3 -2
  97. package/registry/workflows/product-building/retrospect.md +3 -2
  98. package/registry/workflows/product-building/spec.md +5 -4
  99. package/registry/workflows/product-building/test.md +3 -2
  100. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +562 -562
  101. package/registry/workflows/replicate/website-discovery-analysis.md +3 -3
  102. package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +632 -632
  103. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +669 -669
  104. package/tsconfig.json +2 -1
@@ -1,559 +1,559 @@
1
- #!/bin/bash
2
- # Unified code quality check script
3
- # Can be run at different stages: pre-commit, pre-pr, or ci
4
- # Usage: bash code-quality-check.sh [pre-commit|pre-pr|ci]
5
-
6
- MODE="${1:-pre-pr}" # Default to pre-pr if not specified
7
-
8
- set -e
9
-
10
- echo "🔍 Running code quality checks (mode: $MODE)..."
11
- echo ""
12
-
13
- FAILED=0
14
- WARNINGS=0
15
-
16
- # Determine what files to check based on mode
17
- if [ "$MODE" = "pre-commit" ]; then
18
- # Pre-commit: only check staged files
19
- TS_FILES=$(git diff --cached --name-only | grep -E '\.(ts|tsx)$' || true)
20
- CHECK_SCOPE="staged files"
21
- elif [ "$MODE" = "ci" ]; then
22
- # CI: check only files changed in this PR
23
- # Compare against the base branch (e.g., master or feature/*)
24
- BASE_BRANCH="${GITHUB_BASE_REF:-origin/master}"
25
- echo "â„šī¸ Comparing against base: $BASE_BRANCH"
26
-
27
- # Get all changed TypeScript files in the PR
28
- TS_FILES=$(git diff --name-only $BASE_BRANCH...HEAD | grep -E '\.(ts|tsx)$' || true)
29
-
30
- if [ -z "$TS_FILES" ]; then
31
- echo "â„šī¸ No TypeScript files changed in this PR"
32
- CHECK_SCOPE="no files changed"
33
- else
34
- FILE_COUNT=$(echo "$TS_FILES" | wc -l | tr -d ' ')
35
- CHECK_SCOPE="$FILE_COUNT changed file(s) in PR"
36
- fi
37
- elif [ "$MODE" = "pre-pr" ]; then
38
- # Pre-PR: check entire src directory (local development)
39
- TS_FILES=$(find src -name "*.ts" -o -name "*.tsx" 2>/dev/null || true)
40
- CHECK_SCOPE="entire codebase"
41
- fi
42
- # Load configuration from .fraim/config.json
43
- CONFIG_FILE=".fraim/config.json"
44
- if [ -f "$CONFIG_FILE" ]; then
45
- # Extract OpenAPI path using node
46
- OPENAPI_PATH=$(node -e "const fs = require('fs'); try { const config = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf-8')); console.log(config.paths?.openapi || 'src/openapi/OpenAPI.json'); } catch(e) { console.log('src/openapi/OpenAPI.json'); }")
47
- ARCH_DOC=$(node -e "const fs = require('fs'); try { const config = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf-8')); console.log('.ai-agents/rules/' + (config.persona?.name?.toLowerCase() || 'persona') + '-architecture.md'); } catch(e) { console.log('.ai-agents/rules/persona-architecture.md'); }")
48
- else
49
- OPENAPI_PATH="src/openapi/OpenAPI.json"
50
- ARCH_DOC=".ai-agents/rules/persona-architecture.md"
51
- fi
52
-
53
- echo "Checking: $CHECK_SCOPE"
54
- echo ""
55
-
56
- # GATE 1: Check for 'as any' type bypassing
57
- echo "================================================"
58
- echo "📋 GATE 1: No 'as any' Type Bypassing"
59
- echo "================================================"
60
-
61
- if [ -z "$TS_FILES" ]; then
62
- echo "â„šī¸ No TypeScript files to check"
63
- else
64
- if echo "$TS_FILES" | xargs grep -n ' as any' 2>/dev/null; then
65
- echo ""
66
- echo "❌ FAILED: Found 'as any' type assertions"
67
- echo " Rule: Use proper TypeScript interfaces, not 'as any'"
68
- echo " See: .ai-agents/rules/code-quality-and-debugging-patterns.md#rule-1"
69
- FAILED=1
70
- else
71
- echo "✅ PASSED: No 'as any' type bypassing found"
72
- fi
73
- fi
74
- echo ""
75
-
76
- # GATE 1.5: Tautological Tests Check
77
- echo "================================================"
78
- echo "📋 GATE 1.5: No Tautological Test Patterns"
79
- echo "================================================"
80
-
81
- if bash "$(dirname "$0")/detect-tautological-tests.sh"; then
82
- echo "✅ PASSED: No tautological tests found"
83
- else
84
- echo "❌ FAILED: Tautological test patterns detected"
85
- echo " Rule: Tests must fail if product code is removed. Don't test types/constants."
86
- echo " See: .ai-agents/rules/integrity-and-test-ethics.md#critical-invalid-test-patterns-tautology-type-testing"
87
- FAILED=1
88
- fi
89
- echo ""
90
-
91
-
92
- # GATE 2: TypeScript Compilation
93
- echo "================================================"
94
- echo "📋 GATE 2: TypeScript Compilation"
95
- echo "================================================"
96
-
97
- if command -v npx &> /dev/null; then
98
- if npx tsc --noEmit --skipLibCheck 2>&1 | head -50; then
99
- echo "✅ PASSED: TypeScript compilation successful"
100
- else
101
- echo "❌ FAILED: TypeScript compilation errors"
102
- echo " Fix all TypeScript errors before proceeding"
103
- FAILED=1
104
- fi
105
- else
106
- echo "â„šī¸ npx not found - skipping TypeScript check"
107
- fi
108
- echo ""
109
-
110
- # GATE 3: Linter
111
- echo "================================================"
112
- echo "📋 GATE 3: Linter (ESLint)"
113
- echo "================================================"
114
-
115
- if command -v npm &> /dev/null; then
116
- if npm run lint 2>&1 | head -50; then
117
- echo "✅ PASSED: Linter checks passed"
118
- else
119
- echo "âš ī¸ WARNING: Linter has issues"
120
- WARNINGS=1
121
- fi
122
- else
123
- echo "â„šī¸ npm not found - skipping lint check"
124
- fi
125
- echo ""
126
-
127
- # GATE 4: Git Status (pre-pr and ci only)
128
- if [ "$MODE" != "pre-commit" ]; then
129
- echo "================================================"
130
- echo "📋 GATE 4: Git Status"
131
- echo "================================================"
132
-
133
- if [ -n "$(git status --porcelain)" ]; then
134
- echo "âš ī¸ WARNING: Uncommitted changes detected"
135
- git status --short
136
- WARNINGS=1
137
- else
138
- echo "✅ PASSED: Working directory is clean"
139
- fi
140
- echo ""
141
- fi
142
-
143
- # GATE 5: Commits Pushed (pre-pr only)
144
- if [ "$MODE" = "pre-pr" ]; then
145
- echo "================================================"
146
- echo "📋 GATE 5: Commits Pushed to Remote"
147
- echo "================================================"
148
-
149
- CURRENT_BRANCH=$(git branch --show-current)
150
- if git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline 2>/dev/null | grep . > /dev/null; then
151
- echo "âš ī¸ WARNING: Unpushed commits detected"
152
- git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline
153
- WARNINGS=1
154
- else
155
- echo "✅ PASSED: All commits pushed to remote"
156
- fi
157
- echo ""
158
- fi
159
-
160
- # GATE 6: PR Comments Addressed (pre-pr only)
161
- if [ "$MODE" = "pre-pr" ]; then
162
- echo "================================================"
163
- echo "📋 GATE 6: PR Comments Addressed"
164
- echo "================================================"
165
-
166
- # Check if gh CLI is available
167
- if ! command -v gh &> /dev/null; then
168
- echo "â„šī¸ gh CLI not found - skipping PR comment check"
169
- echo ""
170
- else
171
- # Try to get PR number for current branch
172
- PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
173
-
174
- if [ -z "$PR_NUMBER" ]; then
175
- echo "â„šī¸ No PR found for current branch - skipping comment check"
176
- else
177
- echo "Found PR #$PR_NUMBER"
178
-
179
- # Get PR comments count
180
- COMMENT_COUNT=$(gh api repos/:owner/:repo/pulls/$PR_NUMBER/comments --jq 'length' 2>/dev/null || echo "0")
181
-
182
- if [ "$COMMENT_COUNT" -gt 0 ]; then
183
- echo "âš ī¸ WARNING: PR has $COMMENT_COUNT review comments"
184
- echo " Please ensure all comments are addressed before marking ready for review"
185
- echo ""
186
- echo " To view comments:"
187
- echo " gh pr view $PR_NUMBER --comments"
188
- echo ""
189
- echo " To reply to a comment:"
190
- echo " gh api repos/:owner/:repo/pulls/comments/{comment_id}/replies -X POST -f body='your response'"
191
- WARNINGS=1
192
- else
193
- echo "✅ PASSED: No outstanding PR comments"
194
- fi
195
- fi
196
- fi
197
- echo ""
198
- fi
199
-
200
- # GATE 7: Build Evidence Verification (pre-pr only)
201
- if [ "$MODE" = "pre-pr" ]; then
202
- echo "================================================"
203
- echo "📋 GATE 7: Build Evidence Verification"
204
- echo "================================================"
205
-
206
- # Check if build has been run (look for build output or recent dist/ directory)
207
- BUILD_EVIDENCE_FOUND=0
208
-
209
- # Method 1: Check if dist/ directory exists and has recent files
210
- if [ -d "dist" ]; then
211
- # Check if dist has files modified in last 2 hours
212
- if find dist -type f -newermt "2 hours ago" 2>/dev/null | grep -q .; then
213
- BUILD_EVIDENCE_FOUND=1
214
- echo "✅ Found: Recent files in dist/ directory"
215
- fi
216
- fi
217
-
218
- # Method 2: Check for build logs
219
- if [ -f "server.log" ] && tail -50 server.log 2>/dev/null | grep -qiE "(Build.*success|Compiled successfully|build.*complete)"; then
220
- BUILD_EVIDENCE_FOUND=1
221
- echo "✅ Found: Build success in server.log"
222
- fi
223
-
224
- # Method 3: Check if TypeScript compilation succeeds now
225
- if command -v npx &> /dev/null; then
226
- if npx tsc --noEmit --skipLibCheck > /dev/null 2>&1; then
227
- BUILD_EVIDENCE_FOUND=1
228
- echo "✅ Found: TypeScript compilation succeeds (runtime check)"
229
- fi
230
- fi
231
-
232
- if [ $BUILD_EVIDENCE_FOUND -eq 0 ]; then
233
- echo "❌ FAILED: No build evidence found"
234
- echo " Required: Run 'npm run build' and verify it succeeds before marking PR ready"
235
- echo " Evidence can be: dist/ files, build logs, or successful compilation"
236
- FAILED=1
237
- else
238
- echo "✅ PASSED: Build evidence verified"
239
- fi
240
- echo ""
241
- fi
242
-
243
- # GATE 8: Test Execution Verification (pre-pr only)
244
- if [ "$MODE" = "pre-pr" ]; then
245
- echo "================================================"
246
- echo "📋 GATE 8: Test Execution Verification"
247
- echo "================================================"
248
-
249
- # Check if test files were created in this PR/branch
250
- NEW_TEST_FILES=$(find . -name "test-*.ts" -newer .git/HEAD 2>/dev/null | grep -v node_modules | head -10 || true)
251
-
252
- if [ -n "$NEW_TEST_FILES" ]; then
253
- echo "âš ī¸ WARNING: New test files detected:"
254
- echo "$NEW_TEST_FILES" | sed 's/^/ - /'
255
- echo " Rule: All new test files must be executed before submitting evidence"
256
- echo " Check: Verify test execution results are included in PR evidence"
257
- WARNINGS=1
258
- else
259
- echo "✅ PASSED: No new test files detected (or tests were executed)"
260
- fi
261
-
262
- # Check evidence files for "pending" automated validations
263
- EVIDENCE_FILES=$(find . -name "implementation-evidence-*.md" -o -name "*evidence*.md" 2>/dev/null | head -5 || true)
264
- if [ -n "$EVIDENCE_FILES" ]; then
265
- PENDING_AUTO=$(grep -l "pending.*automated\|pending.*test\|manual validation.*pending" $EVIDENCE_FILES 2>/dev/null | head -3 || true)
266
- if [ -n "$PENDING_AUTO" ]; then
267
- echo "âš ī¸ WARNING: Evidence files mention 'pending' automated validations:"
268
- echo "$PENDING_AUTO" | sed 's/^/ - /'
269
- echo " Rule: Cannot mark automated validations as 'pending' without attempting them first"
270
- echo " Check: Verify all test files have been executed before submitting evidence"
271
- WARNINGS=1
272
- fi
273
- fi
274
- echo ""
275
- fi
276
-
277
- # GATE 9: Test Evidence Verification (pre-pr only)
278
- if [ "$MODE" = "pre-pr" ]; then
279
- echo "================================================"
280
- echo "📋 GATE 9: Test Evidence Verification"
281
- echo "================================================"
282
-
283
- TEST_EVIDENCE_FOUND=0
284
-
285
- # Method 1: Check PR comments for test evidence
286
- if command -v gh &> /dev/null; then
287
- PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
288
- if [ -n "$PR_NUMBER" ]; then
289
- # Search PR comments for test evidence keywords
290
- if gh api repos/:owner/:repo/pulls/$PR_NUMBER/comments --jq '.[].body' 2>/dev/null | grep -qiE "(test.*pass|test.*evidence|test.*result|exit code.*0|✅.*test)" 2>/dev/null; then
291
- TEST_EVIDENCE_FOUND=1
292
- echo "✅ Found: Test evidence in PR comments"
293
- fi
294
- fi
295
- fi
296
-
297
- # Method 2: Check for test log files with pass indicators
298
- if [ -f "test.log" ] && grep -qE "(pass|PASS|✅|exit code.*0)" test.log 2>/dev/null; then
299
- TEST_EVIDENCE_FOUND=1
300
- echo "✅ Found: Test evidence in test.log"
301
- fi
302
-
303
- # Method 3: Check for npm test exit codes (if test.log exists and shows recent runs)
304
- # Note: We don't run tests here (too slow), just check for evidence of recent test runs
305
- if [ -f "test.log" ] && [ -n "$(find test.log -mmin -60 2>/dev/null)" ]; then
306
- # If test.log was modified in last hour, assume tests were run
307
- if grep -qE "(pass|PASS|✅)" test.log 2>/dev/null; then
308
- TEST_EVIDENCE_FOUND=1
309
- echo "✅ Found: Recent test run in test.log"
310
- fi
311
- fi
312
-
313
- if [ $TEST_EVIDENCE_FOUND -eq 0 ]; then
314
- echo "❌ FAILED: No test evidence found"
315
- echo " Required: Provide test evidence before marking PR ready"
316
- echo " Evidence can be: PR comment with test results, test.log file, or passing test run"
317
- echo " Evidence must include exit codes and test names"
318
- FAILED=1
319
- else
320
- echo "✅ PASSED: Test evidence verified"
321
- fi
322
- echo ""
323
- fi
324
-
325
- # GATE 11: Issue Label Verification (pre-pr only)
326
- if [ "$MODE" = "pre-pr" ]; then
327
- echo "================================================"
328
- echo "📋 GATE 10: Issue Label Verification"
329
- echo "================================================"
330
-
331
- if ! command -v gh &> /dev/null; then
332
- echo "â„šī¸ gh CLI not found - skipping issue label check"
333
- echo ""
334
- else
335
- # Extract issue number from branch name
336
- CURRENT_BRANCH=$(git branch --show-current)
337
- ISSUE_NUMBER=$(echo "$CURRENT_BRANCH" | sed -n 's/feature\/\([0-9]\+\).*/\1/p')
338
-
339
- if [ -z "$ISSUE_NUMBER" ]; then
340
- echo "âš ī¸ WARNING: Could not extract issue number from branch: $CURRENT_BRANCH"
341
- echo " Expected format: feature/533-slug"
342
- echo " Skipping label verification"
343
- else
344
- echo "Checking labels for issue #$ISSUE_NUMBER"
345
-
346
- # Get issue labels
347
- LABELS=$(gh api repos/:owner/:repo/issues/$ISSUE_NUMBER --jq '.labels[].name' 2>/dev/null || echo "")
348
-
349
- if [ -z "$LABELS" ]; then
350
- echo "❌ FAILED: Could not fetch issue labels"
351
- echo " Check that issue #$ISSUE_NUMBER exists and is accessible"
352
- FAILED=1
353
- else
354
- # Check for phase label
355
- HAS_PHASE_LABEL=false
356
- PHASE_LABEL=""
357
- while IFS= read -r label; do
358
- case "$label" in
359
- phase:spec|phase:design|phase:impl|phase:tests)
360
- HAS_PHASE_LABEL=true
361
- PHASE_LABEL="$label"
362
- break
363
- ;;
364
- esac
365
- done <<< "$LABELS"
366
-
367
- # Check status labels
368
- HAS_STATUS_WIP=false
369
- HAS_STATUS_NEEDS_REVIEW=false
370
- while IFS= read -r label; do
371
- case "$label" in
372
- status:wip)
373
- HAS_STATUS_WIP=true
374
- ;;
375
- status:needs-review)
376
- HAS_STATUS_NEEDS_REVIEW=true
377
- ;;
378
- esac
379
- done <<< "$LABELS"
380
-
381
- # Validation
382
- if [ "$HAS_PHASE_LABEL" = false ]; then
383
- echo "❌ FAILED: Issue missing phase label"
384
- echo " Required: phase:spec, phase:design, phase:impl, or phase:tests"
385
- echo " Current labels: $LABELS"
386
- FAILED=1
387
- elif [ "$HAS_STATUS_NEEDS_REVIEW" = true ] && [ "$HAS_STATUS_WIP" = true ]; then
388
- echo "❌ FAILED: Issue has both status:wip and status:needs-review"
389
- echo " Remove status:wip before marking ready for review"
390
- echo " Current labels: $LABELS"
391
- FAILED=1
392
- else
393
- echo "✅ PASSED: Issue labels correct"
394
- echo " Phase: $PHASE_LABEL"
395
- if [ "$HAS_STATUS_NEEDS_REVIEW" = true ]; then
396
- echo " Status: status:needs-review"
397
- elif [ "$HAS_STATUS_WIP" = true ]; then
398
- echo " Status: status:wip"
399
- else
400
- echo " Status: (none)"
401
- fi
402
- fi
403
- fi
404
- fi
405
- fi
406
- echo ""
407
- fi
408
-
409
- # GATE 10: Validation Plan Coverage (pre-pr only)
410
- if [ "$MODE" = "pre-pr" ]; then
411
- echo "================================================"
412
- echo "📋 GATE 9: Test Coverage Alignment"
413
- echo "================================================"
414
-
415
- # Extract issue number from branch
416
- CURRENT_BRANCH=$(git branch --show-current)
417
- ISSUE_NUMBER=$(echo "$CURRENT_BRANCH" | sed -n 's/feature\/\([0-9]\+\).*/\1/p')
418
-
419
- if [ -z "$ISSUE_NUMBER" ]; then
420
- echo "â„šī¸ Could not extract issue number from branch - skipping validation plan check"
421
- elif command -v npx &> /dev/null; then
422
- # Run validation coverage checker
423
- COVERAGE_OUTPUT=$(GIT_BRANCH="$CURRENT_BRANCH" npx tsx "$(dirname "$0")/validate-test-coverage.ts" "$ISSUE_NUMBER" 2>&1)
424
- COVERAGE_EXIT=$?
425
-
426
- echo "$COVERAGE_OUTPUT"
427
-
428
- if [ $COVERAGE_EXIT -eq 1 ]; then
429
- # Coverage incomplete
430
- FAILED=1
431
- elif echo "$COVERAGE_OUTPUT" | grep -qi "skipped\|no.*validation plan\|no spec"; then
432
- # No spec/design or no validation plan - Gate 9 warns but doesn't block
433
- echo "âš ī¸ WARNING: Validation plan check skipped (no spec/design or no validation plan)"
434
- echo " This is acceptable, but consider adding validation plan to spec/design for future issues"
435
- WARNINGS=1
436
- fi
437
- else
438
- echo "â„šī¸ npx not available - skipping validation plan coverage check"
439
- echo " Install: npm (Node.js package manager)"
440
- fi
441
- echo ""
442
- fi
443
-
444
- # GATE 12: ChatGPT Length Limits (pre-pr only)
445
- if [ "$MODE" = "pre-pr" ]; then
446
- echo "================================================"
447
- echo "📋 GATE 11: ChatGPT Length Limits"
448
- echo "================================================"
449
-
450
- CHATGPT_LIMITS_FAILED=0
451
-
452
- # Check instructions.txt length (8,000 char limit)
453
- if [ -f "src/openapi/instructions.txt" ]; then
454
- if command -v python &> /dev/null || command -v python3 &> /dev/null; then
455
- PYTHON_CMD=$(command -v python3 2>/dev/null || command -v python 2>/dev/null)
456
- INST_LENGTH=$($PYTHON_CMD -c "f = open('src/openapi/instructions.txt', 'r', encoding='utf-8'); content = f.read(); f.close(); print(len(content))" 2>/dev/null || echo "0")
457
-
458
- if [ "$INST_LENGTH" -gt 8000 ]; then
459
- echo "❌ FAILED: instructions.txt exceeds 8,000 character limit"
460
- echo " Current length: $INST_LENGTH characters"
461
- echo " Limit: 8,000 characters"
462
- echo " Solution: Move detailed content to KB files (KB-*.txt) and reference them"
463
- echo " See: $ARCH_DOC#chatgpt-length-limitations"
464
- CHATGPT_LIMITS_FAILED=1
465
- else
466
- echo "✅ PASSED: instructions.txt length ($INST_LENGTH chars) within limit (8,000)"
467
- fi
468
- else
469
- echo "â„šī¸ python not found - skipping instructions.txt length check"
470
- fi
471
- fi
472
-
473
- # Check OpenAPI operation description lengths (300 char limit)
474
- if [ -f "$OPENAPI_PATH" ]; then
475
- if command -v python &> /dev/null || command -v python3 &> /dev/null; then
476
- PYTHON_CMD=$(command -v python3 2>/dev/null || command -v python 2>/dev/null)
477
- LONG_DESCS=$($PYTHON_CMD -c "
478
- import json
479
- try:
480
- f = open('$OPENAPI_PATH', 'r', encoding='utf-8')
481
- spec = json.load(f)
482
- f.close()
483
- violations = []
484
- for path, methods in spec.get('paths', {}).items():
485
- for method, details in methods.items():
486
- if isinstance(details, dict) and 'description' in details:
487
- desc = details['description']
488
- if len(desc) > 300:
489
- violations.append(f'{path} {method.upper()}: {len(desc)} chars')
490
- if violations:
491
- print('\n'.join(violations))
492
- else:
493
- print('OK')
494
- except Exception as e:
495
- print(f'ERROR: {e}')
496
- " 2>/dev/null || echo "ERROR")
497
-
498
- if [ "$LONG_DESCS" != "OK" ] && [ -n "$LONG_DESCS" ] && [ "$LONG_DESCS" != "ERROR" ]; then
499
- echo "❌ FAILED: OpenAPI operation descriptions exceed 300 character limit"
500
- echo "$LONG_DESCS" | while IFS= read -r line; do
501
- echo " $line"
502
- done
503
- echo " Solution: Shorten descriptions, move details to KB files, reference KB files"
504
- echo " See: $ARCH_DOC#chatgpt-length-limitations"
505
- CHATGPT_LIMITS_FAILED=1
506
- elif [ "$LONG_DESCS" = "ERROR" ]; then
507
- echo "âš ī¸ WARNING: Could not validate OpenAPI description lengths (JSON parsing error)"
508
- WARNINGS=1
509
- else
510
- echo "✅ PASSED: All OpenAPI operation descriptions within limit (300 chars)"
511
- fi
512
- else
513
- echo "â„šī¸ python not found - skipping OpenAPI description length check"
514
- fi
515
- fi
516
-
517
- if [ $CHATGPT_LIMITS_FAILED -eq 1 ]; then
518
- FAILED=1
519
- fi
520
- echo ""
521
- fi
522
-
523
- # Summary
524
- echo "================================================"
525
- echo "📊 QUALITY CHECK SUMMARY ($MODE mode)"
526
- echo "================================================"
527
- echo ""
528
-
529
- if [ $FAILED -eq 1 ]; then
530
- echo "❌ CHECKS FAILED"
531
- echo ""
532
- echo "Critical issues found. Cannot proceed."
533
- echo "See .ai-agents/rules/code-quality-and-debugging-patterns.md"
534
- exit 1
535
- elif [ $WARNINGS -gt 0 ]; then
536
- echo "âš ī¸ CHECKS PASSED WITH WARNINGS"
537
- echo ""
538
- echo "Some warnings found. Consider addressing before proceeding."
539
-
540
- if [ "$MODE" = "pre-commit" ]; then
541
- echo "You can still commit, but consider fixing warnings."
542
- exit 0
543
- else
544
- exit 0
545
- fi
546
- else
547
- echo "✅ ALL CHECKS PASSED"
548
- echo ""
549
-
550
- if [ "$MODE" = "pre-commit" ]; then
551
- echo "Ready to commit!"
552
- elif [ "$MODE" = "pre-pr" ]; then
553
- echo "Ready to create PR!"
554
- echo "Run: gh pr create --title \"your title\" --body \"your description\""
555
- else
556
- echo "CI checks complete!"
557
- fi
558
- exit 0
559
- fi
1
+ #!/bin/bash
2
+ # Unified code quality check script
3
+ # Can be run at different stages: pre-commit, pre-pr, or ci
4
+ # Usage: bash code-quality-check.sh [pre-commit|pre-pr|ci]
5
+
6
+ MODE="${1:-pre-pr}" # Default to pre-pr if not specified
7
+
8
+ set -e
9
+
10
+ echo "🔍 Running code quality checks (mode: $MODE)..."
11
+ echo ""
12
+
13
+ FAILED=0
14
+ WARNINGS=0
15
+
16
+ # Determine what files to check based on mode
17
+ if [ "$MODE" = "pre-commit" ]; then
18
+ # Pre-commit: only check staged files
19
+ TS_FILES=$(git diff --cached --name-only | grep -E '\.(ts|tsx)$' || true)
20
+ CHECK_SCOPE="staged files"
21
+ elif [ "$MODE" = "ci" ]; then
22
+ # CI: check only files changed in this PR
23
+ # Compare against the base branch (e.g., master or feature/*)
24
+ BASE_BRANCH="${GITHUB_BASE_REF:-origin/master}"
25
+ echo "â„šī¸ Comparing against base: $BASE_BRANCH"
26
+
27
+ # Get all changed TypeScript files in the PR
28
+ TS_FILES=$(git diff --name-only $BASE_BRANCH...HEAD | grep -E '\.(ts|tsx)$' || true)
29
+
30
+ if [ -z "$TS_FILES" ]; then
31
+ echo "â„šī¸ No TypeScript files changed in this PR"
32
+ CHECK_SCOPE="no files changed"
33
+ else
34
+ FILE_COUNT=$(echo "$TS_FILES" | wc -l | tr -d ' ')
35
+ CHECK_SCOPE="$FILE_COUNT changed file(s) in PR"
36
+ fi
37
+ elif [ "$MODE" = "pre-pr" ]; then
38
+ # Pre-PR: check entire src directory (local development)
39
+ TS_FILES=$(find src -name "*.ts" -o -name "*.tsx" 2>/dev/null || true)
40
+ CHECK_SCOPE="entire codebase"
41
+ fi
42
+ # Load configuration from config.json
43
+ CONFIG_FILE=".fraim/config.json"
44
+ if [ -f "$CONFIG_FILE" ]; then
45
+ # Extract OpenAPI path using node
46
+ OPENAPI_PATH=$(node -e "const fs = require('fs'); try { const config = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf-8')); console.log(config.paths?.openapi || 'src/openapi/OpenAPI.json'); } catch(e) { console.log('src/openapi/OpenAPI.json'); }")
47
+ ARCH_DOC=$(node -e "const fs = require('fs'); try { const config = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf-8')); console.log('rules/' + (config.persona?.name?.toLowerCase() || 'persona') + '-architecture.md'); } catch(e) { console.log('rules/persona-architecture.md'); }")
48
+ else
49
+ OPENAPI_PATH="src/openapi/OpenAPI.json"
50
+ ARCH_DOC="rules/persona-architecture.md"
51
+ fi
52
+
53
+ echo "Checking: $CHECK_SCOPE"
54
+ echo ""
55
+
56
+ # GATE 1: Check for 'as any' type bypassing
57
+ echo "================================================"
58
+ echo "📋 GATE 1: No 'as any' Type Bypassing"
59
+ echo "================================================"
60
+
61
+ if [ -z "$TS_FILES" ]; then
62
+ echo "â„šī¸ No TypeScript files to check"
63
+ else
64
+ if echo "$TS_FILES" | xargs grep -n ' as any' 2>/dev/null; then
65
+ echo ""
66
+ echo "❌ FAILED: Found 'as any' type assertions"
67
+ echo " Rule: Use proper TypeScript interfaces, not 'as any'"
68
+ echo " See: rules/code-quality-and-debugging-patterns.md#rule-1"
69
+ FAILED=1
70
+ else
71
+ echo "✅ PASSED: No 'as any' type bypassing found"
72
+ fi
73
+ fi
74
+ echo ""
75
+
76
+ # GATE 1.5: Tautological Tests Check
77
+ echo "================================================"
78
+ echo "📋 GATE 1.5: No Tautological Test Patterns"
79
+ echo "================================================"
80
+
81
+ if bash "$(dirname "$0")/detect-tautological-tests.sh"; then
82
+ echo "✅ PASSED: No tautological tests found"
83
+ else
84
+ echo "❌ FAILED: Tautological test patterns detected"
85
+ echo " Rule: Tests must fail if product code is removed. Don't test types/constants."
86
+ echo " See: rules/integrity-and-test-ethics.md#critical-invalid-test-patterns-tautology-type-testing"
87
+ FAILED=1
88
+ fi
89
+ echo ""
90
+
91
+
92
+ # GATE 2: TypeScript Compilation
93
+ echo "================================================"
94
+ echo "📋 GATE 2: TypeScript Compilation"
95
+ echo "================================================"
96
+
97
+ if command -v npx &> /dev/null; then
98
+ if npx tsc --noEmit --skipLibCheck 2>&1 | head -50; then
99
+ echo "✅ PASSED: TypeScript compilation successful"
100
+ else
101
+ echo "❌ FAILED: TypeScript compilation errors"
102
+ echo " Fix all TypeScript errors before proceeding"
103
+ FAILED=1
104
+ fi
105
+ else
106
+ echo "â„šī¸ npx not found - skipping TypeScript check"
107
+ fi
108
+ echo ""
109
+
110
+ # GATE 3: Linter
111
+ echo "================================================"
112
+ echo "📋 GATE 3: Linter (ESLint)"
113
+ echo "================================================"
114
+
115
+ if command -v npm &> /dev/null; then
116
+ if npm run lint 2>&1 | head -50; then
117
+ echo "✅ PASSED: Linter checks passed"
118
+ else
119
+ echo "âš ī¸ WARNING: Linter has issues"
120
+ WARNINGS=1
121
+ fi
122
+ else
123
+ echo "â„šī¸ npm not found - skipping lint check"
124
+ fi
125
+ echo ""
126
+
127
+ # GATE 4: Git Status (pre-pr and ci only)
128
+ if [ "$MODE" != "pre-commit" ]; then
129
+ echo "================================================"
130
+ echo "📋 GATE 4: Git Status"
131
+ echo "================================================"
132
+
133
+ if [ -n "$(git status --porcelain)" ]; then
134
+ echo "âš ī¸ WARNING: Uncommitted changes detected"
135
+ git status --short
136
+ WARNINGS=1
137
+ else
138
+ echo "✅ PASSED: Working directory is clean"
139
+ fi
140
+ echo ""
141
+ fi
142
+
143
+ # GATE 5: Commits Pushed (pre-pr only)
144
+ if [ "$MODE" = "pre-pr" ]; then
145
+ echo "================================================"
146
+ echo "📋 GATE 5: Commits Pushed to Remote"
147
+ echo "================================================"
148
+
149
+ CURRENT_BRANCH=$(git branch --show-current)
150
+ if git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline 2>/dev/null | grep . > /dev/null; then
151
+ echo "âš ī¸ WARNING: Unpushed commits detected"
152
+ git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline
153
+ WARNINGS=1
154
+ else
155
+ echo "✅ PASSED: All commits pushed to remote"
156
+ fi
157
+ echo ""
158
+ fi
159
+
160
+ # GATE 6: PR Comments Addressed (pre-pr only)
161
+ if [ "$MODE" = "pre-pr" ]; then
162
+ echo "================================================"
163
+ echo "📋 GATE 6: PR Comments Addressed"
164
+ echo "================================================"
165
+
166
+ # Check if gh CLI is available
167
+ if ! command -v gh &> /dev/null; then
168
+ echo "â„šī¸ gh CLI not found - skipping PR comment check"
169
+ echo ""
170
+ else
171
+ # Try to get PR number for current branch
172
+ PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
173
+
174
+ if [ -z "$PR_NUMBER" ]; then
175
+ echo "â„šī¸ No PR found for current branch - skipping comment check"
176
+ else
177
+ echo "Found PR #$PR_NUMBER"
178
+
179
+ # Get PR comments count
180
+ COMMENT_COUNT=$(gh api repos/:owner/:repo/pulls/$PR_NUMBER/comments --jq 'length' 2>/dev/null || echo "0")
181
+
182
+ if [ "$COMMENT_COUNT" -gt 0 ]; then
183
+ echo "âš ī¸ WARNING: PR has $COMMENT_COUNT review comments"
184
+ echo " Please ensure all comments are addressed before marking ready for review"
185
+ echo ""
186
+ echo " To view comments:"
187
+ echo " gh pr view $PR_NUMBER --comments"
188
+ echo ""
189
+ echo " To reply to a comment:"
190
+ echo " gh api repos/:owner/:repo/pulls/comments/{comment_id}/replies -X POST -f body='your response'"
191
+ WARNINGS=1
192
+ else
193
+ echo "✅ PASSED: No outstanding PR comments"
194
+ fi
195
+ fi
196
+ fi
197
+ echo ""
198
+ fi
199
+
200
+ # GATE 7: Build Evidence Verification (pre-pr only)
201
+ if [ "$MODE" = "pre-pr" ]; then
202
+ echo "================================================"
203
+ echo "📋 GATE 7: Build Evidence Verification"
204
+ echo "================================================"
205
+
206
+ # Check if build has been run (look for build output or recent dist/ directory)
207
+ BUILD_EVIDENCE_FOUND=0
208
+
209
+ # Method 1: Check if dist/ directory exists and has recent files
210
+ if [ -d "dist" ]; then
211
+ # Check if dist has files modified in last 2 hours
212
+ if find dist -type f -newermt "2 hours ago" 2>/dev/null | grep -q .; then
213
+ BUILD_EVIDENCE_FOUND=1
214
+ echo "✅ Found: Recent files in dist/ directory"
215
+ fi
216
+ fi
217
+
218
+ # Method 2: Check for build logs
219
+ if [ -f "server.log" ] && tail -50 server.log 2>/dev/null | grep -qiE "(Build.*success|Compiled successfully|build.*complete)"; then
220
+ BUILD_EVIDENCE_FOUND=1
221
+ echo "✅ Found: Build success in server.log"
222
+ fi
223
+
224
+ # Method 3: Check if TypeScript compilation succeeds now
225
+ if command -v npx &> /dev/null; then
226
+ if npx tsc --noEmit --skipLibCheck > /dev/null 2>&1; then
227
+ BUILD_EVIDENCE_FOUND=1
228
+ echo "✅ Found: TypeScript compilation succeeds (runtime check)"
229
+ fi
230
+ fi
231
+
232
+ if [ $BUILD_EVIDENCE_FOUND -eq 0 ]; then
233
+ echo "❌ FAILED: No build evidence found"
234
+ echo " Required: Run 'npm run build' and verify it succeeds before marking PR ready"
235
+ echo " Evidence can be: dist/ files, build logs, or successful compilation"
236
+ FAILED=1
237
+ else
238
+ echo "✅ PASSED: Build evidence verified"
239
+ fi
240
+ echo ""
241
+ fi
242
+
243
+ # GATE 8: Test Execution Verification (pre-pr only)
244
+ if [ "$MODE" = "pre-pr" ]; then
245
+ echo "================================================"
246
+ echo "📋 GATE 8: Test Execution Verification"
247
+ echo "================================================"
248
+
249
+ # Check if test files were created in this PR/branch
250
+ NEW_TEST_FILES=$(find . -name "test-*.ts" -newer .git/HEAD 2>/dev/null | grep -v node_modules | head -10 || true)
251
+
252
+ if [ -n "$NEW_TEST_FILES" ]; then
253
+ echo "âš ī¸ WARNING: New test files detected:"
254
+ echo "$NEW_TEST_FILES" | sed 's/^/ - /'
255
+ echo " Rule: All new test files must be executed before submitting evidence"
256
+ echo " Check: Verify test execution results are included in PR evidence"
257
+ WARNINGS=1
258
+ else
259
+ echo "✅ PASSED: No new test files detected (or tests were executed)"
260
+ fi
261
+
262
+ # Check evidence files for "pending" automated validations
263
+ EVIDENCE_FILES=$(find . -name "implementation-evidence-*.md" -o -name "*evidence*.md" 2>/dev/null | head -5 || true)
264
+ if [ -n "$EVIDENCE_FILES" ]; then
265
+ PENDING_AUTO=$(grep -l "pending.*automated\|pending.*test\|manual validation.*pending" $EVIDENCE_FILES 2>/dev/null | head -3 || true)
266
+ if [ -n "$PENDING_AUTO" ]; then
267
+ echo "âš ī¸ WARNING: Evidence files mention 'pending' automated validations:"
268
+ echo "$PENDING_AUTO" | sed 's/^/ - /'
269
+ echo " Rule: Cannot mark automated validations as 'pending' without attempting them first"
270
+ echo " Check: Verify all test files have been executed before submitting evidence"
271
+ WARNINGS=1
272
+ fi
273
+ fi
274
+ echo ""
275
+ fi
276
+
277
+ # GATE 9: Test Evidence Verification (pre-pr only)
278
+ if [ "$MODE" = "pre-pr" ]; then
279
+ echo "================================================"
280
+ echo "📋 GATE 9: Test Evidence Verification"
281
+ echo "================================================"
282
+
283
+ TEST_EVIDENCE_FOUND=0
284
+
285
+ # Method 1: Check PR comments for test evidence
286
+ if command -v gh &> /dev/null; then
287
+ PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
288
+ if [ -n "$PR_NUMBER" ]; then
289
+ # Search PR comments for test evidence keywords
290
+ if gh api repos/:owner/:repo/pulls/$PR_NUMBER/comments --jq '.[].body' 2>/dev/null | grep -qiE "(test.*pass|test.*evidence|test.*result|exit code.*0|✅.*test)" 2>/dev/null; then
291
+ TEST_EVIDENCE_FOUND=1
292
+ echo "✅ Found: Test evidence in PR comments"
293
+ fi
294
+ fi
295
+ fi
296
+
297
+ # Method 2: Check for test log files with pass indicators
298
+ if [ -f "test.log" ] && grep -qE "(pass|PASS|✅|exit code.*0)" test.log 2>/dev/null; then
299
+ TEST_EVIDENCE_FOUND=1
300
+ echo "✅ Found: Test evidence in test.log"
301
+ fi
302
+
303
+ # Method 3: Check for npm test exit codes (if test.log exists and shows recent runs)
304
+ # Note: We don't run tests here (too slow), just check for evidence of recent test runs
305
+ if [ -f "test.log" ] && [ -n "$(find test.log -mmin -60 2>/dev/null)" ]; then
306
+ # If test.log was modified in last hour, assume tests were run
307
+ if grep -qE "(pass|PASS|✅)" test.log 2>/dev/null; then
308
+ TEST_EVIDENCE_FOUND=1
309
+ echo "✅ Found: Recent test run in test.log"
310
+ fi
311
+ fi
312
+
313
+ if [ $TEST_EVIDENCE_FOUND -eq 0 ]; then
314
+ echo "❌ FAILED: No test evidence found"
315
+ echo " Required: Provide test evidence before marking PR ready"
316
+ echo " Evidence can be: PR comment with test results, test.log file, or passing test run"
317
+ echo " Evidence must include exit codes and test names"
318
+ FAILED=1
319
+ else
320
+ echo "✅ PASSED: Test evidence verified"
321
+ fi
322
+ echo ""
323
+ fi
324
+
325
+ # GATE 11: Issue Label Verification (pre-pr only)
326
+ if [ "$MODE" = "pre-pr" ]; then
327
+ echo "================================================"
328
+ echo "📋 GATE 10: Issue Label Verification"
329
+ echo "================================================"
330
+
331
+ if ! command -v gh &> /dev/null; then
332
+ echo "â„šī¸ gh CLI not found - skipping issue label check"
333
+ echo ""
334
+ else
335
+ # Extract issue number from branch name
336
+ CURRENT_BRANCH=$(git branch --show-current)
337
+ ISSUE_NUMBER=$(echo "$CURRENT_BRANCH" | sed -n 's/feature\/\([0-9]\+\).*/\1/p')
338
+
339
+ if [ -z "$ISSUE_NUMBER" ]; then
340
+ echo "âš ī¸ WARNING: Could not extract issue number from branch: $CURRENT_BRANCH"
341
+ echo " Expected format: feature/533-slug"
342
+ echo " Skipping label verification"
343
+ else
344
+ echo "Checking labels for issue #$ISSUE_NUMBER"
345
+
346
+ # Get issue labels
347
+ LABELS=$(gh api repos/:owner/:repo/issues/$ISSUE_NUMBER --jq '.labels[].name' 2>/dev/null || echo "")
348
+
349
+ if [ -z "$LABELS" ]; then
350
+ echo "❌ FAILED: Could not fetch issue labels"
351
+ echo " Check that issue #$ISSUE_NUMBER exists and is accessible"
352
+ FAILED=1
353
+ else
354
+ # Check for phase label
355
+ HAS_PHASE_LABEL=false
356
+ PHASE_LABEL=""
357
+ while IFS= read -r label; do
358
+ case "$label" in
359
+ phase:spec|phase:design|phase:impl|phase:tests)
360
+ HAS_PHASE_LABEL=true
361
+ PHASE_LABEL="$label"
362
+ break
363
+ ;;
364
+ esac
365
+ done <<< "$LABELS"
366
+
367
+ # Check status labels
368
+ HAS_STATUS_WIP=false
369
+ HAS_STATUS_NEEDS_REVIEW=false
370
+ while IFS= read -r label; do
371
+ case "$label" in
372
+ status:wip)
373
+ HAS_STATUS_WIP=true
374
+ ;;
375
+ status:needs-review)
376
+ HAS_STATUS_NEEDS_REVIEW=true
377
+ ;;
378
+ esac
379
+ done <<< "$LABELS"
380
+
381
+ # Validation
382
+ if [ "$HAS_PHASE_LABEL" = false ]; then
383
+ echo "❌ FAILED: Issue missing phase label"
384
+ echo " Required: phase:spec, phase:design, phase:impl, or phase:tests"
385
+ echo " Current labels: $LABELS"
386
+ FAILED=1
387
+ elif [ "$HAS_STATUS_NEEDS_REVIEW" = true ] && [ "$HAS_STATUS_WIP" = true ]; then
388
+ echo "❌ FAILED: Issue has both status:wip and status:needs-review"
389
+ echo " Remove status:wip before marking ready for review"
390
+ echo " Current labels: $LABELS"
391
+ FAILED=1
392
+ else
393
+ echo "✅ PASSED: Issue labels correct"
394
+ echo " Phase: $PHASE_LABEL"
395
+ if [ "$HAS_STATUS_NEEDS_REVIEW" = true ]; then
396
+ echo " Status: status:needs-review"
397
+ elif [ "$HAS_STATUS_WIP" = true ]; then
398
+ echo " Status: status:wip"
399
+ else
400
+ echo " Status: (none)"
401
+ fi
402
+ fi
403
+ fi
404
+ fi
405
+ fi
406
+ echo ""
407
+ fi
408
+
409
+ # GATE 10: Validation Plan Coverage (pre-pr only)
410
+ if [ "$MODE" = "pre-pr" ]; then
411
+ echo "================================================"
412
+ echo "📋 GATE 9: Test Coverage Alignment"
413
+ echo "================================================"
414
+
415
+ # Extract issue number from branch
416
+ CURRENT_BRANCH=$(git branch --show-current)
417
+ ISSUE_NUMBER=$(echo "$CURRENT_BRANCH" | sed -n 's/feature\/\([0-9]\+\).*/\1/p')
418
+
419
+ if [ -z "$ISSUE_NUMBER" ]; then
420
+ echo "â„šī¸ Could not extract issue number from branch - skipping validation plan check"
421
+ elif command -v npx &> /dev/null; then
422
+ # Run validation coverage checker
423
+ COVERAGE_OUTPUT=$(GIT_BRANCH="$CURRENT_BRANCH" npx tsx "$(dirname "$0")/validate-test-coverage.ts" "$ISSUE_NUMBER" 2>&1)
424
+ COVERAGE_EXIT=$?
425
+
426
+ echo "$COVERAGE_OUTPUT"
427
+
428
+ if [ $COVERAGE_EXIT -eq 1 ]; then
429
+ # Coverage incomplete
430
+ FAILED=1
431
+ elif echo "$COVERAGE_OUTPUT" | grep -qi "skipped\|no.*validation plan\|no spec"; then
432
+ # No spec/design or no validation plan - Gate 9 warns but doesn't block
433
+ echo "âš ī¸ WARNING: Validation plan check skipped (no spec/design or no validation plan)"
434
+ echo " This is acceptable, but consider adding validation plan to spec/design for future issues"
435
+ WARNINGS=1
436
+ fi
437
+ else
438
+ echo "â„šī¸ npx not available - skipping validation plan coverage check"
439
+ echo " Install: npm (Node.js package manager)"
440
+ fi
441
+ echo ""
442
+ fi
443
+
444
+ # GATE 12: ChatGPT Length Limits (pre-pr only)
445
+ if [ "$MODE" = "pre-pr" ]; then
446
+ echo "================================================"
447
+ echo "📋 GATE 11: ChatGPT Length Limits"
448
+ echo "================================================"
449
+
450
+ CHATGPT_LIMITS_FAILED=0
451
+
452
+ # Check instructions.txt length (8,000 char limit)
453
+ if [ -f "src/openapi/instructions.txt" ]; then
454
+ if command -v python &> /dev/null || command -v python3 &> /dev/null; then
455
+ PYTHON_CMD=$(command -v python3 2>/dev/null || command -v python 2>/dev/null)
456
+ INST_LENGTH=$($PYTHON_CMD -c "f = open('src/openapi/instructions.txt', 'r', encoding='utf-8'); content = f.read(); f.close(); print(len(content))" 2>/dev/null || echo "0")
457
+
458
+ if [ "$INST_LENGTH" -gt 8000 ]; then
459
+ echo "❌ FAILED: instructions.txt exceeds 8,000 character limit"
460
+ echo " Current length: $INST_LENGTH characters"
461
+ echo " Limit: 8,000 characters"
462
+ echo " Solution: Move detailed content to KB files (KB-*.txt) and reference them"
463
+ echo " See: $ARCH_DOC#chatgpt-length-limitations"
464
+ CHATGPT_LIMITS_FAILED=1
465
+ else
466
+ echo "✅ PASSED: instructions.txt length ($INST_LENGTH chars) within limit (8,000)"
467
+ fi
468
+ else
469
+ echo "â„šī¸ python not found - skipping instructions.txt length check"
470
+ fi
471
+ fi
472
+
473
+ # Check OpenAPI operation description lengths (300 char limit)
474
+ if [ -f "$OPENAPI_PATH" ]; then
475
+ if command -v python &> /dev/null || command -v python3 &> /dev/null; then
476
+ PYTHON_CMD=$(command -v python3 2>/dev/null || command -v python 2>/dev/null)
477
+ LONG_DESCS=$($PYTHON_CMD -c "
478
+ import json
479
+ try:
480
+ f = open('$OPENAPI_PATH', 'r', encoding='utf-8')
481
+ spec = json.load(f)
482
+ f.close()
483
+ violations = []
484
+ for path, methods in spec.get('paths', {}).items():
485
+ for method, details in methods.items():
486
+ if isinstance(details, dict) and 'description' in details:
487
+ desc = details['description']
488
+ if len(desc) > 300:
489
+ violations.append(f'{path} {method.upper()}: {len(desc)} chars')
490
+ if violations:
491
+ print('\n'.join(violations))
492
+ else:
493
+ print('OK')
494
+ except Exception as e:
495
+ print(f'ERROR: {e}')
496
+ " 2>/dev/null || echo "ERROR")
497
+
498
+ if [ "$LONG_DESCS" != "OK" ] && [ -n "$LONG_DESCS" ] && [ "$LONG_DESCS" != "ERROR" ]; then
499
+ echo "❌ FAILED: OpenAPI operation descriptions exceed 300 character limit"
500
+ echo "$LONG_DESCS" | while IFS= read -r line; do
501
+ echo " $line"
502
+ done
503
+ echo " Solution: Shorten descriptions, move details to KB files, reference KB files"
504
+ echo " See: $ARCH_DOC#chatgpt-length-limitations"
505
+ CHATGPT_LIMITS_FAILED=1
506
+ elif [ "$LONG_DESCS" = "ERROR" ]; then
507
+ echo "âš ī¸ WARNING: Could not validate OpenAPI description lengths (JSON parsing error)"
508
+ WARNINGS=1
509
+ else
510
+ echo "✅ PASSED: All OpenAPI operation descriptions within limit (300 chars)"
511
+ fi
512
+ else
513
+ echo "â„šī¸ python not found - skipping OpenAPI description length check"
514
+ fi
515
+ fi
516
+
517
+ if [ $CHATGPT_LIMITS_FAILED -eq 1 ]; then
518
+ FAILED=1
519
+ fi
520
+ echo ""
521
+ fi
522
+
523
+ # Summary
524
+ echo "================================================"
525
+ echo "📊 QUALITY CHECK SUMMARY ($MODE mode)"
526
+ echo "================================================"
527
+ echo ""
528
+
529
+ if [ $FAILED -eq 1 ]; then
530
+ echo "❌ CHECKS FAILED"
531
+ echo ""
532
+ echo "Critical issues found. Cannot proceed."
533
+ echo "See rules/code-quality-and-debugging-patterns.md"
534
+ exit 1
535
+ elif [ $WARNINGS -gt 0 ]; then
536
+ echo "âš ī¸ CHECKS PASSED WITH WARNINGS"
537
+ echo ""
538
+ echo "Some warnings found. Consider addressing before proceeding."
539
+
540
+ if [ "$MODE" = "pre-commit" ]; then
541
+ echo "You can still commit, but consider fixing warnings."
542
+ exit 0
543
+ else
544
+ exit 0
545
+ fi
546
+ else
547
+ echo "✅ ALL CHECKS PASSED"
548
+ echo ""
549
+
550
+ if [ "$MODE" = "pre-commit" ]; then
551
+ echo "Ready to commit!"
552
+ elif [ "$MODE" = "pre-pr" ]; then
553
+ echo "Ready to create PR!"
554
+ echo "Run: gh pr create --title \"your title\" --body \"your description\""
555
+ else
556
+ echo "CI checks complete!"
557
+ fi
558
+ exit 0
559
+ fi