## Summary
Reintroduces a weekly QTD report generation cycle (every Monday 13:00 UTC, reporting on the current in-flight month) alongside the existing Day-2 monthly cron. Both cadences serve the same SVP / C-level audience and use the same QTD framing.
- Backend: new cadence='weekly' path in run_scheduled_reports (current-month period, mode='weekly', week_number = ISO Mon-Sun week-of-quarter, future-period guard bypassed, quarter-first-day-Monday skip, no --period flag). New cron entry crons/weekly_qtd_report_cron.py. Mode Literal extends to {monthly, eoq, weekly} across record_run, ReportRunRecord, generate_report, _build_title, and the QtdReportRun Pydantic model. Defensive mode IN ('monthly', 'eoq') filter removed from ledger.list_runs so weekly rows surface. LEGACY_WEEKLY_FOLDER_NAME renamed to WEEKLY_FOLDER_NAME = "Weekly". Weekly failure paths thread week_number correctly so the ledger's latest-wins dedup works for weekly retries.
- Doc title: {BU} | QTD BvA | Q2 FY2026 | Through June 7 2026 (W10).
- week_number semantics: ISO Mon-Sun week-of-quarter, 1–13. W1 may be partial when the quarter starts mid-week (Wed Apr 1 FY2026 → W1 = Apr 1–5, 5 days); W2–W13 are full Mon-Sun weeks.
- Edge case: when a Monday cron run coincides with the quarter's first day (doesn't happen in FY2026, defensive for future fiscal calendars), the run no-ops: log line, no ledger row, no doc, no refresh.
- Frontend: weekly rows surface in the /monthly-financial-reporting list, sorted by generated_at DESC. formatMode extended to render Through {Mon D} (Wn) for weekly. Send button gates on the latest row per (business_unit, entity_type, mode) instead of "latest period only" (which collapsed when weekly + monthly share a period). activePeriod filters weekly out so email dispatch continues to use the latest monthly-close period — weekly email dispatch is a follow-on. Section copy updated to mention both cadences.
- Example report approved by stakeholder Raviraja Rao - [IgniteTech | QTD BvA | Q2 FY2026 | Through May 13 2026 (W6)](https://docs.google.com/document/d/11nGcojVTcXyM9VrHR9ORYPv3GZ5ZyMBqkh4kys-r55A/edit?tab=t.0)
EventBridge schedule for the new weekly cron will be added separately (infra).
Linear: [KLAIR-2639](https://linear.app/builder-team/issue/KLAIR-2639/generate-qtd-reports-weekly-alongside-existing-monthly-cadence)
## Out-of-scope (intentionally NOT in this PR)
- EventBridge schedule changes (infra, handled separately).
- LLM commentary changes (on for weekly, same prompt as monthly).
- Action item / RAG threshold changes (same as monthly).
- DB migration (the schema already accepts weekly mode + non-null week_number).
- Weekly backfill flag (not currently required).
- send_test_email.py / bva-emails-list.csv (the CSV-driven manual send is already cadence-agnostic).
- Module rename (services/monthly_qtd_report/ stays misnamed; future cleanup).
- Detailed UI changes
## Test plan
- [x] Backend: uv run pytest tests/monthly_qtd_report/ — 445 passed, 7 deselected.
- [x] Backend: uv run pyright services/monthly_qtd_report/ crons/weekly_qtd_report_cron.py models/qtd_report_models.py — 0 errors on the changed surface (pre-existing python-docx stub errors in doc_builder.py are unchanged by this branch).
- [x] Backend: uv run ruff format + uv run ruff check — clean.
- [x] Frontend: pnpm test -- QtdReportsView — all 22 tests pass (9 view + 8 send + 6 formatMode).
- [x] Frontend: pnpm tsc --noEmit — 0 errors.
- [x] Frontend: pnpm lint:pr — 0 errors.
- [ ] Manual: invoke crons/weekly_qtd_report_cron.py against staging with MONTHLY_QTD_CRON_USER_EMAIL set; verify a Weekly/ subfolder appears under QTD Reports/{Unit}/FY2026/ and the doc title reads Through {date} (W{n}).
- [ ] Manual: open /monthly-financial-reporting as super-admin; confirm new weekly rows appear chronologically interleaved with monthly rows; confirm exactly one Send button per (BU, entity_type, mode) latest row; confirm clicking Send on the monthly row dispatches under the monthly period even when a newer weekly row is at the top of the list.
## Notes for reviewers
- BoardDoc/__tests__/DocumentEditor.reloadIntegration.spec.tsx and BoardDoc/__tests__/EditorToolbar.revisionStale.spec.tsx fail due to a missing @tiptap/extension-table dependency. This is pre-existing on main — no commits on this branch touched klair-client/src/screens/BoardDoc/.
- The weekly cadence is a deliberate reversal of the recent weekly→monthly consolidation (commit 2860183c9, KLAIR-2602, 2026-05-04). David Harpur is aware; updated stakeholder direction now requires both cadences in parallel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)