# AGENTS.md — Chấm bài viết

## Mục tiêu

Nhận một file JSON chứa bài làm rồi ghi kết quả vào `./grading_results/<input_stem>_graded.json`.

Ví dụ khi LMS gọi test15 với `dm_grading_runs.id = 5`:

```text
Input:  ./exam_5.json
Output: ./grading_results/exam_5_graded.json
```

Mỗi lần chạy dùng một file riêng theo id; không ghi đè `exam_01.json` mẫu.

File bài làm có các trường chính sau:

```text
- prompt: hướng dẫn và rubric chấm.
- de_bai_luc_thi: đề thực tế học viên nhận khi làm bài.
- bai_lam_writing: bài viết của học viên.
- part_id: dùng để định danh kết quả.
- baimau: đề/sample gốc (tham chiếu).
```

Ưu tiên kết quả chấm hợp lý và đúng rubric; không để sai lệch format nhỏ làm bài thất bại.

## Quy trình

1. Đọc file bài làm và trường `prompt`. Không sửa file nguồn.
2. Dùng `de_bai_luc_thi` làm đề bài và `bai_lam_writing` làm bài làm.
3. Nếu `prompt` còn placeholder `{essayPrompt}` / `{essay}` thì thay bằng `de_bai_luc_thi` / `bai_lam_writing`.
4. Chấm trực tiếp bằng prompt đã hoàn chỉnh.
5. Trả đúng output mà prompt yêu cầu (JSON hoặc text).

## Nguyên tắc chấm

Prompt trong file bài làm là nguồn sự thật cho rubric, thang điểm, word-count cap, làm tròn, ngôn ngữ feedback và schema.

Không tự thay rubric bằng rubric IELTS chung hoặc tự thêm/bỏ tiêu chí.
Không đọc `prompts.json` riêng nếu file bài đã có trường `prompt`.

Nếu prompt yêu cầu JSON:

- output phải parse được;
- giữ đúng các key và score chính;
- score phải nằm trong thang điểm;
- không thêm nội dung ngoài output yêu cầu.

Nếu prompt yêu cầu text (ví dụ Placement Test band score), giữ nguyên văn output đó.

## Kiểm tra kết quả

Chỉ kiểm tra những lỗi ảnh hưởng thực sự đến kết quả:

- JSON có parse được không (khi prompt yêu cầu JSON);
- có đủ score/tiêu chí chính không;
- score có nằm trong thang điểm không;
- overall có sai lệch rõ ràng không;
- feedback có phù hợp bài làm và không bịa nội dung quan trọng không.

## Output

Ghi JSON UTF-8 vào:

```text
./grading_results/<input_stem>_graded.json
```

Nếu thư mục chưa tồn tại thì tạo.

Ghi atomic: ghi `<output>.tmp`, validate xong rồi đổi tên thành filename chính thức.
Khi hoàn tất, in đường dẫn tuyệt đối của file kết quả.

Wrapper:

```json
[
  {
    "grading_id": "part_id",
    "status": "success",
    "result": {}
  }
]
```

Quy ước `result`:

- Nếu prompt yêu cầu JSON: `result` là nguyên object JSON do prompt trả.
- Nếu prompt yêu cầu text: `result` là string chứa nguyên văn output.

Khi lỗi:

```json
[
  {
    "grading_id": "part_id",
    "status": "error",
    "error": "Mô tả lỗi cụ thể",
    "result": null
  }
]
```

Trước khi hoàn tất, bảo đảm file output parse được và có đúng 1 kết quả cho bài đang chấm.

## Thông báo hoàn tất cho LMS

Sau khi file kết quả đã ghi thành công, hệ thống host (Laravel) sẽ gọi API nội bộ để báo đã chấm xong.

- Agent không tự gọi HTTP.
- Không được báo hoàn tất trước khi `./grading_results/<input_stem>_graded.json` đã tồn tại và parse được.
