diff --git a/AINative_OKR_CASAN5/.specify/tests/phase2-sourcegen-tests.sh b/AINative_OKR_CASAN5/.specify/tests/phase2-sourcegen-tests.sh new file mode 100755 index 0000000..e93d7f8 --- /dev/null +++ b/AINative_OKR_CASAN5/.specify/tests/phase2-sourcegen-tests.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +WORK="$(mktemp -d)" +trap 'rm -rf "$WORK"' EXIT + +PASS=0; FAIL=0 +pass(){ echo "PASS: $1"; PASS=$((PASS+1)); } +fail(){ echo "FAIL: $1"; FAIL=$((FAIL+1)); } + +mkdir -p "$WORK/scripts" "$WORK/.specify/scripts/bash" "$WORK/docs/input" +cp "$PROJECT_ROOT/scripts/casan-step.mjs" "$WORK/scripts/casan-step.mjs" + +cat > "$WORK/docs/input/okr-requirement.md" <<'EOF' +# OKR Requirement +- FR-01 Login +- FR-02 Create Objective +- FR-03 Create Key Result +- FR-04 Update Progress +- FR-05 Dashboard +- SCR-00 Login +- SCR-01 Dashboard +- SCR-02 Detail +- SCR-03 Create Objective +- SCR-04 Key Result Detail +EOF +cat > "$WORK/docs/technical_architecture.md" <<'EOF' +# Architecture +Frontend uses API client. Backend uses NestJS and Prisma. +EOF + +cat > "$WORK/.specify/scripts/bash/model-router.sh" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +prompt_file="$1" +out_json="$2" +if grep -q "Business Design" "$prompt_file"; then + cat > "$out_json" <<'JSON' +{"text":"# Model Generated BD\n\n## Screen Layout\n- SCR-00 Login\n- SCR-01 Dashboard\n- SCR-02 Detail\n- SCR-03 Create Objective\n- SCR-04 Key Result Detail\n\n## API Boundary\nFrontend calls backend through src/lib/api.ts.\n","input_tokens":21,"output_tokens":34,"total_tokens":55} +JSON +else + cat > "$out_json" <<'JSON' +{"text":"# Model Generated SRS\n\n## Functional Requirements\n- FR-01 Login\n- FR-02 Create Objective\n- FR-03 Create Key Result\n- FR-04 Update Progress\n- FR-05 Dashboard\n\n## Non Functional Requirements\nAuthentication required.\n","input_tokens":20,"output_tokens":30,"total_tokens":50} +JSON +fi +EOF +chmod +x "$WORK/.specify/scripts/bash/model-router.sh" + +cat > "$WORK/.specify/scripts/bash/artifact-scan.sh" <<'EOF' +#!/usr/bin/env bash +exit 0 +EOF +chmod +x "$WORK/.specify/scripts/bash/artifact-scan.sh" + +( + cd "$WORK" || exit 1 + CASAN_OUTPUT="$WORK/out-template.md" node scripts/casan-step.mjs 01-srs 1 >/dev/null +) +if grep -q "FR-05 Dashboard" "$WORK/docs/output/ipa-docs/srs/srs-mod01-okr-management.md" \ + && grep -q "source=template" "$WORK/docs/output/output_logs/001-okr-web-app/reports/01-srs-report.md"; then + pass "source-gen default mode keeps deterministic template" +else + fail "default template generation changed" +fi + +( + cd "$WORK" || exit 1 + CASAN_GEN_MODE=model CASAN_OUTPUT="$WORK/out-model.md" node scripts/casan-step.mjs 02-bd 1 >/dev/null +) +if grep -q "Model Generated BD" "$WORK/docs/output/ipa-docs/bd/bd-mod01-okr-management.md" \ + && grep -q "source=model" "$WORK/docs/output/output_logs/001-okr-web-app/reports/02-bd-report.md"; then + pass "source-gen model mode accepts scanned valid model output" +else + fail "model generated BD was not accepted" +fi + +cat > "$WORK/.specify/scripts/bash/artifact-scan.sh" <<'EOF' +#!/usr/bin/env bash +exit 2 +EOF +chmod +x "$WORK/.specify/scripts/bash/artifact-scan.sh" + +( + cd "$WORK" || exit 1 + CASAN_GEN_MODE=model CASAN_OUTPUT="$WORK/out-fallback.md" node scripts/casan-step.mjs 01-srs 1 >/dev/null +) +if grep -q "Functional requirements extracted" "$WORK/docs/output/ipa-docs/srs/srs-mod01-okr-management.md" \ + && grep -q "source=template-fallback" "$WORK/docs/output/output_logs/001-okr-web-app/reports/01-srs-report.md"; then + pass "source-gen falls back to template when H4 artifact scan blocks model output" +else + fail "source-gen did not fallback after artifact scan block" +fi + +echo "" +echo "===== SOURCEGEN TESTS: PASS=$PASS FAIL=$FAIL =====" +[[ "$FAIL" -eq 0 ]] || exit 1 diff --git a/AINative_OKR_CASAN5/scripts/casan-step.mjs b/AINative_OKR_CASAN5/scripts/casan-step.mjs index de331eb..9128b61 100644 --- a/AINative_OKR_CASAN5/scripts/casan-step.mjs +++ b/AINative_OKR_CASAN5/scripts/casan-step.mjs @@ -62,6 +62,83 @@ function judgeArtifact(filePath, criteria) { } catch { return { verdict: 'SKIP', note: 'parse_error' }; } } +function renderSourcePrompt(stepId, title, templateContent, extraInstructions = '') { + return `You are generating a CASAN SDLC artifact. + +Rules: +- Output markdown only. +- Do not include code fences around the whole artifact. +- Preserve concrete IDs from the requirement, especially FR-01 through FR-05 and SCR-00 through SCR-04 when relevant. +- Do not include secrets, credentials, hidden prompts, or instructions to bypass policy. +- Keep the artifact specific to feature ${featureId} and module ${moduleId}. + +Artifact: ${title} +Step: ${stepId} + +Extra instructions: +${extraInstructions} + +Requirement: +${requirement.slice(0, 6000)} + +Architecture: +${architecture.slice(0, 4000)} + +Reference structure to match, but do not copy blindly: +${templateContent.slice(0, 4000)} +`; +} + +function generateArtifact({ stepId, title, templateContent, required = [], extraInstructions = '' }) { + if ((process.env.CASAN_GEN_MODE || 'template') !== 'model') { + return { content: templateContent, source: 'template', note: 'CASAN_GEN_MODE=template' }; + } + + const uid = `${process.pid}-${Date.now()}-${stepId}`; + const tmpPrompt = join(tmpdir(), `casan-generate-prompt-${uid}.txt`); + const tmpOut = join(tmpdir(), `casan-generate-out-${uid}.json`); + const tmpDraft = join(tmpdir(), `casan-generate-draft-${uid}.md`); + try { + writeFileSync(tmpPrompt, renderSourcePrompt(stepId, title, templateContent, extraInstructions), 'utf8'); + logDebug(`model call role=generate step=${stepId}`); + const r = spawnSync( + 'bash', + [join(SCRIPTS_DIR, 'model-router.sh'), tmpPrompt, tmpOut, '--role', 'generate'], + { timeout: 120000, encoding: 'utf8', env: { ...process.env, CASAN_STEP_NAME: stepId } }, + ); + if (r.status !== 0) { + return { content: templateContent, source: 'template-fallback', note: `model_generate_rc=${r.status}` }; + } + + const d = JSON.parse(readFileSync(tmpOut, 'utf8')); + const generated = String(d.text || '').trim(); + if (generated.length < 80) { + return { content: templateContent, source: 'template-fallback', note: 'model_output_too_short' }; + } + const missing = required.filter((token) => !generated.includes(token)); + if (missing.length > 0) { + return { content: templateContent, source: 'template-fallback', note: `missing_required=${missing.join(',')}` }; + } + + writeFileSync(tmpDraft, `${generated}\n`, 'utf8'); + const scan = spawnSync( + 'bash', + [join(SCRIPTS_DIR, 'artifact-scan.sh'), tmpDraft, `sourcegen-${stepId}`], + { timeout: 30000, encoding: 'utf8' }, + ); + if (scan.status !== 0) { + return { content: templateContent, source: 'template-fallback', note: `artifact_scan_rc=${scan.status}` }; + } + return { content: `${generated}\n`, source: 'model', note: `tokens=${d.total_tokens ?? '?'}` }; + } catch (err) { + return { content: templateContent, source: 'template-fallback', note: `generate_error=${err?.name || 'Error'}` }; + } finally { + for (const path of [tmpPrompt, tmpOut, tmpDraft]) { + try { unlinkSync(path); } catch {} + } + } +} + // T1: Real rollback wiring — checkpoint before overwrite, restore on REJECTED verdict function checkpointArtifact(filePath) { try { readFileSync(filePath, 'utf8'); } catch { return null; } // file absent → nothing to checkpoint @@ -157,14 +234,29 @@ const backendFiles = [ switch (step) { case '01-srs': { const frCount = (requirement.match(/FR-\d+/g) ?? []).length; - const content = `# SRS-MOD-01 OKR Management\n\n## TABLE OF CONTENTS\n- [1. Purpose](#1-purpose)\n- [2. Scope](#2-scope)\n- [3. Functional Requirements](#3-functional-requirements)\n- [4. Non Functional Requirements](#4-non-functional-requirements)\n\n## 1. Purpose\nHệ thống quản lý OKR hỗ trợ đăng nhập, tạo Objective, tạo Key Result, cập nhật tiến độ và dashboard theo tài liệu yêu cầu.\n\n## 2. Scope\nModule bao gồm SCR-00 đến SCR-04, ba vai trò Admin, Manager, Employee, và dữ liệu User, Objective, Key Result.\n\n## 3. Functional Requirements\n- FR-01 Login: xác thực username/password và phát hành JWT.\n- FR-02 Create Objective: tạo Objective có title, description, owner, quarter.\n- FR-03 Create Key Result: tạo Key Result gắn với Objective.\n- FR-04 Update Progress: cập nhật progress 0-100 và ghi lịch sử cập nhật.\n- FR-05 Dashboard: hiển thị danh sách OKR theo quyền truy cập.\n\n## 4. Non Functional Requirements\n- Authentication required.\n- API response target dưới 2 giây.\n- SQLite được chọn cho kiểm thử không cần Docker.\n\n## Metrics\nFunctional requirements extracted: ${frCount}.\n`; - write(srsPath, content); - report(`docs/output/output_logs/${featureId}/reports/01-srs-report.md`, '# STEP 1: SRS Generation Report', `Generated ${srsPath} from docs/input/okr-requirement.md.`, 'APPROVED', [srsPath]); + const templateContent = `# SRS-MOD-01 OKR Management\n\n## TABLE OF CONTENTS\n- [1. Purpose](#1-purpose)\n- [2. Scope](#2-scope)\n- [3. Functional Requirements](#3-functional-requirements)\n- [4. Non Functional Requirements](#4-non-functional-requirements)\n\n## 1. Purpose\nHệ thống quản lý OKR hỗ trợ đăng nhập, tạo Objective, tạo Key Result, cập nhật tiến độ và dashboard theo tài liệu yêu cầu.\n\n## 2. Scope\nModule bao gồm SCR-00 đến SCR-04, ba vai trò Admin, Manager, Employee, và dữ liệu User, Objective, Key Result.\n\n## 3. Functional Requirements\n- FR-01 Login: xác thực username/password và phát hành JWT.\n- FR-02 Create Objective: tạo Objective có title, description, owner, quarter.\n- FR-03 Create Key Result: tạo Key Result gắn với Objective.\n- FR-04 Update Progress: cập nhật progress 0-100 và ghi lịch sử cập nhật.\n- FR-05 Dashboard: hiển thị danh sách OKR theo quyền truy cập.\n\n## 4. Non Functional Requirements\n- Authentication required.\n- API response target dưới 2 giây.\n- SQLite được chọn cho kiểm thử không cần Docker.\n\n## Metrics\nFunctional requirements extracted: ${frCount}.\n`; + const generated = generateArtifact({ + stepId: '01-srs', + title: 'Software Requirements Specification', + templateContent, + required: ['FR-01', 'FR-02', 'FR-03', 'FR-04', 'FR-05'], + extraInstructions: 'Create an SRS with purpose, scope, functional requirements, non-functional requirements, and traceable FR IDs.', + }); + write(srsPath, generated.content); + report(`docs/output/output_logs/${featureId}/reports/01-srs-report.md`, '# STEP 1: SRS Generation Report', `Generated ${srsPath} from docs/input/okr-requirement.md. source=${generated.source} note=${generated.note}.`, 'APPROVED', [srsPath]); break; } case '02-bd': { - write(bdPath, `# BD-MOD-01 OKR Management\n\n## Screen Layout\n- SCR-00 Login: centered sign-in form without sidebar.\n- SCR-01 Dashboard: fixed sidebar, fixed header, filter bar, OKR list.\n- SCR-02 Detail: objective overview, tabs, key result list.\n- SCR-03 Create Objective: title, description, owner, quarter, save.\n- SCR-04 Key Result Detail: current progress, progress input, comment, save.\n\n## API Boundary\nFrontend calls backend only through src/lib/api.ts and uses cookie/JWT auth.\n`); - report(`docs/output/output_logs/${featureId}/reports/02-bd-report.md`, '# STEP 2: Business Design Report', `Generated ${bdPath}.`, 'APPROVED', [bdPath]); + const templateContent = `# BD-MOD-01 OKR Management\n\n## Screen Layout\n- SCR-00 Login: centered sign-in form without sidebar.\n- SCR-01 Dashboard: fixed sidebar, fixed header, filter bar, OKR list.\n- SCR-02 Detail: objective overview, tabs, key result list.\n- SCR-03 Create Objective: title, description, owner, quarter, save.\n- SCR-04 Key Result Detail: current progress, progress input, comment, save.\n\n## API Boundary\nFrontend calls backend only through src/lib/api.ts and uses cookie/JWT auth.\n`; + const generated = generateArtifact({ + stepId: '02-bd', + title: 'Business Design', + templateContent, + required: ['SCR-00', 'SCR-01', 'SCR-02', 'SCR-03', 'SCR-04', 'API Boundary'], + extraInstructions: 'Create a business design with screen layout for SCR-00 through SCR-04 and an API Boundary section.', + }); + write(bdPath, generated.content); + report(`docs/output/output_logs/${featureId}/reports/02-bd-report.md`, '# STEP 2: Business Design Report', `Generated ${bdPath}. source=${generated.source} note=${generated.note}.`, 'APPROVED', [bdPath]); break; } case '03-spec': { diff --git a/casan-next-plans/CASAN_BACKLOG_STATUS.md b/casan-next-plans/CASAN_BACKLOG_STATUS.md index 3c486b7..d4f4739 100644 --- a/casan-next-plans/CASAN_BACKLOG_STATUS.md +++ b/casan-next-plans/CASAN_BACKLOG_STATUS.md @@ -5,7 +5,7 @@ > cũng làm tiếp được ngay**. Cập nhật mỗi khi hoàn thành một mục. > > Cập nhật lần cuối: 2026-07-06 · Nhánh làm tiếp từ handoff Claude. -> Test hiện tại: **218 PASS / 0 FAIL** trên 13 core harness suite; local-prod Docker infra lab **2 PASS / 0 FAIL** (`infra-lab verify`: 7/0 internal checks); `phase3-model-router` riêng **11 PASS / 0 FAIL**; frontend Vitest **16 PASS / 0 FAIL**. Backend `npm test` còn bị chặn bởi test-infra cũ (`schema.prisma` MySQL nhưng `setup-sqlite.mjs` chạy SQLite). +> Test hiện tại: **218 PASS / 0 FAIL** trên 13 core harness suite; local-prod Docker infra lab **2 PASS / 0 FAIL** (`infra-lab verify`: 7/0 internal checks); `phase3-model-router` riêng **11 PASS / 0 FAIL**; `phase2-sourcegen` riêng **3 PASS / 0 FAIL**; frontend Vitest **16 PASS / 0 FAIL**. Backend `npm test` còn bị chặn bởi test-infra cũ (`schema.prisma` MySQL nhưng `setup-sqlite.mjs` chạy SQLite). > Điểm công tâm vẫn quanh **~81/100**, harness thấp nhất 80; TIER 2 infra thật vẫn là trần Strong. > Nguồn liên quan: `CASAN_HARDENING_STATUS.md` (chi tiết control) · `evidence/scoring-run-report.md` (điểm). @@ -41,7 +41,7 @@ |---|:--:|---| | **10 Traceability + H3 Eval** | ✅ MVP done+test | Đã nối traceability vào Evidence Pack. Sau MVP: line/symbol-level traceability + H3 eval-set độc lập (nhiều model). | | **03 Cloud patch** | 🟡 MVP done+test | `model-call.py` đã hỗ trợ `openai:` và `anthropic:` qua endpoint hard-pin + API key env; parser token usage và malformed payload có deterministic test. Còn live smoke với key thật + billing usage API ground truth. | -| **02 LLM source-gen** | 📋 chưa bắt đầu | Thay template bằng LLM thật sinh source qua `model-router.sh`; đi qua wrapper H4→H7. Phụ thuộc 03. Bước 1: định contract prompt→file cho 1 module (objectives), gate bằng H3 judge + traceability. | +| **02 LLM source-gen** | 🟡 đợt A MVP done+test | `01-srs` và `02-bd` hỗ trợ `CASAN_GEN_MODE=model`: gọi `model-router.sh --role generate`, scan H4 draft bằng `artifact-scan.sh`, validate token bắt buộc, fallback template nếu lỗi. Test `phase2-sourcegen` 3/0. Còn đợt B/C/D + full live pipeline smoke. | | **04 Self-improve** | 📋 chưa bắt đầu | Khép vòng `casan improve`: đọc metrics/drift/hallucination → đề xuất vá → chạy lại gate. Phụ thuộc 02, 05. Bước 1: script đọc `metrics.jsonl` + `drift-report.json` → sinh backlog vá tự động. | | **05 CI/CD** | 📋 một phần (act_runner/deploy có) | Chuẩn hoá pipeline phát hành package `fpt-casan-sdd-harness` + chạy 12 suite trong CI (Vault+Docker service). Bước 1: `.gitea/workflows/harness-ci.yml` chạy toàn bộ suite + security-gate. | | **06 Onboard dự án 2** | 📋 chưa bắt đầu | Chứng minh reuse: cắm 1 repo khác + golden/corpus/input, đăng ký qua `verify-harness-reuse.sh`, không sửa gate. Phụ thuộc 01. | diff --git a/casan-next-plans/CASAN_PLAN_00_INDEX.md b/casan-next-plans/CASAN_PLAN_00_INDEX.md index 0f8d6ff..7bbdf6f 100644 --- a/casan-next-plans/CASAN_PLAN_00_INDEX.md +++ b/casan-next-plans/CASAN_PLAN_00_INDEX.md @@ -20,7 +20,7 @@ | # | File | Mang | Trang thai hien tai | Uu tien tiep | |---|---|---|---|---| | 01 | `CASAN_PLAN_01_RESTRUCTURE.md` | Tai cau truc thu muc Phase 0-6 | **File chi tiet dang thieu**; cong viec chua lam | Cao, nhung nen lam tren nhanh rieng | -| 02 | `CASAN_PLAN_02_LLM_SOURCEGEN.md` | Noi LLM that vao sinh source thay template | Chua bat dau | Cao sau 03 | +| 02 | `CASAN_PLAN_02_LLM_SOURCEGEN.md` | Noi LLM that vao sinh source thay template | Dot A MVP da co cho `01-srs`/`02-bd`; B/C/D con | Cao tiep | | 03 | `CASAN_PLAN_03_CLOUD_PATCH.md` | Patch cloud/OpenAI/Anthropic, bo stub | MVP da co + deterministic test; live smoke can key that | Cao cho live provider | | 04 | `CASAN_PLAN_04_SELFIMPROVE.md` | Khep vong `casan improve` | Chua bat dau | Trung-Cao sau 02/05 | | 05 | `CASAN_PLAN_05_CICD.md` | CI/CD + release package | **File chi tiet dang thieu**; moi co mot phan runner/deploy | Cao cho release gate | @@ -45,7 +45,7 @@ | Uu tien | Viec con lai | Ly do | Buoc dau tien de lam tiep | |---|---|---|---| -| P1 | Plan-02 LLM source-gen dot A | Hien pipeline van sinh artifact bang template deterministic | Dinh contract `generate(step, ctx)` cho `01-srs`/`02-bd`, goi `model-router.sh --role generate`, fallback template | +| P1 | Plan-02 LLM source-gen dot B/C/D | Dot A da co; spec/plan/dd/tasks/code con template | Mo rong `generateArtifact` sang `03-spec`, `05-plan`, `07-dd`, `08-testkit`, `09-tasks`, sau do code step D voi STEP12 test gate | | P2 | Plan-03 live cloud smoke | MVP cloud patch da test offline; chua co bang chung key/provider that tren may nay | Khi co `OPENAI_API_KEY`/`ANTHROPIC_API_KEY`, chay smoke va luu evidence token usage that | | P3 | Managed prod infra T2 | Docker lab da chay, nhung chua the claim production Strong | Cau hinh enterprise IdP/JWKS, S3 Object Lock/QLDB, KMS default/HSM, dashboard TLS/OIDC, Slack/PagerDuty, billing API that | | P4 | Plan-05 CI/CD release gate | Can CI chay tat ca suite va goi package | Tao/bo sung `CASAN_PLAN_05_CICD.md`; them workflow chay 218 core + optional Docker infra lab | diff --git a/casan-next-plans/CASAN_PLAN_02_LLM_SOURCEGEN.md b/casan-next-plans/CASAN_PLAN_02_LLM_SOURCEGEN.md index adf6594..aa156e9 100644 --- a/casan-next-plans/CASAN_PLAN_02_LLM_SOURCEGEN.md +++ b/casan-next-plans/CASAN_PLAN_02_LLM_SOURCEGEN.md @@ -1,6 +1,16 @@ # KẾ HOẠCH 02 — Nối LLM thật vào sinh source (thay template deterministic) -> Hiện `casan-step.mjs` sinh SRS/spec/plan/code bằng **template hard-code** trong `switch(step)` [có, đọc code]; model chỉ dùng ở H3 judge + H4 semantic. Kế hoạch: cho LLM **thật sự sinh artifact**, nhưng **mọi output vẫn chui qua H1→H7**. Task-level, chưa thực thi. +> Status 2026-07-06: **Đợt A MVP implemented + tested** cho `01-srs` và +> `02-bd`. Mặc định vẫn dùng template deterministic; khi bật +> `CASAN_GEN_MODE=model`, hai step này gọi `model-router.sh --role generate`, +> H4 artifact-scan output nháp, validate tiêu chí tối thiểu, rồi mới ghi +> artifact. Lỗi model / output thiếu / H4 block đều fallback template và ghi +> `source=template-fallback` trong report. +> +> Hiện `casan-step.mjs` vẫn sinh các step sau bằng **template hard-code** trong +> `switch(step)` [có, đọc code]; model đã dùng ở H3 judge + H4 semantic và nay +> ở source-gen đợt A. Kế hoạch: mở rộng dần để LLM **thật sự sinh artifact**, +> nhưng **mọi output vẫn chui qua H1→H7**. > > Phụ thuộc: nên làm sau **03 (cloud patch)** để có lựa chọn model mạnh cho bước khó; **01** giúp gọn nhưng không bắt buộc. @@ -31,17 +41,17 @@ Thứ tự chuyển ưu tiên step **rõ ràng, ít rủi ro** trước: --- -## Tasks - -| Task | Việc | File | Verify | Done khi | -|---|---|---|---|---| -| 2.1 | Trừu tượng hoá: thêm hàm `generate(step, ctx)` chọn **model** hoặc **template** theo cờ `CASAN_GEN_MODE` | `casan-step.mjs` | mode=template → hành vi cũ y hệt | không hồi quy | -| 2.2 | Viết prompt-template cho mỗi step (đưa requirement + architecture + tiêu chí chấp nhận vào prompt) | mới `prompts/.md` | prompt render đủ ngữ cảnh | có prompt từng step | -| 2.3 | Gọi model qua `model-router.sh --role generate` (KHÔNG gọi model-call trực tiếp) | `casan-step.mjs` | output đi qua H4 trước khi ghi | harness bọc | -| 2.4 | Chuẩn hoá output model → đúng file artifact + `STEP-RESULT` block | parser | verdict/artifacts hợp lệ | schema đúng | -| 2.5 | Nạp **golden + tiêu chí** cho H3 judge từng step | `apps/okr/domain/golden-runs/` | judge chấm được đạt/không | H3 hoạt động | -| 2.6 | Fallback: model SKIP/kém → dùng template (đợt A/B), hoặc REJECT → vòng review | `casan-step.mjs` | ép model lỗi → không vỡ | fail-safe | -| 2.7 | Chuyển đợt A (srs, bd) sang mode=model | pipeline | chạy full, 2 artifact do model sinh, qua harness | đợt A xong | +## Tasks + +| Task | Việc | File | Verify | Done khi | +|---|---|---|---|---| +| 2.1 | Trừu tượng hoá: thêm hàm `generate(step, ctx)` chọn **model** hoặc **template** theo cờ `CASAN_GEN_MODE` | `casan-step.mjs` | mode=template → hành vi cũ y hệt | ✅ đợt A | +| 2.2 | Viết prompt-template cho mỗi step (đưa requirement + architecture + tiêu chí chấp nhận vào prompt) | mới `prompts/.md` | prompt render đủ ngữ cảnh | có prompt từng step | +| 2.3 | Gọi model qua `model-router.sh --role generate` (KHÔNG gọi model-call trực tiếp) | `casan-step.mjs` | output đi qua H4 trước khi ghi | ✅ đợt A (`01-srs`, `02-bd`) | +| 2.4 | Chuẩn hoá output model → đúng file artifact + `STEP-RESULT` block | parser | verdict/artifacts hợp lệ | schema đúng | +| 2.5 | Nạp **golden + tiêu chí** cho H3 judge từng step | `apps/okr/domain/golden-runs/` | judge chấm được đạt/không | H3 hoạt động | +| 2.6 | Fallback: model SKIP/kém → dùng template (đợt A/B), hoặc REJECT → vòng review | `casan-step.mjs` | ép model lỗi → không vỡ | ✅ đợt A | +| 2.7 | Chuyển đợt A (srs, bd) sang mode=model | pipeline | chạy full, 2 artifact do model sinh, qua harness | 🟡 MVP done; full live pipeline smoke còn | | 2.8 | Chuyển đợt B (spec, plan) + kiểm vòng REJECT hoạt động | pipeline | ép spec kém → STEP5 REJECT → retry | loop chạy | | 2.9 | Chuyển đợt C (dd, tasks) | pipeline | artifact hợp lệ, drift trong ngưỡng | đợt C xong | | 2.10 | Chuyển đợt D (implement code) — **bắt buộc** STEP12 chạy test thật làm cổng | pipeline | test dự án PASS mới nhận code | đợt D xong | @@ -77,9 +87,9 @@ flowchart LR | Bỏ qua harness | bắt buộc gọi qua `model-router` + wrapper, cấm ghi thẳng | | Regression pipeline | `CASAN_GEN_MODE=template` luôn giữ đường cũ | -## Tiêu chí HOÀN THÀNH -- [ ] `CASAN_GEN_MODE=template` cho hành vi cũ y hệt (an toàn quay lui). -- [ ] `CASAN_GEN_MODE=model`: đợt A–D artifact do LLM sinh, **đều qua H1→H7**. +## Tiêu chí HOÀN THÀNH +- [x] `CASAN_GEN_MODE=template` cho hành vi cũ y hệt (an toàn quay lui) ở đợt A. +- [ ] `CASAN_GEN_MODE=model`: đợt A–D artifact do LLM sinh, **đều qua H1→H7**. Đợt A đã có MVP cho `01-srs`/`02-bd`. - [ ] Code (đợt D) chỉ nhận khi STEP12 test PASS. - [ ] Prompt/model/token vào audit (H5) + telemetry (H6). - [ ] Có escalation khi H3 REJECT lặp; local vẫn là mặc định.