
ci-compliance
Validate code changes against CI/CD requirements (lint, test, build, commit messages) for Go, Web, a
CI Compliance Skill
Purpose
This skill ensures all code changes meet the One Percent Trading Bot platform's CI/CD requirements before pushing to remote. It encapsulates our comprehensive linting, testing, and build standards to prevent CI failures.
When to Use This Skill
CRITICAL: Run this skill BEFORE every git push, BEFORE creating PRs, and AFTER making significant code changes.
This skill should be invoked:
- Before pushing code to remote (
git push) - Before creating or updating pull requests
- After implementing features or fixes that touch multiple subsystems
- When the user explicitly asks to "check CI", "validate changes", or "run pre-push checks"
- When working on code that has historically caused lint failures
- As a final validation step before considering work "done"
DO NOT run this skill:
- For trivial documentation-only changes (e.g., editing README without code changes)
- When the user explicitly bypasses it (though warn them of the risks)
Subsystem Detection
The codebase is a monorepo with multiple subsystems. Detect which subsystems have changed and run appropriate checks:
Go Services
Trigger when changed:
- Any
**/*.gofiles go.mod,go.sumhermelos/Dockerfile,janomus/Dockerfile.golangci.yml
Checks to run:
- golangci-lint - Linter with auto-fix where possible
- go test -race ./... - Tests with race detection
- Build validation - Both
janomusandhermelos
golangci-lint configuration (.golangci.yml):
version: "2"
run:
timeout: 5m
go: "1.25.2"
formatters:
enable:
- goimports
settings:
goimports:
local-prefixes:
- "github.com/haykay/one-percent-trading-bot"
linters:
enable:
- errcheck
- govet
- ineffassign
- staticcheck
- unused
- forcetypeassert
Common Go lint failures:
- Missing error checks (
errcheck) - Force type assertions without ok check (
forcetypeassert) - Unused variables/imports (
unused) - Incorrect import grouping (goimports - should have local imports last)
Web Console
Trigger when changed:
- Any files in
web/**
Checks to run (from web/ directory):
- ESLint -
npm run lint - Prettier format check -
npm run format:check - TypeScript type check -
npm run typecheck - Vitest tests -
npm run test - Production build -
npm run build
Common Web lint failures:
- ESLint errors (unused imports, react-hooks violations)
- Formatting issues (Prettier - use
npm run format:fixto auto-fix) - TypeScript type errors
- Test failures
- Build failures (usually TypeScript errors)
Python (Pundora)
Trigger when changed:
- Any files in
pundora/**/*.py pundora/requirements*.txt
Checks to run:
- Ruff check --fix - Lint with auto-fix
- Ruff format - Format code
- pytest pundora/server - Run tests
- pip-audit (security) -
pip-audit -r pundora/requirements.txt --strict
Common Python lint failures:
- Import order violations (Ruff auto-fixes most)
- Line length violations (Ruff auto-fixes)
- Unused imports (Ruff auto-fixes)
- Security vulnerabilities in dependencies (requires manual dependency updates)
Commit Messages
Always check commit messages for ALL commits being pushed.
Format requirements:
<type>(<scope>): <Summary in sentence case>
Optional body with line length ≤ 72 characters. Body should provide
additional context when the summary alone isn't sufficient.
Valid types: feat, fix, docs, style, refactor, test, chore, ci, perf, build
Valid scopes: api, auth, matrix, pundora, web, infra, k8s, ci, deps, config
Validation rules:
- Header max length: 72 chars (prefer 50 chars)
- Body line max length: 72 chars
- Subject must be sentence-case (capitalize first word only)
- Type and scope must be lowercase
Common commit message failures:
- Header too long (>72 chars) - MOST COMMON ISSUE
- Body lines too long (>72 chars) - wrap text
- Wrong case (e.g., "Fix" instead of "fix", "API" instead of "api")
- Invalid type/scope
- Subject not sentence-case
Examples:
✅ feat(api): Add bridge activation (31 chars)
✅ fix(matrix): Handle rate limiting in sync loop (47 chars)
❌ feat(api): Add comprehensive error handling for bridge activation failures (75 chars) - TOO LONG
❌ Fix(api): Add auth (wrong case - "Fix" should be "fix")
❌ feat(API): Add endpoint (wrong case - "API" should be "api")
Execution Steps
Follow this systematic approach:
0. Validate Current Branch (CRITICAL - Run First!)
🚨 NEVER allow commits or work to proceed on main/master branch!
# Check current branch
git branch --show-current
If on main or master:
-
STOP IMMEDIATELY - Do not proceed with any checks
-
Alert the user - Explain the branch protection policy
-
Guide recovery:
# If no commits yet - just switch branches git checkout -b feature/my-feature # If already committed to main (CRITICAL ERROR) git branch feature/my-feature # Save commits git reset --hard origin/main # Reset main git checkout feature/my-feature # Switch to feature branch -
Branch protection policy:
- ALL development must occur on feature branches
- Commits to main cannot be pushed to remote
- Pre-commit hook blocks commits to main/master
- This is enforced to prevent dead-end commits
Branch naming conventions:
- Feature:
feature/descriptionorname/description - Fix:
fix/description - Example:
ethan/fix-auth,feature/add-bridge
1. Detect Changed Files
# Get the main branch name
MAIN_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main")
# Get changed files since main
git diff --name-only "$MAIN_BRANCH"...HEAD
2. Validate Commit Messages
For ALL commits being pushed (not just the latest commit):
# Get commits being pushed (commits in current branch not in main)
git rev-list "$MAIN_BRANCH"..HEAD
# For each commit, validate with commitlint
git log -1 --format=%B <commit-sha> | npx commitlint
IMPORTANT: Validate the FULL commit message (title + body), not just the title. Many failures come from body line length violations.
🚨 CRITICAL: Check PR Body Line Length Before Pushing
GitHub Actions validates the PR body separately from commits. This is a common source of CI failures:
The problem:
- Commit message validated by pre-push hook ✅
- Push creates PR with auto-populated body from commit
- GitHub Actions validates PR body - may fail even if commit passed!
Prevention:
- Count line lengths BEFORE creating the commit
- Use Python to verify:
echo "text" | python3 -c "import sys; print(max(len(line.rstrip()) for line in sys.stdin))" - ALL body lines must be ≤72 chars (no exceptions!)
If you must amend after pushing:
- Amend the commit with wrapped lines
- Force push:
git push --force-with-lease - Update PR body immediately:
gh api repos/haykay/one-percent-trading-bot/pulls/NNN --method PATCH --field body="$(git log -1 --format=%B)"
Why this happens:
- Pre-push hook validates commits
- GitHub Actions validates PR body (
.github/workflows/commitlint.yml) - Amending commit updates the commit but NOT the PR body
- Must manually update PR body after amending
3. Run Subsystem Checks
Based on changed files detected in step 1, run the appropriate checks:
Go Services (if Go files changed)
# Lint entire codebase
golangci-lint run
# Auto-fix where possible
golangci-lint run --fix
# Run tests with race detection
go test -race -cover ./...
# Build both services
go build -v -o hermelos/hermelos ./hermelos
go build -v -o janomus/janomus ./janomus
# Clean up build artifacts
rm -f hermelos/hermelos janomus/janomus
Web Console (if web/ files changed)
cd web
# Ensure dependencies installed
npm ci
# ESLint
npm run lint
# Prettier format check
npm run format:check
# TypeScript type check
npm run typecheck
# Tests
npm run test
# Production build
npm run build
cd ..
Python (if pundora/ files changed)
# Prefer .venv if exists, otherwise use system ruff
RUFF=".venv/bin/ruff"
if ! [ -x "$RUFF" ]; then
RUFF="ruff"
fi
PY_BIN=".venv/bin/python"
if ! [ -x "$PY_BIN" ]; then
PY_BIN="python"
fi
# Lint and auto-fix
$RUFF check --fix pundora/
# Format
$RUFF format pundora/
# Tests
$PY_BIN -m pytest pundora/server
# Security audit (optional but recommended)
pip-audit -r pundora/requirements.txt --strict
4. Report Results
Provide a clear summary:
Success format:
✅ CI Compliance Check PASSED
Checked subsystems:
✅ Go services: lint, test, build
✅ Commit messages: 3 commits validated
All checks passed! Safe to push.
Failure format:
❌ CI Compliance Check FAILED
Issues found:
❌ Go services (golangci-lint):
- api/handlers/bridges.go:123: Error not checked (errcheck)
- common/synapse/client.go:45: Force type assertion (forcetypeassert)
❌ Commit messages:
- Commit abc1234: Header too long (75 chars, max 72)
"feat(api): Add comprehensive error handling for bridge activation failures"
✅ Web console: All checks passed
Fix these issues before pushing. Some issues may be auto-fixable:
- Run: golangci-lint run --fix
- Rewrite commit message: git rebase -i main (edit the commit)
Auto-Fix Capabilities
When failures are detected, attempt auto-fixes where possible:
Go
- goimports - Auto-fixes import order and grouping
- golangci-lint --fix - Auto-fixes some linters (unused imports, formatting)
- Manual required - Error checks, type assertions
Web
- Prettier -
npm run format:fix(auto-fixes formatting) - ESLint - Some rules auto-fixable with
npm run lint -- --fix - Manual required - Type errors, logic errors, test failures
Python
- Ruff check --fix - Auto-fixes most linting issues (imports, formatting)
- Ruff format - Auto-formats code
- Manual required - Logic errors, test failures, security vulnerabilities
Commit Messages
- No auto-fix - User must rewrite commits
- Suggest solution:
git rebase -i mainto edit commit messages
Error Recovery
When checks fail:
- Identify root cause - Read error messages carefully
- Attempt auto-fix - Run auto-fix commands for the subsystem
- Re-run checks - Verify fixes worked
- Report remaining issues - If manual fixes needed, provide clear guidance
- Never bypass - Do NOT suggest
--no-verifyunless user explicitly requests
Performance Optimization
- Run checks in parallel when possible (Go lint + test + build can run concurrently)
- Skip subsystems that haven't changed (don't run Web checks if only Go changed)
- Cache-friendly - Use
go test -cover(not-coverprofile) to avoid file I/O overhead - Smart commit validation - Only validate commits being pushed, not entire branch history
Integration with Git Hooks
This skill mirrors the .husky/pre-push hook but provides:
- Better reporting - Clearer error messages and guidance
- Interactive fixes - Can apply auto-fixes and re-run checks
- Context awareness - Understands the codebase and common failure patterns
- Educational - Explains WHY checks failed and HOW to fix them
Common Failure Patterns
Pattern 1: Golangci-lint Import Order
Symptom:
File is not goimports-ed with -local github.com/haykay/one-percent-trading-bot
Cause: Imports not grouped correctly (stdlib, external, local)
Fix: Run golangci-lint run --fix or manually reorder imports:
import (
// Standard library
"context"
"fmt"
// External packages
"github.com/stretchr/testify/assert"
// Local packages
"github.com/haykay/one-percent-trading-bot/models"
)
Pattern 2: Commit Header Too Long
Symptom: header-max-length: Header exceeds 72 characters
Cause: Summary too verbose
Fix: Make summary concise, move details to body:
❌ feat(api): Add comprehensive error handling for bridge activation failures
✅ feat(api): Add bridge activation error handling
Add comprehensive error handling for bridge activation failures including
timeout handling, credential validation, and graceful degradation.
Pattern 3: Unchecked Errors
Symptom: Error return value is not checked (errcheck)
Cause: Function returns error but caller ignores it
Fix: Check and handle the error:
❌ client.SendMessage(roomID, text)
✅ if err := client.SendMessage(roomID, text); err != nil {
return fmt.Errorf("failed to send message: %w", err)
}
Pattern 4: Force Type Assertion
Symptom: type assertion must be checked (forcetypeassert)
Cause: Type assertion without ok check
Fix: Use two-value form:
❌ user := value.(*User)
✅ user, ok := value.(*User)
if !ok {
return fmt.Errorf("expected *User, got %T", value)
}
Success Metrics
After running this skill, the user should:
- Have zero CI failures when pushing to GitHub
- Understand WHY their code failed checks
- Know HOW to fix failures (with auto-fix commands provided)
- Have increased confidence in code quality
- Spend less time fixing CI failures in PRs
Skill Invocation Examples
User: "Check if my code is ready to push" → Run full CI compliance check
User: "I'm getting golangci-lint failures" → Run Go-specific checks with detailed error reporting
User: "Fix my commit messages" → Validate commits and suggest rewrites for failures
User: "Run pre-push checks" → Run full CI compliance check
Final Reminders
- ALWAYS validate branch first - Never proceed if on main/master branch
- Never suggest
--no-verify- Bypassing checks leads to CI failures - Auto-fix when possible - Run auto-fix commands before reporting failures
- Be educational - Explain errors, don't just report them
- Check ALL commits - Not just the latest one
- Mirror CI exactly - Use same commands as GitHub Actions workflows
- Enforce branch protection - Block any attempt to commit to main/master