diff --git a/harnesses/composites/code-airouter-deepseekv4flash-repo/v1/harness.yaml b/harnesses/composites/code-airouter-deepseekv4flash-repo/v1/harness.yaml new file mode 100644 index 0000000..0cb2d8b --- /dev/null +++ b/harnesses/composites/code-airouter-deepseekv4flash-repo/v1/harness.yaml @@ -0,0 +1,15 @@ +kind: composite +name: code-airouter-deepseekv4flash-repo +version: 1 +description: "Code agent with Airouter DeepSeek V4 Flash + repo clone via SSH" + +# Inherits airouter context's label gate — only the airouter dispatcher +# advertises this composite (see dispatcher/poller._collect_supported_harnesses). +requires_labels: [airouter] + +layers: + - context: deepseek-code-methodology/v1 + - context: best-practices/v1 + - context: airouter/v1 + - context: gitea-ssh/v1 + - context: agent-repo/v1 diff --git a/harnesses/contexts/deepseek-code-methodology/v1/CLAUDE.md b/harnesses/contexts/deepseek-code-methodology/v1/CLAUDE.md new file mode 100644 index 0000000..5f2ca07 --- /dev/null +++ b/harnesses/contexts/deepseek-code-methodology/v1/CLAUDE.md @@ -0,0 +1,111 @@ +# Code Methodology — DeepSeek V4 Flash + +You are running on **DeepSeek V4 Flash** via the agentic tool-calling runner. Reasoning mode is active — your `` blocks are part of normal output, not something to be scaffolded. + +## Hard rules (violations fail the task) + +1. **NEVER use the `Write` tool on a file that already exists.** Read first, then `Edit` for targeted changes. `Write` is only for creating new files that do not yet exist. + - Real incident (2026-05-08, task `4a2f2988`): an agent was asked to add a single parameter to a single function in `controlplane/api/identity_deps.py`. It used `Write` and accidentally produced a file containing only that one function — 9 other functions were silently deleted. The narrow test passed (the function was correct in isolation) but every consumer broke with `ImportError`. The branch was rejected. **The agent thought it had succeeded.** Don't be that agent. Use `Read` + `Edit` for changes to existing files, every time. +2. **Only modify files directly required by the task.** Do not refactor adjacent code, fix unrelated tests, or upgrade dependencies. Before committing, run `git diff --name-only HEAD` — if any unexpected file appears, revert it with `git checkout `. +3. **NEVER delete existing functions, classes, or imports.** Only ADD new code. Append new functions after the last existing one. If you need to change behavior, add a new function — do not remove the old one. +4. **Verify you haven't deleted lines before committing:** + ```bash + git diff HEAD | grep '^-[^-]' | grep -v '^\-\-\-' | head -20 + ``` + If this shows deleted non-blank lines from existing code, you have broken something — revert and try again with a targeted `Edit`. +5. **Only run the specific test file for your change.** Never run the full test suite. + ``` + python -m pytest tests/test_.py -v --tb=short -x + ``` +6. **Do not create backup copies** (`*_orig`, `*_old`, `*_bak`, `*_backup`). +7. **Do not rename existing files before modifying them.** +8. **When the task is done, respond with plain text and stop.** Do not call any tool to signal completion. There is no "finish", "done", or "report" tool — emitting one wastes a turn and the runner will treat it as more work. + +## How to work + +1. Read the task. Identify the spec requirement ID if one is referenced; implement exactly that requirement. +2. Read the files mentioned in the task before changing them. +3. Find an existing similar file. Copy its structure. Change only what your task requires. +4. Make small steps. After each, run the single test file from rule 3. +5. When tests pass, write a short summary as plain text. Stop. + +## When you get stuck + +If the same error appears 3 times: + +- Stop trying the same fix. +- Reread the error message once. +- Ask: "Am I editing the right file?" "Should I mock this instead of debugging the environment?" +- Try a completely different approach. + +If a directory or file does not exist where you expect it: do not debug the environment. Mock it or create a test fixture. + +## Best practices + +This container has cross-project best practices mounted at `/workspace/best-practices/`. **For any non-trivial Python task, read the relevant topic file before writing code.** + +- `/workspace/best-practices/python-patterns.md` — Pydantic v2 validators, `threading.Lock` vs `RLock`, `extra='ignore'` silent drops, subprocess mocking, `model_validator`, packaging +- `/workspace/best-practices/test-driven-development.md` — for tasks that involve writing tests +- `/workspace/best-practices/spec-driven-development.md` — when a `spec/` file is referenced +- `/workspace/best-practices/security-architecture.md` — for anything touching auth, credentials, or external boundaries +- `/workspace/best-practices/BESTPRACTICES.md` — index of all topics + +## Python conventions (this codebase) + +- Python 3.12+ with type hints +- Pydantic v2 for data models — use `@model_validator(mode='after')` for cross-field validation; `@field_validator` does **not** fire for default values +- pytest for tests; async tests must be `async def` with `@pytest.mark.asyncio` (a sync `def test_*` calling async code silently passes without executing) +- Structured JSON logging +- Configuration via environment variables — no hardcoded config + +## Python safety rules + +### Module imports +Never call `sys.exit()` at module level or inside `except ImportError`. Use a flag: + +```python +_HAS_OPENAI = True +try: + import openai +except ImportError: + _HAS_OPENAI = False +``` + +Check the flag at call time, not at import time. + +### Threading +`threading.Lock` is non-reentrant — same-thread re-acquisition deadlocks silently. When in doubt, use `threading.RLock`. + +### Pydantic gotcha +After adding a field to a shared model, every Protocol implementation and every `_to_row` / `_row_to_*` mapping must learn the new field, or it will silently round-trip as `None` in the implementation you missed. + +## Tool-calling notes + +- Use the standard tools provided. Don't invent tool names. +- Tool arguments must be valid JSON. If you get an "invalid JSON" error back, re-read the schema and try once more with the corrected shape. +- You can call multiple tools in one turn (parallel) when their results are independent. Don't batch sequentially-dependent calls — wait for the prior result first. + +## Session log + +Before stopping, write a short log to `/project/memory/log/.