Skip to main content
Problems are recurring root causes that Moda discovers by grouping signals (frustrations, tool failures, and other detections) across conversations. Signal attributions land within minutes, and the ranked list is updated automatically as evidence accumulates. These endpoints mirror the Problems dashboard and add a feedback channel that steers discovery. Problem IDs are UUIDs. If a problem was merged into another, its old ID still resolves — responses report the surviving ID in problem_id and set alias_resolved: true.

GET /problems

The ranked problem list with coverage and freshness metadata.

Query parameters

integer
default:"30"
1–90. Bounds which computation runs count toward the list.
integer
default:"25"
1–25. This endpoint’s cap is 25.

Response fields

object
days_back, open_problems, reopened, total_problems, signals_attributed, explained_coverage_pct.
object
The tenant-wide coverage meter: attributed_signals, unexplained_signals, coverage_pct, historically_attributed_signals, historical_coverage_pct.
array
The trusted ranked list — only rows whose verification_status is current, ordered by rank. Each row has problem_id, display_name, cause_statement, lifecycle (open, fixed_monitoring, reopened, resolved), rank_score, rubric_version, total_attributions, family_weighted_count, affected_users, affected_conversations, agg_prm_delta, abandonment_rate, recency_score, trend_score, multi_family, family_counts, coverage_overall, coverage_by_family, audit_pass_rate (or null), verification_status, verified_causal_version.
array
Same row shape as problems, for rows whose verification is failed, unverified, or stale. They are still live problems and still visible, but never ranked. Treat failed and unverified rows as hypotheses; stale rows rank again after re-verification.
object
macros[] — macro themes grouping leaf problems (problem_id, display_name, display_description, tier, child_count, children[]) — and unparented_leaf_count.
array
Provisional problems not yet in the ranked list: problem_id, display_name, display_description, family (or null), evidence_support (report_backed_members, attribution_count), verification_status, provisional: true.
object
When things were last computed: book_computed_at, latest_assignment_at, lag_seconds, discovery (latest session stats or null), verification (counts by status), remainder_backlog (pending_groups, pending_mass).
integer
Feedback rows submitted but not yet applied.

Example

This example is trimmed for readability: with limit=1 only the top-ranked row is shown, and the untrusted rows implied by the verification counts (stale: 1, unverified: 1) are omitted.

GET /problems/:id

Full detail for one problem. Returns 200 with found: false for an unknown or malformed ID — not 404.

Response fields

boolean
false when the ID does not resolve to a problem; all other blocks are then empty or null.
string / string / boolean
The surviving problem ID, the ID you requested, and whether a merged-away ID was folded to its survivor.
object | null
The same row shape as the list on GET /problems.
object | null
The latest problem definition: version, cause_statement, display_name, display_description, lifecycle, parent_problem_id, change_reason, match_criteria, counter_examples, scope_hints, updated_at, tier (macro or leaf), provisional, affected_surface, causal_content_version.
array
Rank history: {run_ts, rank_score, total_attributions, rubric_version, coverage_overall} per computation run, newest first.
array
Child problems for macro problems: {problem_id, display_name, cause_statement, lifecycle, version}.
object
audit_pass_rate, judge_audit ({passed, total}), counterfactual_replay ({passed, total}), and samples[] — individual verification checks with kind, passed, rubric_version, conversation_id, segment_id, rationale, verified_at.
array
A first page of evidence rows (see /problems/:id/evidence for the full paginated set and field list).
array
{conversation_id, user_id, signal_count, family_counts, last_signal_at} rollups.
object
The same tenant-wide coverage meter as the list endpoint.
object
First page of investigation reports: {items[], has_more, next_cursor} (full set on /problems/:id/reports).
object
Verification confidence for the current problem version: current_rubric_version, causal_content_version, verification_status, audited_causal_content_version, per-version breakdowns (current, stale), and passed/failed samples.
array
Lineage events: {problem_id, event_id, event_kind, related_problem_id, rubric_version, causal_content_version, reason, created_ts}.
object
known_users, unknown_identity_conversations, total_conversations, identity_coverage_pct — impact is split so conversations without a known user are never reported as zero users.
object
tier, parent (or null), children[].
object | null
Precomputed narrative blocks (executive_summary, causal_chain, suggested_investigation, representative_story_keys, limitations) plus computation metadata. null until a dossier has been generated.
array
Representative examples, each {story_kind, evidence, verification} where story_kind is one of top_confidence, ground_truth_passed, disputed, replay_verified, newest.

Example

The example trims header to a few fields for readability; the live response returns the complete list-row shape documented under GET /problems.

GET /problems/:id/reports

Investigation reports for one problem, keyset-paginated.

Query parameters

integer
default:"20"
1–50.
string
The next_cursor from a previous page.
Each report has report_id, conversation_id, segment_id, status (investigated, no_problem, or rejected), problem_found, mechanism, narrative, citations[] ({path, ref, quote}), signals_explained, signals_total, signals_explained_ids[], signals_unexplained_ids[], suspected_surface, severity, confidence, primary_family, investigated_at.

GET /problems/:id/conversations

Conversations attributed to one problem, keyset-paginated, with per-conversation counts and an anchor for deep-linking.

Query parameters

integer
default:"25"
1–50.
string
The next_cursor from a previous page.
string
Filter to one signal family (for example tool_failure, emotion).
string
How the conversation joined the problem: rubric_match or local_causal_chain.
Use latest_anchor.anchor_msg_index with /conversations/:id/context to read the moment the signal fired.

GET /problems/:id/evidence

All evidence attributions for one problem, keyset-paginated. Rows have the same shape as the evidence block on GET /problems/:id: attribution_id, conversation_id, segment_id, anchor_signal_id, anchor_msg_index, signal_family, signal_type, confidence, causal_rationale, door, replay_verified (or null), evidence_snippet, dedup_count, user_id, assigned_at, snippet_parsed (structured parse of evidence_snippet, null for legacy raw-text rows), snippet_legacy_raw_text, report_id (or null for fast-lane rows).

Query parameters

integer
default:"25"
1–50.
string
The next_cursor from a previous page.

POST /problems/:id/feedback

Records feedback on a problem. Feedback does not edit the problem directly — it is incorporated automatically. mark_fixed also arms automatic reopening if the problem recurs. This is the endpoint behind moda problem-feedback.

Body fields

string
required
One of mark_fixed, dismiss, flag_attribution, rename.
string
Up to 2,000 characters. Required for dismiss and flag_attribution.
string
Required for flag_attribution. A non-UUID value returns 400; a UUID that does not belong to this problem returns 404.
string
Up to 255 characters. Required for rename.
string
default:"data-api"
Recorded as the acting identity, up to 255 characters.
This endpoint is idempotent: feedback_id is derived deterministically from the payload, so resubmitting identical feedback while it is still pending returns the same feedback_id with duplicate: true and records nothing new. Safe to retry.
A malformed (non-UUID) problem ID returns 400.

GET /problems/:id/feedback

Feedback history for one problem, with pending/consumed state.

POST /feedback

General feedback about data quality — a wrong cluster label, a mismatched frustration cause, missing data. This is separate from problem feedback (which moda problem-feedback sends): it flags issues with what the Data API returned, and it is what moda feedback sends. Returns 202.

Body fields

string
required
One of bad_cluster_label, mismatched_frustration, missing_data, noisy_data, wrong_tool_failure, incorrect_loop, api_quirk, other.
string
default:"low"
One of info, low, medium, high.
string
Up to 4,000 characters describing what looked wrong.
string
One of cli, sdk, ui.
string
The agent submitting the feedback, up to 64 characters.
string
Up to 32 characters.
object
Free-form references, for example {"conversation_id": "...", "tool_name": "..."}.
object
Free-form context about the command or query that produced the suspect result.
Unlike problem feedback, this endpoint is not idempotent — every request creates a new feedback record with a random feedback_id. Do not retry it automatically.

Next steps

  • Dashboard: Problems — the same problem book as a kanban with dossiers.
  • Signals — the raw detections that problems are built from.
  • Conversations — read the context around any evidence anchor.