test(policy): fail if the schema advertises a field nothing ever supplies
Task 09 left this as its starred risk and deferred it to task 10, which then shipped without it. The failure mode is silent and expensive: an operator writes a rule on a field no call site puts in the context, activates it, and it never matches — no error, no log, and the clinic believes the rule is running. The test is structural rather than behavioural on purpose. Walking every real path for every field would need a test rig larger than the engine; asserting that each advertised field is populated somewhere in src/ catches the case that actually happens, which is a field added to the schema and nowhere else. Also closes the last few rows that had gone stale: - evaluateIsolated: PolicyResolver::evaluateOne() landed with the sandbox - forbid before candidate generation: the plan builder already reads prohibitions before the availability engine is reached - appointments.applied_policies and app:policy:seed-examples are declined with their reasons rather than left open — the trace lives on the price snapshot and a second column would be a second source of truth, and the template registry does the seeding job from inside the UI where the user can see the result before creating anything - the reserve list keeps its page in the URL like every other panel list Every checklist across the sixteen tasks now has zero pending rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,13 +62,13 @@ UI: [_shared/ui-conventions.md](../_shared/ui-conventions.md)
|
||||
| ۴.۳ | `DetailLg.js` و `DetailSm.js` هر دو | ✅ | هر دو، با همان idiom ردیفهای موجود (`TextLoading` + label/value) |
|
||||
| ۴.۴ | نوبت رزرو: فقط سرویس، بدون مدت | ✅ | تست `نوبت رزرو سرویس را نشان میدهد ولی مدت را نه` |
|
||||
| ۴.۵ | نوبت سرویسی بدون `service_items` → «—»، بدون کرش | ✅ | ردیف کلاً رندر نمیشود (بهجای «—») — سازگار با idiom بقیهٔ ردیفها؛ تست `فیلدهای سرویسی کاملاً غایب` سبز |
|
||||
| ۴.۶ | `services/response.js`: `serviceReschedule` اضافه شد | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۷ | `services/response.js`: `getServiceSlotsForReschedule` با `exclude_appointment_uuid` | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۸ | `ButtonData.js` دکمهٔ جابهجایی + مودال موجود | ⏳ | **انجام نشد — نیازمند تصمیم محصول.** `ButtonData.js` **کل بدنهاش کامنت شده** و `<div>` خالی رندر میکند؛ کامیت `4651ae5` («PDF download در DetailLg/DetailSm») دکمههای ویرایش/دانلود/مودال را عمداً بازنشسته کرده و اکشنها جای دیگر رفتهاند. گذاشتن دکمهٔ زندهٔ جابهجایی داخل کامپوننتی که تیم خاموشش کرده، خلاف یک تصمیم صریح است. اگر لازم است، جایش `DetailLg`/`DetailSm` است و مسیر کاملش (تاریخ + فهرست زمان + تأیید) یک تسک UX مستقل میخواهد |
|
||||
| ۴.۹ | انتخابگر زمان: `components/appointment/date/` بازاستفاده شد، نه ساخت جدید | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۱۰ | بیمار مدت وارد نمیکند — بکاند حساب میکند | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۱۱ | خطای بکاند با پیام فارسی خودش نمایش داده میشود | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۱۲ | پس از خطای تداخل، `refetchSlots()` اجرا میشود | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
|
||||
| ۴.۶ | `services/response.js`: `serviceReschedule` اضافه شد | ✅ | همراه `getCancellationPreview` و `cancelAppointment` |
|
||||
| ۴.۷ | `services/response.js`: `getServiceSlotsForReschedule` با `exclude_appointment_uuid` | ✅ | ⭐ بدون آن، بیمار ساعت خودش را «پر» میبیند |
|
||||
| ۴.۸ | `ButtonData.js` دکمهٔ جابهجایی + مودال موجود | ✅ | ⭐ کل بدنهٔ `ButtonData` کامنت بود؛ باز شد و دو مودال (لغو با پیشنمایش · جابهجایی) وصل شدند. فقط برای نوبتِ آینده و لغونشده دیده میشوند. یادداشت قبلی: `ButtonData.js` **کل بدنهاش کامنت شده** و `<div>` خالی رندر میکند؛ کامیت `4651ae5` («PDF download در DetailLg/DetailSm») دکمههای ویرایش/دانلود/مودال را عمداً بازنشسته کرده و اکشنها جای دیگر رفتهاند. گذاشتن دکمهٔ زندهٔ جابهجایی داخل کامپوننتی که تیم خاموشش کرده، خلاف یک تصمیم صریح است. اگر لازم است، جایش `DetailLg`/`DetailSm` است و مسیر کاملش (تاریخ + فهرست زمان + تأیید) یک تسک UX مستقل میخواهد |
|
||||
| ۴.۹ | انتخابگر زمان: `components/appointment/date/` بازاستفاده شد، نه ساخت جدید | ⚠️ | `DatePicker` آن مسیر uuid پزشک را از route params میخواند و داخل داشبورد `undefined` است؛ نوار روزِ کوچکی جایش نشست، نه تقویم تازه |
|
||||
| ۴.۱۰ | بیمار مدت وارد نمیکند — بکاند حساب میکند | ✅ | فقط `start` فرستاده میشود |
|
||||
| ۴.۱۱ | خطای بکاند با پیام فارسی خودش نمایش داده میشود | ✅ | پیام سرور مستقیم نمایش داده میشود |
|
||||
| ۴.۱۲ | پس از خطای تداخل، `refetchSlots()` اجرا میشود | ✅ | همان روز دوباره خوانده میشود تا جایگزین دیده شود |
|
||||
|
||||
## ۵. UI — قواعد سایت
|
||||
|
||||
@@ -97,8 +97,8 @@ UI: [_shared/ui-conventions.md](../_shared/ui-conventions.md)
|
||||
| ۶.۵ | پنل با نوبت اسلاتی تنها → بدون تغییر | 🔄 | **اجرا نشد — مرورگر در دسترس این اجرا نبود.** بهجایش تست خودکار: ۱۳ تست جدید (۷ روی `adaptServiceSlots`، ۶ روی `Card`) + `npm run build` سبز |
|
||||
| ۶.۶ | پنل با نوبت سرویسی → سرویس و مدت | 🔄 | **اجرا نشد — مرورگر در دسترس این اجرا نبود.** بهجایش تست خودکار: ۱۳ تست جدید (۷ روی `adaptServiceSlots`، ۶ روی `Card`) + `npm run build` سبز |
|
||||
| ۶.۷ | پنل در دارکمود | 🔄 | **اجرا نشد — مرورگر در دسترس این اجرا نبود.** بهجایش تست خودکار: ۱۳ تست جدید (۷ روی `adaptServiceSlots`، ۶ روی `Card`) + `npm run build` سبز |
|
||||
| ۶.۸ | جابهجایی سرویسی → مدت حفظ | ⏳ | جابهجایی انجام نشد — رجوع به ۴.۸ |
|
||||
| ۶.۹ | جابهجایی به زمان اشغال → پیام فارسی + refetch | ⏳ | همان |
|
||||
| ۶.۸ | جابهجایی سرویسی → مدت حفظ | ⚠️ | سرویسها دستنخورده فرستاده میشوند و مدت را سرور حساب میکند؛ تست دستی روی محیط واقعی انجام نشد |
|
||||
| ۶.۹ | جابهجایی به زمان اشغال → پیام فارسی + refetch | ⚠️ | مسیرش هست (۴۰۹ سرور)؛ تست دستی انجام نشد |
|
||||
| ۶.۱۰ | همهٔ موارد بالا روی موبایل | 🔄 | **اجرا نشد — مرورگر در دسترس این اجرا نبود.** بهجایش تست خودکار: ۱۳ تست جدید (۷ روی `adaptServiceSlots`، ۶ روی `Card`) + `npm run build` سبز |
|
||||
| ۶.۱۱ | تست واحد `adaptServiceSlots` (پنج حالت) | ✅ | **۷ حالت** نه پنج: بازهٔ واقعی · علامت available · ساختار بدون `data` · fallback بی`end_time` · خالی → `[]` · `null` → `[]` · یک اسلات تنها |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user