Anaya Care Docs

Assessments & Change of Conditions

Part of the Anaya Care product wiki. See 00-overview.md.

Purpose

This module covers every "assessment" concept in the platform and how a client's changing condition is (and is not) propagated into their care plan and care provider tasks:

  1. Initial Assessment — a pre-client intake record (prospect name, contact, service needs, and a Simplified Routine Task Inventory) that, once completed, can be converted into a Care Proposal (apps/backend/src/initial-assessments/).
  2. Client Assessments — six per-client clinical/lifestyle assessments stored as separate collections, each with a one-document-per-client rule: Simplified Routine Task Inventory, Routine Task Inventory, Montessori Profile, Allen Cognitive Level, Home Safety, and Meal Assessment (apps/backend/src/clients/services/client-assessments.service.ts).
  3. Care Readiness Assessment — an AI-generated pre-shift quiz a care provider takes on mobile before starting a shift (apps/backend/src/shifts/entities/care-readiness-assessment.entity.ts). It shares the ClientAssessmentType.CareReadinessAssessment enum value but is otherwise a separate feature.
  4. Change of Conditions — the product label for Health Observations: free-text condition notes a caregiver records during an active shift, which go through a submit → review → acknowledge workflow (apps/backend/src/health-observations/).

Entities & Data Model

InitialAssessment

  • Collection: initial_assessments (apps/backend/src/initial-assessments/entities/initial-assessment.entity.ts)
FieldTypeNotes
businessObjectId → Businessrequired, indexed (tenant scope)
clientName, phoneStringprospect identity (no Client ref — pre-client)
birthdayDate
weight, height{ value, unit }units from WeightUnit/HeightUnit
addressAddressSchema
service{ type, schedules }type ∈ In-Home Care | Hospice Care | Respite Care | Placement | null; per-day { hours }
contactPerson{ name, phone, email, relationship }
howDidClientHearAboutUs, howDidClientHearAboutUsOther, petsDescriptionObjectrich text (Slate JSON) or plain string
reasonForSeekingHelpString
havePetsBoolean
assessmentSimplifiedRoutineTaskInventorySchemaembedded SRTI (see below)
narrative, narrativeGeneratedAtString / DateAI-generated narrative text
statusHistoryArray { status, notes, timestamp, author }newest entry first (unshift); current status = statusHistory[0].status
authorObjectId → Userrequired
careProposalObjectId → CareProposal | nullone-to-one link, set on conversion

The embedded SRTI is a tree of ScoreNotes ({ score, notes }) leaves under four sections: memoryCareSupport, adl (selfCare, dressing, eating, toileting, mobility, continence, communication, medicationManagement), iadl, and adaptations (apps/backend/src/common/entities/simplified-routine-task-inventory.entity.ts:350-362).

Client assessment entities (six)

All six share the same shape — business (required ObjectId, indexed), client (ObjectId → Client), status (ClientAssessmentStatus), assessment (type-specific payload), timestamps — and all enforce one document per client via a unique sparse { client: 1 } index.

Entity (class)CollectionAssessment payloadSource
ClientSimplifiedRoutineTaskInventoryclient_simplified_routine_task_inventoriesshared SRTI schema (same as initial assessment)apps/backend/src/clients/entities/client-simplified-routine-task-inventory.entity.ts
ClientRoutineTaskInventoryclient_routine_task_inventoriesrating categories (1–n ratings with checked criteria) for Physical ADL, Instrumental ADL, Communication, Work Readinessapps/backend/src/clients/entities/client-routine-task-inventory.entity.ts
ClientMontessoriProfileclient_montessori_profileslikesDislikes, personalHistory, dailyRoutine, cognitionLanguage, observation sub-schemasapps/backend/src/clients/entities/client-montessori-profile.entity.ts
ClientAllenCognitiveLevelclient_allen_cognitive_levelsmode (enum 1.0-1.26.0) + structured recommendations (what makes sense, common problems, functional goals, treatment plan focus, approach)apps/backend/src/clients/entities/client-allen-cognitive-level.entity.ts
ClientHomeSafetyclient_home_safeties12 checklist categories (bathroom, kitchen, windows, …) of { checked, text, notes } items + free-text recommendationsapps/backend/src/clients/entities/client-home-safety.entity.ts
ClientMealAssessmentclient_meal_assessments4 domains: swallowing/dysphagia (IDDSI levels), nutritional status (MNA-SF), feeding abilities, dietary needs/preferences + recommendationsapps/backend/src/clients/entities/client-meal-assessment.entity.ts

Shared enums (packages/shared/src/enums/domain-status.ts):

  • ClientAssessmentStatus = Not Started | Draft | Completed (lines 175–179)
  • ClientAssessmentType = the six types above + CareReadinessAssessment (lines 184–192)
  • InitialAssessmentStatus = Draft | Completed | Converted to Care Proposal | Archived (lines 374–379)
  • ObservationStatus (change of conditions) = draft | submitted | reviewed | acknowledged (lines 561–566)
  • AssessmentStatus (care readiness) = pending | generating | in_progress | completed (lines 384–389)

HealthObservation ("Change of Conditions")

  • Collection: health_observations (apps/backend/src/health-observations/entities/health-observation.entity.ts)
FieldTypeNotes
businessObjectId → Businessrequired, indexed
shiftAssignmentObjectId → ShiftAssignmentrequired — every observation belongs to a shift
clientObjectId → Clientrequired
caregiverObjectId → Userrequired (the author)
notesStringrequired — the entire clinical content is one free-text field
observedAtDateoptional
statusObservationStatusdefault draft, indexed
submittedAt, reviewedBy/reviewedAt/reviewNotes, acknowledgedBy/acknowledgedAtmixedper-stage audit fields

CareReadinessAssessment (pre-shift)

  • Collection: default Mongoose pluralization (no explicit collection option in the schema — apps/backend/src/shifts/entities/care-readiness-assessment.entity.ts)
  • Fields: business, shiftAssignment, client, caregiver, questions[] (AI-generated multiple choice), attempts[] (responses, 0–100 score, passed), status (AssessmentStatus), passingScore, passed, autoGenerated, generationJobId/StartedAt. Generation runs through the BullMQ queue care-readiness-assessment (apps/backend/src/shifts/care-readiness-assessment.service.ts:63).

ER diagram

Workflows & State Machines

Initial Assessment lifecycle

Roles: anyone holding the relevant BusinessPermission.INITIAL_ASSESSMENTS_* permission (in practice Admin/CareManager on web).

  1. CreatePOST /initial-assessments requires INITIAL_ASSESSMENTS_CREATE; record starts as Draft with a fully defaulted SRTI (initial-assessments.controller.ts:32-33, initial-assessments.service.ts create()/getDefaultAssessmentData()).
  2. Edit / save draftPUT /:id and PUT /:id/draft require INITIAL_ASSESSMENTS_EDIT; each save unshifts a new Draft status entry ("Updated"/"Saved as draft") onto statusHistory (initial-assessments.service.ts update(), saveAsDraft()).
  3. Optional AI narrative flow — guided Q&A produces a narrative (PUT /:id/narrative, persisted via saveNarrative()) and an extraction that is deep-merged onto the form (POST /:id/apply-extraction, applyExtraction()/mergeAssessment(); score leaves only overwritten when the extracted score is a non-empty string). Web UI: apps/web/app/(app)/(admin)/dashboard/initial-assessments/[id]/guided-narrative/.
  4. CompletePUT /:id/status with target Completed. The service validates the transition, checks the per-target permission, then runs hard field validation: clientName, birthday, address1, service.type, full contact person, plus every SRTI score must be non-empty (validateRequiredFieldsForCompletion() and collectIncompleteAssessmentFieldErrors() in apps/backend/src/common/utils/is-simplified-routine-task-inventory-completed.ts). Failures throw FieldValidationException with form-path field names.
  5. ConvertPOST /:id/convert-to-care-proposal requires INITIAL_ASSESSMENTS_CONVERT; see the dedicated subsection below.
  6. Duplicate / Archive / Delete — duplicate copies all data as a fresh Draft (drops careProposal, re-authors to current user); delete (INITIAL_ASSESSMENTS_DELETE) optionally cascades to the linked care proposal via ?deleteLinkedCareProposal (initial-assessments.service.ts duplicate(), delete()).

Transition table: apps/backend/src/initial-assessments/utils/status-transitions.util.ts (INITIAL_ASSESSMENT_STATUS_TRANSITIONS, requiredPermissionForTransition).

Client assessments lifecycle

Roles: web dashboard users (Admin/CareManager). All six assessments behave identically (client-assessments.service.ts):

  1. SavePUT /clients/:clientId/assessments/<type> upserts the single per-client document and always forces status: Draft on save (saveSimplifiedRoutineTaskInventory() etc. — $set: { assessment, status: ClientAssessmentStatus.Draft }).
  2. Mark Completed / revert to DraftPUT /clients/:clientId/assessments/status with { type, status } (clients.controller.ts:666); web button "Set to Completed" / back to Draft (apps/web/.../assessments/_components/client-assessment-change-button.tsx). There is no transition validation and no field-completeness validation — any status can be set at any time (updateAssessmentStatus() does a plain $set).
  3. DeleteDELETE /clients/:clientId/assessments/<type> removes the document.
  4. ProgressGET /clients/:clientId/assessments-progress returns the status of all six (missing doc ⇒ Not Started).

Only Completed assessments feed AI narrative context (getNarrativeAssessments() filters status: Completed).

Change of Conditions (Health Observations) workflow

Roles: CareProvider (mobile) creates/submits; Admin/CareManager (web) reviews; acknowledge is unrestricted (see gaps).

  1. Create (mobile, during active shift)createObservation() requires the caller to be the shift's caregiver and the shift currentStatus === IN_PROGRESS; starts as draft, or submitted immediately when submitForReview is set (health-observations.service.ts createObservation()). Mobile screen: apps/mobile/app/(client)/[id]/health-observations/create.tsx (menu label "Change of Condition" in apps/mobile/app/(client)/[id]/index.tsx:245).
  2. Update/Delete — caregiver-only, draft status only (updateObservation(), deleteObservation()).
  3. Submit — caregiver-only, draft → submitted, sets submittedAt, emits health-observation.submitted (submitObservation()).
  4. Review (web)submitted → reviewed; reviewer records approved + required reviewNotes; emits health-observation.reviewed (reviewObservation(); dialog apps/web/.../change-of-conditions/_components/review-observation-dialog.tsx). Note: approved: false still moves the record to reviewed — the boolean is only carried on the event payload and is not persisted on the document.
  5. Acknowledge — sets acknowledged + platform log. No status precondition — an observation in any state (including draft) can be acknowledged (acknowledgeObservation() has no status check).

CRITICAL PAIN POINT — Change of Conditions does NOT cascade to the care plan or tasks

Searched the whole repo for change of condition, changeOfCondition, condition change, reassessment, re-assessment. Findings:

What "change of conditions" actually is in code: it is purely a UI label for the HealthObservation entity — a single free-text notes field per record tied to a shift (health-observation.entity.ts). There is no structured "condition" data, no link to assessments, care plans, or tasks.

The only automated consequence of a submitted observation is a shift-handover decision: health-observation.submitted is consumed by HandoverTriggerListener (apps/backend/src/shift-handovers/listeners/handover-trigger.listener.ts:31), which enqueues an AI job (HANDOVER_QUEUE, sourceReportType: 'coc') that decides whether the next caregiver gets a login handover alert (apps/backend/src/shift-handovers/ai-handover-decision.service.ts:137). Even this is skipped with only a warning when businessId is missing from the event payload (listener lines 33–41, marked TODO).

The cascade to the care plan / care provider tasks does not exist:

  • health-observation.reviewed is emitted (health-observations.service.ts reviewObservation()) but has zero listeners anywhere in the codebase (repo-wide grep found only the emitter).
  • Nothing in health-observations/, clients/services/client-care-plans*, or the AI agent modules references health observations as an input. The care-plan context builder (apps/backend/src/ai/agents/care-plan/agents/context-builder.agent.ts) and the tasks validation agent (apps/backend/src/ai/agents/care-provider-tasks/agents/tasks-validation.agent.ts:138) build context from the client narrative, medications, schedules, and completed client assessments — health observations are not included.
  • Saving or completing any of the six client assessments triggers nothing beyond a platform-log event and a client.updatedAt bump (client-assessments.service.ts emitClientAssessmentLog()).
  • Care plan regeneration is manual only: POST /clients/:clientId/generate-care-plan (clients.controller.ts:1204) and care provider tasks via POST /clients/:clientId/care-provider-tasks/generate (client-care-provider-tasks.controller.ts:82-84, permission CARE_TASKS_GENERATE). Both run as BullMQ jobs (clients/processors/care-plan.processor.ts, care-provider-tasks.processor.ts).

Bottom line: when a client's condition changes, the operational loop today is: caregiver writes a free-text observation → care manager reads/reviews it on web → care manager must remember to manually update the relevant client assessment(s) and then manually re-run care plan generation and task generation. There is no prompt, no flag, no queue, and no reference connecting an observation to a care plan revision. This is the platform's biggest unmodeled workflow — flagged in Open Questions & Gaps #1–#4.

SECOND PAIN POINT — Initial Assessment → Care Proposal dependency (assessment side)

  • Linking field: InitialAssessment.careProposal (ObjectId → CareProposal, default null) — the link is one-way; CareProposal has no initialAssessment back-reference (grep of care-proposal.entity.ts finds none). Reverse lookup is by query: findByLinkedCareProposalId() (initial-assessments.service.ts).
  • Status gate: convertToCareProposal() rejects when the latest status is Draft ("must be in completed status") and when careProposal is already set ("already converted") (initial-assessments.service.ts convertToCareProposal()). Note the check is status === Draft — not status === Completed — so an Archived assessment would also pass this guard (the state machine separately prevents Archived → ConvertedToCareProposal only via updateStatus, which the convert endpoint does not call). Flagged in gaps.
  • What is copied on conversion (care-proposals.service.ts:312-440 createFromInitialAssessment()): client name split into first/last, birthday, weight/height, address, pets, contact person (only if non-empty), service type + normalized 7-day schedule, narrative, author; the embedded SRTI is snapshotted into a separate CareProposalAssessment document (care-proposal-assessment.entity.ts, field assessment, linked by careProposal) via createAndLinkAssessment(..., true); an assessment-derived rateComputation.assessmentScore is computed via calculateAssessmentPoints().
  • After conversion: assessment status becomes Converted to Care Proposal and careProposal is set in one save. If the proposal is later deleted, unlinkCareProposal() reverts the assessment to Completed with an audit note.
  • Downstream: when the proposal becomes a client, the proposal's SRTI is seeded into client_simplified_routine_task_inventories with status Completed (clients.service.ts:423seedFromCareProposal() in client-assessments.service.ts), so the client-side "Initial Assessment" page starts pre-filled. Full proposal state machine: 03-care-proposals.md.

Care Readiness Assessment (pre-shift, mobile)

  1. Generation is requested for a shift (caller must be the shift's caregiver or same-business staff — canAccessShiftAssessment(), care-readiness-assessment.service.ts:77-152); a BullMQ job (care-readiness-assessment queue) calls the AI service (apps/backend/src/ai/services/ai-client-care-readiness-assessment.service.ts) to produce client-specific questions; status moves pending → generating → in_progress.
  2. The care provider takes the quiz on mobile (apps/mobile/app/(assessments)/index.tsx, take.tsx); attempts record a 0–100 score and passed against passingScore; status completed.

Business Rules & Constraints

  • Initial assessment status is derived from statusHistory[0] — history is prepended, never replaced (initial-assessments.service.ts updateStatus(): assessment.statusHistory.unshift(...)).
  • Initial assessment status transitions are enforced by an explicit state machine and per-target permission check on top of the route decorator (utils/status-transitions.util.ts; updateStatus() re-checks requiredPermissionForTransition).
  • Completing an initial assessment requires all base fields and every SRTI score filled; errors come back as form-path FieldErrors (initial-assessments.service.ts validateRequiredFieldsForCompletion(); common/utils/is-simplified-routine-task-inventory-completed.ts collectMissingScores()).
  • An initial assessment can be converted at most once; conversion is blocked while a careProposal link exists (convertToCareProposal() and also updateStatus() — both throw "Assessment already converted to care proposal").
  • The careProposal-already-set guard in updateStatus() runs after transition validation, so even valid transitions are blocked once converted (initial-assessments.service.ts updateStatus() tail).
  • List visibility is permission-scoped: initial_assessments:view:own filters by author; :all sees everything; there is deliberately no :assigned tier (buildViewScopeFilter() in initial-assessments.service.ts).
  • Each of the six client assessments allows exactly one document per client — unique sparse index { client: 1 } on all six schemas (e.g. client-montessori-profile.entity.ts bottom).
  • Saving any client assessment always resets its status to Draft, even if it was Completed (client-assessments.service.ts, every save* method).
  • Client assessment status changes have no transition rules and no completeness validation (updateAssessmentStatus() — plain $set).
  • Client assessment routes in clients.controller.ts (lines 488–630) carry only the class-level JwtAuthGuard (@Controller('clients') + @UseGuards(JwtAuthGuard), line ~91) — no @RequirePermissions on get/save/delete/status for assessments.
  • Deleting a client deletes all six assessment docs (deleteAllForClient(), called from clients.service.ts:1622); duplicating a client copies them (copyAllAssessments(), clients.service.ts:1746).
  • Only Completed client assessments are included in the AI narrative used by care-plan and task generation (getNarrativeAssessments() filter status: ClientAssessmentStatus.Completed).
  • Health observations can only be created by the shift's own caregiver while the shift is IN_PROGRESS (health-observations.service.ts createObservation()).
  • Only draft observations may be edited, deleted, or submitted, and only by their author (updateObservation(), deleteObservation(), submitObservation()).
  • Only submitted observations may be reviewed; the reviewer's approved boolean is not persisted (reviewObservation() stores status/reviewer/notes only).
  • Acknowledging has no status or role precondition in the service (acknowledgeObservation()).
  • The "review required" notification to care managers is dead code: usersToNotify is a hardcoded empty array with a // TODO: Get care managers to notify (submitObservation() in health-observations.service.ts).
  • Observation search uses the raw user string in a RegExp without escaping (getObservations(): new RegExp(filters.search, 'i')) — unlike initial assessments, which use escapeRegExp (initial-assessments.service.ts findAll()).

Surfaces (Web & Mobile)

Web (Admin / CareManager dashboard)

  • Initial assessments pipelineapps/web/app/(app)/(admin)/dashboard/initial-assessments/ (list with status tabs/counts, add, [id]/edit form, [id]/guided-narrative AI flow). Status changes via dropdown (_components/initial-assessment-change-status-dropdown-item.tsx); conversion to care proposal is triggered from these components (initial-assessment-card.tsx, initial-assessment-form.tsx).
  • Client assessmentsapps/web/app/(app)/(admin)/dashboard/clients/[id]/edit/assessments/ with subpages initial-assessment (the client's SRTI, reusing the name), rti, montessori-profile, acl, home-safety, meal-assessment. Per-assessment status badge and "Set to Completed"/back-to-Draft button (_components/client-assessment-change-button.tsx). The client sidebar shows per-assessment progress from GET /assessments-progress (_components/client-routes.tsx:133-201). Home Safety has an AI "generate recommendations" action (POST .../home-safety/generate-recommendations, clients.controller.ts:578).
  • Standalone assessments indexdashboard/assessments/ mirrors the client assessment forms and also contains four Coming Soon placeholders: always-fresh, care-bliss, caring-touch, healing-ally (each renders <ComingSoon …under development… />, e.g. dashboard/assessments/always-fresh/page.tsx). caring-touch also appears in the client sidebar (client-routes.tsx:210).
  • Change of conditionsdashboard/clients/[id]/edit/change-of-conditions/page.tsx: stat cards, filterable observation table, detail sheet, and the review dialog (approve/needs-attention + required notes). No mobile equivalent for review.
  • Frontend-only rules: none material beyond presentation — but note the absence of backend permission checks on client assessment routes means any UI-level role gating there (admin-only dashboard routing) is effectively the only restriction.

Mobile (CareProvider / Family)

  • Change of Condition — care providers create/submit observations from a client's page: apps/mobile/app/(client)/[id]/health-observations/ (index.tsx list, create.tsx, [observationId].tsx); menu entry labeled "Change of Condition" ((client)/[id]/index.tsx:245). The backend enforces the active-shift rule.
  • Care Readiness Assessmentapps/mobile/app/(assessments)/index.tsx (generation progress, results) and take.tsx (quiz), driven by useCareReadinessAssessmentGeneration and careReadinessAssessmentApi.
  • The six client assessments and initial assessments have no mobile surface — web only.

Cross-Module Dependencies

  • assessments → care proposals: InitialAssessmentsService injects CareProposalsService (forwardRef) and calls createFromInitialAssessment() / remove(); care proposals call back unlinkCareProposal() and findByLinkedCareProposalId() (initial-assessments.service.ts). The SRTI is copied into CareProposalAssessment (care-proposals/entities/care-proposal-assessment.entity.ts). See 03-care-proposals.md.
  • care proposals → client assessments: on client creation from a proposal, ClientsService calls ClientAssessmentsService.seedFromCareProposal() to upsert the client SRTI as Completed (clients.service.ts:423). Backfill script: apps/backend/src/scripts/backfill-client-srti-from-care-proposal.ts.
  • assessments → AI care plan generation: ContextBuilderAgent (care-plan agent pipeline) injects ClientAssessmentsService and folds getNarrativeAssessments() (Completed-only) into the generation narrative (ai/agents/care-plan/agents/context-builder.agent.ts:113). Generation itself is queue-based and manually triggered (clients/processors/care-plan.processor.ts). See 04-care-plans-and-tasks.md.
  • assessments → AI care provider tasks generation: TasksValidationAgent likewise pulls completed assessments into the task-generation narrative (ai/agents/care-provider-tasks/agents/tasks-validation.agent.ts:138).
  • health observations → shift handovers: health-observation.submitted event → HandoverTriggerListener → BullMQ HANDOVER_QUEUE → AI decision on alerting the incoming caregiver (shift-handovers/listeners/handover-trigger.listener.ts, shift-handovers/ai-handover-decision.service.ts).
  • health observations → notifications: registry entries HealthObservationReview / HealthObservationUpdate exist (notification/notification-registry.ts:630-645), but the review notification send is short-circuited by the empty usersToNotify TODO.
  • health observations → shift summaries / tracking: shift summary PDFs/reports include a "Change of Conditions" section (clients/services/shift-summary.service.ts:1518, packages/shared/src/types/report-schemas.ts:53); client tracking summary counts observations (clients/services/client-tracking-summary.service.ts:176-203).
  • assessments → platform logs: every create/update emits PLATFORM_LOG_ACTIVITY_EVENT (initial-assessments.service.ts, client-assessments.service.ts emitClientAssessmentLog()).
  • Incident reports share the handover trigger path but are documented in 09-incident-reports.md.

Open Questions & Gaps

  1. No change-of-conditions cascade (major). A reviewed/acknowledged health observation never touches the care plan, care provider tasks, or any client assessment. health-observation.reviewed has no listeners; care plan and task regeneration are manual endpoints (clients.controller.ts:1204; client-care-provider-tasks.controller.ts:82). Is the intended workflow "care manager manually reassesses and regenerates", or is an automated/reminded cascade missing? Nothing in code answers this.
  2. Health observations carry no structured data. The entire "change of conditions" payload is one free-text notes field (health-observation.entity.ts). There is no condition category, severity, affected ADL domain, or link to an assessment — so even a future cascade would have nothing structured to act on.
  3. The reviewer's approve/needs-attention decision is discarded. reviewObservation() emits approved on an event no one consumes and does not persist it; an observation rejected as "needs attention" looks identical to an approved one in the database (health-observations.service.ts).
  4. Care managers are never notified of submitted observations. submitObservation() has const usersToNotify: string[] = [] with a TODO; the registry entry HealthObservationReview is effectively dead (health-observations.service.ts; notification-registry.ts:631). Review currently depends on someone opening the web page.
  5. acknowledgeObservation() has no status or role guard — any authenticated user can acknowledge an observation in any state, including unsubmitted drafts (health-observations.service.ts).
  6. Client assessment endpoints lack permission decorators. Get/save/delete/status for all six assessments (clients.controller.ts:488-690) are protected only by JWT — any authenticated user in any role can modify a client's assessments if they know the client id. Intended permission model cannot be determined from code.
  7. No transition or completeness validation for client assessment statuses. Any status can be set at any time, and saving a Completed assessment silently reverts it to Draft (client-assessments.service.ts) — meaning a routine edit drops the assessment out of AI narrative context until someone re-marks it Completed. Is that intended?
  8. Convert guard checks !== Draft, not === Completed. convertToCareProposal() only rejects Draft, so an Archived assessment that was never completed since archiving could be converted directly (initial-assessments.service.ts convertToCareProposal()); intended behavior cannot be determined from code.
  9. ClientAssessmentType.CareReadinessAssessment is not handled by updateAssessmentStatus()'s model map — passing it returns "Unknown assessment type" (client-assessments.service.ts). Either the enum value or the handler is incomplete.
  10. updateStatus/saveAsDraft/update/saveNarrative/applyExtraction on initial assessments are not tenant-scoped — they findById without the business/view-scope filter applied in findAll/findById(user) (initial-assessments.service.ts). Whether route-level guards fully compensate cannot be determined from this module's code.
  11. Observation search regex injection. getObservations() builds new RegExp(filters.search) unescaped, unlike the escaped pattern used for initial assessments (health-observations.service.ts vs initial-assessments.service.ts).
  12. Four assessment types are stubs: Always Fresh, Care Bliss, Caring Touch, Healing Ally render ComingSoon placeholders on web (dashboard/assessments/*/page.tsx) with no backend entities; caring-touch already appears in the client sidebar (client-routes.tsx:210).
  13. Handover trigger silently skips legacy events missing businessId (handover-trigger.listener.ts:33-41, TODO in code) — though the current emitter does include it, any other emitter path would drop the COC handover evaluation with only a warning log.

On this page