# Reporting a Gap to the Dev Team — `report_feedback`

> You exhausted the self-sufficiency loop (read the error, retried reads, triangulated with alternate
> tools) and the wall is real: a tool is genuinely broken, a capability doesn't exist, or the docs don't
> say how to do what the user asked. `report_feedback` is the formal channel to put that on the Ninjo dev
> team's radar — it files a Linear ticket and pings the team in Slack. It is **not** a way to deflect work,
> and it does **not** unblock the current task: the user still leaves the turn with the best achievable
> result + a precise next step (see `knowledge/self-sufficiency.md`).

---

## When to call it

Only **after** the self-sufficiency loop confirms a real blocker — never as a first resort. Then pick the type:

| Type | Use when | Lands as (Linear) |
|---|---|---|
| `ERROR` | A tool errored / misbehaved, or a platform feature is broken — confirmed, not a transient timeout you didn't retry. | Bug (High priority) |
| `FEATURE_REQUEST` | A capability is **genuinely missing** — no MCP tool can do what's needed (e.g. robust story-trigger binding repair). | Feature |
| `MISSING_INFO` | The docs/playbook/knowledge are unclear or insufficient — you couldn't find how to do something that may already be possible. | Improvement |

Do **not** report: a transient timeout you haven't retried, something a tool in `mcp-tool-reference.md` already
does, or a user-side data issue you can explain. One report per distinct gap — don't file duplicates for the same
blocker across a session.

## How to call it

Two tools. `report_feedback` is enough on its own; attach the session when the full interaction is the evidence.

**1 — (optional) attach the agent session.** Two-step presigned upload, so the bytes never pass through the
model context (same shape as creator-resources):

- `create_feedback_upload_url` → `{ upload_url, s3_key }`. No inputs needed (influencer inferred from the
  connection; an admin passes `influencer_id`).
- PUT the session file to `upload_url` **yourself** via bash — no special header needed, e.g.
  `curl -T session.md "<upload_url>"`. The URL has a short TTL. The file lands in a private bucket; engineers
  read it with AWS creds (the ticket links the durable `s3://` key).

**2 — file the report.** `report_feedback`:

- `operation` — what the **user** was trying to do, tied to their request. (e.g. _"Vincular un trigger de Story al agente mauristacks"_)
- `problem` — the **precise diagnosis**: the exact error, the tool name, what you tried, and what's missing. Not _"tool error, pls check"_. (e.g. _"`upsert_trigger` para story devuelve 200 pero el binding no aparece en `list_triggers` tras 3 intentos; ver platform-internals §3c"_)
- `type` — `ERROR` | `FEATURE_REQUEST` | `MISSING_INFO` (table above).
- `session_s3_key` — the `s3_key` from step 1, when you attached the session.

Returns `{ ok, issue_id, issue_identifier, issue_url, slack_posted }`. Surface the `issue_identifier` to the user
("lo reporté al equipo — NINJO-1234") so they know it's tracked.

## Gotchas

- **No `reason` argument.** Unlike every other cortex-gateway tool (`mcp-tool-reference.md` §Ground rules),
  `report_feedback` takes **no** `reason` — the tool *is* the feedback, so `operation` + `problem` carry the
  content.
- **Fire-and-forget for the team, not a fix for the user.** Filing a ticket does not complete the user's task.
  In the same turn, still deliver the best achievable result and the exact next step.
- **`slack_posted: false` is not a failure.** The Linear issue was created (the URL is in the response); only the
  Slack ping was skipped/failed. Don't retry the whole report on that basis.
- **Don't put secrets in the session.** Strip API keys / tokens before uploading — the session is for the
  conversation, not credentials.

See also: `knowledge/self-sufficiency.md` (run the recovery loop first), `knowledge/mcp-tool-reference.md`
(§Feedback), `knowledge/platform-internals.md` (cite the known bug in `problem` when there is one).
