--- name: submit-a-referral description: Submit a new referral or deal registration on behalf of a partner through chat — fetches the partner's referral form, collects the answers, and sends it via EULER MCP tools. Use this skill whenever a partner wants to register/submit a referral or deal — phrases like "submit a referral", "register a deal", "send a new referral", "I want to refer a company", "register a company as a deal". Partner-facing write action (only a partner can submit their own referrals — a customer admin cannot). --- # submit-a-referral — register a referral through chat ## When to use this skill Invoke when **a partner** wants to **submit a new referral / deal registration** through chat — an interactive write: fetch the partner's form, collect the answers, confirm, send. - "Submit a referral" / "Send a new referral" / "I want to refer a company" - "Register a deal" / "Register {Company} as a deal" / "Log a new deal registration" - `/euler-for-partner-managers:submit-a-referral` DO NOT invoke for: - **Viewing referrals already submitted** — that is `my-referrals` (the read worklist: status of existing referrals). This skill *creates* a new one. - **A customer admin managing partners' referrals** — submitting is a partner-side action; a customer admin cannot submit a partner's referral (the gate blocks them). - Anything that is not a brand-new referral/deal submission. The distinction that selects this skill: **the connected account is the partner, and the intent is to send a NEW referral**, not read existing ones. ## Account type — required: partner This skill is a **partner write** — submitting a referral is the partner's own action. It needs a connection with a `type === 'partner'` entry. **Step 1 is always `list_accounts`.** Apply the account gate in [`references/account-gate.md`](references/account-gate.md) before anything else: - Connected account has a `type === 'partner'` entry → proceed (partner context); take `partner_id` + `affiliate_company_name` from that entry. - **Customer-only connection** (no `type === 'partner'`) → emit the friendly gate message and **STOP** (do not proceed into a raw `forbidden_scope`): "submit-a-referral is a partner action — only a partner can submit their own referrals. You're connected as a customer admin." Include the `dashboard_url` from the customer entry. - Both roles → proceed as the partner (use the partner entry). - Multiple partner accounts → pick by `affiliate_company_name` (the customer to submit to); if ambiguous, ask. One partner + customer pairing per invocation. `partner_id` comes **only** from the chosen `type: 'partner'` entry — **never** from `partner_directory_search` (its `profile_id` is rejected downstream as `partner_not_in_consent`). Translate any escaping `forbidden_scope` into the friendly message; never show the user `forbidden_scope` or any `euler_*` code. ## Flow (exact — do not deviate) Two MCP calls bracket an interactive collect-and-confirm. For exact response field paths and the `answer_field` mapping, consult [`references/mcp-field-paths.md`](references/mcp-field-paths.md). | # | Step | What happens | |---|------|--------------| | 1 | `list_accounts` | Account gate + `partner_id` + customer `affiliate_company_name`. | | 2 | `referrals(action:'get_form_for_partner', partner_id)` | Fetch the form → `form_id`, `questions[]` (each with `question_id`, prompt, `answer_field`), `question_count`, `presentation_guidance`. | | 3 | **Present + collect** | Present the questions to the user **following `presentation_guidance`** (especially for long forms — chunk/group as it says); collect every **required** answer. | | 4 | **CONFIRM with the user** | Read back the collected answers (referred company + type + key answers) and get an explicit go-ahead **before** sending. | | 5 | `submit_referral(partner_id, form_id, answers)` | **ONE** write. `answers` = JSON array of `{question_id, answer_text, multiselect_options[]}`; place each value in the field its question's `answer_field` names. | Then render the confirmation card (§ Output). On error, no success card — surface the friendly reason instead. ## Write discipline (not optional) This is a **write** skill — these rules are the whole point. Treat them as hard constraints, not suggestions: 1. **ONE `submit_referral` call per logical request. NEVER poll or retry it in a loop.** A 2026-05-07 retry loop created **30 orphan referral rows** from a single request. There is **no polling** of the write — if you must wait for anything, poll a **READ** (`referrals(action:'for_partner')`), never the write. 2. **Trust the MCP's server-side preflight.** It validates the answers against the form and reifies their shape — do **not** re-implement that validation client-side or pre-reject answers it would accept. 3. **`form_id_mismatch` → re-fetch + retry ONCE (deliberate, not blind).** A stale `form_id` means the form changed between step 2 and step 5. Re-call `get_form_for_partner` for the **fresh** `form_id`, re-map the answers, and call `submit_referral` **one** more time. If it still fails, surface the reason and STOP — never wrap the submit in a loop. 4. **Never render a "submitted" card on an error.** On `form_id_mismatch` (after the one retry), validation failure, `forbidden_scope`, or any `euler_*` error — surface the friendly reason + what to fix. A confirmation card means the referral was actually created; never imply success that didn't happen. 5. **Confirm before you send (step 4).** The submit only fires after the user has seen the collected answers and approved them. ## Product how-to questions (`euler_help`) If the user asks how EULER itself works or how to do something in the product — not about their own data — e.g. "how do I register a deal", "where do I find X in the portal", "how does onboarding work" — call `euler_help` with their question and answer briefly from its result. Do not guess about product behavior. This is a tangent to this skill's main job: answer in 1–3 sentences (no HTML report) and return to the task. ## Output A **compact confirmation card** — a single self-contained HTML file (the write's value is the *action*, not a big report). No external CSS/fonts/scripts beyond the one web-font import; opens in a browser, prints, or shares by file/link. ### How to produce the HTML 1. Read [`assets/styles.css`](assets/styles.css) and inline its **FULL** contents into a single `