Completion notes — Guided procedural flows (public)
Date: 2026-07-18 · Spec: specs/2026-07-18-public-conversation-features.md (feature 4) · Plan: plans/2026-07-18-status-tracking-and-guided-flows.md
Feature 3 (gated-SQL status tracking) was dropped same-day after discovery — see the plan's "Discovery 2026-07-18" section.
What shipped (3 commits, all TDD, pnpm check green)
1. Server side — flow-mode compose + suggestions channel (public-web)
lib/orchestrator/suggest.ts—SuggestStreamSplitter: streaming splitter for the model's machine lineSUGGEST: ["…","…"]. Marker-safe across arbitrary chunk splits; only line-startSUGGEST:counts (SUGGESTION…/ mid-line passes through as prose); malformed JSON → line stripped, no suggestions; cap 3, strings only. 8 unit tests.steps/compose.ts— guided mode activates ONLY when a retrieved RAG passage contains a[FLOW:marker: stepwise instruction ("Langkah N dari M", ringkasan alur, next action) + the SUGGEST last-line format (user's language, ≤6 words each). The splitter runs on every answer (flow or not) so a stray SUGGEST line can never leak as prose. NewComposeEventkindsuggestions.sse.ts+orchestrate.ts— newevent: suggestionsSSE frame (checkpointed for SSE-resume like all frames), emitted between content and references.
2. Client side — server-driven chips
packages/streams:StreamEvent+Message.suggestionstypes;OrchestratorProvidermapsevent: suggestions→{type:"suggestions", items}(non-string items dropped; empty frames suppressed). New provider test file.packages/ui:chatStore.setSuggestions(stamps last assistant message) +useAgentStreamcase.SuggestedFollowups.tsx: server chips take precedence; the static category fixtures remain the fallback — exactly the "phase-2" evolution the fixture's own comment anticipated.
3. Content — docs/knowledge-sources/gen_flows.json
3 flow articles (chunk ids gen3_flow_*_0, corpus generated-help), grounded strictly in the existing §1/§1b articles (no new facts):
- [FLOW:pendirian-pt-perorangan] — 6 langkah (PP priority)
- [FLOW:permohonan-apostille] — 7 langkah (incl. spesimen-ditangguhkan caveat, 7-day payment window, Kanwil pickup)
- [FLOW:pendirian-pt-notaris] — 5 langkah (pesan nama 60 hari → akta → PNBP modal-tiered → SK)
README §1c documents the artifact + ingest (idempotent chunk_id upsert, same as §1).
Verification
pnpm checkfully green: typecheck all packages, 181 public-web + 15 internal-web + 27 streams tests, conventions OK.- Splitter/compose/orchestrate/provider behavior all pinned by failing-first tests (RED verified at each step).
Deployed + verified live (same day)
- Deploy — images tag
b849488built in dind (in-image agent pytest 42+64 green), shipped in chunks (scp resumed across the 10-min ceiling), loaded on Server 2, all four stacks up. Health:/api/healthok on :3500, staff :3510 up, staging URL 200. Agent images dedup'd to the previous build (no agent changes — expected); both web images recreated. Quirks hit: no localrsync(tar fallback for infra sync),docker execneeds-ifor stdin scripts. - Ingest —
gen_flows.jsonupserted via the still-present/tmp/ingest_*.pypattern inside ai-ahu-rag:upserted: 3, collection 800 rows. - E2E (staging, real turns) —
- "Bagaimana cara mendirikan PT perorangan?" → ringkasan alur + Langkah detail;event: suggestionsframe:["Siapkan 3 kata nama PT","Cek ketersediaan nama PT","Daftar akun di ptp.ahu.go.id"]; 0 SUGGEST leakage across 115 content frames.
- Chip-click simulation ("Lanjut ke langkah berikutnya" + history) → "Anda sedang berada pada Langkah 1 dari 6 … Langkah 2: Menyiapkan Nama Perseroan" + chips["Lanjut ke Langkah 3","Cara pesan voucher","Syarat nama perseroan"]. The conversational wizard advances correctly with no server-side state.
Ops note: /home/efran/ahu-ai-staging/inbox on Server 2 still holds ~24 GB of old ahu-ai-ocr-*.tar.gz (host disk was already 92% full) — candidate cleanup.
Design notes
- Chip flow state is conversational, not server-side: "Lanjut ke langkah 2" is just the next user message; compose re-retrieves the flow article and details step 2. No thread-state machinery (v2 idea if flows grow branches).
- Suggestions are ephemeral (live stream only) — thread reload shows the conversation without chips; acceptable for v1 and consistent with chips being an input affordance, not content.
- English users get English chips automatically: the SUGGEST instruction says "dalam bahasa pengguna" and sits alongside the lang=en compose rule.