{ "_about": "Golden dataset for the Help skill (`src/agents/handlers/help.HelpAgent`). Unlike intent/readiness this calls the LIVE model: each case declares an analysis state + report-readiness + chat history, the runner streams HelpAgent.astream for real, and asserts RULES the reply must obey (not text similarity — help replies are free prose with no single correct wording). Metric is COMPLIANCE (% of rule assertions that hold), reported separately for held-out vs carried_over cases.", "_groups": "language (reply matches the user's language — the button-path bug), report_guard (never suggest a report when report_ready.ready=false; do suggest it when true — this also IS the 'no action leakage' check, since generate_report is the only gated action), orientation (quality of the suggested starter questions — MANUAL review, not auto-scored).", "_asserts": "language_match {expected} — detect the reply's language (help._detect_reply_language over the OUTPUT) must equal expected. must_not_contain_any {patterns} — none of the (case-insensitive) patterns appear. must_contain_any {patterns} — at least one appears.", "_carried_over": "carried_over:true rows MIRROR an example in config/prompts/help.md (the row `id` IS the help.md ``). They are the regression guard: if the prompt is refactored, the demonstrated rule must still hold. What is mirrored is the INPUT spec + the assertion — NOT the example's reply text (temperature>0 makes exact match invalid). Held-out rows (carried_over:false) are NOT in the prompt; their compliance is the real generalization signal. If help.md's Examples change, keep these ids in sync (manual, like intent).", "_missing_codes": "report_ready.missing uses codes mapped to the real strings is_report_ready emits (imported in run_eval): analysis -> _MISSING_ANALYSIS, delta -> _MISSING_DELTA. Kept as codes so the dataset survives wording changes.", "schema": { "id": "stable handle; for carried_over rows this equals the help.md example id", "group": "language | report_guard | orientation", "carried_over": "bool — mirrors a help.md example", "manual_review": "bool — run but exclude from the auto compliance rate (read output_text)", "state": "{ analysis_title, objective, business_questions[], report_id }", "report_ready": "{ ready: bool, missing: [analysis|delta] }", "history": "[{ role: human|ai, content }] — drives language on the button path", "message": "the human turn; null = button path (HelpAgent falls back to a per-language trigger)", "asserts": "[{ type, ...spec }] — the rules the reply must obey", "note": "human-readable description" }, "cases": [ { "id": "lang_01", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis penjualan", "objective": "memahami performa penjualan bulanan", "business_questions": ["produk mana yang paling laku?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [{ "role": "human", "content": "aku baru upload datanya, terus aku harus ngapain?" }], "message": null, "asserts": [{ "type": "language_match", "expected": "Indonesian" }], "note": "REGRESSION of the button-path bug: Indonesian conversation, message=null. Reply must be Indonesian, not English." }, { "id": "lang_02", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Sales analysis", "objective": "understand monthly sales performance", "business_questions": ["which products drive revenue?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [{ "role": "human", "content": "okay I uploaded my data, what do I do next?" }], "message": null, "asserts": [{ "type": "language_match", "expected": "English" }], "note": "English conversation, button path — reply must stay English." }, { "id": "lang_03", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis churn", "objective": "menurunkan churn pelanggan", "business_questions": ["segmen mana yang paling banyak churn?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [], "message": "gimana caranya mulai analisis ini ya?", "asserts": [{ "type": "language_match", "expected": "Indonesian" }], "note": "Intent path: the real Indonesian user turn drives the language." }, { "id": "lang_04", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Retention analysis", "objective": "understand user retention", "business_questions": ["what drives repeat usage?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [], "message": null, "asserts": [{ "type": "language_match", "expected": "English" }], "note": "Fresh analysis, no chat yet, button path — with no turn to read, the user-authored goal (English objective + business_questions, required at onboarding) drives the language." }, { "id": "lang_06", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis retensi", "objective": "memahami retensi pengguna", "business_questions": ["apa yang mendorong penggunaan berulang?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [], "message": null, "asserts": [{ "type": "language_match", "expected": "Indonesian" }], "note": "Same fresh-analysis path as lang_04 but the goal is Indonesian — the goal signal must yield Indonesian (not the hard fallback, which only fires when the goal is empty too)." }, { "id": "lang_05", "group": "language", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis penjualan", "objective": "memahami tren penjualan", "business_questions": ["bagaimana tren bulanan?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [ { "role": "human", "content": "apa saja yang bisa aku tanyakan tentang data ini?" }, { "role": "ai", "content": "You can start by asking which products sell the most." } ], "message": null, "asserts": [{ "type": "language_match", "expected": "Indonesian" }], "note": "Last AI turn is English but the human turn is Indonesian — mirror the human, reply Indonesian." }, { "id": "help_ex_guard_delta", "group": "report_guard", "carried_over": true, "manual_review": false, "state": { "analysis_title": "Sales analysis", "objective": "understand monthly sales performance", "business_questions": ["which products drive revenue?"], "report_id": "rep-1" }, "report_ready": { "ready": false, "missing": ["delta"] }, "history": [{ "role": "human", "content": "what should I do next?" }], "message": null, "asserts": [{ "type": "must_not_contain_any", "patterns": ["/report", "generate the report", "generate your report", "create the report"] }], "note": "MIRRORS help.md example help_ex_guard_delta. A report exists and nothing new since — must NOT tell the user to generate a report; steer them to run a fresh analysis first." }, { "id": "help_ex_guard_ready", "group": "report_guard", "carried_over": true, "manual_review": false, "state": { "analysis_title": "Sales analysis", "objective": "understand monthly sales performance", "business_questions": ["which products drive revenue?"], "report_id": null }, "report_ready": { "ready": true, "missing": [] }, "history": [{ "role": "human", "content": "what should I do next?" }], "message": null, "asserts": [{ "type": "must_contain_any", "patterns": ["/report", "report"] }], "note": "MIRRORS help.md example help_ex_guard_ready. Enough analysis done — SHOULD nudge toward the report (mention /report or the report option)." }, { "id": "guard_03", "group": "report_guard", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Retention analysis", "objective": "improve 30-day retention", "business_questions": ["which cohort retains best?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [{ "role": "human", "content": "can I get a report now?" }], "message": null, "asserts": [{ "type": "must_not_contain_any", "patterns": ["/report", "generate the report", "generate your report", "you can generate"] }], "note": "No analysis run yet, user asks for a report directly — must NOT offer to generate; redirect to running an analysis first." }, { "id": "guard_04", "group": "report_guard", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis penjualan", "objective": "memahami performa penjualan", "business_questions": ["produk mana yang paling laku?"], "report_id": null }, "report_ready": { "ready": true, "missing": [] }, "history": [{ "role": "human", "content": "selanjutnya aku ngapain?" }], "message": null, "asserts": [ { "type": "must_contain_any", "patterns": ["/report", "laporan", "report"] }, { "type": "language_match", "expected": "Indonesian" } ], "note": "Ready + Indonesian conversation — should nudge toward the report AND stay in Indonesian (two rules at once)." }, { "id": "guard_05", "group": "report_guard", "carried_over": false, "manual_review": false, "state": { "analysis_title": "Analisis churn", "objective": "menurunkan churn", "business_questions": ["segmen mana yang paling churn?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [{ "role": "human", "content": "aku mau bikin laporan dong" }], "message": null, "asserts": [ { "type": "must_not_contain_any", "patterns": ["/report", "silakan buat laporan", "kamu bisa membuat laporan", "generate your report"] }, { "type": "language_match", "expected": "Indonesian" } ], "note": "Indonesian, not ready, user asks for a report — must NOT offer it and must reply in Indonesian." }, { "id": "help_ex_orient", "group": "orientation", "carried_over": true, "manual_review": true, "state": { "analysis_title": "Sales analysis", "objective": "understand monthly sales performance", "business_questions": ["which products drive revenue?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [], "message": null, "asserts": [], "note": "MIRRORS help.md example help_ex_orient. MANUAL: are the 2-3 starter questions concrete, descriptive-first, and tied to the objective? Read output_text." }, { "id": "orient_02", "group": "orientation", "carried_over": false, "manual_review": true, "state": { "analysis_title": "Retention analysis", "objective": "improve 30-day retention", "business_questions": ["which acquisition channel retains best?"], "report_id": null }, "report_ready": { "ready": false, "missing": ["analysis"] }, "history": [ { "role": "human", "content": "which channel brings the most signups?" }, { "role": "ai", "content": "Organic search brought the most signups last month (1,240)." } ], "message": null, "asserts": [], "note": "MANUAL: one question already answered — does help build on it with a NEW follow-up (retention by channel), not re-suggest the answered question? Read output_text." } ] }