Skip to main content

Qontak Chat | Chatbot & AI | AI Agent Configuration — Adj: SOP-Based Simplified Configuration

HEADER BLOCK

FieldValue
PMDimas Fauzi Hidayat
PRD Version1.6
StatusREADY
PRD TypeADJUSTMENT
EpicBOT-4733
SquadBOT (Chatbot)
RFC LinkRFC — SOP Steps, Derivation & Lint
Figma MasterN/A — design lives in qontak-designer branch feat/ai-agents-ut-updates (Steps/SOP capability model)
AnchorYes — Autonomous AI Agent — ANCHOR
Labelsepic:qontak-chat | module:chatbot-ai | feature:ai-agent-simplified-config
Last Updated2026-07-23

Decision provenance: every design decision in this PRD is committed in the grilling decision register D1–D9 (2026-07-22). Code anchors verified against chatbot BE (sync_to_ai_service.rb, process_async_reply.rb) on 2026-07-22.

Table of Contents

2. CONDITIONAL BLOCK: ADJUSTMENT CONTEXT

FieldDetail
Parent Anchor PRDAutonomous AI Agent — ANCHOR
This adjustment coversThe tenant configuration surface of the shipped V2 autonomous agent: (a) the capability authoring model (hand-authored required_slots / milestones / gates / completion → SOP Steps with BE derivation), (b) a save-time linter in SyncToAiService, (c) enum-exit handling in process_async_reply (assign-to-human target application; probe-gated resolve), (d) the capability-drawer rebuild onto the Steps card (the shipped editor is already 3-tab — grounded 2026-07-22, AiAgentEditor.vue:3056-3060), (e) migration behavior for existing V2 agents (derive-on-save), and (f) disabling the shipped Refine rail for flag-ON orgs (CHG-007) pending its Steps-model reconciliation.
Parent PRD still ownsThe V2 runtime engine itself: RAG pipeline, action executors (ActionExecutorFactory / CredentialResolver), the DSAI skill_pack wire contract (unchanged by design), capability vector stores, the async reply pipeline's non-exit paths, and V1 (tree) agents.
Reason for adjustmentEvidence-driven: the ut-2026-06-23 usability study (16 participants) found Milestones = the #1 configuration blocker across every batch and both external clients, with non-technical users unable to self-serve ("no hope" — Rere); the RFC gap analysis (rfc-gap-analysis-2026-07-04.md) confirmed the RFC's own worked examples contain the misconfigurations (circular gates, slot mismatches, dangling targets) that tenants are asked to avoid by hand. Iteration-II UT (ut-2026-07, merged 2026-07-23) validates the direction: "Steps" fixed the Milestone blocker and the merged flow removed "same work three times" (both Strong) — verdict "move toward a limited pilot", pending an external non-technical round.
Scope boundaryProducer-side + FE + linter change behind flag ai_agent_simplified_config. Touches sync_to_ai_service.rb (derivation + lint), process_async_reply.rb / send_message_with_resolve (enum-exit handling), and the chatbot-fe bot-automation editor. No skill_pack wire-format change, no RAG schema change, no executor change.

3. One-liner + Problem

One-liner: Let tenant admins configure a working AI agent by writing their SOP as ordered Steps — while Chatbot BE derives and lints the slots, milestones, gates, and completion they can't reason about.

Problem: The shipped V2 config surface asks tenants to hand-author wire-model artifacts (required_slots, milestone names + action maps, requires_milestone gates, completion types) that even technical users misconfigure — the ut-2026-06-23 study found Milestones incomprehensible to nearly all 16 participants, and the field's recurring production failure modes (premature action fire, deadlocked gates, dead-end error handling) trace directly to this authoring burden. Full background: Autonomous AI Agent — ANCHOR and the D1–D9 decision register.

4. Target Users + Persona Context

Personas inherited from parent: Autonomous AI Agent — ANCHOR.

Adjustment-specific persona note — the ut-2026-06-23 study segments configuring users into three types whose gap this adjustment closes:

PersonaRoleGoalPainWorkaround
Primary — Non-technical tenant admin (CS lead / Sales manager, e.g. external participants Dewa, Billy)Configures the AI agent for their orgLaunch a transactional agent without a specialistHits a wall at Capabilities/Milestones ("no hope" without help; self-rated 60% confidence)Relies on the Qontak activation team for every config change (analytics-2026-05: one champion per account across 109 creators)
Secondary — Technical tenant admin (IT / systems role)Builds complex multi-capability agentsExpress nested SOP logic safelyRecovers from Milestone confusion but wastes time reverse-engineering the wire model; routing feels duplicated across three surfacesReads DSAI RFC examples — which are themselves misconfigured
System — Chatbot BE / DSAI teamsProduce and consume the skill_packOne documented producer of the wire formatThree teams read a spec nobody runs (RFC drift, gap analysis C1/C4)Tribal knowledge per team

5. Non-Goals

  1. Changing the skill_pack wire format or DSAI runtime validators — the whole point is producer-side derivation behind the existing contract. Any THEN option or completion type with no wire representation is cut, not contracted (D8).
  2. Extending the shipped Refine flow to the Steps model — Refine is now live end-to-end (BE post '/refine' ai_agents_controller.rb:404, landed 2026-07-10 BOT-4594; FE useRefineAgent.ts calling PATCH /v2/ai_agents/:id/refine, landed 2026-07-14 — supersedes v1.1's stale "zero consumers" evidence). Its pack builder (use_cases/mappers/skill_pack_builder.rb) operates on the authored-field capability shape, so it cannot serve derived Steps-model agents unchanged. MVP decision: Refine is disabled for flag-ON orgs (CHG-007); reconciling Refine with the Steps model is a follow-up phase (§16 row 7). Flag-OFF orgs keep shipped Refine untouched. (D7, re-based on grounding 2026-07-22.)
  3. Tier-2 advanced overrides (manual gate editing, milestone_reached completion, per-skill turn_budget) — reserved for a future Advanced panel; MVP ships zero Tier-2 decisions.
  4. Migrating V1 (tree) agents — V1 agents stay read-only exactly as today.
  5. Building new action types — unblocking the actions pool (AISC-S07) is in scope as a dependency; authoring net-new executors is not.
  6. A visual flow map — the ordered Steps list is the MVP's visibility answer (D6); a flow map is built only if the validation task test fails on cross-capability invisibility.

6. Constraints

FieldValue
PlatformSame as parent — web only (chatbot-fe bot-automation module)
PerformanceDerivation + linter run synchronously inside the existing save/sync call; combined overhead ≤ 500ms p95 on a 10-capability agent (no perceptible save regression)
Backward compatskill_pack wire format unchanged. Existing V2 agents keep their authored fields until first human edit under the new editor (derive-on-save, D2); legacy authored required_slots / slot_action_args_map / milestone maps remain honored by the passthrough path while the flag is OFF for the org
Feature flagai_agent_simplified_config | default: OFF — BE system_preferences rollout-group flag; gates the Steps editor (FE) and the derivation/lint path (BE) per org; derive-on-save fires only when ON
Rollout noteBefore any org is flagged ON: run the batch lint dry-run across all live V2 agents and hand the would-fail list to support (D2). The DSAI staging probe (D3) must complete before the "Resolve conversation" THEN option ships in the dropdown
Plan / tierSame plans as the parent AI Agent feature — this adjustment introduces no new plan gating
Role scopeAuthoring inherited from existing bot-automation AI-agent config access; no new roles or permission surface (mirrors the story-level Permission Model)
Description/goal limit10000 characters, enforced as maxlength on the goal/instructions inputs — net-new enforcement: the shipped editor has no maxlength (AiAgentEditor.vue:2157); 10000 exists today only as a create-wizard cap (CreateAiAgent.vue:139) and a counter-only display (AiAgentIdentityForm.vue:300). Input-capping only — never a save-time failure (D9 intent preserved)
Dry-run report lifecycleThe batch dry-run would-fail list is exported once per run to the support workspace; retained until GA + 1 quarter, then deleted with the passthrough-path cleanup ticket (§10.1)

7. Feature Changes

Change ID: CHG-001 — Capability authoring model: Milestones → SOP Steps

FieldDetail
Change TypeModified behavior + modified component
Page/bot-automation/ai-agents/{id} (capability drawer)
Page IntentTenant admin defines what a capability does
BeforeCapability card exposes authored required_slots, a Milestones table, per-action milestone gates (unlockedAfter), an Action-sequence table, and a Completion-condition card ("Completes When")
AfterCapability = {title, keywords, goal, instructions, steps[], knowledge, actions}. One merged Instructions & Steps card: instructions textarea + drag-reorderable step cards (name, description, optional multi-select actions). No slots, milestone, gate, or completion field anywhere. Design as built on feat/ai-agents-ut-updates. The card carries explicit prompt-hierarchy helper copyInstructions = always-on rules for this capability; Steps = the ordered procedure the agent executes (and what Qontak compiles into checkpoints) — because ut-2026-07 found hierarchy overlap (Goals/Guidance/Instructions/Steps, "which wins?") is the new #1 comprehension risk (Strong) and Instructions-vs-Steps redundancy is High severity
ElementBeforeAfter
Milestones tableAuthored names + action mapRemoved — milestones derived per action (<action>_succeeded)
Required parameters blockAuthored slot listRemoved — slots derived from completion action args
Completion card"Completes When" picker/free-textRemoved — completion derived = last action of last actioned step (D4)
Triggers fieldtriggersRenamed keywords
Description fielddescriptionRenamed goal

Change ID: CHG-002 — BE derivation layer in SyncToAiService

FieldDetail
Change TypeModified behavior (producer-side)
PageN/A — backend
Page Intent
Beforebuild_skill passes tenant-authored required_slots (:134), slot_action_args_map (:135) through; build_milestone_action_map (:408) re-emits an authored map; a gate is emitted only if FE sends a['milestone'] (:432). FE really does send all these fields today (chatbot-fe useSaveAgent.ts:238-284)
AfterAt sync time BE derives: required_slots = arg names of the derived completion action; slot_action_args_map omitted (identity by construction); milestones = one <action>_succeeded per attached action (steps without actions emit none); requires_milestone = chain gates from SOP step order (each actioned step gated on the previous actioned step's success — D1); completion = {type: action_success, action: <last action of last actioned step>}, omitted for knowledge-only capabilities (D4)

Change ID: CHG-003 — Save-time linter (6 checks)

FieldDetail
Change TypeNew behavior in existing save/sync flow
PageErrors surface in the editor at save
Page IntentTenant admin saves a capability
BeforeAny config that serializes syncs to DSAI — including circular gates, dangling switch targets, and completion actions missing from the action list (the RFC's own example bugs)
AfterSync fails with an actionable, capability-named error on: ① circular gate ② unreachable-milestone gate ③ dangling routing/exception target ④ completion action not in the skill's action list ⑤ slot/arg incoherence (asserted; free by construction) ⑥ cross-capability exception collision — the same action carrying conflicting compiled action_error rules in two capabilities (D5). No partial skill_pack is ever pushed

Change ID: CHG-004 — Pattern A home: per-step Exceptions

FieldDetail
Change TypeModified behavior + modified component
PageCapability drawer, step cards
Page IntentTenant admin defines error recovery for a step
BeforeError-recovery rules live only in the agent-wide Routing tab; the prototype's WHEN exposes only an action picker, so a rule matches any failure of that action — Pattern A ("belum terdaftar" → registration) is inexpressible
AfterEach step carries WHEN/THEN Exceptions: WHEN = this step's action fails, optionally with message containing ⟨text⟩ and/or status code ⟨code⟩ (new FE inputs); THEN = switch capability / assign to human / resolve (probe-gated). Exceptions compile to the existing pack-level {action_error, body_contains, error_code} rules. The global Routing tab is reserved for user-intent + catch-all rules and never carries action_error (D5)

Change ID: CHG-005 — Closed THEN dropdowns + enum-exit handling in BE

FieldDetail
Change TypeModified behavior (FE dropdown + BE runtime)
PageStep exceptions + Routing tab THEN controls
Page IntentTenant admin picks a rule outcome
BeforePrototype offers "Switch action" and "Ask clarification" (no wire representation); process_async_reply (app/api/internal_service/v1/ai_agent/use_cases/process_async_reply.rb) routes only on exit.id tree-edges (:159-161) — no enum reason is ever applied, so "assign to human" has no runtime effect and no home for its target
AfterTHEN = switch capability · assign to human · resolve (resolve ships only if the D3 probe confirms verbatim relay). "Assign to human" stores the picked agent/division in parameters.routing and BE applies it when exit.reason == "user_request_human_handoff" arrives; unrecognized reasons fall back to the fallback intent and log. "Switch action" / "Ask clarification" are cut (D8)

Change ID: CHG-006 — Existing V2 agents: derive-on-save

FieldDetail
Change TypeModified migration behavior
PageCapability drawer (first edit of a legacy-authored agent)
Page IntentTenant admin edits an agent authored under the 6-tab editor
BeforeN/A — new situation introduced by this adjustment
AfterPublished agents are untouched until next human edit. On first save under the new editor, FE no longer sends authored fields; BE derives + lints, and the editor shows a "checkpoints recalculated" notice. Old capabilities open with instructions preserved and steps empty. Pre-rollout, a batch lint dry-run over all live V2 agents produces the would-fail list for support (D2)

Change ID: CHG-007 — Refine rail disabled for flag-ON orgs

FieldDetail
Change TypeModified behavior (feature gating)
Page/bot-automation/ai-agents/{id} (editor side rail)
Page IntentTenant admin refines agent config with AI assistance
BeforeRefine is live in production: FE RefinePanel/useRefineAgent.tsPATCH /v2/ai_agents/:id/refine → BE refine.rb builds packs via use_cases/mappers/skill_pack_builder.rb — a second skill_pack producer that reads the authored-field capability shape
AfterFor ai_agent_simplified_config = ON orgs, the Refine rail is hidden with "coming soon for Steps agents" messaging — its pack builder cannot serve derived agents unchanged. Flag-OFF orgs keep shipped Refine exactly as today. Reconciliation (teach SkillPackBuilder + refine_skill_pack_merger the Steps model, or route refine through the derivation layer) is a follow-up phase (§16 row 7)

8. API & Webhook Behavior

No public API or webhook contract changes. Two internal contract behaviors change (plain-language; endpoint specifics resolved in the RFC):

#BehaviorEntity AffectedTriggered ByExpected BehaviorFailure Behavior
1Derived skill_pack productionskill_pack pushed to qontak-ai-noncore-mragTenant admin saves agent config (flag ON)BE derives slots/milestones/map/gates/completion from the SOP, lints (6 checks), then pushes a wire-identical skill_pack; DSAI validators run unchanged on generated valuesAny lint failure → sync aborts with a capability-named error surfaced in the editor; no partial skill_pack is pushed
2Enum-exit application at runtimeRoom assignment / resolution in chatbot BEDSAI async reply carries exit.reason (from a matched rule)user_request_human_handoff → room assigned to the agent/division stored in parameters.routing; resolve_conversation (probe-gated, D3) → room resolved via the existing resolve pathUnrecognized exit.reason → fall back to the fallback intent (no crash), log the unmapped reason with agent + rule context

9. System Flow + User Stories + ACs

9.1. System Flow

Flow: Configure → derive → lint → sync → runtime exit mapping · Type: User Journey + API Sequence

  1. Tenant admin opens the 3-tab editor (Profile / Capabilities / Routing) and edits a capability: title, keywords, goal, instructions, ordered steps (each step optionally carrying actions and WHEN/THEN exceptions).
  2. Admin saves. FE sends the SOP-shaped capability (no slots/milestone/gate/completion fields).
  3. SyncToAiService derives: completion (last action of last actioned step), required_slots (completion action's args), milestones (one per attached action), chain gates (SOP step order).
  4. Linter runs the 6 checks against the derived + authored config.
  5. If any check fails → sync aborts; the editor shows the capability-named error; nothing reaches DSAI.
  6. If clean → BE pushes the wire-identical skill_pack; DSAI validators receive machine-generated values.
  7. At runtime, a customer message triggers the agent; a step's action fails matching an exception (action_error + body_contains) → DSAI applies the rule.
  8. THEN = switch → conversation continues in the target capability. THEN = assign-to-human → DSAI returns exit.reason: user_request_human_handoff; BE assigns the room to the stored target. THEN = resolve (probe-gated) → BE resolves the room.
  9. If BE receives an unrecognized exit reason → fallback intent + logged unmapped reason.

📊 System Flow — Simplified Configuration

sequenceDiagram
actor Admin as Tenant admin
participant FE as chatbot-fe editor
participant BE as Chatbot BE (SyncToAiService)
participant DSAI as DSAI runtime
Admin->>FE: Author SOP (steps + exceptions), Save
FE->>BE: Capability (no slots/milestones/completion)
BE->>BE: Derive slots, milestones, gates, completion
BE->>BE: Lint (6 checks)
alt lint fails
BE-->>FE: Capability-named error
FE-->>Admin: Save blocked, fix shown
else lint passes
BE->>DSAI: skill_pack (wire unchanged)
end
Note over DSAI: Runtime — step action fails,<br/>exception rule matches
DSAI-->>BE: async reply with exit.reason
alt reason = user_request_human_handoff
BE->>BE: Assign room to stored target
else reason unrecognized
BE->>BE: Fallback intent + log unmapped reason
end

9.2. User Stories

[AISC-S01] — Configure a capability as an SOP

User StoryAs a tenant admin, I want to define a capability as ordered steps with keywords and a goal, so that I can build a working transactional agent without learning slots, milestones, or gates.
Before StateCapability card requires authored required_slots, milestone names + action map, per-action gates, and a Completion condition — the exact fields the ut-2026-06-23 study found incomprehensible.
After DeltaCapability = title, keywords, goal, instructions, drag-ordered steps (name, description, optional multi-select actions). No wire-model field is ever shown.
ImportanceMust Have
Mockup / Technical NotesDesign: qontak-designer feat/ai-agents-ut-updates — merged Instructions & Steps card, [id].vue

Data Fields:
title (string, required) — user input
keywords (string[], optional) — user input (renamed from triggers)
goal (string ≤10000, required) — user input (renamed from description)
instructions (string, optional) — user input
steps[] {id, name, description, actions[], exceptions[]} (ordered) — user input

Before-After Behavior: Admin previously authored 5 wire-model artifacts per capability; after this story they author only their SOP.
Acceptance Criteria— Happy Path —
• AC-1: Given the capability drawer under flag ON, when the admin opens it, then only title, keywords, goal, instructions, steps, knowledge, and actions are authorable — no required_slots, milestone, gate, or completion field is rendered.
• AC-2: Given a capability with ≥1 step, when the admin drags a step to a new position and saves, then the persisted step order matches the on-screen order after reload.
• AC-3: Given a step, when the admin attaches multiple actions via the multi-select picker, then all attached actions persist on that step.
— Error / Unhappy Path —
• ERR-1: Given a goal or instructions input at 10000 characters, when the admin keeps typing, then input is capped by a net-new maxlength=10000 (the shipped editor enforces nothing today — AiAgentEditor.vue:2157; 10000 exists only as the create-wizard cap and a counter display) and no save-time error can ever occur from length (D9 intent).
— Permission Model —
• CAN: roles with existing bot-automation AI-agent config access (inherited)
• CANNOT: roles without bot-automation access
• Unauthorized: module not visible (existing behavior, unchanged)
— UI States —
• Loading: drawer skeleton while agent config loads
• Empty: new capability opens with instructions empty and zero steps (no auto-seeded blank step)
• Error: save-blocking lint errors render inline naming the capability (see AISC-S03)
• Success: saved capability renders as a clickable card with goal text + up-to-4 keyword chips + +N overflow

Dependencies: None


[AISC-S02] — Backend derives slots, milestones, gates, and completion

User StoryAs Chatbot BE, I want to generate the wire-model fields from the SOP at sync time, so that DSAI receives a complete, internally consistent skill_pack without hand-authoring.
Before Statebuild_skill passes authored required_slots/slot_action_args_map through (sync_to_ai_service.rb:134-135); build_milestone_action_map re-emits an authored map (:408); gates emitted only when FE sends a['milestone'] (:432); completion authored via the Completion card.
After DeltaAll four field families are derived per CHG-002; the wire format is byte-compatible with today's contract.
ImportanceMust Have
Mockup / Technical NotesTechnical Notes: derivation runs inside the existing sync call; skill_pack schema unchanged (Non-Goal 1). Multi-action steps: "last action of the last actioned step" is the completion anchor (D4). Producer scope: SyncToAiService is the only producer in scope — the second producer, use_cases/mappers/skill_pack_builder.rb (refine path), is neutralized by CHG-007 (Refine disabled for flag-ON orgs) and inherits derivation in the follow-up phase.

Data Fields:
completion (derived) — {type: action_success, action: <tool_name>} or omitted
required_slots (derived) — completion action's arg names
milestones / milestone_action_map (derived) — <action>_succeeded, 1:1
requires_milestone (derived) — chain gates from SOP step order (D1)
Acceptance Criteria— Happy Path —
• AC-1: Given a capability whose last actioned step carries action createorder with args [date, fleet_id, email], when BE builds the skill, then completion == {type: "action_success", action: "createorder…"} and required_slots == ["date","fleet_id","email"].
• AC-2: Given steps ordered getfleets → calculateprice → createorder, when BE builds the skill, then milestones == ["getfleets_succeeded","calculateprice_succeeded","createorder_succeeded"], milestone_action_map maps 1:1, and createorder.configs.requires_milestone == "calculateprice_succeeded" (chain gate from step order).
• AC-3: Given a step with no actions between two actioned steps, when BE derives gates, then the chain skips it — the later actioned step is gated on the previous actioned step's milestone.
• AC-4: Given a knowledge-only capability (zero actions on all steps), when BE builds the skill, then completion and milestones are omitted and the sync still succeeds (probe-verified DSAI tolerance, D3).
• AC-5: Given a 10-capability agent, when derivation + lint run at save, then combined overhead is ≤ 500ms p95 (enforces §6 Performance).
— Error / Unhappy Path —
• ERR-1: Given an action whose args contain a nil/blank type, when BE builds the skill, then the action is skipped per the existing args_with_unresolved_type? guard and derivation anchors to the last actioned step whose args resolve — never crashing the sync.
— Negative —
• NEG-1: Given any capability, when BE builds the skill, then no tag-emission milestone ([MILESTONE:…]) and no authored slot_action_args_map appears in the output.

Dependencies: [AISC-S01]


[AISC-S03] — Save-time linter blocks unbuildable configs

User StoryAs a tenant admin, I want save to fail with a clear, capability-named reason when my config would deadlock or dangle, so that I never publish an agent that silently misbehaves.
Before StateAny serializable config syncs to DSAI — the RFC's own worked examples (circular gates, dangling targets) pass through unchecked.
After DeltaSix deterministic checks run before push (CHG-003); failures abort the sync with actionable errors in the editor.
ImportanceMust Have
Mockup / Technical NotesTechnical Notes: checks ①–④ correspond to real RFC example bugs (D11, §5.3, D12, D13); check ⑤ is free by construction after AISC-S02 but asserted; check ⑥ is new from D5 (pack-level rules are not skill-scoped).

Before-After Behavior: Misconfigurations previously reached production and surfaced as runtime failures; after this story they are blocked at save with the offending capability named.
Acceptance Criteria— Happy Path —
• AC-1: Given a valid config, when the admin saves, then all 6 checks pass and the sync proceeds.
— Error / Unhappy Path —
• ERR-1: Given an action gated on a milestone only its own success fires (possible only via legacy data), when saving, then the sync fails naming the action and the cycle.
• ERR-2: Given a gate referencing a milestone no action fires, when saving, then the sync fails naming the gate.
• ERR-3: Given an exception or routing THEN targeting a non-existent capability, when saving, then the sync fails naming the dangling target.
• ERR-4: Given a derived completion action absent from the skill's action list (legacy-data edge), when saving, then the sync fails.
• ERR-5: Given the same action attached in two capabilities with conflicting exceptions, when saving, then the sync fails (or warns, per RFC severity decision) naming both capabilities and the action (check ⑥, D5).
• ERR-6: Given any linter failure, when it returns, then no partial or invalid skill_pack is pushed to DSAI.

Dependencies: [AISC-S02]


[AISC-S04] — Per-step exception with message matcher (Pattern A)

User StoryAs a tenant admin, I want to route "when this step's order creation fails because the customer isn't registered, send them to registration", so that a known tool failure recovers deterministically instead of dead-ending or over-escalating.
Before StateThe wire supports {action_error, body_contains, error_code} (build_routing_when :528-536, fed by build_routing_rules :520-526) but no FE surface exposes the matcher — a rule can only match any failure of an action, so Pattern A is inexpressible. Error rules live only in the agent-wide Routing tab.
After DeltaEach step card carries WHEN/THEN Exceptions with a structured WHEN (this step's action + optional message-contains and status-code matchers); exceptions are the only action_error surface (D5); global Routing is reserved for user-intent + catch-all.
ImportanceMust Have
Mockup / Technical NotesDesign: step exception WHEN/THEN cards on feat/ai-agents-ut-updatesrestructure required, not just added inputs: the branch's CapabilityStepException today is {when: free-text string, thenMode: switch_action | switch_capability | other(+free text)} with no assign-to-human mode. Change-request to Wulan: structured WHEN (action + optional matchers), closed THEN (switch capability · assign to human · resolve-probe-gated), drop switch_action/other per D8.

Data Fields:
exceptions[].when{action, body_contains?, error_code?} — user input
exceptions[].thenswitch_to_skill | assign_to_human | resolve (closed) — user input

Before-After Behavior: Error recovery moves from an agent-wide tab (research: "same work three times") to the step it protects, with a matcher that finally makes Pattern A expressible.
Acceptance Criteria— Happy Path —
• AC-1: Given a step whose action is createorder, when the admin adds an exception WHEN "fails with message containing 'belum terdaftar'" THEN "Switch to registration" and saves, then the rule compiles to {when: {action_error: "createorder…", body_contains: "belum terdaftar"}, switch_to_skill: "registration"} in the pushed skill_pack.
• AC-2: Given an exception with no matcher, when saved, then it matches any failure of that step's action (documented behavior, not an error).
• AC-3: Given the global Routing tab, when the admin builds a rule, then no action-failure WHEN is offered there — only user-intent and catch-all conditions (D5).
— Error / Unhappy Path —
• ERR-1: Given a switch target that doesn't exist, when saving, then AISC-S03/ERR-3 blocks the save naming the target.
— Permission Model —
• CAN / CANNOT / Unauthorized: inherited from AISC-S01
— UI States —
• Empty: step shows "Add exception" affordance only
• Error: dangling-target lint error names the exception's step
• Success: exception renders as WHEN/THEN card on the step

Dependencies: [AISC-S01], [AISC-S03]


[AISC-S05] — Enum-exit handling in Backend (assign-to-human + probe-gated resolve)

User StoryAs a tenant admin, I want "assign to the Support division" to actually assign the room at runtime, so that handover reaches the right team — and as Chatbot BE, I want to apply enum exit reasons instead of ignoring them.
Before Stateprocess_async_reply (app/api/internal_service/v1/ai_agent/use_cases/process_async_reply.rb) routes only on exit.id tree-edges (:159-161); no enum reason is handled — "assign to human" has no runtime effect, and the RFC exit carries no field for the picked target. Resolve exists only as an agent tool call (references[].action_type == "qontak_chat_room_resolve", :182).
After DeltaNew enum-exit handler: user_request_human_handoff → assign to the target stored Rails-side in parameters.routing; resolve_conversation (BE-minted, only if the D3 staging probe confirms DSAI relays rule-exit reasons verbatim) → resolve the room. Unrecognized reasons → fallback + log. This is the single largest BE work item.
ImportanceMust Have
Mockup / Technical NotesTechnical Notes: target storage in parameters.routing (D3-confirmed plan, ex-Q3); one handler serves all THEN outcomes. Probe first: author a rule with a non-enum reason on staging; verbatim relay → mint resolve_conversation; enum-enforced → cut Resolve from the dropdown (Constraints §Rollout note).

Data Fields:
parameters.routing[].target{type: agent|division, id} — user input (picker)
exit.reason (runtime) — DSAI async reply
Acceptance Criteria— Happy Path —
• AC-1: Given THEN "Assign to human" with division "Support", when saved, then the target persists in parameters.routing and the rule emits {exit: {reason: "user_request_human_handoff"}}.
• AC-2: Given DSAI returns exit.reason == "user_request_human_handoff", when BE processes the async reply, then the room is assigned to the stored division/agent target.
• AC-3: Given the D3 probe confirmed verbatim relay and THEN "Resolve conversation" fired, when BE receives exit.reason == "resolve_conversation", then the room is resolved via the existing resolve path.
• AC-4: Given a room that was auto-assigned or auto-resolved by a rule, when a human reassigns or reopens it through the normal inbox flow, then the standard inbox behavior applies unchanged and the same rule does not re-fire on the same failure within that conversation (rollback = existing inbox operations; no new undo surface).
— Error / Unhappy Path —
• ERR-1: Given an exit reason BE does not recognise, when processing, then BE falls back to the fallback intent (no crash) and logs the unmapped reason with agent + rule context.
• ERR-2: Given a stored target that no longer exists (deleted division), when the exit fires, then BE falls back to the org's default assignment path and logs the stale target.

Dependencies: [AISC-S04]; DSAI staging probe (Dependencies §14)


[AISC-S06] — Steps editor comprehension (3-tab, task-tested)

User StoryAs a tenant admin, I want a Profile / Capabilities / Routing editor where my SOP steps are the visible logic, so that I understand what the agent will do without a specialist.
Before StateThe shipped editor is already 3-tab (Profile / Capabilities / Routing — AiAgentEditor.vue:3056-3060, grounded 2026-07-22; v1.1's "6-tab" claim was stale). The gap is inside the capability drawer: authored milestone/slot/completion fields and a free-text instruction under a "What steps should the agent follow?" label — research verdict: "the logic is invisible" (P1), non-technical users cannot self-serve.
After DeltaTab structure unchanged; the capability drawer is rebuilt onto the merged Instructions & Steps card — the ordered Steps list is the visibility answer, no Checkpoints tags, no flow map in MVP (D6).
ImportanceShould Have
Mockup / Technical NotesDesign: feat/ai-agents-ut-updates (merged card as built).

Before-After Behavior: Progress-display duty moves from milestone artifacts to the SOP steps the tenant authored themselves; FE scope is the drawer rebuild, not a tab collapse.
Acceptance Criteria— Happy Path —
• AC-1: Given the editor under flag ON, when it renders, then the existing 3-tab structure (Profile, Capabilities, Routing) is unchanged (regression guard) and the capability drawer contains the merged Instructions & Steps card.
• AC-2: Given a saved capability, when the admin views it, then steps render as ordered, numbered cards with their actions and exceptions inline — and no milestone/checkpoint artifact appears anywhere.
— Comprehension (validation gate, D6) —
• AC-3: Given the validation session, when a non-technical participant is asked to build a 2-step agent unassisted, then they complete the setup — this is the research's own P1 pass criterion; failure is the evidence that buys a flow map (Non-Goal 6). Status: ut-2026-07 (Iteration II, 6 participants — 5 internal + 1 external technical) validated the Steps direction (Strong) but does NOT satisfy this AC — the external non-technical round remains the gate.
• AC-4: Given the merged card with the hierarchy helper copy (CHG-001), when a validation participant is asked whether Instructions or Steps governs a described behavior, then they answer correctly — the ut-2026-07 P1 "predictability" re-test for the prompt-hierarchy overlap finding.

Dependencies: [AISC-S01]


[AISC-S07] — Actions pool available to step and exception pickers

User StoryAs a tenant admin, I want the step action picker and exception pickers to show my real actions pool, so that transactional and recovery flows aren't limited to 4 hardcoded types.
Before StateFE ACTION_LIST hardcodes 4 items (qontak_crm_deal_create, qontak_crm_ticket_create, qontak_crm_ticket_update, api) — duplicated in two files (modules/bot-automation/constants/bot-automation-actions-constants.ts:6, the one the editor consumes, and modules/ai-agent/constants/ai-agent-actions-constants.ts:75); plus ACTION_FALLBACK (common/services/main/v1/bot-automation-actions.ts:99) holding 3 different items, marked "until /v1/actions backend ships". Both copies must be retired together.
After DeltaPickers list the tenant's full configured actions pool; graceful degradation to the shipped set when the pool is unavailable.
ImportanceCould Have (dependency of the full self-service vision)
Mockup / Technical NotesData Fields:
• actions pool (API response) — tenant's configured actions
Acceptance Criteria— Happy Path —
• AC-1: Given the tenant's configured actions, when a step or exception picker opens, then the full pool is listed.
— Error / Unhappy Path —
• ERR-1: Given the pool is unavailable, when a picker opens, then it degrades to the shipped 4-item set and flags the degradation (no silent empty state).

Dependencies: [AISC-S01]


[AISC-S08] — Derive-on-save migration for existing V2 agents

User StoryAs Chatbot BE, I want legacy-authored agents re-derived only when a human edits them — with a pre-rollout dry-run of who would fail, so that no running production bot changes behavior without a tenant action and support is never blind-sided (D2).
Before StateAll live V2 agents carry hand-authored slots/milestones/gates saved under the 6-tab editor; some contain latent misconfigurations that the old editor accepted silently.
After DeltaFlag-ON orgs: agents untouched until first edit; first save derives + lints with honest messaging. Pre-rollout: batch lint dry-run over all live V2 agents → would-fail list to support.
ImportanceMust Have
Mockup / Technical NotesTechnical Notes: dry-run reuses the AISC-S03 linter in report-only mode; no skill_pack is pushed by the dry-run.

Before-After Behavior: Migration risk moves from "silent behavior change at deploy" to "explicit recalculation at the tenant's own edit, with support pre-briefed."
Acceptance Criteria— Happy Path —
• AC-1: Given a legacy-authored agent in a flag-ON org, when no one edits it, then its synced skill_pack remains byte-identical to its pre-flag state.
• AC-2: Given a legacy capability opened in the new editor, when the drawer renders, then instructions are preserved and the steps list is empty.
• AC-3: Given the first save of a legacy agent under the new editor, when derivation succeeds, then the editor shows a "checkpoints recalculated" notice and the derived pack syncs.
• AC-4: Given the pre-rollout batch dry-run, when it completes, then every live V2 agent has a lint verdict and the would-fail list (org, agent, failing check) is exported for support.
— Error / Unhappy Path —
• ERR-1: Given a legacy agent whose config now fails lint, when the tenant first saves it, then the save is blocked with the capability-named error — and the org was already on the support would-fail list (AC-4).
— Migration guard —
• NEG-1: Given a flag-OFF org, when any agent is saved, then the legacy passthrough path runs unchanged (no derivation, no lint).
• AC-5 (rollback): Given an agent that has been re-derived under flag ON, when the org's flag is flipped OFF, then the agent's authored fields are still intact — derive-on-save never deletes them from parameters (derived values live alongside, not instead) — and the next save/sync runs the passthrough over the preserved authored config. Divergence risk (steps edited under ON, then reverting to stale authored config) is accepted and logged.

Dependencies: [AISC-S03]; flag ai_agent_simplified_config


Guard Rail stories (from Non-Goals)

User StoryImportanceAcceptance Criteria
[AISC-NEG-01] — THEN dropdowns never offer unbuildable options (from Non-Goal 1, D8)Guard RailNEG-1: Given any THEN dropdown (step exception or global routing), when it opens, then "Switch action" and "Ask clarification" are absent; only switch capability, assign to human, and (probe-gated) resolve are offered.
[AISC-NEG-02] — Refine rail disabled for flag-ON orgs, untouched for flag-OFF (from Non-Goal 2, D7 re-based; CHG-007)Guard RailNEG-1: Given a flag-ON org, when the editor renders, then the shipped Refine rail is hidden/disabled with "coming soon for Steps agents" messaging and PATCH /v2/ai_agents/:id/refine is rejected for that org's agents.
NEG-2: Given a flag-OFF org, when the editor renders, then the shipped Refine rail works exactly as today — this adjustment never degrades live Refine for legacy-model orgs.
[AISC-NEG-03] — V1 tree agents untouched (from Non-Goal 4)Guard RailNEG-1: Given a V1 (tree) agent, when viewed under flag ON, then it remains read-only exactly as today — no Steps editor, no derivation, no lint.

10. Rollout

FieldDetail
Rollout typeControlled rollout with flag
Feature flagai_agent_simplified_config | default: OFF (BE system_preferences rollout group; gates FE editor + BE derivation per org)
RolloutStage 1 → Internal QA orgs — new-agent authoring + legacy-edit derivation exercised · Stage 2 → design-partner orgs (opt-in, support pre-briefed with the dry-run would-fail list) · Stage 3 → GA (default ON for new orgs, existing orgs staged)
Backward compatYes — flag-OFF orgs run the legacy passthrough unchanged; wire format identical
MigrationDerive-on-save only (D2): no batch rewrite of live agents, ever; batch lint dry-run is report-only

10.1. Migration Transition Window

FieldDetail
Old behaviorFlag-OFF orgs (and un-edited agents in flag-ON orgs) sync authored fields via the passthrough path — bit-identical to today
New behaviorFirst human save under the new editor derives + lints; "checkpoints recalculated" notice shown
Coexistence periodIndefinite by design — an agent nobody edits is never re-derived; both paths stay live until the last org is flagged ON and edited
End statePassthrough path retired only after GA + one full quarter with zero flag-OFF orgs; tracked as an engineering cleanup ticket, never a silent removal

11. Observability

New or Modified Events:

Event NameTriggerPropertiesChange from parent
ai_agent_config_lint_failedAny of the 6 lint checks blocks a saveorg_id, agent_id, capability, check_id (1–6)New
ai_agent_config_derivedSuccessful derivation on saveorg_id, agent_id, capability_count, derived_field_counts, legacy_first_save (bool)New
ai_agent_exit_reason_appliedEnum-exit handler applies an outcomeorg_id, agent_id, reason, outcome (assigned/resolved/fallback), target_typeNew
ai_agent_exit_reason_unmappedUnrecognized exit.reason receivedorg_id, agent_id, reasonNew — alert if > 0/day per org
ai_agent_dryrun_completedPre-rollout batch lint dry-run finishesorg_count, agent_count, fail_count by check_idNew (one-off, per run)

Dashboard owner: BOT squad. Alert: ai_agent_exit_reason_unmapped > 0/day per org → investigate same day (it means a rule emits a reason the handler doesn't know).

Post-launch monitoring cadence: weekly review for the first 4 weeks post-GA; if lint-block rate exceeds 20% of saves org-wide or self-serve config rate drops week-over-week, investigate immediately.

Observability otherwise unchanged from parent: Autonomous AI Agent — ANCHOR.

12. Success Metrics

MetricDefinitionBaselineTarget
Self-serve config rate% of new AI agents that reach published state without activation-team involvementNear-zero — one champion per account, activation-led (analytics-2026-05, 109 creators)≥ 40% of new agents self-served within 60 days of GA
Validation task-test pass (pre-launch gate, D6)Non-technical participant completes a 2-step agent setup unassisted0/4 non-technical in ut-2026-06-23; ut-2026-07 (Iteration II) validated direction Strong but sampled no non-technical externals≥ 3 of 4 non-technical participants complete unassisted, in the external round
Lint catch rate (quality)Misconfigs blocked at save (ai_agent_config_lint_failed) vs. config-related runtime incidentsN/A — nothing is blocked todayRuntime incidents from the 5 known misconfig classes → 0 for flag-ON orgs
Config-related support tickets (efficiency)Tickets/escalations tagged AI-agent-configPull current tag volume pre-GA−30% for flag-ON orgs within 90 days

13. Launch Plan & Stage Gates

StageAudienceDurationSuccess GateOwner
1 — Internal QA2 internal orgs1–2 weeksAll 6 lint checks exercised; derive-on-save round-trip verified; zero ai_agent_exit_reason_unmappedBOT QA
2 — Design partners3–5 opt-in orgs (support pre-briefed with dry-run list)2–4 weeks≥ 1 legacy agent per org edited + re-derived with no behavior regression; D6 task-test criterion met in validationPM (Dimas)
3 — GANew orgs default ON; existing orgs stagedStage-2 gates held for 2 consecutive weeks; support ticket volume flat or downPM + BOT lead

14. Dependencies

DependencyOwning TeamDeliverable NeededBlocking?
Design branch merge — feat/ai-agents-ut-updates (Steps model; drawer UI pending visual verification per its docs.md)Design (Wulan)Verified prototype = FE build reference; change-request brief covers the exception-model restructure (structured WHEN = action + matchers; closed THEN incl. assign-to-human; drop switch_action/other free-text per D8) + D7/CHG-007 Refine "coming soon" stateNO — FE can build from the branch as-is; verification is a quality gate
DSAI staging probe (D3): does the runtime relay rule-exit reasons verbatim, and tolerate omitted completion?BOT BE (probe executed by us — no DSAI work requested)Probe result recorded in §16; determines whether "Resolve" ships in the THEN dropdownYES — for the Resolve option only; NO for everything else
RFC as-built reconciliation (ex-Q8)DSAI + BOTRFC PMDAT/51153994292 updated to the as-shipped wire contractNO — coordination item, not a build blocker

Per the standing dependency rule: no DSAI build dependency exists in this MVP — the probe is observational, and the one probe-gated feature (Resolve) has a defined cut path (D3/D8).

📊 Dependency Graph — Simplified Configuration

graph LR
PRD[AISC MVP] -->|NO — quality gate| DES[Design branch verification]
PRD -->|YES — Resolve option only| PROBE[DSAI staging probe D3]
PRD -->|NO — coordination| RFC[RFC as-built reconciliation]
PROBE -->|verbatim relay| RESOLVE[Resolve ships in THEN]
PROBE -->|enum enforced| CUT[Resolve cut from MVP]

15. Key Decisions + Alternatives Rejected

15a — Decisions Made (full reasoning: D1–D9 register)

DateDecisionRationale
2026-07-22D1 — Gates derive from SOP step order (chain gates)The config model has no cross-action data-flow structure to read; step order is tenant-authored and deterministic
2026-07-22D4 — Completion derived from last actioned step; no authored completionDesign deleted the Completion card; derivation is the PRD's own philosophy applied consistently; D6 task test checks the bet
2026-07-22D5 — Per-step Exceptions = only action_error surface; global Routing = intent + catch-allMatches the researched user mental model; kills the "same work three times" duplication
2026-07-22D2 — Derive-on-save + pre-rollout batch dry-runNo production bot changes behavior without a tenant action; support pre-briefed
2026-07-22D3 — Probe-then-mint resolve_conversation; cut on enum enforcementZero DSAI work if relay is verbatim; honest cut path if not
2026-07-22D7 (re-based by grounding) — Refine excluded from the Steps MVP; disabled for flag-ON orgs (CHG-007)Original "zero consumers" evidence went stale — Refine shipped end-to-end 2026-07-10/14 while drafting. Its pack builder can't serve derived agents unchanged; disabling for flag-ON orgs keeps the MVP decoupled without touching flag-OFF orgs' live feature
2026-07-22Flag ai_agent_simplified_config, BE rollout group, default OFFStandard chatbot flag pattern; enables org-by-org D2 rollout

15b — Alternatives Rejected

AlternativeWhy RejectedDate
Derive gates via data-flow inference (v1.0 R2 as written)Unimplementable — args are {name,type,description} with no cross-action links; every action would silently fall to "ungated"2026-07-22
Name-matching heuristic for gate derivationSilently wrong on naming coincidences2026-07-22
Re-add a completion dropdown (research asked for dropdown, not removal)Fights the shipped design direction; derivation covers it; task test validates2026-07-22
Pattern A in the global Routing tab (v1.0 R4)Recreates the duplication research condemned; hides recovery away from the step it protects2026-07-22
One-time forced re-derivation of all live V2 agentsChanges running production bots without tenant action2026-07-22
Formal DSAI contract change for resolve (resolve_conversation enum)Cross-team dependency on DSAI against the standing rule; probe + BE-mint achieves it for free if relay is verbatim2026-07-22
Tighten description limit to 4000Adds a save-failure mode for existing agents mid-migration; zero user value2026-07-22

16. Open Questions

#TypeQuestionOwnerDeadline
1Open QuestionD3 staging probe result: verbatim relay or enum enforcement? (Determines Resolve in THEN; cut path defined either way)BOT BEBefore FE builds the THEN dropdown
2Open QuestionLinter check ⑥ severity: hard-fail or warn on cross-capability exception collision? (Hard-fail is safer; warn is gentler on legacy data)PM + BOT BE, at RFCRFC grooming
3AssumptionThe feat/ai-agents-ut-updates drawer UI passes its pending visual verification without model changes (its docs.md lists browser verification as not yet done)Design (Wulan)Before FE build starts
4RiskDerived completion may disagree with a legacy agent's authored completion on first edit — mitigation: D2 messaging ("checkpoints recalculated") + dry-run list gives support the affected orgs before any tenant hits itBOT BEStage 2 entry
5RiskTask test (D6/AISC-S06 AC-3) fails for non-technical users — mitigation: pre-agreed fallback = read-only flow strip (Non-Goal 6 reverses with evidence); does not block Stage 1. Update 2026-07-23: ut-2026-07 de-risks the direction (Steps clearer — Strong) but the non-technical external round is still requiredPM (Dimas)External non-technical round
9RiskPrompt-hierarchy overlap (Goals/Guidance/Instructions/Steps) = the new #1 comprehension risk per ut-2026-07 (Strong; Instructions-vs-Steps redundancy High) — mitigation: hierarchy helper copy in CHG-001 + AISC-S06/AC-4 predictability probe; design brief carries the layer-labeling workPM + Design (Wulan)Before the external validation round
10Open Questionut-2026-07 finding 4: Routing "THEN" visually demoted under "WHEN" (rules left half-configured) + capability cards not obviously clickable — both routed to the Wulan change-request brief (THEN gets equal visual weight; clickable signifiers)Design (Wulan)Change-request brief
6Open Questionfallback constants emission (no_skill_match, turn_budget_exceeded) + reconciling the turn cap with the Rails message_limit Redis counter — kept out of MVP scope; schedule as follow-up ADJUSTMENT?PM (Dimas)Post-MVP triage
7Open QuestionRefine × Steps-model reconciliation (CHG-007 exit): teach SkillPackBuilder + refine_skill_pack_merger the derived model, or route refine through the derivation layer — scoped as the follow-up phase that re-enables Refine for flag-ON orgsPM (Dimas) + BOT BEPhase-2 scoping, after MVP GA gate

PRD CHANGELOG

VersionDateBySectionTypeSummary
1.02026-07-07ClaudeAllCREATEDAdjustment PRD drafted pre-validation (Downloads draft; milestone-derivation model, Routing-tab Pattern A)
1.12026-07-22ClaudeAllREWRITTENRebuilt on the grilled D1–D9 decision register: Steps/SOP model replaces Milestones + Completion (per feat/ai-agents-ut-updates); chain gates from step order; per-step Exceptions = Pattern A home; derive-on-save migration + dry-run; probe-gated resolve; PIH ut-2026-06-23 wired as sources; landed in documents repo
1.22026-07-22ClaudeCB, S5, S6, S7 (CHG-007 new), S9.2, S15, S16GROUNDED FIXESFrom ground-prd assessment (P0/P1/P2): Refine shipped end-to-end → Non-Goal 2 + NEG-02 re-based, Refine disabled for flag-ON orgs (CHG-007), second skill_pack producer scoped; "6-tab" claim corrected (editor already 3-tab, scope right-sized); maxlength=10000 marked net-new enforcement; design-branch exception model restructure specced in AISC-S04; stale file:line anchors + process_async_reply path refreshed; ACTION_LIST duplication named. Plus score-report items: rollback ACs (AISC-S05/AC-4, AISC-S08/AC-5), plan/tier + role-scope + dry-run-retention constraint rows
1.32026-07-22ClaudeHeaderMODIFIEDStatus DRAFT → READY (frontmatter draft → in-review) after 9.0/9.0 all-gates-pass score on the grounded v1.2; PM (Dimas) declared READY 2026-07-22
1.42026-07-22ClaudeHeaderMODIFIEDEpic filled: BOT-4733 (child Epic under umbrella BOT-4601, added to README allow-set)
1.52026-07-22ClaudeHeaderMODIFIEDRFC Link filled: rfcs/simplified-configuration.md (rfc-starter, agent-execution-ready)
1.62026-07-23ClaudeSources, CB, S7 (CHG-001), S9.2 (AISC-S06), S12, S16MODIFIEDGrounded on PIH ut-2026-07 (Iteration II UT, merged by Devina): Steps direction validated Strong; prompt-hierarchy overlap = new #1 risk → hierarchy helper copy (CHG-001) + AISC-S06/AC-4 predictability probe + S16 rows 9-10; D6 external non-technical round still the gate; sources + informs wired two-way