Qontak Chat | Chatbot & AI | Structured Guardrails & Decline Quality — Phase 1: Typed Guardrails
HEADER BLOCK
| Field | Value |
|---|---|
| PM | Dimas Fauzi Hidayat |
| PRD Version | 1.0 |
| Status | DRAFT |
| PRD Type | NEW |
| Epic | Pending — add once Epic is created |
| Squad | BOT (Chatbot) |
| RFC Link | Pending — BE + DSAI contract RFC required |
| Figma Master | Pending — designer adds (Guardrail type selector + Answer Corrections page) |
| Anchor | No — standalone initiative (README); DSAI is a blocking dependency, not a contributing-squad PRD (see §17 OQ-3) |
| Labels | epic:qontak-chat | module:chatbot-ai | feature:structured-guardrails |
| Last Updated | 2026-07-23 |
Evidence provenance: every number traces to the telesales quality-flag audit (Jun–Jul 2026); code anchors verified against
chatbotBE on 2026-07-23 (sync_to_ai_service.rb:110-117— guardrails merged into onecontext_clarificationblob).
Table of Contents
- HEADER BLOCK
- 2. One-liner + Problem
- 3. Target Users + Persona Context
- 4. Non-Goals
- 5. Constraints
- 6. Scope Changes
- 7. Feature Changes
- 8. New Features
- 9. API & Webhook Behavior
- 10. System Flow + User Stories + ACs
- 11. Rollout
- 12. Observability
- 13. Success Metrics
- 14. Launch Plan & Stage Gates
- 15. Dependencies
- 16. Key Decisions + Alternatives Rejected
- 17. Open Questions
- PRD CHANGELOG
2. One-liner + Problem
One-liner: Give Org Admins typed Guardrails and dead-end-free declines, so the AI Agent refuses only what is truly forbidden and steers every winnable customer toward sales.
Problem:
All Guardrails an admin writes are merged into one undifferentiated instruction (sync_to_ai_service.rb:110-117 concatenates guidances + guardrails into a single context_clarification string), so the agent applies them with one blunt behavior: refuse. In the audited telesales period this refused ~50 genuine businesses (umroh travel, motorbike rental, embroidery) with the same "cannot fulfil that request" used for spyware and spam requests — and produced three different refusal wordings for the same policy. Separately, 525 "not available" replies (free trial, stickers, cheaper packages) ended the topic with no alternative and no handover, dead-ending customers a salesperson could still convert.
3. Target Users + Persona Context
| Persona | Role | Goal | Pain | Workaround |
|---|---|---|---|---|
| Primary — Org Admin (AI Agent owner) | Configures the agent (Profile → Guardrails, Guidance, Capabilities) | Refuse abuse firmly, welcome real businesses, never state wrong product facts | One free-text blob gives no control over HOW the agent refuses; a wrong "not available" answer takes days to fix (knowledge edit + re-train) | Rewording guardrail text and hoping the model interprets it narrowly; re-uploading knowledge files per wrong answer |
| Secondary — Sales / Telesales Agent | Human agent receiving handovers | Get the not-our-market-yet and price-sensitive customers the bot turns away | Those customers are refused or dead-ended before any human sees them | None — the conversations end inside the bot |
4. Non-Goals
- Admins still decide what is forbidden. This PRD adds structure and per-type behavior — it does not auto-generate or auto-classify policy content.
- No bulk knowledge re-authoring tool. Quick answer correction targets one wrong answer at a time; knowledge files remain the bulk mechanism.
- Answer corrections do not edit knowledge source files. They are an override layer on top; the underlying files stay untouched.
- No multilingual refusal template variants in Phase 1 — one canonical refusal template per agent (in the agent's configured language).
- No changes to close/handover decisions on buying-intent conversations — that is the Lead Protection ADJUSTMENT.
- No changes to which requests reach the agent (spam gatekeeping is its own initiative).
5. Constraints
Platform: Web admin (AI Agent editor + AI Agents area) + agent runtime.
Performance: Answer correction takes effect in live conversations ≤ 5 minutes after
save — no re-training, no vector re-build. Guardrail type change takes
effect on next agent sync (≤ 5 minutes).
Data limits: Max 100 active answer corrections per agent (Phase 1); correction text
≤ 1,000 characters; refusal template ≤ 500 characters.
Plan scope: Same plans that have the autonomous AI Agent today (Advanced package).
Feature flag: ai_agent_structured_guardrails | default: OFF (per org)
Read/write: Org Admin: full read/write on guardrail types and corrections.
Agent/Supervisor roles: none in Phase 1.
6. Scope Changes
Backend (typed guardrail persistence + structured sync, answer-correction store and injection, events) · Frontend (type selector + refusal template field in the Guardrails section; new Answer Corrections page) · Design (both surfaces).
7. Feature Changes
Change ID: CHG-001 — Guardrails section gains a type per rule + a canonical refusal template
Change Type: Modified component
Page: /bot-automation/ai-agent/{id} (AI Agent editor, Profile tab → Guardrails)
Page Intent: Admin writes the rules the agent must not break
Before:
- Each guardrail is a free-text name + description; all descriptions are merged into
one instruction (sync_to_ai_service.rb:110-117); the only behavior is "refuse",
worded freshly by the model each time.
After:
- Each guardrail carries a type: "Forbidden" (refuse with the canonical template
verbatim) or "Not our market" (ask ONE qualifying question, then hand over to
sales — never refuse).
- A per-agent "Refusal message" field (pre-filled default, ≤ 500 chars) defines the
canonical template used verbatim for all Forbidden refusals.
- Existing rows default to Forbidden with a "Type defaulted — review" badge (§11.1).
| Element | Before | After |
|---|---|---|
| Guardrail row | Name + description | Name + description + type selector |
| Refusal wording | LLM-generated, 3 variants observed | One editable canonical template, used verbatim |
| Not-our-market inquiry | Refused like abuse | Qualified + handed to sales |
Figma: Pending — designer adds (extends the existing Guardrails section pattern).
Change ID: CHG-002 — Declines never dead-end
Change Type: Modified behavior
Page: N/A — agent runtime behavior
Page Intent: Customer asks for something the product does not offer
Before:
- The agent states the feature/package is not available and ends the topic; all 525
audited declines offered nothing further.
After:
- Every decline must end with exactly one of: (a) the closest available alternative,
(b) an offer to hand over to sales, or (c) a roadmap acknowledgement + follow-up
offer. Encoded as enforced skill-pack behavior shipped with the structured
guardrail sync (DSAI behavior change, §15).
- Dead-end declines are logged (ai_agent_decline_dead_end) and must trend to ≤ 10%.
| Element | Before | After |
|---|---|---|
| Decline reply | "Not available." (topic ends) | "Not available, but [alternative / sales handover / roadmap + follow-up]" |
8. New Features
Feature: Answer Corrections page
URL: /bot-automation/answer-corrections (AI Agents area; final placement with design)
Access: Org Admin (same role that edits the autonomous AI Agent today)
Component Tree:
AnswerCorrectionsPage
├── CorrectionsTable — list of active corrections (question pattern, corrected
│ │ answer, author, created date, status)
│ ├── CorrectionRow — one correction, with edit/disable actions
│ └── EmptyState — no corrections yet
├── AddCorrectionDrawer — create/edit form
│ ├── QuestionField — the customer question / topic the correction applies to
│ ├── CorrectedAnswerField — what the agent should say (≤ 1,000 chars)
│ └── AgentSelector — which agent(s) the correction applies to
└── UsageBadge — per row: times served (from correction_served events)
UI States:
Empty: "No answer corrections yet. Correct a wrong answer without re-training your
agent." + [Add correction] button.
Loading: Skeleton rows (3) while fetching.
Error: "Could not load corrections. Try again." + Retry. Log: correction_page_load_error.
Success: Table with corrections, usage badges, and per-row status (Active / Disabled).
Figma: Pending — designer adds (fits the bot-automation / AI Agents module page patterns).
9. API & Webhook Behavior
| # | Behavior | Entity Affected | Triggered By | Expected Behavior | Failure Behavior |
|---|---|---|---|---|---|
| 1 | Save typed guardrails | AI Agent profile (guardrails carry type + refusal template) | Admin saves the Guardrails section | Persisted with the agent config; agent re-sync sends the STRUCTURED guardrail list to the AI Service (replaces today's merged blob) — DSAI contract, §15. (RFC resolves: exact skill-pack schema.) | Validation error if a guardrail lacks a type (flag-ON orgs); sync failure → existing editor retry pattern, config not lost |
| 2 | Serve a canonical refusal | Agent reply in a live conversation | Customer request matches a Forbidden guardrail (AI Service judgment) | Reply is the org's template verbatim; ai_agent_guardrail_refusal emitted with template_version | Template missing upstream → AI Service falls back to its generated refusal AND the event flags template_version=absent (monitoring catches it) |
| 3 | Create / update an answer correction | New: answer-correction record (question pattern, corrected answer, agent scope, status) | Admin saves the AddCorrectionDrawer | Stored backend-side; injected into the agent's context as high-priority guidance on next sync (≤ 5 min). No knowledge file modified; no re-training. (RFC resolves: injection mechanism, matching semantics, dedup with existing knowledge.) | Over the 100-correction cap → save blocked with explanation; sync failure → correction shows "Pending sync" with retry |
10. System Flow + User Stories + ACs
10.1. System Flow
Flow: Customer request meets a typed guardrail / capability decline
Type: User Journey
1. Admin has typed guardrails + a refusal template configured (flag ON, synced)
2. Customer sends a request on WhatsApp
3. Agent evaluates the request against its guardrails (AI Service)
4. Branch — Forbidden match: agent replies with the canonical refusal template
verbatim → ai_agent_guardrail_refusal
5. Branch — Not-our-market match: agent asks ONE qualifying question, then hands the
conversation to sales → ai_agent_guardrail_redirect
6. Branch — no guardrail match, but the request needs a capability/package we lack:
agent declines WITH an alternative, sales-handover offer, or roadmap follow-up
→ ai_agent_decline_with_alternative (dead-ends logged separately)
7. Branch — agent's answer is wrong (admin discovers it): admin adds an answer
correction → served in live replies ≤ 5 minutes, no re-training
8. Failure branch: template missing upstream → generated refusal + flagged event (§9 B2)
📊 System Flow — Typed Guardrails & Decline Handling
graph TD
A[Customer request] --> B{Matches a<br/>guardrail?}
B -- Forbidden --> C[Reply = canonical template verbatim]
C --> C1[Event: guardrail_refusal]
B -- Not our market --> D[Ask 1 qualifying question]
D --> E[Hand over to sales]
E --> E1[Event: guardrail_redirect]
B -- No match --> F{Request needs a missing<br/>capability/package?}
F -- No --> G[Normal answering incl. corrections]
F -- Yes --> H[Decline + alternative /<br/>sales offer / roadmap follow-up]
H --> H1[Event: decline_with_alternative<br/>or decline_dead_end]
I[Admin saves answer correction] -.served <= 5 min.-> G
10.2. User Stories
[SGDQ-S01] — Admin assigns a type to each Guardrail and edits the refusal template
| User Story | As an Org Admin, I want to say HOW the agent should treat each guardrail — refuse or redirect, so that abuse is refused firmly while real businesses are welcomed. |
| Before State | Guardrails are free-text rows merged into one instruction (sync_to_ai_service.rb:110-117); no type, no template — the model invents refusal wording. |
| After Delta | Each guardrail carries Forbidden / Not-our-market; a per-agent refusal template exists; save syncs the structured list upstream. |
| Importance | Must Have |
| Mockup / Technical Notes | Design: Pending — designer adds. Data Fields: • guardrail.type (enum forbidden/not_our_market, required flag-ON) — admin input• profile.refusal_template (text ≤ 500 chars, default provided) — admin inputBefore-After Behavior: Admin previously wrote free text and hoped; after this story each rule has an enforced behavior and one approved refusal wording. |
| Acceptance Criteria | — Happy Path — • AC-1: Given my org has the ai_agent_structured_guardrails flag, when I open Profile → Guardrails, then every guardrail row shows a type selector (Forbidden / Not our market) and the agent-level "Refusal message" field with the default template.• AC-2: Given I set a guardrail to "Not our market" and save, then the config persists and the structured guardrail list is synced to the AI Service on the next agent sync (≤ 5 minutes). • AC-3: Given the flag just turned ON for my org, when I open Guardrails, then all pre-existing rows are typed "Forbidden" with a "Type defaulted — review" badge, and behavior is no more permissive than before. • AC-4: Given I try to save a new guardrail without choosing a type, then the save is blocked with the editor's standard required-field validation. • AC-5: Given my org does NOT have the flag, then the Guardrails section renders exactly as today (no selector, no template). — Error / Unhappy Path — • ERR-1: Given the agent sync fails after save, then the editor shows the existing sync-retry pattern and my typed guardrails remain saved locally. — Permission Model — • CAN: Org Admin (same role that edits AI Agent settings) • CANNOT: Agent/Supervisor roles without agent-edit permission • Unauthorized: section read-only / not rendered, matching editor-wide behavior — UI States — • Loading: editor-standard skeleton • Empty: no guardrails yet — existing "Add guardrail" affordance, type required on add • Error: editor-standard toast on failed save; ERR-1 retry on failed sync • Success: "AI agent changes saved" toast (existing) |
Dependencies: DSAI structured-guardrail contract (§15)
[SGDQ-S02] — Forbidden requests get one canonical refusal
| User Story | As an Org Admin, I want every refusal to use my approved wording, so that the brand speaks with one voice and refusals are auditable. |
| Before State | The model generates refusal wording freely — 3 near-identical variants observed for the same policy in the audit. |
| After Delta | Every Forbidden-guardrail refusal is the org's template verbatim. |
| Importance | Must Have |
| Mockup / Technical Notes | Design: N/A — WhatsApp conversation output. Before-After Behavior: Refusal wording was model-improvised; after this story it is the approved template, byte-identical every time. |
| Acceptance Criteria | — Happy Path — • AC-1: Given a Forbidden guardrail ("no WhatsApp spying requests") and a synced template, when a customer asks "saya ingin sadap wa istri saya", then the reply equals the template verbatim, and ai_agent_guardrail_refusal is emitted with the template_version.• AC-2: Given 10 different forbidden requests across a week, when their refusals are sampled, then 100% use the identical template text (§13 consistency KPI). • AC-3: Given a request that matches NO guardrail, when the agent answers, then no refusal template is used and no refusal event fires (junk/off-topic falls through to normal answering — §17 Assumption 4). — Error / Unhappy Path — • ERR-1: Given the template is missing upstream (sync gap), when a Forbidden refusal triggers, then the AI Service falls back to a generated refusal AND the event carries template_version=absent (monitoring catches it). — Permission Model — • N/A — runtime behavior; template editing covered by SGDQ-S01 — UI States — • N/A — WhatsApp conversation output |
Dependencies: [SGDQ-S01]; DSAI canonical-template contract (§15)
[SGDQ-S03] — Not-our-market requests are qualified and handed to sales, never refused
| User Story | As a Sales/Telesales Agent, I want out-of-ICP businesses qualified and routed to me, so that we can serve or nurture them instead of insulting them with a refusal. |
| Before State | Legitimate businesses outside the current ICP (umroh travel, motorbike rental) are refused with the same message as spyware requests — ~50 lost leads in the audit. |
| After Delta | A Not-our-market guardrail match asks one qualifying question, then hands the conversation to sales. |
| Importance | Must Have |
| Mockup / Technical Notes | Design: N/A — WhatsApp conversation output; handover uses existing assign paths. Before-After Behavior: Out-of-ICP businesses were refused like abusers; after this story they are qualified and routed to a human. |
| Acceptance Criteria | — Happy Path — • AC-1: Given a Not-our-market guardrail covering consumer-vertical businesses, when a customer writes "tour travel umroh", then the agent asks one qualifying question (business name / need) instead of refusing, and after the customer answers, the conversation is handed over to sales, and ai_agent_guardrail_redirect is emitted with outcome=handover.• AC-2: Given the customer never answers the qualifying question, when the conversation goes idle, then the existing idle behavior applies (no special handling in this PRD). • AC-3: Given a request matching a Forbidden guardrail, when it is evaluated, then it is never treated as Not-our-market (Forbidden wins if both match). — Error / Unhappy Path — • ERR-1: Given no sales handover destination is available (assignment cannot complete), when a Not-our-market redirect triggers, then the agent still asks the qualifying question and does NOT refuse, and the room is left open for a human (outcome=qualified, no handover). — Permission Model — • N/A — runtime behavior — UI States — • N/A — WhatsApp conversation output |
Dependencies: [SGDQ-S01]; DSAI per-type behavior contract (§15)
[SGDQ-S04] — Declines always offer an alternative or a path to sales
| User Story | As a customer whose need the product doesn't exactly meet, I want to hear what IS possible, so that I can still become a customer instead of walking away. |
| Before State | All 525 audited declines ended the topic with nothing offered. |
| After Delta | Every decline ends with an alternative, a sales-handover offer, or a roadmap acknowledgement + follow-up offer; dead-ends are logged. |
| Importance | Should Have |
| Mockup / Technical Notes | Design: N/A — runtime behavior shipped with the structured guardrail sync (§15). Before-After Behavior: Declines were conversation-ending; after this story every decline carries a next step. |
| Acceptance Criteria | — Happy Path — • AC-1: Given a customer asks for a free trial (not offered), when the agent declines, then the reply includes at least one of: closest package option, an offer to connect with sales, or a follow-up offer, and ai_agent_decline_with_alternative is emitted.• AC-2: Given a decline reply contains no alternative (model slip), then ai_agent_decline_dead_end is emitted so the rate is measurable against the §13 targets. |
Dependencies: DSAI behavior contract (ships with the structured guardrail sync)
[SGDQ-S05] — Admin corrects a wrong answer in minutes, without re-training
| User Story | As an Org Admin, I want to patch one wrong answer immediately, so that the bot stops repeating it while the knowledge base catches up. |
| Before State | Fixing one wrong bot answer means editing knowledge files and re-training/re-vectorizing — days of latency. No override layer exists. |
| After Delta | The Answer Corrections page stores per-question overrides that reach live replies ≤ 5 minutes after save. |
| Importance | Should Have |
| Mockup / Technical Notes | Design: Pending — designer adds (§8 component tree + UI states). Data Fields: • correction.question (text, required) — admin input• correction.answer (text ≤ 1,000 chars, required) — admin input• correction.agent_ids (id[], required) — admin input• correction.status (enum active/disabled/pending_sync) — systemBefore-After Behavior: A wrong answer previously took days to fix; after this story it takes minutes. |
| Acceptance Criteria | — Happy Path — • AC-1: Given the bot wrongly says "reaction messages are not supported", when I add a correction ("Reaction messages are supported on WhatsApp inbox since July 2026") scoped to this agent and save, then within 5 minutes new conversations asking about reactions use the corrected answer, and ai_agent_answer_correction_served fires on each use.• AC-2: Given I disable a correction, then it stops being served on the next sync and its row shows "Disabled". • AC-3: Given the agent already has 100 active corrections, when I try to add another, then the save is blocked with a message explaining the Phase-1 cap. • AC-4: Given I enter a corrected answer longer than 1,000 characters, when I try to save, then the field shows a character-limit validation and the save is blocked (§5 data limit). — Error / Unhappy Path — • ERR-1: Given the sync to the runtime fails after save, then the correction row shows "Pending sync" with a retry action, and no stale answer is served as corrected. — Permission Model — • CAN: Org Admin • CANNOT: Agent/Supervisor roles • Unauthorized: page not accessible (same rule as the AI Agent editor) — UI States — • §8 (Empty / Loading / Error / Success) |
Dependencies: None on DSAI (backend-owned injection, §16 D-3)
Negative / Guard Rail Stories (from Non-Goals)
| User Story | Importance | Acceptance Criteria |
|---|---|---|
| [SGDQ-NEG-01] — Guardrail content is never auto-generated (from Non-Goal 1) | Guard Rail | NEG-1: Given the system processes an org's guardrails, when types are assigned or synced, then no guardrail content is ever auto-generated or auto-reclassified — only an admin changes what a rule says or means. |
| [SGDQ-NEG-02] — Corrections never touch knowledge files (from Non-Goal 3) | Guard Rail | NEG-1: Given an answer correction exists for a topic, when the underlying knowledge files are viewed or exported, then they are byte-identical to what the admin uploaded. |
| [SGDQ-NEG-03] — Close/handover decisions untouched (from Non-Goal 5) | Guard Rail | NEG-1: Given a buying-intent conversation is being closed by the bot, when this PRD's features are active, then close/handover decisions are untouched by guardrail typing — that behavior belongs to lead-protection. |
11. Rollout
Feature flag: ai_agent_structured_guardrails (see §5 — OFF by default)
Rollout: Stage 1 → Internal QA (staging org + 1 test org) — 1 week
Stage 2 → Qontak Telesales org (the audited org) — 2 weeks, flag ON
Stage 3 → Closed beta: 5–10 customer orgs with active guardrails
GA → All Advanced-package orgs (flag default flips ON)
Backward compat: Flag-OFF orgs keep today's merged-guardrail behavior exactly.
Migration: Yes — existing free-text guardrails need a type when the flag turns ON.
11.1. Migration Transition Window
Old record behavior: When the flag turns ON for an org, every existing guardrail defaults
to type "Forbidden" — preserving today's refusal behavior for
untouched rows (nothing silently becomes more permissive). The
editor badges these rows "Type defaulted — review".
New record behavior: New guardrails require an explicit type at creation.
Coexistence period: Per org, from flag ON until the admin reviews the defaulted rows —
no hard deadline; the badge persists until reviewed.
End state: All guardrails typed; badge disappears. Flag-OFF orgs never migrate.
11.2. Semantic Regression Rollback
Model flag: ai_agent_structured_guardrails | default: OFF (per org)
Regression metric: Wrong-refusal share — % of refusals hitting genuine business
inquiries, measured on a weekly manual sample of 30 refused
conversations per pilot org (same rubric as the audit)
Rollback threshold: Wrong-refusal share > 15% for a pilot org, or refusal volume rises
> 30% week-over-week with flat traffic
Rollback path: PM turns the org's flag OFF (instant, no deploy) → org reverts to
merged-guardrail behavior; DSAI behavior falls back with the flag
Monitoring: guardrail_refusal / guardrail_redirect volumes (§12), weekly in pilot
12. Observability
Key Events:
| Event Name | Trigger | Properties |
|---|---|---|
ai_agent_guardrail_refusal | Agent refuses under a Forbidden-type guardrail | room_id, org_id, guardrail_id, template_version, timestamp |
ai_agent_guardrail_redirect | Agent qualifies + hands over under a Not-our-market guardrail | room_id, org_id, guardrail_id, outcome (handover/qualified), timestamp |
ai_agent_decline_with_alternative | Agent declines a capability but offers an alternative/handover | room_id, org_id, alternative_type (package/handover/roadmap), timestamp |
ai_agent_decline_dead_end | Agent declines with no alternative offered (should trend to zero) | room_id, org_id, timestamp |
ai_agent_answer_correction_created | Admin saves a correction | org_id, agent_id, correction_id, author |
ai_agent_answer_correction_served | A live reply used a correction | room_id, org_id, correction_id, timestamp |
Dashboard owner: BOT squad
Review cadence: Weekly for the first 4 weeks after each stage, then monthly. Owner: PM (Dimas).
Alerts:
- decline_dead_end > 20% of all declines per org per day → Slack #bot-squad
- correction_served = 0 for 7 days while corrections exist → Slack #bot-squad
(corrections not reaching the runtime — sync problem)
Rollback consideration:
Wrong-refusal share > 15% unresolved for 1 week → PM turns the org flag OFF (§11.2).
13. Success Metrics
⭐ Primary KPI: Wrong refusals of genuine businesses
Definition: Refused conversations judged "real business we should have qualified"
on the weekly 30-conversation sample (audit rubric).
Baseline: ~50 conversations / 7 weeks on the audited org (≈6% of refusals).
Target: ≤ 1% of refusals within 30 days of Stage 2 flag ON.
- Refusal wording consistency
Definition: Distinct refusal variants observed for Forbidden guardrails.
Baseline: 3 near-identical LLM-generated variants (audit).
Target: 1 canonical template per agent, 100% of Forbidden refusals, at Stage 2 exit.
- Decline dead-end rate
Definition: decline_dead_end ÷ all declines.
Baseline: Effectively 100% of the 525 audited declines offered nothing.
Target: ≤ 20% within 30 days of Stage 2; ≤ 10% at GA.
- Time to correct a wrong answer
Definition: Save of an answer correction → correction served in live replies.
Baseline: Days (knowledge re-upload + re-train today).
Target: ≤ 5 minutes, p95, from Stage 1 onward.
14. Launch Plan & Stage Gates
| Stage | Audience | Duration | Success Gate to Advance | Owner |
|---|---|---|---|---|
| Internal Alpha | Staging + 1 test org | 1 week | All ACs pass; correction served ≤ 5 min verified; canonical template verbatim on Forbidden refusals | PM + QA |
| Pilot | Qontak Telesales org | 2 weeks | Wrong-refusal share ≤ 1% on weekly samples; dead-end rate ≤ 20%; zero regression on flag-OFF orgs | PM (Dimas) |
| Closed Beta | 5–10 customer orgs with active guardrails | 3 weeks | Pilot gates sustained across beta orgs; no correction-sync alerts | PM + CSM |
| GA | All Advanced-package orgs | Ongoing | Beta gates sustained 2 consecutive weeks | PM + PMM |
15. Dependencies
| Dependency | Owning Team | Deliverable Needed | Blocking? |
|---|---|---|---|
| AI Service structured-guardrail support | DSAI | Consume a typed guardrail structure (type + description + response behavior) instead of the merged text blob; enforce per-type behavior (Forbidden → canonical template verbatim; Not-our-market → qualify + handover); contract agreed and dated before this PRD moves to READY | YES |
| Canonical refusal template rendering | DSAI | Forbidden refusals reproduce the org's template verbatim (no free generation) | YES |
| Guardrail type selector + Answer Corrections page design | Design (Wulan) | Figma frames for both surfaces | YES — for UI stories (S01, S05); BE contract work can start without it |
| Answer-correction injection into agent context | BOT (internal) | Corrections delivered to the runtime as high-priority context without re-training | NO — internal build item |
16. Key Decisions + Alternatives Rejected
16a — Decisions Made
| Date | Decision | Rationale |
|---|---|---|
| 2026-07-23 | D-1: Exactly two guardrail types in Phase 1 — Forbidden and Not our market | The audit found exactly these two populations conflated (300 correct refusals vs ~50 real businesses); more types = more admin confusion before the model is proven |
| 2026-07-23 | D-2: Hard DSAI dependency — structured schema + canonical template enforced upstream, not simulated via prompt text | PM decision 2026-07-23: do it properly once; an unenforced prompt-level version cannot guarantee template consistency, which is the primary KPI's sibling metric |
| 2026-07-23 | D-3: Answer corrections are a backend-owned override layer injected as high-priority context — no DSAI schema change | Keeps the DSAI surface limited to guardrails; corrections must take effect in minutes, which retraining and contract cycles cannot deliver |
| 2026-07-23 | D-4: On flag ON, existing guardrails default to type "Forbidden" | Never make an org silently more permissive; admins relax rules explicitly (§11.1) |
16b — Alternatives Rejected
| Alternative | Why Rejected | Date |
|---|---|---|
| Prompt-level phase first (restructure the blob text, no DSAI change) | Cannot enforce the canonical template — the model still writes its own refusal; consistency KPI unmeetable; PM chose the enforced contract | 2026-07-23 |
| Ship corrections inside DSAI (AI-Service-side correction store) | Puts a minutes-level product loop behind a cross-team contract; BE injection achieves the same with existing sync paths | 2026-07-23 |
| Auto-classify existing guardrails into types with an LLM | Risk of silently relaxing a rule the admin wrote as forbidden; defaulting to Forbidden + badge is safer | 2026-07-23 |
| A third type "Redirect to human" in Phase 1 | Overlaps Not-our-market behavior; audit data shows two clean populations | 2026-07-23 |
17. Open Questions
| # | Type | Question | Owner | Deadline |
|---|---|---|---|---|
| 1 | Risk | DSAI contract slips and blocks the whole PRD. Mitigation: requirements doc + agreed delivery date is a READY gate (§15); if the date slips > 1 sprint, PM re-decides between waiting and the rejected prompt-level fallback. | PM (Dimas) + DSAI | Before READY |
| 2 | Risk | One canonical refusal template feels too rigid for some brands. Mitigation: template is editable per agent (default provided); one per agent language in Phase 1 (Non-Goal 4). | PM (Dimas) | Closed Beta entry |
| 3 | Open Question | Does the DSAI work need a formal SUPPORT PRD under an ANCHOR, per hierarchy rules, or is the dated contract in §15 sufficient? | PM (Dimas) + TPM | Before READY |
| 4 | Assumption | Two guardrail types cover the audited population (300 forbidden / ~50 real-business); the 626 junk refusals need no type — they match no guardrail and fall through to normal answering. | PM (Dimas) | Pilot exit |
| 5 | Open Question | Should decline_dead_end events feed the supervisor alerting initiative (ai-agent-monitoring) as a live signal? | PM (Dimas) | 2026-09-30 |
PRD CHANGELOG
| Version | Date | By | Section | Type | Summary |
|---|---|---|---|---|---|
| 1.0 | 2026-07-23 | Claude | All | CREATED | NEW PRD created from the Jun–Jul 2026 telesales quality audit (~50 wrong refusals, 525 dead-end declines) |