# KẾ HOẠCH 18 — Governed Chat Console (Chat-as-Loop qua Control Plane) > Status 2026-07-08: **✅ MVP-0 + MVP-1 + MVP-2 + MVP-3 done+test.** > Đã implement **Ask CASAN — Read-only Evidence Assistant** qua harness + Control > Panel (`/api/v1/chat/ask`, `/chat` UI): Prompt Router deterministic > `READ_ONLY/OPERATOR/BLOCK/NOT_SUPPORTED`, context whitelist, H4 scan in/out, H5 > chat audit hash-chain, H6 token telemetry, answer kèm evidence sources. **MVP-1 > Operator** đã có registered actions `run tests` / `build pack` / `verify pack` > qua `action-gate`, không free-command, kết quả có artifact provenance. **MVP-2 > Track 4 foundation** đã có `agent-registry.yaml`, agent/skill resolver, RBAC > gate chọn agent, delegation hold, tool allowlist block, Control Panel agent picker. > **Operator Track 5/6** đã bind mỗi side-effect turn vào Plan-17 `loop-run.sh`, > verify trace/replay, H4 preflight/context/tool-output scan, và chỉ release action > sau khi draft được certify. **CODEGEN-as-loop** đã có draft-only artifact scan + > loop certification. **Track 8.1/8.2/8.3/8.4** đã có replay/verify-chain > foundation, Command Center Chat/Loop widget đọc chat audit/replay evidence thật, > và escalation vào approvals inbox. > **Track 9/MVP-3** đã partition chat state theo tenant, guard explicit paths, > ghi encrypted audit snapshot, và scope kill-switch/quota theo tenant. > Mục tiêu > tổng thể vẫn là thêm **cửa sổ chat** vào Control Plane (Plan-13) như một > **bề mặt tương tác của core harness** — mỗi lượt chat là **một loop-run được > governance** (Plan-17), đi qua đúng H1→H7, không có đường vòng. Đây **không** phải > một chatbot; nó là **governed agent console**. > > Nhãn trạng thái: xem legend ở `CASAN_BACKLOG_STATUS.md`. > Phụ thuộc: **17** (Loop Contract — turn = loop-run; budget/convergence/verify/trace) · > **13** (Control Plane — API bọc harness, HITL inbox §3.4, Command Center §8.6) · > **14** (RBAC — ai được chat/chọn agent nào) · **16** (fail-closed, approval JWT thật, > secure-by-default, tamper-evidence — Plan-18 PHẢI tuân) · **03/02** (model-router + > skill/agent) · **08** (nén context giữa vòng) · **07** (H5 audit, C4 approval, C7 > kill-switch). **Chặn cứng multi-user:** SEC-23 (tenant-partition) — chat state là > per-tenant, không được dùng file chung. > > **⚠️ Scope note (chống lan man — đọc trước khi implement):** file này mô tả **target > architecture** cho Governed Chat Console production. **KHÔNG implement toàn bộ một > lần.** MVP đầu tiên chỉ là **Ask CASAN — Read-only Evidence Assistant**: Prompt > Router chỉ `READ_ONLY/BLOCK/NOT_SUPPORTED`, context whitelist (Evidence Pack/reports/ > docs), H4 scan in/out, H5 audit chat, H6 token tracking, trả lời **kèm nguồn > evidence**. Operator/Codegen/Agent-selection/Chat-as-loop/tenant-hardening làm **theo > phase sau** (xem §1b). Thứ tự bắt buộc: **MVP-0 → MVP-1 → MVP-2 → MVP-3**; không mở > khoá phase sau khi phase trước chưa xanh CI. --- ## 1. Bối cảnh — vì sao là "chat", vì sao qua harness CASAN đã là **loop-engineering** (Plan-17): `observe→act→verify→correct` với gate mỗi vòng, budget, hội tụ, leo thang cho người. Nhưng bộ máy đó hiện **chạy batch/CLI** — con người không "ngồi trong vòng lặp". **Chat console** biến vòng lặp đó thành một **bề mặt hội thoại**: người nhập ý định → agent chạy một loop-run được governance → người thấy từng bước, duyệt khi cần, bấm dừng khi muốn. **Ranh giới quyết định (nếu vi phạm thì đừng làm):** | Chatbot thường (❌ không làm) | Governed Chat Console (✅ plan này) | |---|---| | Input → model → stream thẳng ra | Input → **H4 preflight/injection** → route → **act qua action-gate** → **H3/H4 verify** → mới lộ | | Tool call tự do | Mọi tool-call qua `action-gate` + `tool-exec` sandbox + tool-allowlist theo agent | | Chọn agent = tiện ích UI | Chọn agent = **quyết định routing được RBAC + approval + audit** | | Lịch sử = 1 file/log chung | Lịch sử **per-tenant** (SEC-23), hash-linked, replay được | | "Model nói xong là xong" | `DONE` chỉ hợp lệ khi verify đạt **success-criteria** (Plan-17 §3) | > **Một câu:** chat không phải kênh mới để *né* harness; chat là **cửa để harness trở > nên hữu hình**. Giá trị nằm ở chỗ mỗi lượt đều **verify được, replay được, > click-to-evidence được**. ### Bám tư tưởng (FPT §4.3/§4.4/§14 · tư tưởng CASAN) - **Human-led, AI-first** hiện thân trực tiếp: chat là nơi con người **nhìn thấy & hành động** trong vòng lặp (nối Plan-13 §3.4 approvals inbox + delegation L0–L5). - **Core harness là lõi, không phải source-gen:** chat là **vỏ mỏng** trên harness core (single-source governance) — nó **không** thêm quyền phán quyết mới, không tái hiện gate. Ưu tiên vẫn là củng cố core (Index P1); chat đứng **sau** Plan-17. - **Governance-first, không "wow rỗng":** mọi số trên UI có provenance envelope (Plan-13 §8.6) — đọc từ artifact thật, không vanity. --- ## 1b. Lát cắt MVP & thứ tự thực thi (bắt buộc — chống scope-creep) > Plan-18 = **target architecture**. Để làm gần mà không ngợp, cắt thành **4 lát**, > mỗi lát tự đứng được (shippable) và **không** mở khoá lát sau nếu lát trước chưa > xanh CI. Đây là phần chống "càng làm càng nhiều chức năng". | MVP | Tên | Làm gì | KHÔNG làm | Phụ thuộc thêm | Tracks | |---|---|---|---|---|---| | **MVP-0** | **Ask CASAN** (Read-only Evidence Assistant) | Chat panel đọc **whitelist** (Evidence Pack/reports/docs); Prompt Router `READ_ONLY/BLOCK/NOT_SUPPORTED`; H4 scan in/out; H5 audit; H6 token; trả lời **kèm nguồn** | Không command · không file-write · không skill/agent exec · không tenant/RBAC nặng | **Không cần Plan-17/14/SEC-23** — chỉ H4/H5/H6 (đã có) + model-router read-only | 0 (rút gọn), 1, 2, M (tối thiểu), 7 (UI tối thiểu) | | **MVP-1** | **Operator** (registered actions) | Whitelist hành động an toàn: `run tests` / `build pack` / `verify pack` qua `action-gate` | Không codegen · không agent tự chọn · không loop tự chủ · không free-command | +Plan-07 action-gate/kill-switch | 3 | | **MVP-2** | **Chat-as-Loop + Agent/Skill** | Turn = loop-run (Plan-17); agent/skill selection (RBAC+allowlist); codegen qua H4; streaming draft-hold | Không multi-tenant production | **+Plan-17 (T1–T3), +Plan-14 RBAC** | 4, 5, 6, 8 | | **MVP-3** | **Multi-tenant governed production** | tenant-partition (SEC-23), per-tenant encrypt, approvals inbox đầy đủ, replay/verify-chain KMS | — | **+SEC-23, +Plan-07 TIER-2** | 9, 8 (đầy đủ) | > **Quy tắc cổng:** MVP-0 **không** phụ thuộc Plan-17/14/SEC-23 ⇒ làm được ngay trên > nền hiện có. Loop-core (Plan-17) + RBAC (14) chỉ cần từ **MVP-2**; tenant-partition > (SEC-23) chỉ cần ở **MVP-3**. Một tính năng chỉ "thật" khi có test đối kháng xanh. --- ## 2. Nguyên tắc (bắt buộc — kế thừa Plan-16 + Plan-17) 1. **Không đường vòng.** Chat input là input-vector trực tiếp ⇒ đi qua **cùng** `harness-preflight` (PII→cloud), `security-check`/H4, `context-assemble-scan`, `tool-output-scan` như mọi luồng khác. UI/API **không** được bypass gate. 2. **Single-source governance.** Chat backend gọi lại `.specify/**` harness core (đúng mô hình "API bọc harness" của Plan-13). **Cấm** reimplement verdict ở tầng chat. 3. **Secure-by-default = L1.** Mặc định người duyệt mọi hành động có side-effect; tăng tự chủ (L→L+1) là **security-sensitive** ⇒ approval JWT thật + SoD + versioned + rollback (bài học ARCH-03/SEC-07). Profile `prod` bật enforce mặc định. 4. **Fail-closed toàn diện.** Gate lỗi/timeout/không đọc được policy ⇒ **chặn lượt** (không "cứ trả lời"). Kế thừa SEC-04/SEC-09. 5. **Tenant-partition từ ngày đầu.** `chat_id`/lịch sử/loop-trace phân vùng theo `tenant_id` + quyền FS; không file chung (MT-01/SEC-23). RBAC ở **cả tầng dữ liệu**, không chỉ API. 6. **Streaming có kỷ luật.** Được stream **draft** nhưng gắn nhãn `UNCERTIFIED` tới khi H3/H4 pass; **side-effect/tool-call bị giữ** cho tới lúc pass (xem §3c). 7. **Mọi lượt replay được.** Turn = loop-run ⇒ ghi vào loop-trace hash-linked (Plan-17 Track 4). Không nhúng secret (chỉ `*_ref`). --- ## 3. Định nghĩa — "Chat Turn = Loop Run" Một **chat** là chuỗi **turn**. **Mỗi turn = một loop-run của Plan-17** (không định nghĩa vòng lặp riêng — tái dùng Loop Contract §3 của Plan-17). Bản ghi bất biến: ``` ChatTurn = { chat_id, tenant_id, turn_id, actor, user_msg_ref, # tham chiếu (không nhúng PII/secret thô) agent_selected, skill_selected, tool_allowlist, delegation_level, # bind theo agent (§3c) loop_run_id, # NỐI Plan-17: turn chạy như 1 loop-run preflight_verdict, # H4: PII→cloud / injection (PASS|DENY) iterations[], # từng Iteration theo Loop Contract (Plan-17 §3) output_ref, certified, # certified=false ('UNCERTIFIED') tới khi H3/H4 PASS decision # ANSWERED | ESCALATED | HALTED | DENIED } ``` **Điều kiện kết thúc turn** (ánh xạ thẳng Plan-17 §3): - `ANSWERED` — verify đạt success-criteria ⇒ output `certified=true`. - `ESCALATED(human)` — gate DENY nghiêm trọng / stall rủi ro cao ⇒ vào approvals inbox (Plan-13 §3.4). - `HALTED` — budget governor (Plan-17 T1) / convergence (T2) / loop-breaker người bấm. - `DENIED` — RBAC/preflight chặn ngay từ đầu. ### 3a. Kiến trúc luồng một turn ```mermaid flowchart TD U["User msg + chọn agent/skill"] --> RB{"RBAC (14):
được chat + chọn agent này?"} RB -- no --> DEN["DENIED + lý do (audit)"] RB -- yes --> BIND["bind tool-allowlist + delegation_level (§3c)"] BIND --> PF{"H4 preflight:
PII→cloud, injection scan"} PF -- DENY --> DEN PF -- PASS --> H1["H1 context assemble + compress (Plan-08, must-keep)"] H1 --> RT["model-router --role + agent (03/02)"] RT --> LOOP["loop-run.sh (Plan-17): observe→act→verify→correct"] LOOP --> ACT["act: tool-call → action-gate + tool-exec sandbox
(chỉ tool trong allowlist)"] ACT --> VG{"loop-gate verify (Plan-17 T3):
H3 eval + H4 security"} VG -- FAIL --> CORR["structured correction (bounded, T1)"] --> ACT VG -- DENY/sensitive --> ESC["ESCALATE → approvals inbox (13 §3.4)"] VG -- PASS --> REVEAL["reveal output (certified=true)"] LOOP -. draft .-> DRAFT["stream UNCERTIFIED (side-effect giữ) (§3c)"] REVEAL --> TR["loop-trace record (T4) + H5 audit (per-tenant)"] TR --> GOV{"budget governor (T1) + convergence (T2)"} GOV -- continue --> H1 GOV -- DONE/HALT --> END["kết thúc turn (replayable)"] style VG fill:#fff3cd,stroke:#8a6d3b,stroke-width:2px style RB fill:#d0e8ff,stroke:#2c3e91,stroke-width:2px ``` ### 3b. Điểm căng đã quyết: **Streaming vs Verify-before-output** - **Read-only agent (L0):** cho **stream trực tiếp** (không side-effect) — vẫn qua preflight, output vẫn đi qua H3/H4 rồi mới `certified=true`. - **Agent có side-effect (≥L1):** **stream draft `UNCERTIFIED`** cho UX, nhưng **mọi tool-call/ghi file/exec bị GIỮ** đến khi `loop-gate` PASS; nếu DENY → draft bị thu hồi, không có tác dụng phụ nào xảy ra. - **Bất biến:** draft **không bao giờ** được thực thi tool trước gate. "Nhìn thấy" ≠ "đã làm". ### 3c. Chọn skill/agent = **routing được governance** (không phải dropdown tự do) - `agent-registry.yaml` (managed qua Control Plane, versioned + audit): mỗi agent khai báo `tool_allowlist`, `max_delegation_level`, `roles_allowed`, `model_role`. - Chọn agent ⇒ **bind** `tool_allowlist` + `delegation_level` cho turn đó; RBAC (14) quyết ai được chọn agent nào; chọn agent tự chủ cao hơn mức cho phép = **security- sensitive** ⇒ approval JWT thật + SoD. - Skill (code-gen) chạy **trong** allowlist của agent + vẫn qua H4 artifact-scan như Plan-02. Không có skill nào "thoát" gate. ### 3d. Prompt Mode Router (rule-first, model-assisted) — cổng phân loại TRƯỚC loop > Không phải chat nào cũng cần một loop-run nặng. **Router phân loại ý định TRƯỚC**, > rồi mới quyết mức xử lý — read-only thì nhẹ, operator/codegen mới nặng. Đây là lý do > MVP-0 không cần Plan-17: `READ_ONLY` không kích hoạt loop-run. | Mode | Ý nghĩa | Cho phép | Gate / mức | MVP | |---|---|---|---|:--:| | `READ_ONLY` | Hỏi–đáp trên evidence/doc whitelist | đọc context whitelist | H4 in/out, không side-effect | 0 | | `ANALYSIS` | Suy luận/tổng hợp không side-effect | đọc rộng hơn + reasoning | H4 in/out, L0 | 0/1 | | `OPERATOR` | Chạy hành động đã đăng ký | run/build/verify pack | action-gate + approval theo mức | 1 | | `CODEGEN` | Sinh/sửa mã | skill trong allowlist | H4 artifact-scan + loop-gate | 2 | | `ADMIN`/`GOVERNANCE` | Đổi settings/policy/delegation | control-plane-settings | approval JWT + SoD (security-sensitive) | 2/3 | | `BLOCK`/`NOT_SUPPORTED` | Injection / ngoài phạm vi / nguy hiểm | — | DENY + audit | 0 | **Nguyên tắc router:** - **Rule-first, deterministic:** phân loại theo *requested-capabilities* + *denied-verbs* + *bypass-terms* (regex/keyword), **không** phụ thuộc model. - **Model-assisted chỉ cho ca mơ hồ**, và **rule thắng nếu rủi ro cao hơn** (model nói `READ_ONLY` nhưng rule thấy `rm -rf`/`deploy`/`chmod` ⇒ giữ mức cao / `BLOCK`). - **Preview cho người:** UI hiện `mode phát hiện + risk + gates + có cần approval`. - **Fail-closed:** router lỗi / không đọc được policy ⇒ `BLOCK`; kết quả phân loại ghi vào H5 audit. --- ## 4. Tasks theo track (gắn nhãn MVP) > Thứ tự đọc = thứ tự làm: **Router → Read-only → session/audit → operator → agent → > loop → streaming → API/UI → replay → tenant.** Mỗi track gắn nhãn MVP; **không** làm > track của MVP sau khi MVP trước chưa xanh CI. Tất cả verify trong **WSL** (deterministic). ### Track 0 — Prompt Mode Router `[MVP-0 rút gọn → đầy đủ ở MVP-1/2]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.0.1 | ✅ Định nghĩa modes + policy map `READ_ONLY/OPERATOR/BLOCK/NOT_SUPPORTED` | `packages/casan-harness/config/prompt-modes.yaml` | schema validate; thiếu/corrupt policy → BLOCK | | 18.0.2 | ✅ Classifier **deterministic**: requested-capabilities + denied-verbs + bypass-terms | `packages/casan-harness/scripts/bash/prompt-mode-router.py` | `rm -rf`/injection → BLOCK; `deploy` → NOT_SUPPORTED | | 18.0.3 | ✅ Model-assisted **skip-aware**; MVP-0 không cần model | cùng file | không model → vẫn phân loại bằng rule | | 18.0.4 | ✅ **Rule thắng model** khi rule rủi ro cao hơn | cùng file | model=READ_ONLY + rule=BLOCK/NOT_SUPPORTED → giữ rule | | 18.0.5 | ✅ Preview `{mode, risk, gates, needs_approval}` cho UI | cùng file | payload đúng cho từng mode | | 18.0.6 | ✅ Kết quả router được ghi trong ChatTurn H5; fail-closed lỗi policy → BLOCK | `chat-readonly.py` | router lỗi → BLOCK + audit turn | ### Track 1 — Read-only Ask CASAN (Evidence Assistant) `[MVP-0]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.1.1 | ✅ Context **whitelist**: Evidence Pack + reports + docs (đọc-only, chặn path ngoài whitelist) | `packages/casan-harness/scripts/bash/chat-readonly.py` | hỏi ngoài whitelist → không lộ | | 18.1.2 | ✅ Trả lời **kèm nguồn** (`answer + sources[]`, provenance envelope) | cùng file | mỗi câu trả lời có ≥1 source ref | | 18.1.3 | ✅ H4 scan **input + output**; H6 token tracking mỗi lượt | nối `security-check.sh` + metrics jsonl | injection → DENY; token ghi H6 | | 18.1.4 | ✅ Cấm tuyệt đối side-effect ở mode này (no command/no write/no skill) | router guard | side-effect → NOT_SUPPORTED/BLOCK | ### Track 2 — Chat session + audit trace `[MVP-0]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.2.1 | ✅ Schema phiên `chat_id/turn_id/actor` (tenant-ready; MVP-0 single-tenant OK) | `packages/casan-harness/config/chat-session.schema.json` | schema validate | | 18.2.2 | ✅ Ghi `ChatTurn` (§3) append-only, hash-linked H5 (không nhúng PII/secret, chỉ hash/ref/preview) | `chat-readonly.py verify-audit` | N turn → chain liên tục; secret không lộ | | 18.2.3 | ✅ Không lưu raw message; audit lưu hash/ref/preview đã scan | cùng file | msg có secret token → audit không lộ raw secret | ### Track M — Model Provider Binding `[MVP-0 tối thiểu → lớn dần]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.M.1 | `provider_id` per agent + `model_role` per skill; routing theo mode (nối Plan-03/02) | mới `config/model-providers.yaml` | mode → provider đúng | | 18.M.2 | Data policy `local/internal/cloud`: **PII/secret → cloud phải qua C3 guard** | nối `data-exfil-guard.sh` (C3) | PII→cloud không guard → BLOCK | | 18.M.3 | Credential ngoài repo (env/secret store), không commit | nối `secrets-scan.sh` | key trong repo → scan FAIL | | 18.M.4 | Provider-call audit + token/cost telemetry → H6 | nối H6 | mỗi call → có bản ghi cost | ### Track 3 — Operator mode (registered actions) `[MVP-1]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.3.1 | ✅ Whitelist hành động: `run tests` / `build pack` / `verify pack` (đăng ký, **không** free-command) | `packages/casan-harness/config/operator-actions.yaml` | lệnh ngoài whitelist → DENY | | 18.3.2 | ✅ Mỗi action qua `action-gate` (ALLOW/WARN/REQUIRE_APPROVAL/BLOCK) | `chat-operator.py` + `action-gate.sh` | dangerous → BLOCK; network → REQUIRE_APPROVAL | | 18.3.3 | ✅ Kết quả action là artifact có provenance, hiển thị lại trong chat | `chat-operator.py` + `/chat` UI | action → evidence link | ### Track 4 — Agent/Skill selection governance `[MVP-2]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.4.1 | ✅ `agent-registry.yaml` versioned (tool_allowlist, max_delegation, roles_allowed, model_role) + resolver bind theo turn | `packages/casan-harness/config/agent-registry.yaml` + `chat-agent-resolver.py` | chọn agent → allowlist đúng | | 18.4.2 | ✅ RBAC gate chọn agent (14): role không đủ → DENY; vượt `max_delegation` → security-sensitive → approval hold | nối `rbac-check.py` (`chat:select_agent`) | role thấp chọn agent tự chủ → DENY | | 18.4.3 | ✅ Tool-call runtime chỉ tool **trong allowlist**; ngoài → BLOCK trước runtime | `chat-agent-resolver.py` | tool ngoài allowlist → BLOCK | | 18.4.4 | ✅ Skill code-gen chạy trong allowlist + H4 artifact-scan (Plan-02) trước output | `chat-turn.py` + `artifact-scan.sh` | skill sinh mã có injection → BLOCK | ### Track 5 — Chat-as-loop pipeline `[MVP-2]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.5.1 | 🟡 OPERATOR path done: preflight → router → agent bind → `loop-run.sh` → trace/replay → action release (**gọi harness core, không reimplement**). CODEGEN/full model-router path còn pending | `chat-turn.py` | bỏ gate/draft injection → test FAIL | | 18.5.2 | 🟡 OPERATOR turn = loop-run: budget governor + convergence + verify-contract (Plan-17 T1/T2/T3) | nối Plan-17 `loop-run.sh`/`loop-trace.py` | operator turn có `loop_run`, trace verify + replay OK | | 18.5.3 | ✅ Preflight bắt buộc cho OPERATOR: `harness-preflight` + `context-assemble-scan` + `tool-output-scan`, fail-closed | nối H4 | injection trong msg → DENY, side-effect không chạy | ### Track 6 — Streaming / verify reconciliation `[MVP-2]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.6.1 | ✅ OPERATOR draft-hold: draft artifact `UNCERTIFIED` giữ side-effect tới khi `loop-run` PASS | `chat-turn.py` + API | side-effect trước gate → không xảy ra | | 18.6.2 | ✅ DENY sau draft/preflight → draft held, turn `DENIED/HALTED`, audit; không action | cùng | draft bị DENY → không tác dụng phụ | | 18.6.3 | ✅ L0 read-only stream thẳng; ≥L1 OPERATOR bắt buộc draft-hold | resolver + `chat-turn.py` | L1 operator không stream-exec thẳng | ### Track 7 — Chat API (NestJS) + UI (React) trên Command Center `[MVP-0 tối thiểu → lớn dần]` | Task | Việc | File | Verify | |---|---|---|---| | 18.7.1 | ✅ Chat API (NestJS) **bọc** harness (MVP-0/1: read-only + operator; single-source, không verdict riêng) | `packages/casan-control-panel/backend/src/chat/*` | API gọi `chat-turn.py`; `console:test` xanh | | 18.7.2 | ✅ Chat panel React + hiển thị **evidence sources**, registered actions, action-gate + badge `mode/risk` | `packages/casan-control-panel/frontend/src/pages/Chat.tsx` | `console:build` xanh | | 18.7.3 | 🟡 agent/skill picker theo RBAC + delegation-level + loop certification badges + replay/evidence surfaces đã có; nút **loop-breaker** trực tiếp vẫn là target UI follow-up | Control Plane UI | picker hiện locked agent, backend DENY agent ngoài quyền; OPERATOR/CODEGEN hiện `loop_run` | | 18.7.4 | Fail-loud: API/telemetry chết → UI `STALE/503` (tái dùng D3 `/healthz`) | nối Plan-07 D3 | ngắt backend → UI báo stale | ### Track 8 — Replay / Evidence / Command Center widgets `[MVP-2 → MVP-3]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.8.1 | ✅ **Replay** một turn (verify lại artifact đã ghi) phát hiện tamper/non-determinism | `chat-replay.py` + `loop-trace.py replay` | sửa artifact turn → replay lệch | | 18.8.2 | ✅ `verify-chain` lịch sử chat (tamper-evidence, SEC-01/02; KMS khi TIER-2 là follow-up) | `chat-replay.py verify-chain` | sửa 1 turn → chain BREAK | | 18.8.3 | ✅ Widget **Chat/Loop** trên Command Center (13 §8.6): ticker per-iteration, budget gauge, click → Evidence drawer | `GET /api/v1/command` + `/command` | số khớp fixture; click → evidence | | 18.8.4 | ✅ **Approvals/Escalation panel**: turn `ESCALATED` vào approvals inbox (13 §3.4), duyệt/từ chối (JWT + SoD + lý do) | `chat-turn.py` + `approval-inbox.py` + `/approvals` | escalate → pending; JWT giả → DENY | ### Track 9 — Multi-tenant hardening `[MVP-3]` | Task | Việc | File | Verify (WSL) | |---|---|---|---| | 18.9.1 | ✅ tenant-partition state + quyền FS (SEC-23); RBAC ở **cả tầng dữ liệu** | `tenant-store.sh` + chat audit/replay paths | tenant A không đọc/ghi state B | | 18.9.2 | ✅ per-tenant encrypt at-rest (MT-02 offline snapshot) | `tenant-crypt.sh` | admin/tenant B không decrypt audit A | | 18.9.3 | ✅ quota / kill-switch scope theo tenant (MT-03) | `kill-switch.sh` + `cost-spike-detect.sh` | 1 tenant burn budget không ảnh hưởng tenant khác | --- ## 5. Red-team / test (kế thừa phong cách adversarial-harness) | Test | Kỳ vọng | |---|---| | Injection trong chat msg (VI/JA/split/base64) | preflight/H4 → DENY, không tới model context | | Prompt Router: model=READ_ONLY nhưng msg có `rm -rf`/`deploy` | **rule thắng** → OPERATOR/BLOCK, không READ_ONLY | | Read-only hỏi tài liệu ngoài whitelist | không lộ nội dung ngoài whitelist | | PII/secret → cloud provider không qua C3 | BLOCK trước khi gọi provider | | Bypass-attempt: gọi API bỏ qua preflight | pipeline từ chối (không có đường vòng) | | Agent ngoài quyền (RBAC) | DENIED trước khi chạy | | Chọn delegation vượt mức (không approval) | security-sensitive → DENY tới khi có JWT + SoD | | Tool-call ngoài allowlist của agent | action-gate BLOCK | | Streaming abuse: side-effect trước gate | GIỮ; không tác dụng phụ; DENY → thu hồi draft | | Cross-tenant: chat A đọc lịch sử B | chặn ở tầng dữ liệu (SEC-23) | | Runaway chat (loop vô hạn) | HALT(budget) (Plan-17 T1) | | Self-declared done (model nói xong, verify fail) | KHÔNG `ANSWERED/certified` | | Replay tamper (sửa turn đã ghi) | replay lệch + chain BREAK | **File test (theo MVP):** MVP-0 — `phase-chat-prompt-router-tests.sh`, `phase-chat-readonly-tests.sh`, `phase-chat-session-audit-tests.sh`; MVP-1 — `phase-chat-operator-tests.sh`; MVP-2 — `phase-chat-agent-select-tests.sh`, `phase-chat-pipeline-tests.sh`, `phase-chat-stream-hold-tests.sh`, `phase-chat-replay-tests.sh`, `phase-chat-approval-tests.sh`, `phase-chat-codegen-tests.sh`; MVP-3 — `phase-chat-tenant-tests.sh`. Chạy **WSL** (deterministic, mock model; nhánh live cần Ollama SKIP-aware). Nối `ci-harness-gate.sh`; cập nhật tổng test ở `CASAN_HARDENING_STATUS.md`. --- ## 6. Tiêu chí hoàn thành (Definition of Done) **MVP-0 (Ask CASAN read-only) — cổng ship đầu tiên:** - [x] Prompt Router phân loại `READ_ONLY/BLOCK/NOT_SUPPORTED` deterministic; **rule thắng model**; router lỗi → BLOCK. - [x] Chat chỉ đọc **whitelist**; hỏi ngoài whitelist không lộ; **không** command/write/skill. - [x] H4 scan input+output; H5 audit mỗi lượt; H6 token tracking. PII→cloud full provider policy vẫn thuộc Track M/Plan-15 khi bật model provider thật. - [x] Trả lời **kèm ≥1 nguồn evidence**; UI hiện sources + badge mode/risk. - [x] Suite MVP-0 xanh và nối CI; không đụng OKR app. Verify: `phase-chat-prompt-router` 6/0, `phase-chat-readonly` 5/0, `phase-chat-session-audit` 3/0, `console:test` 23/0, `console:build` xanh. **MVP-1 (Operator registered actions):** - [x] Registered action whitelist có `run-chat-tests`, `build-evidence-pack`, `verify-evidence-pack`; không chạy free-command. - [x] Mọi action đi qua `action-gate`; BLOCK/REQUIRE_APPROVAL không thực thi command. - [x] Kết quả action ghi artifact có provenance và được hiển thị lại trong `/chat`. - [x] Suite MVP-1 xanh và nối CI. Verify: `phase-chat-operator` 8/0, prompt-router 8/0, read-only 5/0, session-audit 3/0, `console:test` 24/0, `console:build` xanh. **MVP-2 Track 4 foundation (Agent/Skill selection governance):** - [x] Agent registry versioned có `tool_allowlist`, `max_delegation_level`, `roles_allowed`, `model_role`. - [x] Agent resolver bind theo turn, ghi audit hash-chain, fail-closed khi registry lỗi. - [x] RBAC gate `chat:select_agent`; role thấp chọn agent tự chủ → DENY; cross-tenant → DENY. - [x] Delegation vượt agent max → `REQUIRES_APPROVAL`; tool ngoài allowlist → BLOCK trước runtime. - [x] Control Panel `GET /api/v1/chat/agents`, `/chat` agent/skill/delegation picker, response có `agent_binding`. Verify: `phase-chat-agent-select` 8/0, RBAC 12/0, SEC-23 RBAC 6/0, `console:test` 25/0, `console:build` xanh. - [x] CODEGEN draft path binds `codegen-draft`/`sourcegen-draft`, proves `artifact-scan` + `tool-output-scan` in allowlist, blocks injected generated artifacts, and certifies draft-only artifact through Plan-17 loop-run. Verify: `phase-chat-codegen` 4/0, `phase-chat-prompt-router` 9/0. **MVP-2 Track 5/6 OPERATOR slice (Chat-as-loop + draft-hold):** - [x] OPERATOR turns create an `UNCERTIFIED` draft artifact, run `harness-preflight`, `context-assemble-scan`, `loop-run.sh`, `loop-trace verify-chain`, and `loop-trace replay` before action release. - [x] Side effects are held until `loop_run.draft_certified=true`; denied drafts keep `side_effect_released=false` and do not execute the registered action. - [x] Tool output is scanned with `tool-output-scan.sh` before returning the operator result to chat. - [x] Control Panel response includes `loop_run`; `/chat` displays loop certification/replay status. Verify: `phase-chat-pipeline` 4/0, `phase-chat-stream-hold` 2/0, `phase-chat-operator` 8/0, `console:test` 25/0, `console:build` xanh. **MVP-2 Track 8.1/8.2 (Replay / verify-chain foundation):** - [x] `chat-replay.py verify-chain` recomputes chat audit hash-chain and fails closed on edited records. - [x] `chat-replay.py replay` verifies recorded evidence artifact hashes and replays OPERATOR loop traces via `loop-trace.py replay`. - [x] Control Plane `GET /api/v1/chat/replay` wraps harness replay; no verdict reimplementation in NestJS. - [x] Tampered operator evidence artifact → `DRIFT`; tampered chat audit → `BREAK`. Verify: `phase-chat-replay` 4/0, `console:test` 25/0, `console:build` xanh. **MVP-2 Track 8.3 (Command Center Chat/Loop widget):** - [x] `GET /api/v1/command` exposes `chat_loop` widget backed by `.specify/logs/chat/chat-turns.jsonl` and harness `chat-replay.py`. - [x] Widget metrics include turns, answered/action-completed counts, loop-run count, replay records, replayed loops, and token budget gauge from real chat metrics. - [x] `/command` renders the Chat/Loop card in the existing evidence drawer flow; ticker includes recent chat/loop turns. - [x] Fixture test proves counts and budget gauge match evidence. Verify: `console:test` 26/0, `console:build` xanh, `phase-chat-replay` 4/0. **MVP-2 Track 8.4 (Approvals / escalation):** - [x] Delegation escalation (`REQUIRES_APPROVAL`) from chat creates an `ESCALATED` ChatTurn and pending `chat.escalate` proposal in `approval-inbox.py`. - [x] Approval inbox keeps SoD and reason requirements; strict mode / supplied approval JWT calls `approval-verify.sh` and fake JWT is denied before proposal mutation. - [x] Control Panel `/approvals` can pass an approval JWT for strict review; dev mode remains backward-compatible. - [x] Verify: `phase-chat-approval` 4/0, `phase-chat-agent-select` 8/0, `phase-chat-replay` 4/0, `console:test` 28/0, `console:build` xanh. **MVP-3 Track 9 (Multi-tenant hardening):** - [x] Non-default tenant chat turns write audit/head/agent-binding/metrics/artifacts/loop state under `tenant-store.sh` partitions; default single-tenant path remains backward-compatible. - [x] `chat-replay.py` and explicit chat audit overrides are guarded by tenant-store, so tenant A cannot point replay at tenant B's audit path. - [x] Chat audit writes create per-tenant encrypted `.enc` snapshots via `tenant-crypt.sh`; tenant B cannot decrypt tenant A's snapshot. - [x] Chat entry checks tenant-scoped kill-switch and tenant cost quota before work; tenant A halt/quota does not halt tenant B. - [x] Verify: `phase-chat-tenant` 8/0, `console:test` 29/0, `console:build` xanh. **Full (target architecture) — DoD tổng:** - [ ] Turn chạy **đúng như một loop-run Plan-17** (không định nghĩa vòng lặp riêng). - [ ] **Không đường vòng:** test chứng minh bỏ bất kỳ gate nào (preflight/verify) → FAIL. - [ ] Chọn agent/skill qua **RBAC + allowlist**; nâng delegation cần **approval JWT + SoD**. - [ ] Streaming: side-effect **luôn** sau gate; draft DENY → thu hồi, không tác dụng phụ. - [x] Chat state **per-tenant**; test cross-tenant bị chặn ở tầng dữ liệu. - [ ] Turn **replay được** + `verify-chain` phát hiện tamper. - [ ] API chỉ **bọc** harness (không verdict riêng); UI đọc **artifact thật** + click-to-evidence. - [ ] Không đụng OKR app; core harness giữ nguyên số test + thêm suite chat. --- ## 7. Ghi chú trung thực & Non-goals (không lan man) - **[MVP-0 + MVP-1 + MVP-2 + MVP-3] — ✅ done+test.** Ask CASAN read-only, Operator registered actions, agent/skill governance foundation, CODEGEN draft-as-loop, OPERATOR chat-as-loop/draft-hold, replay/verify-chain foundation, Command Center Chat/Loop widget, approvals escalation đã có harness CLI + Control Panel API/UI. Multi-tenant chat state, replay guard, encrypted audit snapshot, tenant kill-switch, và tenant quota đã có test đối kháng. - **MVP-first (chống lan man):** **MVP-0 (Ask CASAN read-only) KHÔNG phụ thuộc Plan-17/ 14/SEC-23** — làm được ngay trên nền H4/H5/H6 hiện có. Chỉ **MVP-2 trở đi** (chat-as- loop + agent) mới cần Plan-17 (T1–T3) + Plan-14 RBAC; **MVP-3** mới cần SEC-23 tenant. Thứ tự bắt buộc: **MVP-0 → MVP-1 → MVP-2 → MVP-3**, không nhảy cóc. - **Phụ thuộc cứng Plan-16:** enforcement chỉ "thật" khi approval JWT thật (SEC-07), fail-closed (SEC-04/09), secure-by-default (SEC-17), tamper-evidence (SEC-01/02) đã vá. - **Non-goals (KHÔNG làm trong plan này):** - Không làm chatbot đa mục đích/khách hàng cuối; đây là **ops/dev console** nội bộ. - Không thêm quyền phán quyết mới ở tầng chat (single-source harness). - Không tự sinh agent/skill mới ngoài `agent-registry` đã governance. - Không stream side-effect; không autonomous-by-default. - Không thay thế core harness track — chat là **vỏ mỏng**, đứng sau core (Index P1). - **Rẻ + verify offline trước:** bắt đầu **Track 0 (18.0.x Prompt Router)** + **Track 1 (18.1.x Read-only Ask CASAN)** + **Track 2 (18.2.x session/audit)** — thuần bash/python, deterministic, mock model, WSL; không cần Plan-17/14/infra. Đây chính là **MVP-0**. - **Giá trị định vị:** biến core harness thành **bề mặt hội thoại có governance** — câu chuyện "wow thực chất": mỗi lượt chat **verify được, replay được, click-to- evidence được**, và là hiện thân trực tiếp của **Human-led, AI-first**. --- _Liên quan: `CASAN_PLAN_17_LOOP_ENGINEERING.md` (Loop Contract — turn = loop-run) · `CASAN_PLAN_13_CONTROL_PLANE.md` (§3.4 HITL inbox, §8.6 Command Center, API bọc harness) · `CASAN_PLAN_14_RBAC.md` (ai được chat/chọn agent) · `CASAN_PLAN_16_SECURITY_AUDIT_REMEDIATION.md` (fail-closed, approval JWT thật, tamper-evidence, SEC-23 tenant-partition) · `CASAN_PLAN_03_CLOUD_PATCH.md` + `CASAN_PLAN_02_LLM_SOURCEGEN.md` (model-router + skill/agent) · `CASAN_PLAN_08_CONTEXT_COMPRESSION.md` (nén context giữa vòng) · `CASAN_PLAN_07_PRODUCTION_HARDENING.md` (H5 audit, C4 approval, C7 kill-switch, D3 fail-loud)._