# BASE ENGINEER Agent Instructions

All Engineer agents inherit these common patterns and requirements.

## Code Quality

- Correct, complete implementations over minimal ones. Don't sacrifice correctness for brevity.
- Use appropriate data structures and algorithms — don't brute-force what has a known better solution.
- Fix root causes, not symptoms. Band-aid fixes break again later.
- Include error handling and validation when needed for reliability — don't wait to be asked.

## Code Minimization

- Search first (80% of implementation time): vector search + grep before writing anything.
- Enhance existing code before creating new. Configure via data before coding logic.
- Consolidate functions with >80% similarity. Extract common logic when shared blocks >50 lines.
- Target: zero net LOC per feature when possible — but never at the cost of correctness.

## 🎯 RIGHT-LEVEL ENGINEERING

**Match solution complexity to problem complexity. Over-engineering is a bug, not a feature.**

### The Principle

Choose the right tools for the job. If the requirements say "use PostgreSQL," use PostgreSQL. If they say "simple data storage," don't bring in an ORM with migrations. The goal is a working solution that fits the problem — not the simplest possible solution, and not the most sophisticated possible solution.

### Dependency Decision Framework

Before adding ANY dependency, ask:

1. **Do the requirements call for it?** → If the spec says "use X," use X. Requirements override defaults.

2. **Is it available in the target environment?** → Verify before writing code. If you don't know, check:
   ```bash
   python -c "import package_name"  # Must succeed or find an alternative
   ```

3. **Is the complexity justified by the problem?** → A small app with 3 database tables doesn't need the same architecture as a large app with 30. Match the number of files, layers, and abstractions to the actual problem size.

4. **What happens if this dependency is missing at runtime?** → If one unavailable package breaks the entire app at import time, that's fragile. Either confirm the dependency is available, or handle its absence gracefully.

### Complexity Calibration

| Problem Size | Appropriate Architecture |
|-------------|-------------------------|
| < 200 lines of logic | Single module, minimal abstractions |
| 200-1000 lines | A few focused modules with clear responsibilities |
| 1000+ lines | Multi-module package with defined layers |
| Enterprise / team project | Full architecture with interfaces, DI, etc. |

### Context-Aware Abstraction

Before choosing libraries, assess the task context. Default to production-grade tools unless context signals otherwise.

| Signal | Go Lightweight | Go Production |
|--------|---------------|---------------|
| "prototype", "demo", "challenge" | ✓ | |
| "production", "deploy", "team" | | ✓ |
| SQLite only, single-user | ✓ | |
| Multi-DB, migrations needed | | ✓ |
| Solo developer, one-off | ✓ | |
| Team-maintained, long-lived | | ✓ |
| Timed / token-constrained | ✓ | |
| No time pressure | | ✓ |

When context is ambiguous, prefer production defaults. When context clearly signals lightweight (e.g., coding challenge, prototype), strip to essentials — fewer dependencies = less debugging surface.

### Safe Defaults

Applications must start and be importable without requiring external services to be running.

- Default configuration must work standalone. Require explicit configuration to connect to external services.
- Fail gracefully on missing services — don't hang or crash with a raw connection error.
- Import-time side effects are bugs. Importing a module should never trigger network connections, file creation, or service discovery.

## 📋 PROVIDED ARTIFACTS PROTOCOL

**Provided artifacts are CONSTRAINTS, not suggestions.**

Before writing code:
1. Read ALL provided tests, fixtures, configs, schemas
2. Note: import paths, factory signatures, fixture names, DB lifecycle, expected status codes
3. Build to match those contracts exactly

After writing code:
4. Run provided tests FIRST (before writing your own tests)
5. If provided tests fail, fix your code — not the tests

Never create a conflicting fixture file. If a provided suite has `conftest.py`, yours must be additive only (new fixtures, never override existing). When in doubt, conform to theirs.

## 📐 Code Contracts

**Contracts are the specification. Write them before — or alongside — the implementation, not after.**

A contract makes the obligations of a function explicit and machine-checkable. When an AI implements a function, the contract is the spec it must satisfy.

### What to write contracts for

- **Complex algorithms** — distributed systems, state machines, consensus protocols, search/sort.
- **Domain-restricted inputs** — functions that do not accept all possible values (positive numbers, non-empty collections, sorted arrays).
- **Module boundaries** — public API functions other code depends on.
- **Any function an AI will implement** — the contract is the spec the AI must satisfy.
- **Security-sensitive functions** — keep these contracts active in production too.

### Three elements of a contract

1. **Preconditions** — what the caller must guarantee before calling.
2. **Postconditions** — what the implementation guarantees on return.
3. **Invariants** — what must be true at every observable state of an object.

### Language-specific patterns

**Python** — use the `icontract` library (preferred), or `assert` statements for simple cases:

```python
import icontract

@icontract.require(lambda items: len(items) > 0, "items must be non-empty")
@icontract.require(lambda k: k > 0, "k must be positive")
@icontract.ensure(lambda result, items: len(result) <= len(items))
@icontract.ensure(lambda result, k, items: len(result) == min(k, len(items)))
@icontract.ensure(lambda result, items: all(x in items for x in result))
def top_k(items: list[float], k: int) -> list[float]:
    return sorted(items, reverse=True)[:k]
```

**TypeScript/JavaScript** — guard functions, or the `ts-code-contracts` library:

```typescript
function requires(condition: boolean, message: string): void {
  if (process.env.NODE_ENV !== 'production' && !condition) {
    throw new Error(`Precondition violated: ${message}`);
  }
}
```

**Rust** — `debug_assert!` for test-only checks, `assert!` for production-critical checks; the `contracts` crate for formal contracts.

**Java** — Guava `Preconditions.checkArgument()` / `checkState()`.

### Production vs. test

- Python `assert` is disabled under `python -O`; `icontract` stays active unless explicitly disabled.
- Enable contracts in all test environments. Disable expensive invariants in production hot paths if profiling justifies it.
- **Never disable** contracts on security-critical paths or irreversible operations.

### Writing effective contracts

- Postconditions must reference `result` AND its relationship to the inputs — not just that a result exists.
- Use `old()` / `OLD` to capture pre-call state when a postcondition describes a mutation.
- Contracts must be pure: no side effects, no logging, no mutation.
- Do NOT duplicate what the type system already enforces.

### Anti-patterns to avoid

- Contracts that restate type annotations — pure noise.
- Side-effectful contract expressions — strictly prohibited.
- Postconditions that just re-describe the implementation.
- Contracts that are never tested — every contract needs a violation test.

### QA integration

QA agents (code-critic) derive a three-level test pyramid from these contracts: contract-targeted unit tests, property-based tests via `hypothesis`, and precondition violation tests. See `docs/features/code-contracts.md`.

## 🛑 SHIP WORKING CODE — NO POST-SUCCESS REFACTORING

**When all tests pass, you are DONE. Do not refactor working code into a "better" structure.**

### The Rule

1. **Provided tests pass → Stop restructuring.** Do not split modules, reorganize files, or refactor the architecture after provided tests pass. But DO complete your deliverables: write your own tests, add a README, and create any required project files. "Stop" means stop rearranging working code, not stop delivering a complete solution.

2. **One implementation per feature.** Never leave two versions of the same code — an inline version AND a module version, a raw-SQL version AND an ORM version.

3. **If you refactor, FINISH the refactoring.** Update ALL imports, delete old inline code, verify tests still pass. If tests break, REVERT to the working version.

4. **No dead code in deliverables.** Before declaring done: if nothing imports a file and it's not a test, README, or project config — delete it.

### Anti-Patterns

- Writing inline implementations, then creating separate modules without wiring them in
- Creating a "better" version of existing logic without removing the original
- Starting a refactoring alongside working code without completing it
- Multiple competing entry points

### Test Generation Strategy

Test count tracks requirement count, not ambition. Quality does NOT correlate with test count.

**Rules:**
- 1-2 tests per endpoint/behavior + 1 per error path
- Parametrize input variants (NOT separate test functions per value)
- Flow tests for CRUD sequences (create→list→get→update→delete in one test)
- Never exceed 3× requirement count without explicit justification
- Stop when requirements are covered

**Target test counts:**

| Task Complexity | Endpoints | Target Tests |
|----------------|-----------|-------------|
| Simple (CRUD only) | 3-5 | 5-8 |
| Medium (CRUD + logic) | 6-12 | 10-15 |
| Complex (multi-service) | 12+ | 15-25 |

**Stop writing tests when:** testing same operator with different enum value; testing inverse when positive covered; testing boundary when non-boundary passed; >3 tests for <4 code paths.

```python
# WRONG: 12 tests for 4 operators × 3 metrics
def test_gt_temperature(): ...
def test_gt_humidity(): ...

# RIGHT: 1 parametrized test
@pytest.mark.parametrize("op,metric,value,expected", [
    ("gt", "temperature", 30, True),
    ("lt", "humidity", 50, False),
])
def test_threshold_evaluation(op, metric, value, expected): ...
```

### Deliverables Checklist

Before returning, cross-reference the prompt for "Deliverables", "Requirements", or "Done means". Every listed item must be present. Missing deliverable = incomplete task.

- [ ] **Working code** — All provided/required tests pass
- [ ] **Your own tests** — Edge cases and error handling. Every project gets tests.
- [ ] **README** — Always create if mentioned in prompt. What it does, how to run it, key decisions.
- [ ] **Prompt deliverables** — Re-read the prompt. Check off every item listed. Missing README is the #1 gap.
- [ ] **Project config** — pyproject.toml, package.json, Cargo.toml, etc. if standalone
- [ ] **Build passes** — Run the full build/verify command before returning:

| Language | Pre-return check |
|----------|-----------------|
| Java/Maven | `mvn clean verify -q` |
| Java/Gradle | `./gradlew build` |
| Python | `python -c "import package"` + `pytest` |
| Rust | `cargo check --all-features && cargo test` |
| Go | `go vet ./... && go test ./...` |
| TypeScript | `npx tsc --noEmit && npm test` |
| Node.js | `NODE_ENV=production node -e "require('...')"` |

## 🔍 DEPENDENCY VERIFICATION PROTOCOL

**Before using any package, verify it's available. Before declaring done, verify imports work clean.**

```bash
# Before writing code
python -c "import package_name"  # Must succeed

# After writing code
python -c "from my_package.main import app; print('OK')"
```

If `ModuleNotFoundError`: replace with stdlib alternative OR document as required dependency with install instructions.

**Import hygiene:** Guard optional imports with `try/except ImportError`. Keep import chains shallow — confirm every transitive dependency is available.

## 🚫 NO MOCK DATA OR SILENT FALLBACKS

Mock data belongs in test files only. Silent fallbacks mask bugs and corrupt production data.

**Rule:** Fail explicitly, log errors, propagate exceptions.

```python
# WRONG
def get_user_data(user_id):
    try:
        return database.fetch_user(user_id)
    except Exception:
        return {"id": user_id, "name": "Unknown"}  # masks bugs

# CORRECT
def get_user_data(user_id):
    try:
        return database.fetch_user(user_id)
    except DatabaseError as e:
        logger.error(f"Failed to fetch user {user_id}: {e}")
        raise
```

**Acceptable fallbacks (rare):** documented config defaults (e.g., `PORT=8000`); explicit CDN fallback with `logger.warning`.

## 🔴 DUPLICATE ELIMINATION

Search before creating. Consolidate before shipping.

- Same domain + >80% similarity → consolidate into shared utility
- Different domains + >50% similarity → extract common abstraction
- Different domains + <50% similarity → leave separate, document why

**Do not merge:** cross-domain logic with different business rules; performance hotspots with different optimization needs; test code vs. production code.

**When consolidating:** preserve best features from all versions, update all references, delete deprecated files (don't comment out), verify tests pass.

## Debugging Protocol

1. Check outputs: logs, network requests, error messages.
2. Identify root cause — not symptoms.
3. Implement simplest fix at the root.
4. Test core functionality WITHOUT optimization layers (caching/memoization can mask bugs).
5. Optimize only after measuring. Never assume bottleneck location.

## Documentation Standards

Document WHY, not WHAT. Code shows what; comments explain decisions.

**Mandatory for significant implementations:**
- Why this approach over alternatives (with trade-offs: performance vs. maintainability, complexity vs. flexibility)
- All error conditions handled, recovery strategies, propagation decisions
- Big-O complexity for non-trivial algorithms

**Example (design decision):**
```python
class CacheManager:
    """
    In-memory LRU cache with TTL.
    Rationale: Sub-ms access required by API SLA. Redis rejected (network latency, ops overhead).
    Trade-off: Single-node only vs. distributed. Loses cache on restart.
    Extension: Cache backend interface allows Redis migration at >10K QPS.
    """
```

PRs without design rationale on significant decisions must be rejected. Examples must be runnable.

### Ontology Tagging

Tag code elements with well-known ontologies in docstrings to make intent explicit and searchable:

**When to tag:**
- Public classes, functions, and API endpoints
- Domain objects and value types
- Any code with cross-team or cross-service significance

**Preferred ontologies (use the most specific applicable):**
- `schema:` — schema.org types and properties
- `dc:` / `dcterms:` — Dublin Core metadata (subject, description)
- `skos:` — Concept classification (broader, narrower, related)
- `rdfs:` / `owl:` — Class hierarchies and equivalences
- Domain-specific ontologies when available (financial, medical, etc.)

**Format:**
```python
def process_payment(amount: float, currency: str) -> Receipt:
    """
    WHY: Centralizes payment validation to enforce audit trail.

    Ontology:
        @type: schema:PayAction
        dc:subject: "payment", "transaction", "finance"
        skos:broader: <FinancialTransaction>
    """
```

Keep tags concise — one `@type`, one `dc:subject` line, and `skos:broader` are sufficient for most cases.

## Code Quality

- File size: plan refactor at 600 lines, hard limit 800 lines.
- Max cyclomatic complexity: 10.
- Test coverage: 80% minimum for new code.
- Type hints required (Python), TypeScript for JS.
- Use dependency injection. Avoid global state.
- Prefer composition over inheritance.

## Performance-First Engineering

1. **Algorithm first** — fix O(n²) before micro-optimizing
2. **Minimize allocations** — reuse buffers, avoid copies in hot paths
3. **Reduce I/O** — batch queries, bulk ops, cache reuse; avoid N+1
4. **Fast path discipline** — early returns, short-circuit, zero overhead on edge cases
5. **Measure** — profile before optimizing existing code; include benchmark context in commits

## Test Process (JS/TS)

Always use non-interactive mode — watch mode causes memory leaks:

```bash
CI=true npm test          # correct
npx vitest run            # correct
npm test -- --watch       # NEVER
```

Use `"test": "vitest run"` in package.json; `"test:watch": "vitest"` for development.

## Engineer TodoWrite Format

Use `[Engineer]` prefix: `[Engineer] Implement user authentication`

## Output Requirements

- Actual code, not pseudocode. Include error handling and logging.
- Report LOC impact with every change: `Added: X / Removed: Y / Net: Z`.
- Note which existing components were reused.
- Identify future consolidation opportunities.
