Enforce evidence-first discipline in all reports, plans, and diagnostic documents. No unverified claims.
Every factual claim in a report, plan, or diagnostic document MUST have a corresponding evidence source collected BEFORE the claim is written.
Violation of this rule produces garbage reports that waste the user's time and destroy trust.
| Claim Type | Required Evidence | NOT Acceptable |
|---|---|---|
| Runtime state (process running, port open, env var value) | ps aux, docker inspect, env, curl output | Reading source code and guessing what runs |
| Database content (row exists, column value) | psql / API query result | Inferring from code that writes to the table |
| Configuration (which file sets a value) | grep the actual file + confirm via docker inspect or process cmdline | Seeing one config file and assuming it's the only one |
| Code behavior (function does X) | Direct code citation with file path and line number | Paraphrasing from memory |
| Log evidence (event happened at time T) | docker compose logs grep output | "It probably logged something" |
| Connection state (WS connected, API reachable) | curl / ps aux / backend log grep | UI screenshot alone (could be cached/stale) |
| Network identity (IP belongs to X) | host <IP> or nslookup reverse DNS output | Guessing from IP range ownership |
WRONG: "The function falls back to the first workspace because the resolver has a fallback path."
This reads code logic and assumes runtime behavior. The actual DB table was never queried.
RIGHT: Query the table first, then write the claim with evidence inline.
WRONG: "Setting X is configured in Dockerfile."
Only one config file was checked. Docker Compose merges multiple layers (Dockerfile, docker-compose.yml, overrides, .env). The actual process CMD was never verified.
RIGHT: Run docker inspect <container> | jq '.[0].Config.Cmd' to see the actual CMD, then trace back to the source file.
WRONG: "Process X is not running" (without running pgrep or ps aux)
RIGHT: Run ps aux | grep <process>, paste the output (even if empty), then write the claim.
WRONG: "Client connects from <IP> which belongs to <cloud provider>, therefore it's a cloud-hosted service."
Seeing an IP in a log and inferring the identity of the client based on IP range ownership. The IP could be a CDN, a reverse proxy, a tunnel endpoint, or anything else.
RIGHT: Run host <IP> to get reverse DNS, AND ps aux | grep <relevant_process> on all candidate machines to find where the process actually runs. Only then identify the client.
WRONG: "Env var X is not set in the container, so the subprocess can't reach the backend."
Investigated the Docker container's env vars and network, but the actual process runs on the HOST machine. Never ran ps aux on the host to verify where the process executes.
RIGHT: Before investigating ANY container internals, first determine WHERE the process runs:
# ALWAYS run on the HOST first
ps aux | grep <process_name>
# If found on host: investigate the host environment
# If NOT found on host: THEN check containers
WRONG: "Field X is empty in the DB, so runtime event Y did not happen."
Interpreted a DB field value without first checking the code that writes it. The writer function may never populate that field — the empty value could be a default added downstream by a different layer.
RIGHT: Before interpreting any DB field value as evidence, trace the code path that writes it:
WRONG: "Root cause: env var X defaults to wrong value. Fix: set it in the container."
Declared root cause after checking ONE config layer (container env vars) without checking other layers (settings files, process environment, CLI flags) that may already set the correct value. Also did not verify that the claimed cause actually produces the observed symptom.
RIGHT: A root cause declaration requires:
WRONG: Investigated container internals → container networking → container env vars. Concluded a subprocess can't reach a service from inside Docker.
The actual execution path ran entirely on the host machine — Docker was never in the execution path. The subprocess chain (client → executor → bridge → CLI → MCP server) all ran on the host.
RIGHT: Before investigating any specific hop, trace the FULL execution path first:
FOR a task execution investigation:
1. ps aux | grep <process> on HOST — find where execution starts
2. Read the process's env vars (ps eww -p <PID>)
3. Read the code that spawns the next subprocess — find the command + env
4. For each subprocess in the chain, verify: what binary, what cwd, what env, what config files
5. Only investigate network/connectivity AFTER you know which machine the process runs on
WRONG: "See foo.py:108-116 for the fallback logic." (line range written from memory, never re-read)
RIGHT: Before citing any line number, view_file that range and verify the content matches your claim.
WRONG: "Validation will use data from index X." (never checked what index X actually contains)
RIGHT: Before writing any design that references a data source, verify:
WRONG: "Model has field X — we can use it to build mappings." (field exists on the schema but is never populated)
RIGHT: A model field definition only proves the schema exists. To claim the data is usable:
default_factory=list or default=None, assume empty unless proven otherwiseWRONG: "Function X is dead code — no callers found." (searched only one subdirectory)
RIGHT: When claiming "X is not called anywhere":
backend/app/ — 0 callers"WRONG: "Function returns N items." (number inferred from code, never verified at runtime)
RIGHT: Any specific runtime quantity (row counts, list sizes, process counts) requires a runtime verification command. Run the query and paste the output before citing the number.
When writing any report, plan, or investigation document:
FOR EACH factual claim you are about to write:
1. STOP writing
2. Run the verification command (DB query, grep, ps, curl, docker inspect, etc.)
3. Read the output
4. Write the claim WITH the evidence inline or as a citation
5. If the evidence contradicts your expectation, UPDATE your understanding — do NOT ignore it
When investigating "why does X not work at runtime":
1. LOCATE the process: ps aux | grep <name> on HOST first, then containers
2. READ its env: ps eww -p <PID> | grep <VAR> (or /proc/<PID>/environ on Linux)
3. READ its config files: find the settings file the process actually reads
4. TEST connectivity FROM the correct machine: curl from where the process runs
5. ONLY THEN form a hypothesis and verify it
NEVER skip step 1. Investigating the wrong machine wastes all subsequent effort.
Use one of these formats in the document:
Inline evidence block:
> **Evidence**: `<command that was run>`
> ```
> <actual output pasted here>
> ```
Code citation:
> **Evidence**: [filename.py:L120-L129](file:///path/to/file#L120-L129)
> ```python
> def relevant_function(...):
> ...
> ```
Before delivering any report or plan to the user, verify:
ps aux or pgrep outputdocker inspect, env dump, process cmdline)view_file to confirm the content matches the claimps aux BEFORE investigating env/config/networkAfter applying a fix, verify at EVERY layer in the execution path, not just the layer you changed:
FOR a fix that changes tool/service availability:
1. UNIT: The function you changed now returns the expected output
→ Run the function directly in the same import context as production
2. API: The API endpoint returns the corrected response
→ curl/POST the endpoint and confirm the change is reflected
3. CONSUMER: The consumer of the API (e.g., MCP gateway, CLI) receives the corrected data
→ Check the consumer's tool list or config
4. END-TO-END: The original symptom is resolved
→ Trigger the same user-facing action that was failing
Do NOT declare a fix verified after checking only one layer. A fix at the function level may not propagate if there is caching, a stale process, or a different code path at the API layer.
| Fixed Layer | Often Missed |
|---|---|
| Python function | API serves from a different worker with stale imports |
| Backend API | MCP gateway caches tool list from previous startup |
| Config file | Process needs restart to pick up new config |
| Docker image | Container uses mounted volume that overrides the image |
This skill was created after reports contained multiple unverified claims that wasted the user's time and destroyed trust.
Three errors from a single diagnostic report:
ps aux)Root cause: writing conclusions before collecting evidence.
Five errors from a tool availability investigation:
host or nslookup)ps aux on host)Root cause: investigating the wrong machine because ps aux on the host was never run first.
Five errors from one analysis report: unchecked line citations, design referencing unverified data source, schema field assumed to have data, narrow grep declaring dead code, runtime quantity from memory.
Root cause: writing claims before collecting evidence, and insufficient verification scope for negation claims.