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:
- 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/). - 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). - 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 theClientAssessmentType.CareReadinessAssessmentenum value but is otherwise a separate feature. - 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)
| Field | Type | Notes |
|---|---|---|
business | ObjectId → Business | required, indexed (tenant scope) |
clientName, phone | String | prospect identity (no Client ref — pre-client) |
birthday | Date | |
weight, height | { value, unit } | units from WeightUnit/HeightUnit |
address | AddressSchema | |
service | { type, schedules } | type ∈ In-Home Care | Hospice Care | Respite Care | Placement | null; per-day { hours } |
contactPerson | { name, phone, email, relationship } | |
howDidClientHearAboutUs, howDidClientHearAboutUsOther, petsDescription | Object | rich text (Slate JSON) or plain string |
reasonForSeekingHelp | String | |
havePets | Boolean | |
assessment | SimplifiedRoutineTaskInventorySchema | embedded SRTI (see below) |
narrative, narrativeGeneratedAt | String / Date | AI-generated narrative text |
statusHistory | Array { status, notes, timestamp, author } | newest entry first (unshift); current status = statusHistory[0].status |
author | ObjectId → User | required |
careProposal | ObjectId → CareProposal | null | one-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) | Collection | Assessment payload | Source |
|---|---|---|---|
ClientSimplifiedRoutineTaskInventory | client_simplified_routine_task_inventories | shared SRTI schema (same as initial assessment) | apps/backend/src/clients/entities/client-simplified-routine-task-inventory.entity.ts |
ClientRoutineTaskInventory | client_routine_task_inventories | rating categories (1–n ratings with checked criteria) for Physical ADL, Instrumental ADL, Communication, Work Readiness | apps/backend/src/clients/entities/client-routine-task-inventory.entity.ts |
ClientMontessoriProfile | client_montessori_profiles | likesDislikes, personalHistory, dailyRoutine, cognitionLanguage, observation sub-schemas | apps/backend/src/clients/entities/client-montessori-profile.entity.ts |
ClientAllenCognitiveLevel | client_allen_cognitive_levels | mode (enum 1.0-1.2 … 6.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 |
ClientHomeSafety | client_home_safeties | 12 checklist categories (bathroom, kitchen, windows, …) of { checked, text, notes } items + free-text recommendations | apps/backend/src/clients/entities/client-home-safety.entity.ts |
ClientMealAssessment | client_meal_assessments | 4 domains: swallowing/dysphagia (IDDSI levels), nutritional status (MNA-SF), feeding abilities, dietary needs/preferences + recommendations | apps/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)
| Field | Type | Notes |
|---|---|---|
business | ObjectId → Business | required, indexed |
shiftAssignment | ObjectId → ShiftAssignment | required — every observation belongs to a shift |
client | ObjectId → Client | required |
caregiver | ObjectId → User | required (the author) |
notes | String | required — the entire clinical content is one free-text field |
observedAt | Date | optional |
status | ObservationStatus | default draft, indexed |
submittedAt, reviewedBy/reviewedAt/reviewNotes, acknowledgedBy/acknowledgedAt | mixed | per-stage audit fields |
CareReadinessAssessment (pre-shift)
- Collection: default Mongoose pluralization (no explicit
collectionoption 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 queuecare-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).
- Create —
POST /initial-assessmentsrequiresINITIAL_ASSESSMENTS_CREATE; record starts asDraftwith a fully defaulted SRTI (initial-assessments.controller.ts:32-33,initial-assessments.service.tscreate()/getDefaultAssessmentData()). - Edit / save draft —
PUT /:idandPUT /:id/draftrequireINITIAL_ASSESSMENTS_EDIT; each save unshifts a newDraftstatus entry ("Updated"/"Saved as draft") ontostatusHistory(initial-assessments.service.tsupdate(),saveAsDraft()). - Optional AI narrative flow — guided Q&A produces a narrative (
PUT /:id/narrative, persisted viasaveNarrative()) 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/. - Complete —
PUT /:id/statuswith targetCompleted. 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()andcollectIncompleteAssessmentFieldErrors()inapps/backend/src/common/utils/is-simplified-routine-task-inventory-completed.ts). Failures throwFieldValidationExceptionwith form-path field names. - Convert —
POST /:id/convert-to-care-proposalrequiresINITIAL_ASSESSMENTS_CONVERT; see the dedicated subsection below. - Duplicate / Archive / Delete — duplicate copies all data as a fresh
Draft(dropscareProposal, re-authors to current user); delete (INITIAL_ASSESSMENTS_DELETE) optionally cascades to the linked care proposal via?deleteLinkedCareProposal(initial-assessments.service.tsduplicate(),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):
- Save —
PUT /clients/:clientId/assessments/<type>upserts the single per-client document and always forcesstatus: Drafton save (saveSimplifiedRoutineTaskInventory()etc. —$set: { assessment, status: ClientAssessmentStatus.Draft }). - Mark Completed / revert to Draft —
PUT /clients/:clientId/assessments/statuswith{ 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). - Delete —
DELETE /clients/:clientId/assessments/<type>removes the document. - Progress —
GET /clients/:clientId/assessments-progressreturns 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).
- Create (mobile, during active shift) —
createObservation()requires the caller to be the shift's caregiver and the shiftcurrentStatus === IN_PROGRESS; starts asdraft, orsubmittedimmediately whensubmitForReviewis set (health-observations.service.tscreateObservation()). Mobile screen:apps/mobile/app/(client)/[id]/health-observations/create.tsx(menu label "Change of Condition" inapps/mobile/app/(client)/[id]/index.tsx:245). - Update/Delete — caregiver-only,
draftstatus only (updateObservation(),deleteObservation()). - Submit — caregiver-only,
draft → submitted, setssubmittedAt, emitshealth-observation.submitted(submitObservation()). - Review (web) —
submitted → reviewed; reviewer recordsapproved+ requiredreviewNotes; emitshealth-observation.reviewed(reviewObservation(); dialogapps/web/.../change-of-conditions/_components/review-observation-dialog.tsx). Note:approved: falsestill moves the record toreviewed— the boolean is only carried on the event payload and is not persisted on the document. - Acknowledge — sets
acknowledged+ platform log. No status precondition — an observation in any state (includingdraft) 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.reviewedis emitted (health-observations.service.tsreviewObservation()) 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.updatedAtbump (client-assessments.service.tsemitClientAssessmentLog()). - Care plan regeneration is manual only:
POST /clients/:clientId/generate-care-plan(clients.controller.ts:1204) and care provider tasks viaPOST /clients/:clientId/care-provider-tasks/generate(client-care-provider-tasks.controller.ts:82-84, permissionCARE_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;CareProposalhas noinitialAssessmentback-reference (grep ofcare-proposal.entity.tsfinds none). Reverse lookup is by query:findByLinkedCareProposalId()(initial-assessments.service.ts). - Status gate:
convertToCareProposal()rejects when the latest status isDraft("must be in completed status") and whencareProposalis already set ("already converted") (initial-assessments.service.tsconvertToCareProposal()). Note the check isstatus === Draft— notstatus === Completed— so anArchivedassessment would also pass this guard (the state machine separately preventsArchived → ConvertedToCareProposalonly viaupdateStatus, which the convert endpoint does not call). Flagged in gaps. - What is copied on conversion (
care-proposals.service.ts:312-440createFromInitialAssessment()): 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 separateCareProposalAssessmentdocument (care-proposal-assessment.entity.ts, fieldassessment, linked bycareProposal) viacreateAndLinkAssessment(..., true); an assessment-derivedrateComputation.assessmentScoreis computed viacalculateAssessmentPoints(). - After conversion: assessment status becomes
Converted to Care ProposalandcareProposalis set in one save. If the proposal is later deleted,unlinkCareProposal()reverts the assessment toCompletedwith an audit note. - Downstream: when the proposal becomes a client, the proposal's SRTI is seeded into
client_simplified_routine_task_inventorieswith statusCompleted(clients.service.ts:423→seedFromCareProposal()inclient-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)
- 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-assessmentqueue) calls the AI service (apps/backend/src/ai/services/ai-client-care-readiness-assessment.service.ts) to produce client-specific questions; status movespending → generating → in_progress. - The care provider takes the quiz on mobile (
apps/mobile/app/(assessments)/index.tsx,take.tsx); attempts record a 0–100 score andpassedagainstpassingScore; statuscompleted.
Business Rules & Constraints
- Initial assessment status is derived from
statusHistory[0]— history is prepended, never replaced (initial-assessments.service.tsupdateStatus():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-checksrequiredPermissionForTransition). - Completing an initial assessment requires all base fields and every SRTI score filled; errors come back as form-path
FieldErrors (initial-assessments.service.tsvalidateRequiredFieldsForCompletion();common/utils/is-simplified-routine-task-inventory-completed.tscollectMissingScores()). - An initial assessment can be converted at most once; conversion is blocked while a
careProposallink exists (convertToCareProposal()and alsoupdateStatus()— 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.tsupdateStatus()tail). - List visibility is permission-scoped:
initial_assessments:view:ownfilters byauthor;:allsees everything; there is deliberately no:assignedtier (buildViewScopeFilter()ininitial-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.tsbottom). - Saving any client assessment always resets its status to
Draft, even if it wasCompleted(client-assessments.service.ts, everysave*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-levelJwtAuthGuard(@Controller('clients')+@UseGuards(JwtAuthGuard), line ~91) — no@RequirePermissionson get/save/delete/status for assessments. - Deleting a client deletes all six assessment docs (
deleteAllForClient(), called fromclients.service.ts:1622); duplicating a client copies them (copyAllAssessments(),clients.service.ts:1746). - Only
Completedclient assessments are included in the AI narrative used by care-plan and task generation (getNarrativeAssessments()filterstatus: ClientAssessmentStatus.Completed). - Health observations can only be created by the shift's own caregiver while the shift is
IN_PROGRESS(health-observations.service.tscreateObservation()). - Only
draftobservations may be edited, deleted, or submitted, and only by their author (updateObservation(),deleteObservation(),submitObservation()). - Only
submittedobservations may be reviewed; the reviewer'sapprovedboolean 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:
usersToNotifyis a hardcoded empty array with a// TODO: Get care managers to notify(submitObservation()inhealth-observations.service.ts). - Observation search uses the raw user string in a
RegExpwithout escaping (getObservations():new RegExp(filters.search, 'i')) — unlike initial assessments, which useescapeRegExp(initial-assessments.service.tsfindAll()).
Surfaces (Web & Mobile)
Web (Admin / CareManager dashboard)
- Initial assessments pipeline —
apps/web/app/(app)/(admin)/dashboard/initial-assessments/(list with status tabs/counts,add,[id]/editform,[id]/guided-narrativeAI 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 assessments —
apps/web/app/(app)/(admin)/dashboard/clients/[id]/edit/assessments/with subpagesinitial-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 fromGET /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 index —
dashboard/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-touchalso appears in the client sidebar (client-routes.tsx:210). - Change of conditions —
dashboard/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.tsxlist,create.tsx,[observationId].tsx); menu entry labeled "Change of Condition" ((client)/[id]/index.tsx:245). The backend enforces the active-shift rule. - Care Readiness Assessment —
apps/mobile/app/(assessments)/index.tsx(generation progress, results) andtake.tsx(quiz), driven byuseCareReadinessAssessmentGenerationandcareReadinessAssessmentApi. - The six client assessments and initial assessments have no mobile surface — web only.
Cross-Module Dependencies
- assessments → care proposals:
InitialAssessmentsServiceinjectsCareProposalsService(forwardRef) and callscreateFromInitialAssessment()/remove(); care proposals call backunlinkCareProposal()andfindByLinkedCareProposalId()(initial-assessments.service.ts). The SRTI is copied intoCareProposalAssessment(care-proposals/entities/care-proposal-assessment.entity.ts). See 03-care-proposals.md. - care proposals → client assessments: on client creation from a proposal,
ClientsServicecallsClientAssessmentsService.seedFromCareProposal()to upsert the client SRTI asCompleted(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) injectsClientAssessmentsServiceand foldsgetNarrativeAssessments()(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:
TasksValidationAgentlikewise 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.submittedevent →HandoverTriggerListener→ BullMQHANDOVER_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/HealthObservationUpdateexist (notification/notification-registry.ts:630-645), but the review notification send is short-circuited by the emptyusersToNotifyTODO. - 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.tsemitClientAssessmentLog()). - Incident reports share the handover trigger path but are documented in 09-incident-reports.md.
Open Questions & Gaps
- 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.reviewedhas 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. - Health observations carry no structured data. The entire "change of conditions" payload is one free-text
notesfield (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. - The reviewer's approve/needs-attention decision is discarded.
reviewObservation()emitsapprovedon 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). - Care managers are never notified of submitted observations.
submitObservation()hasconst usersToNotify: string[] = []with a TODO; the registry entryHealthObservationReviewis effectively dead (health-observations.service.ts;notification-registry.ts:631). Review currently depends on someone opening the web page. acknowledgeObservation()has no status or role guard — any authenticated user can acknowledge an observation in any state, including unsubmitted drafts (health-observations.service.ts).- 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. - No transition or completeness validation for client assessment statuses. Any status can be set at any time, and saving a
Completedassessment silently reverts it toDraft(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? - Convert guard checks
!== Draft, not=== Completed.convertToCareProposal()only rejectsDraft, so anArchivedassessment that was never completed since archiving could be converted directly (initial-assessments.service.tsconvertToCareProposal()); intended behavior cannot be determined from code. ClientAssessmentType.CareReadinessAssessmentis not handled byupdateAssessmentStatus()'s model map — passing it returns "Unknown assessment type" (client-assessments.service.ts). Either the enum value or the handler is incomplete.updateStatus/saveAsDraft/update/saveNarrative/applyExtractionon initial assessments are not tenant-scoped — theyfindByIdwithout the business/view-scope filter applied infindAll/findById(user)(initial-assessments.service.ts). Whether route-level guards fully compensate cannot be determined from this module's code.- Observation search regex injection.
getObservations()buildsnew RegExp(filters.search)unescaped, unlike the escaped pattern used for initial assessments (health-observations.service.tsvsinitial-assessments.service.ts). - Four assessment types are stubs: Always Fresh, Care Bliss, Caring Touch, Healing Ally render
ComingSoonplaceholders on web (dashboard/assessments/*/page.tsx) with no backend entities;caring-touchalready appears in the client sidebar (client-routes.tsx:210). - 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.