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 (traces affected), 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. Returns200 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
Per-trace
{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 traces 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.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
Traces attributed to one problem, keyset-paginated, with per-trace 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 trace joined the problem:
rubric_match or local_causal_chain.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 theevidence 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.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 (whichmoda 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.
Next steps
- Dashboard: Problems — the same problem book as a kanban with dossiers.
- Signals — the raw detections that problems are built from.
- Traces — read the context around any evidence anchor.
Problem impact within use cases
GET /api/v1/data/problem-impact connects attributed problem evidence to the
use-case segments in which it occurred. Authenticate with the same API key as
other Data API endpoints; tenant scope comes from that key.
Select a node, a problem, or both.
catalog lists available use cases and
problems. overview returns the distinct affected share for root use cases
(or the selected node’s children). A parent problem includes its current leaf
problems.
affected-use-cases returns affected counts without full population
denominators. trace-use-cases resolves current use-case membership from a
problem’s attributed segments for the specified traces across their history;
it does not apply the days window.
The response includes runId, resolved problemId, window, nodes,
problems, rows, evidence, nextCursor, and computedAt. Metric rows have
node_id, problem_id, and period (current or previous). An empty
problem_id identifies the full analyzed population; * identifies the
distinct union of affected traces across selected problems. Use the empty-ID
row’s analyzed denominator for each problem’s percentage. A problem-only
metrics response includes only affected use cases, with each denominator
covering that use case’s full analyzed population. Never add problem
counts to produce a distinct total. Trend rows include a UTC bucket date
and span the current and preceding windows, or all available history for
days=all without a preceding comparison window. Missing dates have no analyzed
population and no rate.
affected / analyzed is affected share, not task failure rate. traces
counts distinct conversations with matching current segments. analyzed
counts conversations containing at least one matching analyzed segment,
including negative analysis outcomes. segments and analyzed_segments
expose partial analysis coverage. users counts distinct nonempty identities
on affected evidence; identified_traces provides identity coverage.
Evidence returns up to 25 distinct conversations per page with the exact
segment_id and zero-based anchor_msg_index. Continue using nextCursor,
runId, window.to, and the original filters. A cursor from another scope is
rejected. Unmapped evidence is excluded from scoped results.
These are live reads of the current classification and attribution records,
using segment occurrence timestamps. They are not stored historical
snapshots: regeneration, merges, transfers, and retractions can change past
results. Individual source reads can observe concurrent pipeline updates.
409 requests a classification refresh; query failures remain errors, never
zero-count results. No materialized impact counters or refresh jobs are added.