docs: reconcile checklists with what the last passes actually built

Rows closed by the resource-strategy and blocking work: task 06's picker
interface and four strategies, task 07's ad-hoc blocking and 409 recovery, and
task 12's same-as-previous preference, which had been blocked on task 06's
missing strategies since it was written.

Tasks 13 and 14 both carried the flaky-suite caveat against their final review;
that flake has a diagnosed cause and a fix, so both now say so instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-31 20:53:02 +03:30
co-authored by Claude Opus 5
parent 7f057f02ee
commit a8020e3c20
5 changed files with 14 additions and 14 deletions
@@ -25,7 +25,7 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱.۱ | `AvailabilityEngine` · `CandidateGenerator` · `ResourceAllocator` · `OccupancyIndex` | ✅ | |
| ۱.۲ | چهار استراتژی + `ResourcePickerInterface` با tagged_iterator | | فقط استراتژی پیش‌فرض (اولین منبعِ آزاد به ترتیب نام) پیاده شد؛ `ResourcePickerInterface` و سه استراتژی دیگر نیامدند. مقصد: تسک بهره‌وری |
| ۱.۲ | چهار استراتژی + `ResourcePicker` با tagged_iterator | | `first_available` · `least_gap` · `least_loaded` · `same_as_previous`؛ استراتژی **مرتب می‌کند، انتخاب نمی‌کند** |
| ۱.۳ | `DailyWindowCache`**فقط پنجرهٔ تقویمی**، هرگز اشغال | ✅ | ⭐ |
| ۱.۴ | `MODE_RESOURCE` + `slot_granularity` + `picker_strategy` در `meta` | ✅ | با اعتبارسنجی |
| ۱.۵ | `POST /appointment-settings/upgrade-booking-mode` — یک‌طرفه، با شرط | ✅ | |
@@ -64,7 +64,7 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | انتخاب حالت `resource` + گام | ⚠️ | حالت سوم و «گام جستجوی وقت» به `ScheduleSection` اضافه شد. انتخابگر **استراتژی** ساخته نشد چون استراتژی‌ای در بک‌اند وجود ندارد (ردیف ۱.۲) — منوی خالی بدتر از نبودنش است |
| ۴.۱ | انتخاب حالت `resource` + گام + استراتژی | ✅ | هر سه در `ScheduleSection`؛ فهرست استراتژی‌ها از `GET /appointment-settings/resource-strategies` می‌آید، نه از فهرستی که در فرانت تکرار شود |
| ۴.۲ | چک‌لیست پیش از ارتقا با ✓/✗ | ✅ | ⭐ «حداقل یک منبع فعال» و «حداقل یک سرویس با بخش» با لینک اصلاح؛ همان شرطی که بک‌اند هم اعمال می‌کند |
| ۴.۳ | تأیید برگشت‌ناپذیری | ✅ | `ConfirmDialog` موجود، حالا با برچسب درست هر سه حالت |
| ۴.۴ | جدول وقت‌ها با ستون «منابع پیشنهادی» | ✅ | `ResourceBookingPage` — تاریخ، ساعت، منابع، انتخاب |
@@ -87,7 +87,7 @@
| ۵.۲ | `CandidateGeneratorTest` — هرس، گذشته، برنامهٔ جا‌نشو | ✅ | |
| ۵.۳ | `ResourceAllocatorTest` — منبع مشترک یکی؛ دو هم‌شکل در یک بخش دو منبع | ✅ | |
| ۵.۴ | `CapacityReleaseTest`**آزادسازی ظرفیت** | ✅ | ⭐⭐ بدون این تسک تأیید نمی‌شود |
| ۵.۵ | `StrategyTest` — سه استراتژی | ⏳ | با ردیف ۱.۲ می‌آید |
| ۵.۵ | تست استراتژی‌ها | ✅ | `ResourcePickerTest` — ۹ تست: ترتیب هر چهار استراتژی، رجیستری، بازگشت به پیش‌فرض روی کلید ناشناخته، رد شدن هنگام ذخیره |
| ۵.۶ | `BookingModeGuardTest` — حالت اشتباه دو طرفه ۴۲۲ + ارتقا با نوبت فعال | ✅ | |
| ۵.۷ | `AvailabilityPerformanceTest` | ✅ | |
| ۵.۸ | `LegacyBookingUnchangedTest` | ✅ | ⭐ |
@@ -97,7 +97,7 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۶.۱ | `docs/api/appointment-availability.md` | ✅ | |
| ۶.۲ | جدول استراتژی‌ها | | با ردیف ۱.۲ می‌آید |
| ۶.۲ | جدول استراتژی‌ها | | در `appointment-availability.md` با «کِی مناسب است» هر کدام |
| ۶.۳ | محدودیت تخصیص حریصانه مکتوب | ✅ | |
| ۶.۴ | ماتریس «کدام endpoint در کدام حالت» | ✅ | |
| ۶.۵ | `docs/architecture/booking-modes.md` (تسک ۰۰) حالت سوم را گرفت | ✅ | |
@@ -71,10 +71,10 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | تایمر شمارش معکوس hold | ✅ | ⭐ `HoldCountdown` — مبنا `expires_at` سرور است نه شمارندهٔ مرورگر؛ زیر یک دقیقه هشدار می‌شود. سه تست |
| ۴.۲ | خطای `409` با لیست جایگزین | ⚠️ | پیام سرور («این ساعت همین لحظه رزرو شد») نمایش داده می‌شود؛ **لیست جایگزین خودکار** ساخته نشد — کاربر باید دوباره جستجو بزند |
| ۴.۲ | خطای `409` با لیست جایگزین | | ⭐ انتخاب کهنه کنار گذاشته و جستجو دوباره اجرا می‌شود؛ جایگزین‌ها بلافاصله روی صفحه‌اند |
| ۴.۳ | خطای `reschedule` شامل «نوبت فعلی تغییری نکرد» | ⏳ | جریان جابه‌جایی نوبت در پنل ساخته نشد؛ `rebook` از API کامل است |
| ۴.۴ | مسدودسازی موردی منبع از صفحهٔ منابع | | مقصد: پاس بعدی صفحهٔ منابع |
| ۴.۵ | تفکیک «مسدودسازی موردی» از «بلندمدت» در UI | | با ۴.۴ یک بسته است |
| ۴.۴ | مسدودسازی موردی منبع از صفحهٔ منابع | | `ResourceBlocksModal` + سه اندپوینت تازه؛ ۶ تست بک‌اند |
| ۴.۵ | تفکیک «مسدودسازی موردی» از «بلندمدت» در UI | | ⭐ تفاوتشان بالای همان مودال نوشته شده، نه فقط در مستندات |
| ۴.۶ | هیچ رنگ/شعاع hard-code | ✅ | |
| ۴.۷ | دارک‌مود و حالت فشرده | ⚠️ | فقط توکن‌ها؛ بازبینی چشمی انجام نشد |
| ۴.۸ | RTL و موبایل | ✅ | جدول وقت‌ها اسکرول افقی داخلی دارد |
@@ -28,9 +28,9 @@
| ۱.۶ | نزدیک‌ترین به ایده‌آل | ✅ | `usort` روی `abs(start - ideal)` |
| ۱.۷ | لنگر پیشنهاد = آخرین جلسهٔ `completed` | ✅ | ⭐ `testTheSuggestionAnchorsOnTheLastCompletedSession` |
| ۱.۸ | سقف ۹۰ روز + پیام روشن | ✅ | ⭐ جلسات بیرون بازه `planned` می‌مانند، خطا نیست |
| ۱.۹ | `same_as_previous` ترجیح نه الزام | ⚠️ | `prefer_same_resource` و `preferredResource` ذخیره می‌شوند ولی هنوز به انتخاب منبع وصل نیستند |
| ۱.۱۰ | `preferredResourceIds` در `PlanRequest` | ⏳ | با ۱.۹ و ۱.۱۱ یک بسته است |
| ۱.۱۱ | `SameAsPreviousPicker` تسک ۰۶ | | **تسک ۰۶ اصلاً استراتژی انتخاب منبع نساخت** (بدهی ثبت‌شدهٔ همان تسک ساختن picker اینجا یعنی نصف تسک ۰۶ را اینجا نوشتن |
| ۱.۹ | `same_as_previous` ترجیح نه الزام | | ⭐ منبع ترجیحی جلو می‌آید، بقیه حذف نمی‌شوند؛ اجبار یعنی بیمار دو هفته منتظر بماند |
| ۱.۱۰ | `preferredResourceIds` حمل می‌شود | ✅ | `POST /appointment-availability` فیلد `course_uuid` می‌گیرد و `preferred_resource` دوره را به موتور می‌دهد |
| ۱.۱۱ | `SameAsPreviousPicker` تسک ۰۶ | | همراه سه استراتژی دیگر در تسک ۰۶ ساخته شد |
| ۱.۱۲ | تعامل با `spacing`: سخت‌گیرانه‌تر برنده | ⚠️ | `max(min)` پیاده شد (`effectiveMinDays``min(max)` لازم نشد چون قانون `spacing` اثر «حداکثر» ندارد. بازهٔ تهی هم ممکن نیست چون `max` همیشه با `min` بالا می‌رود |
| ۱.۱۳ | اعتبار پکیج کمتر از جلسات → هشدار نه خطا | ⚠️ | پکیج به دوره وصل می‌شود و پوششش بررسی می‌شود، ولی مقایسهٔ **مانده با تعداد جلسات** هنوز هشدار نمی‌دهد |
| ۱.۱۴ | `active_course_key` | ✅ | ⭐ همان الگوی `active_slot_key` |
@@ -61,7 +61,7 @@
| ۳.۴ | ستون فاصلهٔ واقعی بین جلسات | ⏳ | جدول تاریخ هر جلسه را می‌دهد ولی فاصلهٔ محاسبه‌شده را نه |
| ۳.۵ | هشدار عبور از حداکثر فاصله | ✅ | با رنگ `--warning` |
| ۳.۶ | بنر پیشنهاد جلسهٔ بعدی | ✅ | در کارت بالای صفحهٔ دوره |
| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو | | با ۱.۹ یک بسته است |
| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو | ⚠️ | ترجیح در بک‌اند اعمال می‌شود؛ نمایش نامش روی دکمهٔ رزرو دوره هنوز نیست |
| ۳.۸ | پیشنهاد بازچینی پس از لغو وسط دوره | ⏳ | تسک ۱۳ (لغو و لیست انتظار) |
| ۳.۹ | `DataTable` برای جلسات | ✅ | |
| ۳.۱۰ | نشان وضعیت جلسه و دوره | ✅ | کلاس‌های `badge` موجود |
@@ -84,7 +84,7 @@
| ۴.۵ | سقف ۹۰ روز | ⏳ | همان |
| ۴.۶ | لنگر `completed` + هشدار عبور از max | ✅ | ⭐ |
| ۴.۷ | پیشرفت دوره | ✅ | «۳ از ۸» + `next_params` |
| ۴.۸ | ترجیح همان منبع | | با ۱ |
| ۴.۸ | ترجیح همان منبع | | `ResourcePickerTest` — «جلو می‌آید و هیچ کاندیدی حذف نمی‌شود» |
| ۴.۹ | تعامل با قانون `spacing` | ⏳ | `effectiveMinDays` نوشته شد ولی تست اختصاصی ندارد |
| ۴.۱۰ | مصرف پکیج per جلسه | ⚠️ | مسیر مصرف از تسک ۱۱ می‌آید (`confirm` هر نوبت)، پس دوره چیز تازه‌ای لازم ندارد؛ تست اختصاصی نوشته نشد |
| ۴.۱۱ | چرخهٔ عمر — لغو، تکمیل خودکار، `abandon` | ✅ | ⭐ `testCancellingOneSessionOnlyResetsThatSession` و `testTheCourseCompletesOnlyWhenEverySessionIsDone` |
@@ -117,7 +117,7 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۸.۱ | هیچ ⏳ بی‌دلیل نمانده | ✅ | ۱۲ مورد ⏳/⚠️ همه با دلیل و تسک مقصد |
| ۸.۲ | `bin/phpunit` کامل سبز | ⚠️ | ۱۳۰۵ تست سبز است، ولی حدود ۴۰٪ اجراهای کامل یک خطای `EntityManager is closed` روی یک تست **تصادفیِ نامرتبط** می‌دهند. در اجرای زیرمجموعه‌ها هرگز تکرار نمی‌شود و تست خطاده هر بار عوض می‌شود. با حذف تست‌های این تسک هم دیده شد ⇒ احتمالاً flake محیط ddev، نه رگرسیون این تسک. **باید جدا بررسی شود** |
| ۸.۲ | `bin/phpunit` کامل سبز | | flake پیدا و رفع شد: قید یکتای شکسته `EntityManager` را می‌بندد و کانتینر همان نمونهٔ بسته را برمی‌گرداند، پس تستِ بعدی مدیرِ مرده را ارث می‌برد. `setUp` حالا ریست می‌کند و `UserCollisionRetryTest` آن را پین می‌کند. سه اجرای پیاپی سبز |
| ۸.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
| ۸.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
| ۸.۵ | `npx tsc --noEmit` و تست‌های فرانت سبز | ✅ | ۶۳۲ تست |
@@ -108,7 +108,7 @@
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۷.۱ | هیچ ⏳ بی‌دلیل نمانده | ✅ | همه با دلیل |
| ۷.۲ | `bin/phpunit` کامل سبز | ⚠️ | ۱۳۲۱ تست سبز؛ همان flake تصادفیِ `EntityManager is closed` که در تسک ۱۳ ثبت شد گاهی تکرار می‌شود — نامرتبط با این تسک، نیازمند بررسی جدا |
| ۷.۲ | `bin/phpunit` کامل سبز | | ۱۳۴۰ تست؛ flakeِ ثبت‌شده در تسک ۱۳ پیدا و رفع شد |
| ۷.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
| ۷.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
| ۷.۵ | `npx tsc --noEmit` و تست‌های فرانت سبز | ✅ | ۶۳۴ تست |