feat(rules): add initial rule files for concerns, languages, and frameworks

Concerns (6 files):
- coding-style.md (163 lines): patterns, anti-patterns, error handling, SOLID
- naming.md (105 lines): naming conventions table per language
- documentation.md (149 lines): docstrings, WHY vs WHAT, README standards
- testing.md (134 lines): AAA pattern, mocking philosophy, TDD
- git-workflow.md (118 lines): conventional commits, branch naming, PR format
- project-structure.md (82 lines): directory layout, entry points, config placement

Languages (4 files):
- python.md (224 lines): uv, ruff, pyright, pytest, pydantic, idioms, anti-patterns
- typescript.md (150 lines): strict mode, discriminated unions, satisfies, as const
- nix.md (129 lines): flake structure, module patterns, alejandra, anti-patterns
- shell.md (100 lines): set -euo pipefail, shellcheck, quoting, POSIX

Frameworks (1 file):
- n8n.md (42 lines): workflow design, node patterns, Error Trigger, security

Context budget: 975 lines (concerns + python) < 1500 limit

Refs: T6-T16 of rules-system plan
This commit is contained in:
m3tm3re
2026-02-17 19:05:45 +01:00
parent d475dde398
commit 8910413315
12 changed files with 1407 additions and 11 deletions

View File

@@ -0,0 +1,163 @@
# Coding Style
## Critical Rules (MUST follow)
Always prioritize readability over cleverness. Never write code that requires mental gymnastics to understand.
Always fail fast and explicitly. Never silently swallow errors or hide exceptions.
Always keep functions under 20 lines. Never create monolithic functions that do multiple things.
Always validate inputs at function boundaries. Never trust external data implicitly.
## Formatting
Prefer consistent indentation throughout the codebase. Never mix tabs and spaces.
Prefer meaningful variable names over short abbreviations. Never use single letters except for loop counters.
### Correct:
```lang
const maxRetryAttempts = 3;
const connectionTimeout = 5000;
for (let attempt = 1; attempt <= maxRetryAttempts; attempt++) {
// process attempt
}
```
### Incorrect:
```lang
const m = 3;
const t = 5000;
for (let i = 1; i <= m; i++) {
// process attempt
}
```
## Patterns and Anti-Patterns
Never repeat yourself. Always extract duplicated logic into reusable functions.
Prefer composition over inheritance. Never create deep inheritance hierarchies.
Always use guard clauses to reduce nesting. Never write arrow-shaped code.
### Correct:
```lang
def process_user(user):
if not user:
return None
if not user.is_active:
return None
return user.calculate_score()
```
### Incorrect:
```lang
def process_user(user):
if user:
if user.is_active:
return user.calculate_score()
else:
return None
else:
return None
```
## Error Handling
Always handle specific exceptions. Never use broad catch-all exception handlers.
Always log error context, not just the error message. Never let errors vanish without trace.
### Correct:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except NetworkError as e:
log_error(f"Network failed for {url}: {e}")
raise
except ParseError as e:
log_error(f"Parse failed for {url}: {e}")
return fallback_data
```
### Incorrect:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except Exception:
pass
```
## Type Safety
Always use type annotations where supported. Never rely on implicit type coercion.
Prefer explicit type checks over duck typing for public APIs. Never assume type behavior.
### Correct:
```lang
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
```
### Incorrect:
```lang
function calculateTotal(price, quantity) {
return price * quantity;
}
```
## Function Design
Always write pure functions when possible. Never mutate arguments unless required.
Always limit function parameters to 3 or fewer. Never pass objects to hide parameter complexity.
### Correct:
```lang
def create_user(name: str, email: str) -> User:
return User(name=name, email=email, created_at=now())
```
### Incorrect:
```lang
def create_user(config: dict) -> User:
return User(
name=config['name'],
email=config['email'],
created_at=config['timestamp']
)
```
## SOLID Principles
Never let classes depend on concrete implementations. Always depend on abstractions.
Always ensure classes are open for extension but closed for modification. Never change working code to add features.
Prefer many small interfaces over one large interface. Never force clients to depend on methods they don't use.
### Correct:
```lang
class EmailSender {
send(message: Message): void {
// implementation
}
}
class NotificationService {
constructor(private sender: EmailSender) {}
}
```
### Incorrect:
```lang
class NotificationService {
sendEmail(message: Message): void { }
sendSMS(message: Message): void { }
sendPush(message: Message): void { }
}
```
## Critical Rules (REPEAT)
Always write self-documenting code. Never rely on comments to explain complex logic.
Always refactor when you see code smells. Never let technical debt accumulate.
Always test edge cases explicitly. Never assume happy path only behavior.
Never commit commented-out code. Always remove it or restore it.

View File

@@ -0,0 +1,149 @@
# Documentation Rules
## When to Document
**Document public APIs**. Every public function, class, method, and module needs documentation. Users need to know how to use your code.
**Document complex logic**. Algorithms, state machines, and non-obvious implementations need explanations. Future readers will thank you.
**Document business rules**. Encode domain knowledge directly in comments. Don't make anyone reverse-engineer requirements from code.
**Document trade-offs**. When you choose between alternatives, explain why. Help future maintainers understand the decision context.
**Do NOT document obvious code**. Comments like `// get user` add noise. Delete them.
## Docstring Formats
### Python (Google Style)
```python
def calculate_price(quantity: int, unit_price: float, discount: float = 0.0) -> float:
"""Calculate total price after discount.
Args:
quantity: Number of items ordered.
unit_price: Price per item in USD.
discount: Decimal discount rate (0.0 to 1.0).
Returns:
Final price in USD.
Raises:
ValueError: If quantity is negative.
"""
```
### JavaScript/TypeScript (JSDoc)
```javascript
/**
* Validates user input against security rules.
* @param {string} input - Raw user input from form.
* @param {Object} rules - Validation constraints.
* @param {number} rules.maxLength - Maximum allowed length.
* @returns {boolean} True if input passes all rules.
* @throws {ValidationError} If input violates security constraints.
*/
function validateInput(input, rules) {
```
### Bash
```bash
#!/usr/bin/env bash
# Deploy application to production environment.
#
# Usage: ./deploy.sh [environment]
#
# Args:
# environment: Target environment (staging|production). Default: staging.
#
# Exits:
# 0 on success, 1 on deployment failure.
```
## Inline Comments: WHY Not WHAT
**Incorrect:**
```python
# Iterate through all users
for user in users:
# Check if user is active
if user.active:
# Increment counter
count += 1
```
**Correct:**
```python
# Count only active users to calculate monthly revenue
for user in users:
if user.active:
count += 1
```
**Incorrect:**
```javascript
// Set timeout to 5000
setTimeout(() => {
// Show error message
alert('Error');
}, 5000);
```
**Correct:**
```javascript
// 5000ms delay prevents duplicate alerts during rapid retries
setTimeout(() => {
alert('Error');
}, 5000);
```
**Incorrect:**
```bash
# Remove temporary files
rm -rf /tmp/app/*
```
**Correct:**
```bash
# Clear temp directory before batch import to prevent partial state
rm -rf /tmp/app/*
```
**Rule:** Describe the intent and context. Never describe what the code obviously does.
## README Standards
Every project needs a README at the top level.
**Required sections:**
1. **What it does** - One sentence summary
2. **Installation** - Setup commands
3. **Usage** - Basic example
4. **Configuration** - Environment variables and settings
5. **Contributing** - How to contribute
**Example structure:**
```markdown
# Project Name
One-line description of what this project does.
## Installation
```bash
npm install
```
## Usage
```bash
npm start
```
## Configuration
Create `.env` file:
```
API_KEY=your_key_here
```
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
```
**Keep READMEs focused**. Link to separate docs for complex topics. Don't make the README a tutorial.

View File

@@ -0,0 +1,118 @@
# Git Workflow Rules
## Conventional Commits
Format: `<type>(<scope>): <subject>`
### Commit Types
- **feat**: New feature
- `feat(auth): add OAuth2 login flow`
- `feat(api): expose user endpoints`
- **fix**: Bug fix
- `fix(payment): resolve timeout on Stripe calls`
- `fix(ui): button not clickable on mobile`
- **refactor**: Code refactoring (no behavior change)
- `refactor(utils): extract date helpers`
- `refactor(api): simplify error handling`
- **docs**: Documentation only
- `docs(readme): update installation steps`
- `docs(api): add endpoint examples`
- **chore**: Maintenance tasks
- `chore(deps): update Node to 20`
- `chore(ci): add GitHub actions workflow`
- **test**: Tests only
- `test(auth): add unit tests for login`
- `test(e2e): add checkout flow tests`
- **style**: Formatting, no logic change
- `style: sort imports alphabetically`
### Commit Rules
- Subject max 72 chars
- Imperative mood ("add", not "added")
- No period at end
- Reference issues: `Closes #123`
## Branch Naming
Pattern: `<type>/<short-description>`
### Branch Types
- `feature/add-user-dashboard`
- `feature/enable-dark-mode`
- `fix/login-redirect-loop`
- `fix/payment-timeout-error`
- `refactor/extract-user-service`
- `refactor/simplify-auth-flow`
- `hotfix/security-vulnerability`
### Branch Rules
- Lowercase and hyphens
- Max 50 chars
- Delete after merge
## Pull Requests
### PR Title
Follow Conventional Commit format:
- `feat: add user dashboard`
- `fix: resolve login redirect loop`
### PR Description
```markdown
## What
Brief description
## Why
Reason for change
## How
Implementation approach
## Testing
Steps performed
## Checklist
- [ ] Tests pass
- [ ] Code reviewed
- [ ] Docs updated
```
## Merge Strategy
### Squash Merge
- Many small commits
- One cohesive feature
- Clean history
### Merge Commit
- Preserve commit history
- Distinct milestones
- Detailed history preferred
### When to Rebase
- Before opening PR
- Resolving conflicts
- Keeping current with main
## General Rules
- Pull latest from main before starting
- Write atomic commits
- Run tests before pushing
- Request peer review before merge
- Never force push to main/master

105
rules/concerns/naming.md Normal file
View File

@@ -0,0 +1,105 @@
# Naming Conventions
Use consistent naming across all code. Follow language-specific conventions.
## Language Reference
| Type | Python | TypeScript | Nix | Shell |
|------|--------|------------|-----|-------|
| Variables | snake_case | camelCase | camelCase | UPPER_SNAKE |
| Functions | snake_case | camelCase | camelCase | lower_case |
| Classes | PascalCase | PascalCase | - | - |
| Constants | UPPER_SNAKE | UPPER_SNAKE | camelCase | UPPER_SNAKE |
| Files | snake_case | camelCase | hyphen-case | hyphen-case |
| Modules | snake_case | camelCase | - | - |
## General Rules
**Files**: Use hyphen-case for documentation, snake_case for Python, camelCase for TypeScript. Names should describe content.
**Variables**: Use descriptive names. Avoid single letters except loop counters. No Hungarian notation.
**Functions**: Use verb-noun pattern. Name describes what it does, not how it does it.
**Classes**: Use PascalCase with descriptive nouns. Avoid abbreviations.
**Constants**: Use UPPER_SNAKE with descriptive names. Group related constants.
## Examples
Python:
```python
# Variables
user_name = "alice"
is_authenticated = True
# Functions
def get_user_data(user_id):
pass
# Classes
class UserProfile:
pass
# Constants
MAX_RETRIES = 3
API_ENDPOINT = "https://api.example.com"
```
TypeScript:
```typescript
// Variables
const userName = "alice";
const isAuthenticated = true;
// Functions
function getUserData(userId: string): User {
return null;
}
// Classes
class UserProfile {
private name: string;
}
// Constants
const MAX_RETRIES = 3;
const API_ENDPOINT = "https://api.example.com";
```
Nix:
```nix
# Variables
let
userName = "alice";
isAuthenticated = true;
in
# ...
```
Shell:
```bash
# Variables
USER_NAME="alice"
IS_AUTHENTICATED=true
# Functions
get_user_data() {
echo "Getting data"
}
# Constants
MAX_RETRIES=3
API_ENDPOINT="https://api.example.com"
```
## File Naming
Use these patterns consistently. No exceptions.
- Skills: `hyphen-case`
- Python: `snake_case.py`
- TypeScript: `camelCase.ts` or `hyphen-case.ts`
- Nix: `hyphen-case.nix`
- Shell: `hyphen-case.sh`
- Markdown: `UPPERCASE.md` or `sentence-case.md`

View File

@@ -0,0 +1,82 @@
# Project Structure
## Python
Use src layout for all projects. Place application code in `src/<project>/`, tests in `tests/`.
```
project/
├── src/myproject/
│ ├── __init__.py
│ ├── main.py # Entry point
│ └── core/
│ └── module.py
├── tests/
│ ├── __init__.py
│ └── test_module.py
├── pyproject.toml # Config
├── README.md
└── .gitignore
```
**Rules:**
- One module per directory file
- `__init__.py` in every package
- Entry point in `src/myproject/main.py`
- Config in root: `pyproject.toml`, `requirements.txt`
## TypeScript
Use `src/` for source, `dist/` for build output.
```
project/
├── src/
│ ├── index.ts # Entry point
│ ├── core/
│ │ └── module.ts
│ └── types.ts
├── tests/
│ └── module.test.ts
├── package.json # Config
├── tsconfig.json
└── README.md
```
**Rules:**
- One module per file
- Index exports from `src/index.ts`
- Entry point in `src/index.ts`
- Config in root: `package.json`, `tsconfig.json`
## Nix
Use `modules/` for NixOS modules, `pkgs/` for packages.
```
nix-config/
├── modules/
│ ├── default.nix # Module list
│ └── my-service.nix
├── pkgs/
│ └── my-package/
│ └── default.nix
├── flake.nix # Entry point
├── flake.lock
└── README.md
```
**Rules:**
- One module per file in `modules/`
- One package per directory in `pkgs/`
- Entry point in `flake.nix`
- Config in root: `flake.nix`, shell.nix
## General
- Use hyphen-case for directories
- Use kebab-case for file names
- Config files in project root
- Tests separate from source
- Docs in root: README.md, CHANGELOG.md
- Hidden configs: .env, .gitignore

134
rules/concerns/testing.md Normal file
View File

@@ -0,0 +1,134 @@
# Testing Rules
## Arrange-Act-Assert Pattern
Structure every test in three distinct phases:
```python
# Arrange: Set up the test data and conditions
user = User(name="Alice", role="admin")
session = create_test_session(user.id)
# Act: Execute the behavior under test
result = grant_permission(session, "read_documents")
# Assert: Verify the expected outcome
assert result.granted is True
assert result.permissions == ["read_documents"]
```
Never mix phases. Comment each phase clearly for complex setups. Keep Act phase to one line if possible.
## Behavior vs Implementation Testing
Test behavior, not implementation details:
```python
# GOOD: Tests the observable behavior
def test_user_can_login():
response = login("alice@example.com", "password123")
assert response.status_code == 200
assert "session_token" in response.cookies
# BAD: Tests internal implementation
def test_login_sets_database_flag():
login("alice@example.com", "password123")
user = User.get(email="alice@example.com")
assert user._logged_in_flag is True # Private field
```
Focus on inputs and outputs. Test public contracts. Refactor internals freely without breaking tests.
## Mocking Philosophy
Mock external dependencies, not internal code:
```python
# GOOD: Mock external services
@patch("requests.post")
def test_sends_notification_to_slack(mock_post):
send_notification("Build complete!")
mock_post.assert_called_once_with(
"https://slack.com/api/chat.postMessage",
json={"text": "Build complete!"}
)
# BAD: Mock internal methods
@patch("NotificationService._format_message")
def test_notification_formatting(mock_format):
# Don't mock private methods
send_notification("Build complete!")
```
Mock when:
- Dependency is slow (database, network, file system)
- Dependency is unreliable (external APIs)
- Dependency is expensive (third-party services)
Don't mock when:
- Testing the dependency itself
- The dependency is fast and stable
- The mock becomes more complex than real implementation
## Coverage Expectations
Write tests for:
- Critical business logic (aim for 90%+)
- Edge cases and error paths (aim for 80%+)
- Public APIs and contracts (aim for 100%)
Don't obsess over:
- Trivial getters/setters
- Generated code
- One-line wrappers
Coverage is a floor, not a ceiling. A test suite at 100% coverage that doesn't verify behavior is worthless.
## Test-Driven Development
Follow the red-green-refactor cycle:
1. Red: Write failing test for new behavior
2. Green: Write minimum code to pass
3. Refactor: improve code while tests stay green
Write tests first for new features. Write tests after for bug fixes. Never refactor without tests.
## Test Organization
Group tests by feature or behavior, not by file structure. Name tests to describe the scenario:
```python
class TestUserAuthentication:
def test_valid_credentials_succeeds(self):
pass
def test_invalid_credentials_fails(self):
pass
def test_locked_account_fails(self):
pass
```
Each test should stand alone. Avoid shared state between tests. Use fixtures or setup methods to reduce duplication.
## Test Data
Use realistic test data that reflects production scenarios:
```python
# GOOD: Realistic values
user = User(
email="alice@example.com",
name="Alice Smith",
age=28
)
# BAD: Placeholder values
user = User(
email="test@test.com",
name="Test User",
age=999
)
```
Avoid magic strings and numbers. Use named constants for expected values that change often.