Populates platform/business-calendars, orchestration/sla, and
orchestration/escalation (all thin stubs until now) with the real engine:
- business-calendars: a luxon-based day-by-day calendar walk
(addBusinessMinutes/isWithinWorkingHours) excluding non-working hours,
weekends, and holidays — replacing the naive createdAt+hours stub FR-004
explicitly forbids.
- sla: most-specific SLAPolicy resolution (product/category/problemType/
priority, wildcard-or-exact-match, specificity-count + updatedAt
tiebreak), SLARun creation on the first real publish of the
long-unused TICKET_ASSIGNED domain event, durable pause/resume via an
absolute-timestamp shift (no in-memory state, verified across a real
buildApp() restart), and a repeatable BullMQ breach-detection sweep
(src/jobs/sla, itself a previously-unregistered stub) that is directly
callable for tests, not only reachable through a running worker.
- escalation: EscalationPolicy/Rule CRUD (all 10 doc05 trigger types
storable, only resolution_breach/first_response_breach evaluated),
breach-triggered and manual escalation both funnel through one EscalationEvent
+ scoped re-assignment path. AssignmentEngine (007) gains
assignToSpecificNode — a new, explicitly node-scoped entry point,
since escalation must never let 007's general resolution re-derive a
different node than the one a rule or a caller targeted.
Two small pre-existing scaffold gaps were closed along the way:
CategoriesRepository had no findById, and TICKET_ASSIGNED/SLA_BREACHED/
ESCALATION_TRIGGERED were defined since earlier phases but never
published by any code.
Verified against throwaway Docker Postgres/Redis (typecheck, lint,
architecture-check all clean; 148/150 relevant tests pass — the 2
failures are pre-existing, MinIO-dependent, and unrelated to this
feature).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
48 tasks across 9 phases (6 user stories + setup/foundational/polish),
sequenced US1 (policy definition) -> US2 (calendar-aware run creation) ->
US3 (durable pause/resume, P1-complete MVP) -> US4 (breach detection) ->
US5 (breach-triggered escalation) -> US6 (manual escalation), each
dependent on the last since every story builds on the previous one's
mechanism rather than being independently orderable.
Also folds in two design refinements found while cross-checking the
existing scaffold against research.md's plan: TICKET_ASSIGNED (defined in
domain-events.ts since 007, never published) becomes the real wiring point
for SLA-run creation, and src/jobs/sla//src/jobs/escalation/ turn out to
already exist as their own stub scaffolding, reused rather than
duplicated.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Phase 0 research resolves the business-calendar working-hours algorithm
(day-by-day walk via luxon, the first date/timezone dependency in this
codebase), the workingHours JSON shape, most-specific SLA-policy match
(reusing 005/006's resolution pattern), durable pause/resume (absolute
due-date shift, no in-memory state), and a repeatable-job breach-detection
design over per-run delayed jobs. Phase 1 adds data-model.md (one additive
refinement beyond doc06: SLARun.firstResponseBreachedAt), the admin/read
contract, and six quickstart scenarios including a genuine process-restart
boundary test for Constitution Principle VII.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>