# Triage an Issue

> Prioritize an error by customer impact, reproduce its story, and move it through its lifecycle.

Canonical page: https://anectico.com/docs/investigate/triage-issue/


Anectico groups similar error events into Issues. Triage the Issue, not each raw occurrence.

An explicit SDK error capture is the canonical Issue occurrence for that failure. Error-level logs
linked to the capture through `error.id` remain searchable in **Logs** and stay correlated to the
trace, but they do not create duplicate `log_error` Issues. Independent error and fatal logs without
a linked capture still create Issues.

## Start with impact

Open **Issues** and evaluate:

- how many customers are affected;
- the severity and whether the latest grouped capture was handled or unhandled;
- whether important customers or accounts are included;
- whether occurrence volume is increasing;
- the first-seen, last-seen, environment, and release; and
- whether the Issue is new or has regressed after resolution.

Use the search box to narrow the queue by text: it matches, case-insensitively, any part of an
error's message, emitting service, or error class. The search runs over every Issue in the selected
time range, not only the ones already on screen, so the count above the list and the "No issues
found" result are both statements about the whole range. **Load more** continues through a searched
result set the same way it continues through an unsearched one.

Use the dedicated **Platform**, **Service**, **Mechanism**, and **Release** fields to isolate one
deployed workload and capture path. Each is an exact match and all four apply to the same error
occurrence; a group does not match by taking its platform from one occurrence and its release from
another. Applied filters remain in the page URL and in saved searches, so opening an Issue and
navigating back restores the same queue. The event count, affected-customer count, first/last
timestamps, ordering, and pagination are recalculated inside that exact filtered slice, not copied
from the Issue's all-release lifetime totals.

High occurrence count does not always mean high customer impact. Prefer the Issue affecting more real
customers or a critical journey.

Affected-customer totals are customer totals, not raw identity totals: when Anectico has
connected an anonymous identity, login identity, or another alias to the same customer,
that customer counts once. In **Affected customers**, search by display name or any
known identity alias. Search runs across the full canonical result set; use **Load more**
to follow the returned cursor instead of assuming the first page is complete. Account
badges show how many canonical affected customers belong to each account.

The account rollup is not paginated: it lists the 20 accounts with the most affected
customers. The affected-account total is reported separately and counts every account,
including those the list omits — so an Issue spanning more than 20 accounts is reported
as such rather than as exactly 20. When accounts are withheld, **Affected customers &
accounts** says so beneath the badges ("Showing 20 of 213 affected accounts"); when the
badges are the whole rollup it says nothing.

Very large Issues are summarized rather than counted exhaustively. Anectico resolves a
bounded number of affected identities per Issue, and when an Issue exceeds that bound
every total on the card is shown as a floor with a trailing `+` — "Showing 25 of 1,000+
affected customers". Read those as *at least*: the real figure is higher. A total without
the `+` is exact.

A **Person impact** dashboard tile shows exact identified, anonymous, unattributed, and
account totals, and its table lists only the first page of those customers — when it does,
it says how many of how many. Its account badges are truncated the same way as the Issue's
and carry the same "Showing 20 of 213 affected accounts" note.

On a release detail page, the affected-person total and each account count use the same
canonical identity fold, are truncated and marked the same way, and the account list says
how many accounts it is not showing. New and regressed Issue rows are confined to the
selected project and release, even when another project in the organization uses the same
release name.

## Reconstruct one occurrence

Open the Issue and choose an affected customer or recent occurrence. Follow the connected evidence:

1. compare the occurrence's severity, handled state, capture mechanism, and application route;
2. confirm its release/distribution, SDK/platform, device model, OS, and app version/build;
3. inspect the symbolicated stack trace;
4. play the linked replay when available;
5. open the distributed trace;
6. read logs around the failing span; and
7. compare the release and rollout context.

One well-connected occurrence is often more useful than scanning hundreds of identical events.

## Use Customer Detective

Ask a narrow causal question from the Issue page. Treat the result as an evidence map: follow its
citations and confirm the relevant frame, span, log, or replay before changing code.

## Apply a lifecycle action

Viewer access is read-only: viewers can inspect the complete Issue Story, affected
customers and accounts, release context, lifecycle history, linked tickets, and
previous Customer Detective investigations, but responder, ticket, and new
investigation actions are not shown. Ask a member, developer, admin, or owner to
operate the Issue.

- **Resolve** after the fix is deployed or the failure is no longer actionable. Use
  **Resolve in next release** when Anectico should reopen it only after the same Issue
  occurs in a strictly newer release.
- **Ignore permanently** when the error is expected and should not return to the
  active queue. Later occurrences or releases do not reopen it automatically;
  choose **Reopen** when it becomes actionable again.
- **Snooze until…** when action is intentionally deferred until a time, occurrence
  count, newly affected-user count, or escalation condition. Anectico reactivates it
  once when that condition is met without discarding historical occurrences.
- **Assign** when one current organization member owns the next step.

Deleting error data is not a lifecycle action and is not offered in the Issue view. It
is an API operation, described under **Deleting error data** below; use Ignore or
Snooze to quiet an Issue, and deletion only to remove the data itself.

When a resolved-in-next-release Issue occurs in a qualifying newer release, Anectico
marks it as regressed exactly once. Its Issue Story retains the resolution baseline,
shows the regression release, and records the automatic transition in **Lifecycle
history**. A clean intervening release is not blamed. Lifecycle and assignment
writes use the displayed Issue revision; if another responder changed the same
field first, refresh the Issue instead of silently overwriting their decision.

## Deleting error data

Deletion is separate from triage: lifecycle actions decide what an Issue *means*, and
deletion removes the data. It is available through the API only, requires
`errors:delete` (owners and admins), and is permanent — there is no undo, and later
occurrences matching what you deleted stay deleted.

- **Delete one Issue** — `DELETE /api/v1/errors/groups/{group_id}?project_id=…` removes
  the Issue and every occurrence of it. The same failure in another project is a
  separate Issue and is untouched.
- **Erase one customer's errors** — `DELETE /api/v1/persons/{person_id}/errors?project_id=…`
  removes every error occurrence belonging to that person, across every identity they
  have used — the anonymous session as well as the signed-in account. Pass either their
  person ID or any of their distinct IDs; the response lists the identities it acted on.

Erasing a customer leaves the Issues standing, because a failure other customers also
hit is not one person's data; their occurrence and affected-customer counts drop to what
remains. It covers errors only — traces, logs, metrics, product events, and recordings
are removed through their own controls, and none of those has a per-customer delete.

## Link external work

After connecting GitHub, Jira, or Linear, create a provider ticket from the Issue and keep the link on
the Issue rather than copying status into comments:

For GitHub, enter the target repository as exact `owner/name`. The repository is optional only when
the active connection already has a default repository; ordinary GitHub App installations do not
select one default because they may cover multiple repositories.

```bash
ISSUE_ID="grp-7f9c2a1e"
ISSUE_URL="https://app.anectico.com/issues/${ISSUE_ID}"
TICKET_CREATE_KEY="ticket.jira.grp-7f9c2a1e.v1"

anectico tickets create "$ISSUE_ID" \
  --provider jira \
  --issue-url "$ISSUE_URL" \
  --idempotency-key "$TICKET_CREATE_KEY"
anectico tickets list "$ISSUE_ID"
```

Copy the returned `id` and inspect the link with `anectico tickets get <ticket-link-id>`.
Use one canonical provider ticket for the fix; keep the investigation evidence in Anectico.

### Retry ticket creation safely

For ambiguous failures, keep the same active project, `--idempotency-key`, Issue ID, title
(including the default), provider, Issue URL, and GitHub repository. A retry returns the existing
link; changing the create fields is rejected.

| Result | What to do |
| --- | --- |
| Rejected before contacting the provider, such as a missing GitHub repository | Correct the setup and submit again. The rejection does not reserve the Issue's provider-ticket slot. |
| Timeout or interrupted provider request | Retry the unchanged request with the same key. The provider may already have created the ticket. |
| “Ticket creation is already in progress” | Retry with the same key. Anectico holds ambiguous requests for up to 15 minutes while provider search catches up, then returns the existing ticket or creates one if none exists. Explicit provider rejections are not held. |
| `PROVIDER_EFFECT_UNRECORDED` | Do not generate a fresh key. The CLI shows this structured remedy and any returned, bounded ticket ID or URL; ordinary server-fault details remain redacted. |
| Pinned destination is unavailable | Restore the original connection and repository, project, or team, then retry with the same key. Changing the active connection does not redirect a create that already reached the provider. |
| You intentionally want a new ticket after unlinking | Use a new idempotency key. Unlinking removes only the Anectico relationship, not the provider ticket. |

An idempotency key is project-scoped: reusing it in another project creates a separate ticket.
Use a non-secret label of 1–128 ASCII letters, digits, `.`, `_`, `:`, or `-`; do not include
credentials or customer data.

The Issue URL must be an absolute `/issues/<issue-id>` link on your trusted Anectico dashboard
origin. List/get results report the pinned connection, sync state, attempt count, last successful
sync time, and a safe failure code.

## Improve future evidence

If the Issue lacks a customer, replay, readable stack, or release, fix that instrumentation gap while
the failure is fresh. See [Identify customers](/docs/instrument/identity), [Record session replay](/docs/instrument/session-replay), and [Capture errors and releases](/docs/instrument/errors).

## Check customer recovery after a fix

Open the Issue's **Customer recovery** tab. Choose the exact success event your
application emits for this workflow, an optional environment, when to start finding
affected customers, and the start/end of outcome observation. For example, use
`checkout_completed` to check whether customers who hit a checkout error later
completed checkout. Use an environment filter to keep test successes separate from
production failures. The combined window is limited to seven days, must end no later
than now, and must fit within your readable retention period.

The baseline is `[baseline_start, observation_start)`. Only people with an attributed
occurrence of this issue in that baseline enter the report. The outcome window is
`[observation_start, observation_end]`. The dashboard includes the issue's currently
loaded merged sources; API/CLI/MCP callers provide their desired source group IDs.

| Outcome | Evidence |
| --- | --- |
| Recovered | A named success event occurred in the outcome window after the last matching failure. |
| Still failing | A matching failure occurred in the outcome window with no later success; a timestamp tie also stays failing. |
| No retry outcome observed | Neither a matching failure nor the named success event was observed in the outcome window. |

Missing activity is not recovery. By default a success describes the named workflow.
Enable **Match the same logical operation and account** to require explicit matching
operation and account identifiers on failures and success events. Missing operation
IDs are excluded in that mode. Neither mode proves that the release caused the outcome. Unattributed failures cannot be followed. Canonical person mappings combine
aliases; unmapped identifiers appear separately as aliases, without customer-profile
links. An unmapped alias is not a canonical person ID, even if its text looks like one.

The check button returns an on-demand live report. Saved watches, described below,
retain their original baseline references and observe in the background. Late events, identity corrections,
retention and erasure can change a later report. Up to 500 identities are returned;
when `has_more=true`, the counts describe that displayed subset only. Choose a narrower
window or issue-source set to investigate the remainder.

CLI:

```bash
anectico issues recovery --group-ids '<issue-id>,<merged-source-id>' \
  --success-event checkout_completed --environment production \
  --baseline-start '2026-09-09T08:00:00Z' \
  --after '2026-09-09T10:00:00Z' --until '2026-09-09T12:00:00Z'
```

Replace the example dates with your own completed observation window. REST:
`POST /api/v1/errors/recovery?project_id=…` with JSON fields `group_ids` (1–50),
`success_event`, optional `environment`, `baseline_start`, `observation_start`, and
`observation_end` (RFC3339). MCP: `execute_read_action` with `customer_recovery` and the
same fields plus `project_id`. All surfaces require `persons:read`, `errors:read` and
`analytics:read`; MCP also requires `mcp:read`. Organization and project authority come
from the credential and scoped request, never from telemetry identity fields.


### Save a recovery watch

Under the report, enter a watch name and how many more hours to observe, then choose
**Save recovery watch**. The existing baseline, issue source IDs, success event,
environment and operation/account settings become its fixed definition. The combined
baseline and observation period must fit within seven days, with 1–500 baseline
outcomes. There can be at most 100 watches per organization.

The observer checks periodically (normally once a minute), records when evidence
changes, and continues for a day after the observation window closes to catch late
arrivals. Event timestamps must still lie inside the original window. The dashboard
refreshes observation status and the selected report. It does not send customers,
Slack channels or email recipients automatic messages in this version.

A watch stores references to baseline failures, not a copy of customer telemetry.
Newly arriving historical failures do not expand that saved baseline. Every report
rechecks current identity mappings, retention, erasure and the caller's read scopes.
The original baseline size and currently readable outcomes can therefore differ.
Unavailable or missing evidence must not be treated as recovered. Deleting a watch
permanently removes its definition and baseline references; project or organization
deletion also removes its watches.

REST, with `project_id` in the query:

- `POST /api/v1/errors/recovery-watches`: `id` (caller-owned UUID), `title` (1–120
  bytes), and `criteria` using the recovery request fields with a future
  `observation_end`. Reuse the same UUID and body after an uncertain response.
- `GET /api/v1/errors/recovery-watches`: optional `group_id` filter. Returns metadata
  and observation timestamps, without a cached report.
- `GET /api/v1/errors/recovery-watches/{id}`: current readable report.
- `DELETE /api/v1/errors/recovery-watches/{id}`: remove the watch.

MCP watch reads also return `created_by` and `created_at`, matching the REST and CLI
responses. Watch creation requires an observation end in the future; the on-demand
`customer_recovery` report instead requires an end no later than now.

Both the on-demand request and watch criteria accept `match_operation` (boolean)
and paired `account_type` / `account_key`. A report includes logical operation/account
keys and baseline/failure/success evidence IDs when available. In operation mode,
counts are outcomes per person, operation and account, rather than unique people.
The `baseline_error_ids` wire field is reserved for stored baseline references;
creation ignores caller-supplied values and materializes its own verified baseline.

Watch reads require `persons:read`, `errors:read`, `analytics:read`; creation and
deletion additionally require `errors:write`. CLI:

```bash
anectico issues recovery --match-operation --account-type company --account-key acme \
  --group-ids '<issue-id>' --success-event checkout_completed \
  --baseline-start '<RFC3339>' --after '<RFC3339>' --until '<RFC3339>'
anectico issues watches create --file recovery-watch.json
anectico issues watches list --group-id '<issue-id>'
anectico issues watches get '<watch-id>'
anectico issues watches delete '<watch-id>' --yes
```

MCP reads are `list_recovery_watches` and `get_recovery_watch`; admin write actions
are `create_recovery_watch` and `delete_recovery_watch`, using the existing preview
and confirmation flow. The create action takes `id`, `title` and `criteria` including
`project_id`. See [activity context](/docs/instrument/identity#account-and-operation-context-at-the-time-of-activity)
and [diagnostic capture](/docs/instrument/diagnostics#capture-the-next-retry).

## Add the customer's report and compare evidence

The **Problem reports** tab shows explicit submissions that name this Issue. The
**Compare customers** tab compares attributed people with an explicit-success control
cohort in the same window. These are separate evidence sources: a customer's report is
not automatically an exception, and an attribute difference is not proof of cause.

- [Collect and investigate problem reports](/docs/investigate/problem-reports)
- [Compare affected and successful customers](/docs/investigate/customer-comparison)

The replay player's **Highlights** tab links recorded moments to playback timestamps,
Issues and backend traces. No activity is never interpreted as successful recovery.
