---
title: "Submitting an Issue to Be Civic"
description: "When and how an AI agent files an Issue against a Be Civic guide — the envelope, the scrub boundary, the staging window, and the operator-private posture."
audience: "agent"
---

# Submitting an Issue

An **Issue** is a negative signal about a Be Civic guide: something on it is wrong, missing, out of date, or diverges from what the user actually encountered. You file Issues so the operator can correct the closed library. You never edit a guide directly.

## When to file an Issue

File an Issue when, in the course of helping a user, you find that a guide:

- States a step, fee, document, or deadline that no longer matches reality.
- Is missing a branch or step the user's situation needs.
- Cites a source, deeplink, or form URL that no longer reaches the authority.
- Diverges for the user's commune or region from what the canonical guide says.
- Is entirely absent — there is no guide for a procedure the user needs.

If instead you simply ran a guide end to end and it worked (or failed) as written, that is a **Validation**, not an Issue — see [/agents/submit/validation.md](/agents/submit/validation.md). Issues carry prose; Validations are a fixed verdict.

## Endpoint

```
POST /api/issues
Authorization: Bearer <harness_key>
Content-Type: application/json
```

Submitting requires the user's pseudonymous key (the plugin holds it; you do not mint or store it). Anonymous callers are rejected with `401`. CORS is `*`.

## The envelope

```json
{
  "schema_version": 1,
  "submission_id": "iss_<uuidv7>",
  "submitted_at": "<RFC 3339 UTC>",
  "submitting_harness": "be-civic/<version>",
  "submitting_model": "<model-id>[/<effort>]",
  "submission_contract_version": "<semver>",
  "target_type": "process",
  "target_id": "<guide-id>",
  "title": "<single line, <= 120 chars>",
  "body": "<markdown, <= 2000 chars>",
  "label": "rotted",
  "context": { "language_used": "en", "region": "<optional>", "commune_nis5": "<optional>" },
  "evidence": { "evidence_date": "2026-05-30", "evidence_source": "customer-report" }
}
```

Field notes:

- **`target_type`** — what the Issue is about. For a procedure use `process` with the guide's id as `target_id`. Other values exist for the library's supporting entities (`path`, `path_source`, `tool`, `volatile_value`, `reference`, `resource`) and for a missing guide use `knowledge_graph` (then `target_id` may be empty and you suggest a slug in `evidence.proposed_process_id`).
- **`label`** — a closed enum naming the kind of problem: `bug` (something is wrong), `missing` (content that should be there isn't), `rotted` (a citation or link no longer reaches its source), `divergence` (commune- or region-specific deviation), `gap` (use with `target_type: knowledge_graph` when the guide is absent entirely).
- **`title` / `body`** — the human-readable report. `body` is constrained markdown: no inline HTML, no raw URLs as link targets outside the citation allowlist. Single-line fields must not contain newlines.
- **`evidence`** — target-specific. For a procedure: `evidence_date` (what you observed, `YYYY-MM-DD`) and `evidence_source` (`customer-report | citation | corroboration`). For a volatile value, pair the cited row's UID in `target_id` with `{ observed_value, evidence_date }`.
- **`submitting_harness` / `submitting_model`** — the plugin version and the model running you. Both are required; the operator triages partly on model tier.

Do **not** send any worker-set field — `user_id`, `accepted_at`, `cancel_token`, `cohort_anchor`, or scrub metadata. The worker derives the User ID from the key and stamps the rest. Submissions that carry these are rejected with `worker_field_supplied_by_submitter`.

## Scrub expectations — no personal data

An Issue is **anonymous by construction**. Carry no information that could identify the user. The envelope has no name, email, address, national-number, document-number, or IBAN field, and identity-shaped content in free text is rejected at the boundary.

There are three layers; do your part at the first:

1. **You scrub before sending.** Strip the user's specifics from `title` and `body`. Describe the defect in the guide, not the person who hit it. "The Annex 19 fee shown is stale" — not "Jan Peeters paid €X at Schaerbeek on…".
2. **The Worker hard-gate** re-checks every body against the scrub rules and the schema. A hit returns `422` with `error.category: "identity_scrub_reject"` naming the rule category (`identity`, `document_number`, `biometric`, `address`, `other`) — never echoing the matched substring. The submission is not stored.
3. **Named-entity scan on commit** flags context-dependent leaks for operator review.

Repeated scrub rejections accumulate against the user's pseudonymous ID and can trigger an authority hold. Keep submissions clean.

## On accept

`201 Created` with `data: { submission_id, accepted_at, cancel_token, cohort_anchor }`. The `cohort_anchor` is `<target_id>@<version>` — the worker binds your Issue to the guide version you saw. Keep the `cancel_token`: combined with the user's key it lets you cancel within 48 hours via `DELETE /api/submissions/issues/<submission_id>`.

## Staging and visibility

- **Held ~24 hours.** A new content signal does not change the library immediately; it stages for review before it can affect anything.
- **Operator-private.** Issues never surface back to consumer agents through the API. They feed the operator's triage and corpus authoring. An Issue is a signal, not a write path — all canonical changes are operator-authored.
- **Buffer for the user.** Don't file silently mid-task. Collect findings during the session and surface them for the user's approval at session close before submitting — see [/agents/feedback-template.md](/agents/feedback-template.md).
