Skip to main content

Qontak Chat | Chatbot & AI | Structured Guardrails & Decline Quality — Phase 1: Typed Guardrails

HEADER BLOCK

FieldValue
PMDimas Fauzi Hidayat
PRD Version1.0
StatusDRAFT
PRD TypeNEW
EpicPending — add once Epic is created
SquadBOT (Chatbot)
RFC LinkPending — BE + DSAI contract RFC required
Figma MasterPending — designer adds (Guardrail type selector + Answer Corrections page)
AnchorNo — standalone initiative (README); DSAI is a blocking dependency, not a contributing-squad PRD (see §17 OQ-3)
Labelsepic:qontak-chat | module:chatbot-ai | feature:structured-guardrails
Last Updated2026-07-23

Evidence provenance: every number traces to the telesales quality-flag audit (Jun–Jul 2026); code anchors verified against chatbot BE on 2026-07-23 (sync_to_ai_service.rb:110-117 — guardrails merged into one context_clarification blob).

Table of Contents


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

PersonaRoleGoalPainWorkaround
Primary — Org Admin (AI Agent owner)Configures the agent (Profile → Guardrails, Guidance, Capabilities)Refuse abuse firmly, welcome real businesses, never state wrong product factsOne 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 AgentHuman agent receiving handoversGet the not-our-market-yet and price-sensitive customers the bot turns awayThose customers are refused or dead-ended before any human sees themNone — the conversations end inside the bot

4. Non-Goals

  1. Admins still decide what is forbidden. This PRD adds structure and per-type behavior — it does not auto-generate or auto-classify policy content.
  2. No bulk knowledge re-authoring tool. Quick answer correction targets one wrong answer at a time; knowledge files remain the bulk mechanism.
  3. Answer corrections do not edit knowledge source files. They are an override layer on top; the underlying files stay untouched.
  4. No multilingual refusal template variants in Phase 1 — one canonical refusal template per agent (in the agent's configured language).
  5. No changes to close/handover decisions on buying-intent conversations — that is the Lead Protection ADJUSTMENT.
  6. 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).
ElementBeforeAfter
Guardrail rowName + descriptionName + description + type selector
Refusal wordingLLM-generated, 3 variants observedOne editable canonical template, used verbatim
Not-our-market inquiryRefused like abuseQualified + 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%.
ElementBeforeAfter
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

#BehaviorEntity AffectedTriggered ByExpected BehaviorFailure Behavior
1Save typed guardrailsAI Agent profile (guardrails carry type + refusal template)Admin saves the Guardrails sectionPersisted 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
2Serve a canonical refusalAgent reply in a live conversationCustomer request matches a Forbidden guardrail (AI Service judgment)Reply is the org's template verbatim; ai_agent_guardrail_refusal emitted with template_versionTemplate missing upstream → AI Service falls back to its generated refusal AND the event flags template_version=absent (monitoring catches it)
3Create / update an answer correctionNew: answer-correction record (question pattern, corrected answer, agent scope, status)Admin saves the AddCorrectionDrawerStored 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 StoryAs 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 StateGuardrails 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 DeltaEach guardrail carries Forbidden / Not-our-market; a per-agent refusal template exists; save syncs the structured list upstream.
ImportanceMust Have
Mockup / Technical NotesDesign: 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 input

Before-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 StoryAs 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 StateThe model generates refusal wording freely — 3 near-identical variants observed for the same policy in the audit.
After DeltaEvery Forbidden-guardrail refusal is the org's template verbatim.
ImportanceMust Have
Mockup / Technical NotesDesign: 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 StoryAs 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 StateLegitimate 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 DeltaA Not-our-market guardrail match asks one qualifying question, then hands the conversation to sales.
ImportanceMust Have
Mockup / Technical NotesDesign: 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 StoryAs 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 StateAll 525 audited declines ended the topic with nothing offered.
After DeltaEvery decline ends with an alternative, a sales-handover offer, or a roadmap acknowledgement + follow-up offer; dead-ends are logged.
ImportanceShould Have
Mockup / Technical NotesDesign: 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 StoryAs 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 StateFixing one wrong bot answer means editing knowledge files and re-training/re-vectorizing — days of latency. No override layer exists.
After DeltaThe Answer Corrections page stores per-question overrides that reach live replies ≤ 5 minutes after save.
ImportanceShould Have
Mockup / Technical NotesDesign: 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) — system

Before-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 StoryImportanceAcceptance Criteria
[SGDQ-NEG-01] — Guardrail content is never auto-generated (from Non-Goal 1)Guard RailNEG-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 RailNEG-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 RailNEG-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 NameTriggerProperties
ai_agent_guardrail_refusalAgent refuses under a Forbidden-type guardrailroom_id, org_id, guardrail_id, template_version, timestamp
ai_agent_guardrail_redirectAgent qualifies + hands over under a Not-our-market guardrailroom_id, org_id, guardrail_id, outcome (handover/qualified), timestamp
ai_agent_decline_with_alternativeAgent declines a capability but offers an alternative/handoverroom_id, org_id, alternative_type (package/handover/roadmap), timestamp
ai_agent_decline_dead_endAgent declines with no alternative offered (should trend to zero)room_id, org_id, timestamp
ai_agent_answer_correction_createdAdmin saves a correctionorg_id, agent_id, correction_id, author
ai_agent_answer_correction_servedA live reply used a correctionroom_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

StageAudienceDurationSuccess Gate to AdvanceOwner
Internal AlphaStaging + 1 test org1 weekAll ACs pass; correction served ≤ 5 min verified; canonical template verbatim on Forbidden refusalsPM + QA
PilotQontak Telesales org2 weeksWrong-refusal share ≤ 1% on weekly samples; dead-end rate ≤ 20%; zero regression on flag-OFF orgsPM (Dimas)
Closed Beta5–10 customer orgs with active guardrails3 weeksPilot gates sustained across beta orgs; no correction-sync alertsPM + CSM
GAAll Advanced-package orgsOngoingBeta gates sustained 2 consecutive weeksPM + PMM

15. Dependencies

DependencyOwning TeamDeliverable NeededBlocking?
AI Service structured-guardrail supportDSAIConsume 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 READYYES
Canonical refusal template renderingDSAIForbidden refusals reproduce the org's template verbatim (no free generation)YES
Guardrail type selector + Answer Corrections page designDesign (Wulan)Figma frames for both surfacesYES — for UI stories (S01, S05); BE contract work can start without it
Answer-correction injection into agent contextBOT (internal)Corrections delivered to the runtime as high-priority context without re-trainingNO — internal build item

16. Key Decisions + Alternatives Rejected

16a — Decisions Made

DateDecisionRationale
2026-07-23D-1: Exactly two guardrail types in Phase 1 — Forbidden and Not our marketThe 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-23D-2: Hard DSAI dependency — structured schema + canonical template enforced upstream, not simulated via prompt textPM 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-23D-3: Answer corrections are a backend-owned override layer injected as high-priority context — no DSAI schema changeKeeps the DSAI surface limited to guardrails; corrections must take effect in minutes, which retraining and contract cycles cannot deliver
2026-07-23D-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

AlternativeWhy RejectedDate
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 contract2026-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 paths2026-07-23
Auto-classify existing guardrails into types with an LLMRisk of silently relaxing a rule the admin wrote as forbidden; defaulting to Forbidden + badge is safer2026-07-23
A third type "Redirect to human" in Phase 1Overlaps Not-our-market behavior; audit data shows two clean populations2026-07-23

17. Open Questions

#TypeQuestionOwnerDeadline
1RiskDSAI 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) + DSAIBefore READY
2RiskOne 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
3Open QuestionDoes the DSAI work need a formal SUPPORT PRD under an ANCHOR, per hierarchy rules, or is the dated contract in §15 sufficient?PM (Dimas) + TPMBefore READY
4AssumptionTwo 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
5Open QuestionShould decline_dead_end events feed the supervisor alerting initiative (ai-agent-monitoring) as a live signal?PM (Dimas)2026-09-30

PRD CHANGELOG

VersionDateBySectionTypeSummary
1.02026-07-23ClaudeAllCREATEDNEW PRD created from the Jun–Jul 2026 telesales quality audit (~50 wrong refusals, 525 dead-end declines)