docs: add AGENTS.python/go/typescript.md and pre-push check rules
Some checks failed
CI / go-lint (push) Has been cancelled
CI / python-lint (push) Has been cancelled
CI / nodejs-lint (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
Some checks failed
CI / go-lint (push) Has been cancelled
CI / python-lint (push) Has been cancelled
CI / nodejs-lint (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
Mandatory pre-push gates for all three language stacks with exact commands, common pitfalls, and architecture rules. CLAUDE.md updated with quick-reference section linking to the new files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
227
.claude/AGENTS.go.md
Normal file
227
.claude/AGENTS.go.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# AGENTS.go.md — Go Agent Rules
|
||||
|
||||
Applies to: `ai-compliance-sdk/` (Go/Gin service)
|
||||
|
||||
---
|
||||
|
||||
## NON-NEGOTIABLE: Pre-Push Checklist
|
||||
|
||||
**BEFORE every `git push`, run ALL of the following from the module root. A single failure blocks the push.**
|
||||
|
||||
```bash
|
||||
# 1. Format (gofmt is non-negotiable — unformatted code fails CI)
|
||||
gofmt -l . | grep -q . && echo "FORMATTING ERRORS — run: gofmt -w ." && exit 1 || true
|
||||
|
||||
# 2. Vet (catches suspicious code that compiles but is likely wrong)
|
||||
go vet ./...
|
||||
|
||||
# 3. Lint (golangci-lint aggregates 50+ linters — the de-facto standard)
|
||||
golangci-lint run --timeout=5m ./...
|
||||
|
||||
# 4. Tests with race detector
|
||||
go test -race -count=1 ./...
|
||||
|
||||
# 5. Build verification (catches import errors, missing implementations)
|
||||
go build ./...
|
||||
```
|
||||
|
||||
**One-liner pre-push gate:**
|
||||
```bash
|
||||
gofmt -l . | grep -q . && exit 1; go vet ./... && golangci-lint run --timeout=5m && go test -race -count=1 ./... && go build ./...
|
||||
```
|
||||
|
||||
### Why each check matters
|
||||
|
||||
| Check | Catches | Time |
|
||||
|-------|---------|------|
|
||||
| `gofmt` | Formatting violations (CI rejects unformatted code) | <1s |
|
||||
| `go vet` | Printf format mismatches, unreachable code, shadowed vars | <5s |
|
||||
| `golangci-lint` | 50+ static analysis checks (errcheck, staticcheck, etc.) | 10-30s |
|
||||
| `go test -race` | Race conditions (invisible without this flag) | 10-60s |
|
||||
| `go build` | Import errors, interface mismatches | <5s |
|
||||
|
||||
---
|
||||
|
||||
## golangci-lint Configuration
|
||||
|
||||
Config lives in `.golangci.yml` at the repo root. Minimum required linters:
|
||||
|
||||
```yaml
|
||||
linters:
|
||||
enable:
|
||||
- errcheck # unchecked errors are bugs
|
||||
- gosimple # code simplification
|
||||
- govet # go vet findings
|
||||
- ineffassign # useless assignments
|
||||
- staticcheck # advanced static analysis (SA*, S*, QF*)
|
||||
- unused # unused code
|
||||
- gofmt # formatting
|
||||
- goimports # import organization
|
||||
- gocritic # opinionated style checks
|
||||
- noctx # HTTP requests without context
|
||||
- bodyclose # unclosed HTTP response bodies
|
||||
- exhaustive # exhaustive switch on enums
|
||||
- wrapcheck # errors from external packages must be wrapped
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
check-blank: true # blank identifier for errors is a bug
|
||||
govet:
|
||||
enable-all: true
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
```
|
||||
|
||||
**Never suppress with `//nolint:` without a comment explaining why it's safe.**
|
||||
|
||||
---
|
||||
|
||||
## Code Structure (Hexagonal Architecture)
|
||||
|
||||
```
|
||||
ai-compliance-sdk/
|
||||
├── cmd/
|
||||
│ └── server/main.go # thin: parse flags, wire deps, call app.Run()
|
||||
├── internal/
|
||||
│ ├── app/ # dependency wiring
|
||||
│ ├── domain/ # pure business logic, no framework deps
|
||||
│ ├── ports/ # interfaces (repositories, external services)
|
||||
│ ├── adapters/
|
||||
│ │ ├── http/ # Gin handlers (≤30 LOC per handler)
|
||||
│ │ ├── postgres/ # DB adapters implementing ports
|
||||
│ │ └── external/ # third-party API clients
|
||||
│ └── services/ # orchestration between domain + ports
|
||||
└── pkg/ # exported, reusable packages
|
||||
```
|
||||
|
||||
**Handler constraint — max 30 lines per handler:**
|
||||
```go
|
||||
func (h *RiskHandler) GetRisk(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
risk, err := h.service.Get(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
h.handleError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, risk)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
```go
|
||||
// REQUIRED: wrap errors with context
|
||||
if err != nil {
|
||||
return fmt.Errorf("get risk %s: %w", id, err)
|
||||
}
|
||||
|
||||
// REQUIRED: define sentinel errors in domain package
|
||||
var ErrNotFound = errors.New("not found")
|
||||
var ErrUnauthorized = errors.New("unauthorized")
|
||||
|
||||
// REQUIRED: check errors — never use _ for error returns
|
||||
result, err := service.Do(ctx, input)
|
||||
if err != nil {
|
||||
// handle it
|
||||
}
|
||||
```
|
||||
|
||||
**`errcheck` linter enforces this — zero tolerance for unchecked errors.**
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
```
|
||||
internal/
|
||||
├── domain/
|
||||
│ ├── risk.go
|
||||
│ └── risk_test.go # unit: pure functions, no I/O
|
||||
├── adapters/
|
||||
│ ├── http/
|
||||
│ │ ├── handler.go
|
||||
│ │ └── handler_test.go # httptest-based, mock service
|
||||
│ └── postgres/
|
||||
│ ├── repo.go
|
||||
│ └── repo_test.go # integration: testcontainers or real DB
|
||||
```
|
||||
|
||||
**Test naming convention:**
|
||||
```go
|
||||
func TestRiskService_Get_ReturnsRisk(t *testing.T) {}
|
||||
func TestRiskService_Get_NotFound_ReturnsError(t *testing.T) {}
|
||||
func TestRiskService_Get_DBError_WrapsError(t *testing.T) {}
|
||||
```
|
||||
|
||||
**Table-driven tests are mandatory for functions with multiple cases:**
|
||||
```go
|
||||
func TestValidateInput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid", "ok", false},
|
||||
{"empty", "", true},
|
||||
{"too long", strings.Repeat("x", 300), true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateInput(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Pre-push: unit tests only (fast)
|
||||
go test -race -count=1 -run "^TestUnit" ./...
|
||||
|
||||
# CI: all tests
|
||||
go test -race -count=1 -coverprofile=coverage.out ./...
|
||||
go tool cover -func=coverage.out | grep total
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Context Propagation
|
||||
|
||||
Every function that does I/O (DB, HTTP, file) **must** accept and pass `context.Context` as the first argument:
|
||||
|
||||
```go
|
||||
// REQUIRED
|
||||
func (r *RiskRepo) Get(ctx context.Context, id uuid.UUID) (*Risk, error) {
|
||||
return r.db.QueryRowContext(ctx, query, id).Scan(...)
|
||||
}
|
||||
|
||||
// FORBIDDEN — no context
|
||||
func (r *RiskRepo) Get(id uuid.UUID) (*Risk, error) { ... }
|
||||
```
|
||||
|
||||
`noctx` linter enforces HTTP client context. Manual review required for DB calls.
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls That Break CI
|
||||
|
||||
| Pitfall | Prevention |
|
||||
|---------|------------|
|
||||
| Unformatted code | `gofmt -w .` before commit |
|
||||
| Unchecked error return from `rows.Close()` / `resp.Body.Close()` | `errcheck` + `bodyclose` linters |
|
||||
| Goroutine leak (goroutine started but never stopped) | `-race` test flag |
|
||||
| Shadowed `err` variable in nested scope | `govet -shadow` |
|
||||
| HTTP response body not closed | `bodyclose` linter |
|
||||
| `interface{}` instead of `any` (Go 1.18+) | `gocritic` |
|
||||
| Missing context on DB/HTTP calls | `noctx` linter |
|
||||
| Returning concrete type from constructor instead of interface | breaks testability |
|
||||
157
.claude/AGENTS.python.md
Normal file
157
.claude/AGENTS.python.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# AGENTS.python.md — Python Agent Rules
|
||||
|
||||
Applies to: `backend-compliance/`, `ai-compliance-sdk/` (Python path), `compliance-tts-service/`, `document-crawler/`, `dsms-gateway/` (Python services)
|
||||
|
||||
---
|
||||
|
||||
## NON-NEGOTIABLE: Pre-Push Checklist
|
||||
|
||||
**BEFORE every `git push`, run ALL of the following from the service directory. A single failure blocks the push.**
|
||||
|
||||
```bash
|
||||
# 1. Fast lint (Ruff — catches syntax errors, unused imports, style violations)
|
||||
ruff check .
|
||||
|
||||
# 2. Auto-fix safe issues, then re-check
|
||||
ruff check --fix . && ruff check .
|
||||
|
||||
# 3. Type checking (mypy strict on new modules, standard on legacy)
|
||||
mypy . --ignore-missing-imports --no-error-summary
|
||||
|
||||
# 4. Unit tests only (fast, no external deps)
|
||||
pytest tests/unit/ -x -q --no-header
|
||||
|
||||
# 5. Verify the service starts (catches import errors, missing env vars with defaults)
|
||||
python -c "import app" 2>/dev/null || python -c "import main" 2>/dev/null || true
|
||||
```
|
||||
|
||||
**One-liner pre-push gate (run from service root):**
|
||||
```bash
|
||||
ruff check . && mypy . --ignore-missing-imports --no-error-summary && pytest tests/ -x -q --no-header
|
||||
```
|
||||
|
||||
### Why each check matters
|
||||
|
||||
| Check | Catches | Time |
|
||||
|-------|---------|------|
|
||||
| `ruff check` | Syntax errors, unused imports, undefined names | <2s |
|
||||
| `mypy` | Type mismatches, wrong argument types | 5-15s |
|
||||
| `pytest -x` | Logic errors, regressions | 10-60s |
|
||||
| import check | Missing packages, circular imports | <1s |
|
||||
|
||||
---
|
||||
|
||||
## Code Style (Ruff)
|
||||
|
||||
Config lives in `pyproject.toml`. Do **not** add per-file `# noqa` suppressions without a comment explaining why.
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "W", "I", "N", "UP", "B", "C4", "SIM", "TCH"]
|
||||
ignore = ["E501"] # line length handled by formatter
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*" = ["S101"] # assert is fine in tests
|
||||
```
|
||||
|
||||
**Blocked patterns:**
|
||||
- `from module import *` — always name imports explicitly
|
||||
- Bare `except:` — use `except Exception as e:` at minimum
|
||||
- `print()` in production code — use `logger`
|
||||
- Mutable default arguments: `def f(x=[])` → `def f(x=None)`
|
||||
|
||||
---
|
||||
|
||||
## Type Annotations
|
||||
|
||||
All new functions **must** have complete type annotations. Use `from __future__ import annotations` for forward references.
|
||||
|
||||
```python
|
||||
# Required
|
||||
async def get_tenant(tenant_id: str, db: AsyncSession) -> TenantModel | None:
|
||||
...
|
||||
|
||||
# Required for complex types
|
||||
from typing import Sequence
|
||||
def list_risks(filters: dict[str, str]) -> Sequence[RiskModel]:
|
||||
...
|
||||
```
|
||||
|
||||
**Mypy rules:**
|
||||
- `--disallow-untyped-defs` on new files
|
||||
- `--strict` on new modules (not legacy)
|
||||
- Never use `type: ignore` without a comment
|
||||
|
||||
---
|
||||
|
||||
## FastAPI-Specific Rules
|
||||
|
||||
```python
|
||||
# Handlers stay thin — delegate to service layer
|
||||
@router.get("/risks/{risk_id}", response_model=RiskResponse)
|
||||
async def get_risk(risk_id: UUID, service: RiskService = Depends(get_risk_service)):
|
||||
return await service.get(risk_id) # ≤5 lines per handler
|
||||
|
||||
# Always use response_model — never return raw dicts from endpoints
|
||||
# Always validate input with Pydantic — no manual dict parsing
|
||||
# Use HTTPException with specific status codes, never bare 500
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
```
|
||||
tests/
|
||||
├── unit/ # Pure logic tests, no DB/HTTP (run on every push)
|
||||
├── integration/ # Requires running services (run in CI only)
|
||||
└── contracts/ # OpenAPI snapshot tests (run on API changes)
|
||||
```
|
||||
|
||||
**Unit test requirements:**
|
||||
- Every new function → at least one happy-path test
|
||||
- Every bug fix → regression test that would have caught it
|
||||
- Mock all I/O: DB calls, HTTP calls, filesystem reads
|
||||
|
||||
```bash
|
||||
# Run unit tests only (fast, for pre-push)
|
||||
pytest tests/unit/ -x -q
|
||||
|
||||
# Run with coverage (for CI)
|
||||
pytest tests/ --cov=. --cov-report=term-missing --cov-fail-under=70
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Management
|
||||
|
||||
```bash
|
||||
# Check new package license before adding
|
||||
pip show <package> | grep -E "License|Home-page"
|
||||
|
||||
# After adding to requirements.txt — verify no GPL/AGPL
|
||||
pip-licenses --fail-on="GPL;AGPL" 2>/dev/null || echo "Check licenses manually"
|
||||
```
|
||||
|
||||
**Never add:**
|
||||
- GPL/AGPL licensed packages
|
||||
- Packages with known CVEs (`pip audit`)
|
||||
- Packages that only exist for dev (`pytest`, `ruff`) to production requirements
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls That Break CI
|
||||
|
||||
| Pitfall | Prevention |
|
||||
|---------|------------|
|
||||
| `const x = ...` inside dict literal (wrong language!) | Run ruff before push |
|
||||
| Pydantic v1 syntax in v2 project | Use `model_config`, not `class Config` |
|
||||
| Sync function called inside async without `run_in_executor` | mypy + async linter |
|
||||
| Missing `await` on coroutine | mypy catches this |
|
||||
| `datetime.utcnow()` (deprecated) | Use `datetime.now(timezone.utc)` |
|
||||
| Bare `except:` swallowing errors silently | ruff B001/E722 catches this |
|
||||
| Unused imports left in committed code | ruff F401 catches this |
|
||||
186
.claude/AGENTS.typescript.md
Normal file
186
.claude/AGENTS.typescript.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# AGENTS.typescript.md — TypeScript/Next.js Agent Rules
|
||||
|
||||
Applies to: `pitch-deck/`, `admin-v2/` (Next.js apps in this repo)
|
||||
|
||||
---
|
||||
|
||||
## NON-NEGOTIABLE: Pre-Push Checklist
|
||||
|
||||
**BEFORE every `git push`, run ALL of the following from the Next.js app directory. A single failure blocks the push.**
|
||||
|
||||
```bash
|
||||
# 1. Type check (catches the class of bug that broke ChatFAB.tsx — const inside object)
|
||||
npx tsc --noEmit
|
||||
|
||||
# 2. Lint (ESLint with TypeScript-aware rules)
|
||||
npm run lint
|
||||
|
||||
# 3. Production build (THE most important check — passes lint/types but still fails build)
|
||||
npm run build
|
||||
```
|
||||
|
||||
**One-liner pre-push gate:**
|
||||
```bash
|
||||
npx tsc --noEmit && npm run lint && npm run build
|
||||
```
|
||||
|
||||
> **Why `npm run build` is mandatory:** Next.js performs additional checks during build (server component boundaries, missing env vars referenced in code, RSC/client component violations) that `tsc` and ESLint alone do not catch. The ChatFAB syntax error (`const` inside object literal) is exactly the kind of error caught only by build.
|
||||
|
||||
### Why each check matters
|
||||
|
||||
| Check | Catches | Time |
|
||||
|-------|---------|------|
|
||||
| `tsc --noEmit` | Type errors, wrong prop types, missing members | 5-20s |
|
||||
| `eslint` | React hooks rules, import order, unused vars | 5-15s |
|
||||
| `next build` | Server/client boundary violations, missing deps, syntax errors in JSX, env var issues | 30-120s |
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Configuration
|
||||
|
||||
`tsconfig.json` must have strict mode enabled:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Never use `// @ts-ignore` or `// @ts-expect-error` without a comment explaining why it's unavoidable.**
|
||||
|
||||
---
|
||||
|
||||
## ESLint Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"plugin:@typescript-eslint/recommended-type-checked"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"react-hooks/exhaustive-deps": "error",
|
||||
"no-console": "warn"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`@typescript-eslint/no-floating-promises`** — catches `await`-less async calls that silently swallow errors.
|
||||
**`react-hooks/exhaustive-deps`** — catches missing deps in `useEffect`/`useCallback` (source of stale closure bugs).
|
||||
|
||||
---
|
||||
|
||||
## Next.js 15 Rules (App Router)
|
||||
|
||||
### Server vs Client boundary
|
||||
|
||||
```typescript
|
||||
// Server Component (default) — no 'use client' needed
|
||||
// Can: fetch data, access DB, read env vars, import server-only packages
|
||||
async function Page() {
|
||||
const data = await fetchData() // direct async/await
|
||||
return <ClientComponent data={data} />
|
||||
}
|
||||
|
||||
// Client Component — must have 'use client' at top
|
||||
'use client'
|
||||
// Can: use hooks, handle events, access browser APIs
|
||||
// Cannot: import server-only packages (nodemailer, fs, db pool)
|
||||
```
|
||||
|
||||
**Common violation:** Importing `lib/email.ts` (which imports nodemailer) from a client component → use `lib/email-templates.ts` instead.
|
||||
|
||||
### Route Handler typing
|
||||
|
||||
```typescript
|
||||
// Always type request and use NextResponse
|
||||
export async function GET(request: Request): Promise<NextResponse> {
|
||||
const { searchParams } = new URL(request.url)
|
||||
return NextResponse.json({ data })
|
||||
}
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
```typescript
|
||||
// Server-only env vars: access directly
|
||||
const secret = process.env.PITCH_ADMIN_SECRET // fine in server components
|
||||
|
||||
// Client env vars: must be prefixed NEXT_PUBLIC_
|
||||
const url = process.env.NEXT_PUBLIC_API_URL // accessible in browser
|
||||
|
||||
// Never access server-only env vars in 'use client' components
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Architecture
|
||||
|
||||
```
|
||||
app/
|
||||
├── (route-group)/
|
||||
│ ├── page.tsx # Server Component — data fetching
|
||||
│ └── _components/ # Colocated components for this route
|
||||
│ ├── ClientThing.tsx # 'use client' when needed
|
||||
│ └── ServerThing.tsx # Server by default
|
||||
components/
|
||||
│ └── ui/ # Shared presentational components
|
||||
lib/
|
||||
│ ├── server-only-module.ts # import 'server-only' at top
|
||||
│ └── shared-module.ts # safe for both server and client
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- Push `'use client'` boundary as deep as possible (toward leaves)
|
||||
- Never import server-only modules from client components
|
||||
- Colocate `_components/` and `_hooks/` per route when they're route-specific
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
```bash
|
||||
# Type check (fastest, run first)
|
||||
npx tsc --noEmit
|
||||
|
||||
# Unit tests (Vitest)
|
||||
npx vitest run
|
||||
|
||||
# E2E tests (Playwright — CI only, requires running server)
|
||||
npx playwright test
|
||||
```
|
||||
|
||||
**Test every:**
|
||||
- Custom hook (`usePresenterMode`, `useSlideNavigation`)
|
||||
- Utility function (`lib/auth.ts` helpers, `lib/email-templates.ts`)
|
||||
- API route handler (mock DB, assert response shape)
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls That Break CI
|
||||
|
||||
| Pitfall | Prevention |
|
||||
|---------|------------|
|
||||
| `const x = ...` inside object literal | `tsc --noEmit` + `npm run build` |
|
||||
| Server-only import in client component | `import 'server-only'` guard + ESLint |
|
||||
| Missing `await` on async function call | `@typescript-eslint/no-floating-promises` |
|
||||
| `useEffect` with missing dependency | `react-hooks/exhaustive-deps` error |
|
||||
| `any` type hiding type errors | `@typescript-eslint/no-explicit-any` error |
|
||||
| Unused variable left after refactor | `noUnusedLocals` in tsconfig |
|
||||
| `process.env.SECRET` in client component | Next.js build error |
|
||||
| Forgetting `export default` on page component | Next.js build error |
|
||||
| Calling server action from server component | must use route handler instead |
|
||||
| `jose` full import in Edge Runtime | Use specific subpath: `jose/jwt/verify` |
|
||||
@@ -287,6 +287,37 @@ git push origin main && git push gitea main
|
||||
|
||||
---
|
||||
|
||||
## Pre-Push Checks (PFLICHT — VOR JEDEM PUSH)
|
||||
|
||||
> Full detail: `.claude/rules/pre-push-checks.md` | Stack rules: `AGENTS.python.md`, `AGENTS.go.md`, `AGENTS.typescript.md`
|
||||
|
||||
**NIEMALS pushen ohne diese Checks. CI-Failures blockieren das gesamte Deploy.**
|
||||
|
||||
### Python (backend-core, rag-service, embedding-service, control-pipeline)
|
||||
|
||||
```bash
|
||||
cd <service-dir>
|
||||
ruff check . && mypy . --ignore-missing-imports --no-error-summary && pytest tests/ -x -q --no-header
|
||||
```
|
||||
|
||||
### Go (consent-service, billing-service)
|
||||
|
||||
```bash
|
||||
cd <service-dir>
|
||||
gofmt -l . | grep -q . && exit 1; go vet ./... && golangci-lint run --timeout=5m && go test -race ./... && go build ./...
|
||||
```
|
||||
|
||||
### TypeScript/Next.js (pitch-deck, admin-v2)
|
||||
|
||||
```bash
|
||||
cd pitch-deck # or admin-v2
|
||||
npx tsc --noEmit && npm run lint && npm run build
|
||||
```
|
||||
|
||||
> `npm run build` ist PFLICHT — `tsc` allein reicht nicht. Syntax-Fehler wie `const` inside object literal werden nur vom Build gefangen.
|
||||
|
||||
---
|
||||
|
||||
## Kernprinzipien
|
||||
|
||||
### 1. Open Source Policy
|
||||
|
||||
74
.claude/rules/pre-push-checks.md
Normal file
74
.claude/rules/pre-push-checks.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Pre-Push Checks (MANDATORY)
|
||||
|
||||
## Rule
|
||||
|
||||
**NEVER push to any remote without first running and confirming ALL checks pass for every changed language stack.**
|
||||
|
||||
This rule exists because CI failures break the deploy pipeline for everyone and waste ~5 minutes per failed build. A 60-second local check prevents that.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference by Stack
|
||||
|
||||
### Python (backend-compliance, ai-compliance-sdk, compliance-tts-service)
|
||||
|
||||
```bash
|
||||
cd <service-dir>
|
||||
ruff check . && mypy . --ignore-missing-imports --no-error-summary && pytest tests/ -x -q --no-header
|
||||
```
|
||||
|
||||
Blocks on: syntax errors, type errors, failing tests.
|
||||
|
||||
### Go (ai-compliance-sdk Go path)
|
||||
|
||||
```bash
|
||||
cd <service-dir>
|
||||
gofmt -l . | grep -q . && exit 1; go vet ./... && golangci-lint run --timeout=5m && go test -race ./... && go build ./...
|
||||
```
|
||||
|
||||
Blocks on: formatting, vet findings, lint violations, test failures, build errors.
|
||||
|
||||
### TypeScript/Next.js (admin-compliance, developer-portal)
|
||||
|
||||
```bash
|
||||
cd <nextjs-app-dir>
|
||||
npx tsc --noEmit && npm run lint && npm run build
|
||||
```
|
||||
|
||||
Blocks on: type errors, lint violations, **build failures**.
|
||||
|
||||
> `npm run build` is mandatory — `tsc` passes but `next build` fails more often than you'd expect (server/client boundary violations, env var issues, JSX syntax errors).
|
||||
|
||||
---
|
||||
|
||||
## What Claude Must Do Before Every Push
|
||||
|
||||
1. Identify which services/apps were changed in this task
|
||||
2. Run the appropriate gate command(s) from the table above
|
||||
3. If any check fails: fix it, re-run, confirm green
|
||||
4. Only then run `git push origin main`
|
||||
|
||||
**No exceptions.** A push that skips pre-push checks and breaks CI is worse than a delayed push.
|
||||
|
||||
---
|
||||
|
||||
## CI vs Local Checks
|
||||
|
||||
| Stage | Where | What |
|
||||
|-------|-------|------|
|
||||
| Pre-push (local) | Claude runs | Lint + type check + unit tests + build |
|
||||
| CI (Gitea Actions) | Automatic on push | Same + integration tests + contract tests |
|
||||
| Deploy (Coolify) | Automatic after CI | Docker build + health check |
|
||||
|
||||
Local checks catch 90% of CI failures in seconds. CI is the safety net, not the first line of defense.
|
||||
|
||||
---
|
||||
|
||||
## Failures That Were Caused by Skipping Pre-Push Checks
|
||||
|
||||
- `ChatFAB.tsx`: `const textLang` inside fetch object literal — caught by `tsc --noEmit` and `npm run build`
|
||||
- `nodemailer` webpack error: server-only import in client component — caught by `npm run build`
|
||||
- `jose` Edge Runtime error: full package import — caught by `npm run build`
|
||||
- `main.py` `<en>` tags spoken: missing `import re` — caught by `python -c "import main"`
|
||||
|
||||
These all caused a broken deploy. Each would have been caught in <60 seconds locally.
|
||||
Reference in New Issue
Block a user