<!-- Backend protocol verification is ENABLED for this project. -->

## Backend Mode (when `backend.verifyPatterns` matches an edited file)

If the project has the backend protocol cycle enabled (`ironbee backend enable` once at setup) and your edits touch matching paths (e.g. `server/**`, `api/**`, `routes/**`, `controllers/**`), the Stop hook also enforces a Backend cycle. The same `verification-start` covers every active cycle; one platform-agnostic verdict covers them all.

This cycle is **runtime- and language-agnostic** — it works for Node, Java, Python, Go, Rust, Ruby, .NET, PHP, Elixir, Kotlin, Scala. The agent makes real protocol calls (HTTP / gRPC / GraphQL / WebSocket) against the running service, inspects logs, OR reads database state; it never attaches to a process.

### Mode behavior (backend cycle)
- **default** (no arg or `default`): exercise the endpoints your diff touched via ONE of the three evidence paths (protocol-call, log evidence, or DB evidence — see below). Map each changed file → the route(s) / handler(s) / RPC method(s) / table(s) it exposes, then either call them yourself and chain follow-ups to verify side effects, OR set up log capture, OR inspect database state directly.
- **full**: cover every endpoint reachable from files matching `backend.verifyPatterns`, not just the changed files. Cover the success path, at least one error path, and any auth-gated variant for each. For schema / migration changes, verify every affected table.
- `visual` / `functional`: browser-only modes; this cycle behaves as `default` when they are passed.

### Steps (additive to the browser flow above)

The cycle is satisfied by ANY ONE of three evidence paths: protocol-call (you drive the request), log-evidence (something else drives it; you read the logs), or DB-evidence (you inspect database state). Pick whichever fits the task — multiple can be combined.

1. **Confirm the backend service is running** (the user's dev server / Docker compose / k8s port-forward / …). Don't start the service yourself — ask the user if it's not obvious.
2. **Identify the affected layer** — wire endpoint, log output, and/or database state. Map your code change to its observable side(s).
3. **Exercise ONE or more evidence paths**:

   **Path A — Protocol-call (you drive the request):**
   - `MCP:bedt_request_http` — HTTP/1.1 + HTTP/2 (ALPN auto-negotiates).
   - `MCP:bedt_request_grpc` — unary + 3 streaming modes; `.proto` text or descriptor.
   - `MCP:bedt_request_graphql` — query/mutation/persisted query.
   - `MCP:bedt_request_websocket-open` then `bedt_request_websocket-send` / `bedt_request_websocket-receive` / `bedt_request_websocket-close` for stateful WS sessions.
   - `MCP:bedt_request_replay` — re-issue a captured curl command or HAR entry.
   - **Inspect the response** — `status`, body, headers, `traceId`. **4xx/5xx and gRPC non-OK are normal results, not transport errors.** Decide PASS/FAIL based on what the test actually requires.

   **Path B — Log evidence (an external driver hits the endpoint; you read the logs):**
   - `MCP:bedt_log_register-source` — register the running service's log destination (`type: "file"` + `path`, `type: "docker"` + `container`, or `type: "kubernetes"` + `pod`).
   - `MCP:bedt_log_read` / `MCP:bedt_log_read-multi` — point-in-time read with filters (`tail`, `since`/`until`, `pattern`, `level`, `parseJson` + `jsonFilter`, `contextBefore`/`contextAfter`, `select`, `coalesce`).
   - `MCP:bedt_log_follow` + `MCP:bedt_log_get-followed` (and `MCP:bedt_log_stop-follow`) — streaming follow when you need to capture lines that emit AFTER you trigger.
   - **Verify the lines match the expectation** — error gone, expected line present, trace-id chained through, no unexpected ERROR-level entries.

   **Path C — DB evidence (you inspect database state directly):**
   - `MCP:bedt_db_connect` — open a named connection (`type: "postgres" | "mysql" | "sqlite"`, prefer `connectionStringEnv` over inline `connectionString`, default `allowWrites: false`).
   - `MCP:bedt_db_list-tables` / `MCP:bedt_db_describe-table` — discover schema; great for migration verification.
   - `MCP:bedt_db_query` — run a read query (parametrized; readonly mode is enforced server-side).
   - `MCP:bedt_db_snapshot` (+ `MCP:bedt_db_diff`) — pre/post state diff so you can prove a code path changed exactly the rows it should have.
   - `MCP:bedt_db_watch-changes` + `MCP:bedt_db_get-changes` — streaming change capture for verifying writes triggered by a protocol call or external driver.
   - `MCP:bedt_db_transaction-begin/-commit/-rollback` — scope seed data to one test so it doesn't leak.
   - `MCP:bedt_db_disconnect` to clean up (optional — session teardown handles it).
4. **Chain follow-ups across paths** — protocol-call → DB read to verify writes landed, protocol-call → log read to verify trace-id chained, etc. Use `MCP:bedt_request_set-default-headers` for auth tokens (host-scoped), `MCP:bedt_request_set-cookies` for session state on Path A.
5. **Trace correlation (optional, `o11y_*` primitives):** IronBee already pins the verification cycle's traceId on every backend tool call via `_metadata.traceId` (outranks any session pin), so the orchestrator's correlation root is authoritative. Use `MCP:bedt_o11y_get-trace-context` to read it, then pass it to `MCP:bedt_log_read { pattern: "<traceId>" }` to slice logs for one flow. `MCP:bedt_o11y_new-trace-id` / `MCP:bedt_o11y_set-trace-context` are available when you want to anchor a flow under an explicit id (e.g. integration-test runs).
6. **Submit verdict** including the fields matching the path(s) you exercised. If browser and/or node cycles are also active, include their fields in the SAME verdict — do not submit two verdicts.

### Verdict (platform-agnostic)

The verdict shape is the same regardless of which evidence path (protocol-call / log / db) you took — `status` + `checks` (+ `issues` / `fixes` as needed):

```json
{
  "session_id": "...",
  "status": "pass",
  "checks": ["POST /api/orders returned 201 with order id", "GET /api/orders/:id reflects new order"]
}
```

The gate requires that AT LEAST one evidence path was actually exercised in your tool calls — `MCP:bedt_request_*` for protocol-call, `MCP:bedt_log_register-source` + `MCP:bedt_log_read*` / `_follow` for log-evidence, or `MCP:bedt_db_connect` + a read/diff/snapshot/get-changes for DB-evidence. If none were used, the gate will reject.

For a multi-cycle pass (browser + backend, or browser + node + backend), every active cycle's pass criteria must hold.

---

## Default Mode (backend cycle)

Focus on the endpoints you changed — not every endpoint in the service.

### 1. Study the changes
1. Run `git diff --name-only` and `git diff --name-only HEAD~1`
2. **Ignore `.ironbee/`, `.claude/`, `.cursor/`** — tool config, not application code
3. **Read the full diff** for route / handler / controller / service files in scope — note the wire-level address (HTTP method+path, gRPC service+method, GraphQL operation, WebSocket path), request shape, response shape, side effects (DB writes, downstream calls, queue puts)
4. Before opening the request or log tools, you should be able to answer: what endpoints did I touch? What does each return on the happy path? What does each return on the error path? What side effects need verification? Which side (request or log) is easier to drive for this task?

### 2. Verify against the running service
Pick the evidence path(s) that fit the task:

**Protocol-call path** (you drive the request):
- **Call each changed endpoint** with the matching tool — `MCP:bedt_request_http` / `MCP:bedt_request_grpc` / `MCP:bedt_request_graphql` / `MCP:bedt_request_websocket-open`
- **Cross-reference the response against the diff** — status, body shape, headers, gRPC status code
- **Chain a follow-up call** to verify side effects (POST then GET, set then list, mutation then query, …)
- **Test one error path** per new branch — invalid body, missing field, missing auth, 404 path
- **Capture `traceId`** when available — useful for joining with downstream cycle evidence

**Log-evidence path** (an external driver hits it; you read the logs):
- **Register the service's log source** with `MCP:bedt_log_register-source` (file / docker / kubernetes)
- **Read or follow** with `MCP:bedt_log_read` / `MCP:bedt_log_read-multi` (point-in-time, filter by `pattern` / `level` / `since-until` / `jsonFilter`) or `MCP:bedt_log_follow` (streaming for after-the-trigger capture)
- **Correlate with `traceId`** — use `pattern: "<traceId>"` to pull only the lines for one request
- **Verify the expected line is present** AND **no unexpected ERROR-level entries appeared** for the touched route(s)

**DB-evidence path** (you inspect database state directly):
- **Open a named, readonly connection** with `MCP:bedt_db_connect` — prefer `connectionStringEnv` so the secret never flows through the agent context.
- **Discover schema** via `MCP:bedt_db_list-tables` + `MCP:bedt_db_describe-table` for migrations / column additions.
- **Run targeted reads** via `MCP:bedt_db_query` for row-count, content, and constraint checks; `MCP:bedt_db_snapshot` + `MCP:bedt_db_diff` for pre/post state proofs; `MCP:bedt_db_watch-changes` + `MCP:bedt_db_get-changes` for streaming change capture during a triggered call.
- **Disconnect** when done (`MCP:bedt_db_disconnect`) — optional; the session tears connections down at end.

---

## Full Mode (`/ironbee-verify full`, backend cycle)

Exercise every endpoint / log source / DB table reachable from files matching `backend.verifyPatterns`, not just the changed files. Do NOT run `git diff` or scope to recent changes.

- Hit every route / RPC method / GraphQL operation / WebSocket lifecycle in scope (protocol-call) OR cover them via the log feed when an external driver / test suite drives them (log evidence) OR via direct DB inspection for schema / migration coverage (DB evidence)
- Cover the success path AND at least one error path for each
- Cover any auth-gated variant (unauthenticated, wrong role) where authentication is present
- For migrations: verify every affected table's schema (`MCP:bedt_db_describe-table`) + sample row count before / after
- Any unexpected error response, unexpected ERROR-level log line, or unexpected schema drift during the run is a fail, regardless of when it was introduced
