Skip to content

Workflow Reference ​

Phân biệt hai thứ cùng tên "workflow":

docs/workflows/Trang này
Là gìThiết kế — luồng nghiệp vụ mong muốn (WF-01…WF-20)Thi hành — cái đang chạy trong runtime, từng step, có run log
Đọc đểHiểu hệ thống nên hoạt động thế nàoDebug "hôm qua chạy gì, bước nào hỏng"

⚠️ In-process là mặc định: workflow của API chạy trong request, ghi lại bằng run log ba bảng dưới đây. Ba ngoại lệ là Cloudflare Workflows (WorkflowEntrypoint) thật, chạy ngoài hạ tầng run log này (Audit #013 T-10 bắt được trang này chỉ khai một):

WorkflowWorker · binding · classGhi sổ ở đâuTra run
WF-19 LessonForge (SRC-632)nemo12-foundry · LESSON_FORGE · LessonForgecontent_runs + content_run_trialsGET /v1/admin/foundry/runs[/{id}]
WF-20 ItemForge (SRC-638)nemo12-foundry · ITEM_FORGE · ItemForgecontent_runs + content_run_trials (16 câu/bài theo khe)như trên
DictationForge (SRC-669)nemo12-api · DICTATION_FORGE · DictationForgedictation_practice (status pending → running → ready/failed, error)GET /v1/dictation/practices?learner_id= (learner)

Xem SDD-027 cho hai cái đầu, modules/dictation/forge.ts cho cái thứ ba. Xem §5 để biết khi nào một workflow in-process cần đổi sang Cloudflare Workflows.


1. Hạ tầng run log ​

Ba bảng, ba câu hỏi khác nhau:

BảngTrả lời
workflow_runs + workflow_run_steps"Luồng nào đã chạy, bước nào hỏng, mất bao lâu?"
engine_runs"Engine nào đã chạy, với input nào, ra version nào?"
learner_model_versions"Nội dung model tại version N là gì?"

Luật vàng: ghi log không bao giờ được làm hỏng nghiệp vụ chính. Mọi lỗi ghi log bị nuốt và chỉ console.error("RUNLOG_DEGRADED"). Learner mất một dòng log còn hơn mất bài làm.

startWorkflowRun()  → workflow_runs (status='running')
  recordStep()      → workflow_run_steps (seq tăng dần, succeeded|failed|skipped)
  runEngine()       → engine_runs, tự update status khi xong/lỗi
    saveModelVersion() → learner_model_versions (chỉ khi hash đổi)
finishWorkflowRun() → status='succeeded'|'failed', duration_ms, output_json

2. WF-04 — Evidence → Model Update ​

Workflow quan trọng nhất của hệ thống. runModelUpdateWorkflow() trong modules/models/service.ts.

Trigger ​

triggerTừ đâu
AssessmentCompletedNộp bài chẩn đoán (knowledge/routes.ts), nộp đề thi (exams/routes.ts)
GoalChangedKhai/sửa đích thi, thêm lịch thi học kỳ (onboarding/routes.ts) — chạy dưới mã WF-15
EXAM_RESCHEDULEDĐổi ngày thi
admin_recomputeAdmin bấm tính lại (admin/observability.ts)

4 step, thứ tự bắt buộc ​

#StepEngineVì sao đúng thứ tự này
1goal_engineGoalBa step sau đều tham chiếu Goal Model
2context_engineContextCần goal urgent nhất để dựng active_goal_ref
3learner_model_engineLearner ModelCần goal version để nhúng goals_summary
4readiness_engineReadinessCần biết goal trỏ tới blueprint nào để chọn target

Đảo thứ tự sẽ cho ra model tham chiếu version cũ của Goal — không crash, nhưng sai âm thầm. Đây là loại lỗi tệ nhất.

Xử lý lỗi ​

Mỗi step bọc try/catch riêng: một step hỏng không dừng các step sau. Cuối cùng status = failed nếu có bất kỳ step nào hỏng, nhưng những model tính được vẫn được lưu. Suy giảm từng phần tốt hơn mất tất cả.

Hot path gọi qua runModelsSafely() — nếu cả workflow nổ thì chỉ log model_update_degraded, học sinh vẫn nộp được bài.

Output ​

output_json của run chứa tóm tắt từng step:

jsonc
{
  "goal_engine":          { "goals": 3, "conflicts": 1 },
  "context_engine":       { "version": 7, "changed": false },
  "learner_model_engine": { "version": 12, "changed": true },
  "readiness_engine":     { "version": 5, "changed": true }
}

changed: false nghĩa là engine đã chạy nhưng nội dung model không đổi — không phải là engine bị bỏ qua.


3. WF-15 — Declarations Intake ​

Cùng cỗ máy WF-04 nhưng mang mã và tên riêng để tra cứu tách bạch: model đổi vì học sinh khai điều mới (đích thi, lịch thi), không phải vì làm bài.

Điểm gọiinput
Thêm exam target{ exam_target_id, kind }
Sửa exam target{ exam_target_id, kind }, trigger EXAM_RESCHEDULED nếu đổi ngày
Thêm lịch thi học kỳ{ semester_exam_id, exam_date }

4. Xem lại một run ​

Câu hỏiEndpoint (role admin)
Gần đây chạy gì?GET /v1/admin/workflow-runs
Run này gồm bước nào?GET /v1/admin/workflow-runs/{runId}
Engine nào đã chạy?GET /v1/admin/engine-runs
Learner này có model gì?GET /v1/admin/learners/{learnerId}/models
Lịch sử một model?GET /v1/admin/learners/{learnerId}/models/{modelKind}/versions
Nội dung version cụ thể?GET /v1/admin/model-versions/{versionId}
Tính lại ngayPOST /v1/admin/learners/{learnerId}/recompute-models

Đây là cách thực hiện REQ-INT-29 (model version inspectable) — xem được nội dung đầy đủ của từng phiên bản, không chỉ bản mới nhất. Giao diện: admin.nemo12.com.


5. Workflow đã thiết kế nhưng chưa thi hành ​

docs/workflows/ mô tả WF-01…WF-19. Chạy thật trên hạ tầng run log: WF-04 và WF-15; chạy thật trên Cloudflare Workflows: WF-19 (LessonForge, không dùng run log — xem cảnh báo đầu trang). Các luồng còn lại hoặc đang là code inline chưa gắn run log, hoặc chưa xây.

Khi nào cần chuyển sang Cloudflare Workflows thật (thay vì in-process):

  • Luồng chạy > 30 giây hoặc vượt giới hạn CPU của một request.
  • Cần retry có trạng thái qua nhiều bước (crawl đề — SDD-014, generation run — SDD-003).
  • Cần chạy nền không có request nào kích hoạt → xem schedules.

Cho tới lúc đó, in-process + run log là đủ và đơn giản hơn hẳn.

Trace ​

  • REQ-INT-29 (model version inspectable), REQ-NFR-01 (không làm hỏng nghiệp vụ chính).
  • Thiết kế: SDD-002 §14/§15/§19, SDD-006 §2, workflows/.
  • Kiểm chứng: QG-005, QG-009.