# CODEX.md — Quy tắc làm việc trong Dr_GCM

Tệp này phải được đọc cùng `AGENTS.md`, `README.md` và `Memory.md` trước mọi thay đổi. `AGENTS.md` là nguồn yêu cầu đầy đủ; khi có khác biệt, áp dụng yêu cầu chặt chẽ hơn và hỏi người dùng trước quyết định khoa học.

## 1. Bối cảnh và mục tiêu

Xây dựng hệ thống dự báo mùa hạn hán cho Việt Nam từ ensemble ECMWF System 51 và mô hình statistical downscaling/AI. Sản phẩm mục tiêu gồm nhiệt độ trung bình tháng, tổng lượng mưa tháng, SPEI-1/3/6, cấp/sự kiện/xác suất hạn cho LT=1–6, cùng sản phẩm NetCDF, bản đồ, bảng và web vận hành.

## 2. Quy ước thời gian bất biến

- `initial_time` là 00 UTC ngày 01 của tháng khởi tạo; tháng đó là `LT=0`.
- Tháng hiệu lực tiếp theo là `LT=1`, tiếp tục đến `LT=6`. `LT=0` chỉ dùng làm đầu vào nội bộ và không phát hành như sản phẩm vận hành.
- Dữ liệu đầu vào phải bao phủ từ `initial_time` đến đúng 00 UTC ngày 01 của `LT=7`; mốc cuối chỉ là biên phải để hoàn tất LT=6.
- Phải suy ra thống kê tháng từ `forecast_reference_time`, `forecast_period`/`step`, `valid_time`, calendar và interval đại diện. Không suy ra từ tên tệp hoặc chỉ số time.
- Trước aggregation phải xác minh biến tức thời, trung bình hay tích lũy; thời điểm bắt đầu tích lũy; quy tắc de-accumulation; và việc gán giá trị đúng 00 UTC đầu tháng kế tiếp.
- Theo `ECMWF_SEAS5_System51_Variables_Guide.docx`, `tp`, `slhf`, `sshf`, `tsr`, `ttr` là 24-hourly accumulated **cumulative from initialization**: `X(24)` là 0–24 h, `X(48)` là 0–48 h, v.v. Daily increment bắt buộc là `X(t)-X(t-24 h)`; riêng ngày đầu là giá trị tại step 24 vì tích lũy bắt đầu từ 0 tại initialization. Không được coi trực tiếp `X(48)` là ngày thứ hai.
- `tp` đổi m sang mm sau khi lấy hiệu: `Pday=[TP(t)-TP(t-24)]*1000`. Với flux/radiation, daily mean là `[X(t)-X(t-24)]/86400` W m-2; ECMWF dùng positive downward. `ttr` thường âm và `OLR=-MeanTTR` nếu cần OLR positive upward.
- Quy tắc đã được người dùng xác nhận: mọi giá trị lượng mưa nhỏ hơn 0 phải được đặt bằng 0 trước mọi xử lý tiếp theo. Với ECMWF cumulative, áp dụng sau khi lấy hiệu daily và đổi từ m sang mm, trước aggregation; giữ nguyên missing và ghi quy tắc trong provenance.
- Tổng mưa tháng phải là tổng các daily increments đã de-accumulate, đổi sang mm và đặt mọi giá trị âm về 0 trong khoảng `[S,E)`; không dùng trực tiếp `TP(E)-TP(S)` khi có increment âm. Mean flux/radiation tháng vẫn dùng chênh lệch cumulative chia tổng số giây của interval tháng. Phải kiểm tra đủ step, biên tháng, missing/duplicate và reset trước khi tính.
- `t2m`, `sst`, `stl1`, `msl` là 6-hourly instantaneous; step 0 có thể tồn tại theo quy ước nhưng availability phụ thuộc archive. `t2m/sst/stl1`: K; `msl`: Pa. Không coi mẫu instantaneous là trung bình interval.
- Volumetric soil moisture là 24-hourly instantaneous/state, đơn vị m3 m-3, không de-accumulate.
- Giữ chiều ensemble member xuyên suốt xử lý. Không ensemble-mean sớm.

## 3. Dữ liệu và tên biến

- GCM: CDS `seasonal-original-single-levels`, ECMWF, System `51`.
- Dữ liệu phía mô hình dùng cho xây dựng, huấn luyện, hindcast và vận hành phải là **reforecast/hindcast của GCM**. Không dùng reanalysis (ví dụ ERA5/ERA5-Land) làm predictor, nguồn thay thế hoặc để ghép bù chuỗi GCM.
- Tài liệu biến bắt buộc đọc và đối chiếu trước xử lý: `ECMWF_SEAS5_System51_Variables_Guide.docx`. Nếu metadata/dữ liệu thực tế xung đột với tài liệu, dừng bước xử lý và báo cáo; không tự suy diễn.
- Predictands nội bộ: `pr_mod` (tổng lượng mưa tháng, mm/month sau chuẩn hóa) và `t2m_mod` (nhiệt độ trung bình tháng, degC sau chuẩn hóa). Đây cũng là tên canonical bắt buộc trong các tệp monthly và cấu hình climatology; tên raw ECMWF tương ứng là `tp` và `t2m`.
- Predictors dự kiến: `sst`, `st1`, `msl`, `lh`, `sh`, `rn`, `olr`, `sm`. Phải inventory tên thực, `standard_name`, unit, level và temporal convention trước khi ánh xạ.
- C3S dùng tên request `volumetric_soil_moisture` cho ECMWF System 51 trong `seasonal-original-single-levels`; NetCDF dự kiến là `vsw(number, forecast_reference_time, forecast_period, soilLayer, latitude, longitude)`. Các request cũ dùng `volumetric_soil_water_layer_1` không phải phép thử hợp lệ cho interface mới. Workflow bắt buộc pilot 2005-01 và 1981-01, kiểm tra 25 members, bốn soil layers, lead và metadata trước khi tải toàn kỳ. Không suy diễn temporal semantics hoặc độ sâu lớp chỉ từ chỉ số `soilLayer`.
- Quan trắc mặc định do người dùng cung cấp nằm dưới `/home/tanpv/Data/562_VNU/0.25_VN/`; trên máy hiện tại hai tệp dùng được được liên kết vào `data/obs/` từ `/work/projects/G09/OBS_Vn_GRD/0.25/Monthly/`.
- Mask chính thức: `/home/tanpv/Progs/Dr_VN_Ope/DATA/Mask_VN_0.25_Corrected.nc` (symlink tới bản dùng được trên `/work`). Không dựng lại mask từ shapefile nếu chưa được yêu cầu.
- Shapefile tham chiếu: `/home/tanpv/GrADS_SCR/VN_SubRegs1/Vietnam7.*`.
- Metadata quan trắc hiện ghi `var_unit`, nhưng người dùng đã xác nhận đơn vị vật lý: mưa là mm/tháng và nhiệt độ là độ C; bước chuẩn hóa phải sửa metadata đầu ra và ghi provenance.

## 4. Scientific invariants

- Không regrid, đổi unit, de-accumulate hoặc aggregate trước khi inventory grid/metadata gốc và phương pháp được duyệt.
- Cấu hình climatology phải tách thời kỳ valid-time quan trắc 1981-01..2021-06 khỏi thời kỳ initial model 1981-01..2020-12; không dùng một khoảng thời gian chung khi glob có thể chứa forecast vận hành.
- Mask `reg=1..7` quyết định grid cell thuộc sản phẩm.
- PET/SPEI tuân theo `README.tp`: Thornthwaite dùng nhiệt độ tháng và latitude; cân bằng nước `P - PET`; log-logistic 3 tham số fit riêng theo grid cell, calendar month và timescale; calibration 1981–2020; lưu tham số để dự báo vận hành.
- Heat index Thornthwaite dùng climatology fit trên calibration 1981–2020 và được lưu cùng provenance để áp dụng cho vận hành; không tính heat index từ các tháng tương lai chưa quan trắc của năm dự báo.
- Với SPEI-3/6 vận hành, dùng quan trắc đến tháng ngay trước initial time, sau đó dùng dự báo từ LT=0 trở đi. Ví dụ SPEI-6 tại LT=1 gồm bốn tháng quan trắc, LT=0 và LT=1.
- Miền predictor đã xác nhận là 40°N–20°S, 70°E–150°E. Regridding phải được chọn bằng so sánh hindcast ngoài mẫu nhằm giảm sai số, không chọn trước chỉ theo loại biến.
- `t2m_ens` và `pr_ens` là ensemble mean của các AI members. `SPEI_ens` không dùng ensemble mean mà dùng mô hình AI ensemble với các SPEI từ AI members làm thành phần đầu vào.
- Không tự chọn cấu trúc model theo lead/mùa, AI/tuning, xử lý mưa âm/outlier hoặc nền tảng web.
- Không tuyên bố dữ liệu hoàn chỉnh chỉ vì tệp mở được; phải kiểm tra đủ biến, member, step, khoảng thời gian, missing/duplicate, range và file integrity.

## 5. Ngăn data leakage và đánh giá

- Chia train/validation/test theo thời gian; dùng blocked hoặc rolling-origin CV theo năm.
- Fit scaler, EOF/PCA, feature selection, bias correction và tuning chỉ trên training fold.
- Đánh giá riêng theo lead, tháng/mùa khởi tạo và vùng khí hậu khi cỡ mẫu cho phép.
- Baseline bắt buộc: GCM thô, climatology, persistence khi phù hợp, Linear/Ridge và một bias-correction/downscaling đơn giản.
- Bộ metric cuối cùng phải được người dùng xác nhận trước khi dùng chọn mô hình.
- Bộ metric đã xác nhận cho trường liên tục: `t2m` dùng MAE, RMSE, bias/ME và correlation; `pr` dùng RMAE, bias/ME và correlation, không dùng MAE. Regridding phải được đánh giá ngoài mẫu theo các metric tương ứng.

## 6. Cấu trúc và quy ước kỹ thuật

- Mã Python trong `src/dr_gcm/`; test trong `tests/`; cấu hình trong `config/`; script vận hành trong `scripts/`.
- `data` và `outputs` có thể là symlink tới filesystem HPC; không xóa, di chuyển hoặc ghi đè nội dung ngoài yêu cầu được duyệt.
- Đường dẫn ngoài project chỉ là giá trị cấu hình, không hard-code vào logic.
- Mỗi module vận hành cần CLI `--help`, logging, exit code đúng, resume rõ ràng và không bỏ qua lỗi/timestep âm thầm.
- NetCDF đầu ra phải giữ metadata/provenance và tối thiểu có variable/unit, initial time, valid time, lead, member hoặc probability, method và model version.
- Không commit credentials, dữ liệu lớn, cache hoặc output tạm.

## 7. Kiểm tra tối thiểu

```bash
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m pytest -p no:cacheprovider -q
PYTHONPATH=src python3 -m dr_gcm.download_ecmwf_baseline --help
PYTHONPATH=src python3 -m dr_gcm.download_ecmwf_baseline --init 1981-01 --dry-run
PYTHONPATH=src python3 -m dr_gcm.download_ecmwf_pilot --help
PYTHONPATH=src python3 -m dr_gcm.climatology --help
```

Trước xử lý thật phải chạy `dr_gcm.inventory` trên GCM, observation và mask; dùng `--strict` trong bước xác nhận tính đầy đủ.

## 8. HPC và thao tác phải hỏi trước

- Trước tải dữ liệu lớn hoặc job dài: báo phạm vi, dung lượng, thời gian, CPU/RAM/walltime, lệnh và log/output. Phải chờ xác nhận trừ khi người dùng đã cấp quyền rõ ràng cho việc download trong phiên/trạng thái dự án hiện hành.
- Không tự dừng/kill job, xóa file, overwrite dữ liệu, thay symlink, gửi Slurm job hay tăng concurrency.
- Recovery do damaged tape phải chạy một worker, tách biến/chunk, checkpoint từng request và chỉ promote sau khi validator xác nhận đủ biến/member/lead; không chạy đồng thời normal downloader cho cùng initial month.
- Khi một lead đơn tiếp tục lỗi damaged-tape đến giới hạn đã cấu hình, phải ghi `blocked_external` và dừng retry tự động. Có thể tiếp tục tải tuần tự từ initial month kế tiếp bằng một worker, nhưng không được bỏ qua gap trong validation/monthly processing hoặc dựng dữ liệu thay thế không được duyệt.
- Downloader thường phải dùng circuit breaker chỉ cho lỗi `damaged tape` đã được ghi trong manifest: sau ba lỗi liên tiếp, ghi tháng vào ledger deferred rồi tiếp tục tháng sau. Lỗi khác vẫn retry với backoff; deferred không đồng nghĩa hoàn tất.
- Request baseline CDS phải khai báo rõ `data_format=netcdf` và `download_format=unarchived`. Nếu CDS vẫn trả HTTP 403 từ URL object-store đã hết hạn cho request nhiều biến, downloader được phép fallback sang các request một biến tuần tự trong cùng group, checkpoint/validate từng mảnh, merge rồi validate toàn group trước atomic promotion. Không áp dụng fallback này cho 403 xác thực hoặc URL ngoài object-store; không tăng concurrency.
- `baseline_download_monitor.sh` là monitor hiện hành: kiểm tra lock mỗi 300 giây, tự resume tháng chưa hoàn tất từ 1990-04, giữ đúng một CDS worker, và chỉ phục hồi gap tuần tự sau khi dải chính hoàn tất. Recovery giữ chung downloader lock và có cooldown 24 giờ khi nguồn ngoài còn lỗi. Sau cooldown, chỉ các single-lead damaged-tape bị chặn được reset bộ đếm theo cycle; phải giữ `total_attempt_count` và `recovery_cycles` trong manifest, đồng thời vẫn áp giới hạn attempt cho từng cycle.
- Monitor soil moisture phải chờ `baseline_download_monitor.sh` hoàn tất toàn bộ dải chính và gap recovery, sau đó dùng chung `ecmwf_baseline_download.lock`. Không được chạy soil-moisture worker song song với downloader/recovery hiện hành. Hai pilot 2005-01 và 1981-01 phải đạt trước khi tự động chuyển sang toàn kỳ 1981–2020.
- Supervisor recovery được phép tự resume đúng manifest và chỉ bàn giao sang baseline watchdog sau strict validation; phải dùng lock/PID, giữ concurrency bằng một và tồn tại độc lập với phiên đăng nhập.
- Script Slurm phải khai báo CPU, RAM, walltime, log và output.
- Với job lỗi lặp lại hoặc treo, bảo toàn log và output; báo bằng chứng rồi xin quyết định trước khi dừng/thay request.

## 9. Quy trình tài liệu

- Cập nhật `README.md` khi giao diện người dùng, cấu hình, data flow hoặc lệnh vận hành thay đổi.
- Cập nhật `Memory.md` sau thay đổi quan trọng, sau test và trước khi kết thúc phiên.
- Trong `Memory.md`, phân biệt quyết định đã xác nhận, giả định tạm thời, đề xuất và câu hỏi mở; không ghi bí mật.

## 10. Quyết định xác nhận ngày 2026-10-03

- Soil moisture là predictor bắt buộc, không được loại khỏi hệ phương pháp. Phải tiếp tục xác minh archive; nếu System 51 không có hindcast đồng nhất, trình nguồn thay thế hoặc chiến lược ghép dữ liệu để người dùng duyệt trước khi huấn luyện.
- Dùng rolling-origin cross-validation theo năm; độ dài train/validation/test, bước trượt và gap vẫn phải được xác nhận trước hindcast chính thức.
- Huấn luyện mô hình riêng theo lead, nhưng gộp thông tin tháng/mùa bằng season/month encoding thay vì 72 mô hình lead×tháng độc lập.
- Ứng viên gồm Ridge, gradient-boosted trees và ít nhất một foundation model phù hợp. FM cụ thể, fine-tuning, license, input/output và tài nguyên HPC phải được đánh giá và trình duyệt.
- Download baseline chỉ hoàn thành khi đủ raw groups/biến/member/lead, không còn gap/deferred và inventory strict đạt; khi đó phải báo người dùng.

## 11. Quyết định xác nhận ngày 2026-10-14

- Chỉ sử dụng dữ liệu reforecast/hindcast của các GCM cho phía mô hình; không sử dụng reanalysis.
- Nếu ECMWF System 51 không có soil moisture hindcast đồng nhất, mọi phương án thay thế hoặc ghép dữ liệu phải đến từ GCM reforecast và phải được người dùng duyệt trước khi triển khai.
