Flux correction

This commit is contained in:
2026-05-07 21:52:27 +02:00
parent 5d4c223b38
commit f55f5122c3
11 changed files with 90 additions and 6 deletions

View File

@@ -19,6 +19,7 @@ from .auth import (
)
from .curriculum import QUESTIONS
from .program_content import (
apply_program_review_updates,
build_program_tree,
decode_asset_token,
format_adaptive_kit_context,
@@ -52,6 +53,7 @@ async def lifespan(app: FastAPI):
seed_admin_user(db)
finally:
db.close()
apply_program_review_updates()
yield

View File

@@ -29,6 +29,7 @@ def default_content_root() -> Path:
CONTENT_ROOT = Path(os.getenv("PROGRAM_CONTENT_ROOT", default_content_root())).resolve()
LESSON_BACKGROUND = "#f8fafc"
REVIEW_STATE_PATH = Path(os.getenv("PROGRAM_REVIEW_STATE_PATH", CONTENT_ROOT / ".program_review_state.json"))
REVIEW_UPDATES_PATH = Path(os.getenv("PROGRAM_REVIEW_UPDATES_PATH", CONTENT_ROOT / "review_updates"))
GRADE_ALIASES = {
"CM1": "cm1",
@@ -298,6 +299,71 @@ def save_review_state(state: dict) -> None:
)
def iter_review_update_files() -> list[Path]:
candidates = []
single_file = CONTENT_ROOT / ".program_review_updates.json"
if single_file.exists():
candidates.append(single_file)
if REVIEW_UPDATES_PATH.exists():
candidates.extend(sorted(REVIEW_UPDATES_PATH.glob("*.json")))
return candidates
def apply_program_review_updates() -> dict:
state = load_review_state()
applied = 0
skipped = 0
errors = []
for path in iter_review_update_files():
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
errors.append({"file": str(path), "error": f"JSON invalide: {exc}"})
continue
if payload.get("schema") != "professeur-top-review-updates-v1":
skipped += 1
continue
payload_updated_at = payload.get("updated_at") or datetime.utcnow().isoformat(timespec="seconds") + "Z"
payload_reviewer = payload.get("updated_by") or "codex"
for index, update in enumerate(payload.get("updates") or []):
node_key = update.get("node_key") or update.get("path")
if not node_key:
skipped += 1
continue
update_id = update.get("update_id") or f"{path.name}:{index}:{node_key}"
existing = state.get(node_key, {})
if existing.get("codex_update_id") == update_id:
skipped += 1
continue
next_review = {
**existing,
"status": update.get("status") or existing.get("status") or "treated",
"comment": update.get("comment", existing.get("comment", "")),
"reviewer": update.get("reviewer") or payload_reviewer,
"updated_at": update.get("updated_at") or payload_updated_at,
"codex_update_id": update_id,
}
if update.get("treated_note"):
next_review["treated_note"] = update["treated_note"]
state[node_key] = next_review
applied += 1
if applied:
save_review_state(state)
return {
"applied": applied,
"skipped": skipped,
"errors": errors,
"files": [str(path) for path in iter_review_update_files()],
}
def collect_lesson_status(lesson: dict) -> dict:
lesson_dir = CONTENT_ROOT / lesson["id"]
kit_dir = lesson_dir / "kit_adaptatif"