Files
pedwfrontend/memory-bank/change-log.md
T
Robert Bond b87c522137 Merged PR 2435: Add workflow orchestration documentation validation
Add workflow orchestration documentation validation

Related work items: #23754
2026-06-25 11:46:36 +00:00

348 KiB
Raw Blame History

Change Log (AI/Human Curated)

Entry Template

date: YYYY-MM-DD
author: <agent|name>
scope: <files/routes/features>
type: change
rationale: <why change was made>
impact: <user/system/security/i18n/a11y>
status: completed|rolled-back|partial

Summary:
Validation:
Follow-ups:

CL-2026-06-25-WORKFLOW-ORCHESTRATION-DOC-VALIDATION: validate whether existing architecture docs already cover PEDW workflow/orchestration

date: 2026-06-25 author: Cline scope: context/workflow-orchestration-documentation-validation.md, memory-bank/change-log.md type: change rationale: Validate, using existing architecture documentation first, whether PEDW's workflow/orchestration model is already sufficiently documented for appeals and representations without reopening broad workflow discovery or performing route-by-route API review. impact: Documentation/context only; confirms current workflow/orchestration coverage across draft lifecycle, submission/finalisation, storage ownership, queue handoff, CRM transition, PDF/document generation, Notify/email side effects, completion-state handling, integration sequencing, and ownership transitions. No runtime, API, auth/session, CRM, storage, queue, notification, i18n, or behaviour change. status: completed

Summary:

  • Confirmed the required context was read before validation:
    • context/architecture.md
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/api-grouping-workflow-boundary-assessment.md
    • context/api-grouping-adoption-roadmap.md
    • context/portal-api-platform-assessment.md
    • context/integration-map.md
    • memory-bank/change-log.md
    • memory-bank/open-questions.md
  • Created new validation document:
    • context/workflow-orchestration-documentation-validation.md
  • Reused existing documentation as the evidence base and did not perform a new workflow discovery stream.
  • Validated the following workflow areas:
    • draft appeal lifecycle
    • appeal submission / finalisation
    • draft representation lifecycle
    • representation submission / finalisation
    • Azure Storage ownership
    • queue handoff
    • CRM transition boundary
    • PDF/document generation where relevant
    • Notify/email side effects where relevant
    • completion-state handling
    • integration sequencing
    • ownership transitions
  • Main conclusion:
    • existing PEDW architecture documents are already sufficient to describe the workflow/orchestration model at architecture level
    • strongest evidence is already present in context/journey-architecture-map.md, supported by context/api-route-map.md, context/api-grouping-workflow-boundary-assessment.md, context/architecture.md, and context/integration-map.md
    • the only notable gap is limited downstream detail beyond the visible queue handoff / CRM transition boundary, which does not justify another broad workflow discovery stream
  • Final recommendation recorded in the validation document:
    • small documentation consolidation only
    • no new workflow discovery needed at this time

Validation:

  • Documentation-only validation.
  • Existing documentation used as primary evidence.
  • No route inventory, broad code discovery, implementation, migration, or refactor performed.
  • Intended lightweight validation for this slice:
    • git diff --check

Follow-ups:

  • Prefer small documentation consolidation/cross-linking only if follow-up work is requested.
  • Do not open a new broad workflow/orchestration discovery stream unless a specific contradiction or missing boundary emerges.

CL-2026-06-25-API-GROUPING-FACADE-SEARCH-VERTICAL-SLICE: active public search results grouping and service adoption

CL-2026-06-25-API-GROUPING-WORKFLOW-BOUNDARY-ASSESSMENT: classify where the additive façade pattern should stop

date: 2026-06-25 author: Cline scope: context/api-grouping-workflow-boundary-assessment.md, context/api-grouping-adoption-roadmap.md, memory-bank/change-log.md type: change rationale: After completing the main additive façade read slices, perform a bounded architecture assessment to determine which remaining API families are still suitable for the current façade pattern, which require extra caution, which are workflow/orchestration boundaries, and which should be left unchanged for now. impact: Documentation/context only; clarifies the natural stop point of the current façade rollout pattern and guides future planning without any runtime, routing, auth/session, CRM, storage, queue, notification, or behaviour change. status: completed

Summary:

  • Confirmed the required context was read before the assessment:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Created new assessment document:
    • context/api-grouping-workflow-boundary-assessment.md
  • Used representative family inspection only, not a full inventory.
  • Reviewed representative service/routes across the remaining major families, including:
    • account / registration / personal details
    • notifications / email
    • appeals / drafts / finalisation
    • representations / drafts / finalisation
    • storage / blob / file operations
    • auth / session
    • admin / reporting
  • Recorded the A/B/C/D classification model:
    • A — safe façade candidate
    • B — possible façade candidate with caution
    • C — workflow / orchestration boundary
    • D — leave unchanged for now
  • Main findings:
    • the completed façade slices prove the current pattern is strongest for bounded read-only journey families with clear service ownership and trivial delegation
    • the strongest remaining cautious candidate is account read-support only, because the family has a clear service layer but is tightly coupled to identity/bootstrap and includes mutations
    • notifications/email, appeals/drafts/finalisation, and representations/drafts/finalisation all cross workflow/orchestration boundaries and should not use the same façade pattern without a different design
    • storage/blob/file operations, auth/session, and admin/reporting should currently be left unchanged because they are either integration-owned, platform-critical, already coherent enough, or low-value for another façade layer
  • Updated the adoption roadmap with a workflow-boundary checkpoint stating that the current additive façade pattern now has a natural stop point and should not simply continue into orchestration-heavy families.

Validation:

  • Documentation-only validation.
  • Representative inspection only; no full route inventory, no implementation work, and no service/route changes performed.
  • Intended lightweight validation for this slice:
    • git diff --check

Follow-ups:

  • Primary next planning recommendation:
    • workflow/orchestration design assessment
  • Secondary fallback only if another implementation slice is explicitly desired:
    • one narrow account read-support cautious façade slice

CL-2026-06-25-API-GROUPING-FACADE-MYPORTAL-READS-VERTICAL-SLICE: bounded myportal dashboard CRM read/enrichment grouping and service adoption

date: 2026-06-25 author: Cline scope: pages/api/myportal/get-my-cases.js, pages/api/myportal/get-my-lpa-cases.js, pages/api/myportal/get-portal-module-details.js, actions/services/portalDirectService.js, actions/services/caseDirectService.js, tests/phase22/api-grouping-facade-myportal-reads.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Implement the next additive API grouping façade vertical slice for the bounded My Portal dashboard read / enrichment journey by grouping only the proven active CRM read/enrichment routes under pages/api/myportal/ and adopting those grouped routes in the existing owning service layers without changing dashboard storage, auth, watched-case, submission, or account behaviour. impact: Runtime behaviour is intended to remain unchanged; grouped myportal façade routes now cover the proven active dashboard CRM read/enrichment family, legacy endpoint handlers remain canonical, watched-case behaviour remains owned by subscriptions, and no route migration, deletion, contract change, CRM query change, auth/session change, storage/draft change, or submission/orchestration change has occurred. status: completed

Summary:

  • Confirmed the required context was read before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Performed a bounded audit of the active My Portal dashboard read / enrichment journey across the dashboard loader, service layers, and endpoint usage.
  • Audit findings established that:
    • the active entry page is pages/myportal/index.js
    • the active owning service layers for the proven CRM read/enrichment path are:
      • actions/services/portalDirectService.js for getMyCases / getMyLPACases
      • actions/services/caseDirectService.js for getPortalModuleDetails
    • the active CRM-backed dashboard path is:
      • getMyCases(loggedInUser) or getMyLPACases(lpaId)
      • detail-card enrichment fan-out through getPortalModuleDetails(collectionName, caseID)
    • watched cases are already handled by the earlier subscriptions façade slice and were left alone
    • representation and awaiting-submission data on the active dashboard loader are blob-backed in the current path via:
      • getRepsFromBlob(thisSession.user.id)
      • getAwaitingSubmissionFromBlob(thisSession.user.id)
    • getmyrepresentations_api.js and getawaitingsubmission_api.js were investigated but were not proven active in the bounded dashboard loader path for this slice
    • account/auth/bootstrap routes (getPortalLogin, getPersonalAccount, getSession) remain upstream support concerns and out of scope
  • Added grouped façade routes under pages/api/myportal/ for the proven active CRM dashboard family only:
    • get-my-cases.js
    • get-my-lpa-cases.js
    • get-portal-module-details.js
  • Implemented each façade as the smallest safe compatibility wrapper:
    • import the existing legacy endpoint handler
    • delegate req and res directly to that existing handler
  • Updated only the existing owning service call sites needed for the bounded slice:
    • actions/services/portalDirectService.js
      • getMyCases
      • getMyLPACases
    • actions/services/caseDirectService.js
      • getPortalModuleDetails
  • Left the following unchanged:
    • legacy endpoint handlers
    • watched-case grouped subscriptions routes
    • representation routes
    • awaiting-submission routes
    • storage/blob routes
    • account/profile routes
    • auth/session behaviour
    • CRM queries and transforms
    • query parameter names and response contracts
  • Added focused characterization coverage to prove:
    • grouped myportal façade routes delegate correctly
    • legacy endpoint handlers remain present
    • adopted service methods now target grouped myportal routes
    • adopted methods no longer target the legacy endpoint URLs directly
    • request-contract cues remain unchanged
    • excluded route families remain outside this slice
  • Updated the adoption roadmap to record the audited scope boundary, included routes, excluded routes, service adoption status, and behaviour-preservation notes for the My Portal dashboard read / enrichment slice.

Validation:

  • Focused validation only intended for this slice:
    • npx eslint actions/services/portalDirectService.js actions/services/caseDirectService.js pages/api/myportal/*.js tests/phase22/api-grouping-facade-myportal-reads.test.cjs
    • node tests/phase22/api-grouping-facade-myportal-reads.test.cjs
  • No repository-wide validation run.

Follow-ups:

  • The bounded My Portal dashboard read / enrichment family is now a complete façade grouping slice only for the proven active CRM dashboard read/enrichment routes adopted here.
  • Adjacent subscriptions, storage/draft, representation, awaiting-submission, and account/auth support routes remain intentionally outside this slice and should only be considered in separate bounded audits if needed.

CL-2026-06-25-API-GROUPING-FACADE-CASE-DETAILS-VERTICAL-SLICE: bounded case-details read grouping and service adoption

date: 2026-06-25 author: Cline scope: pages/api/cases/get-incident-by-id.js, pages/api/cases/get-case-message.js, pages/api/cases/get-linked-cases.js, pages/api/cases/get-sips-events.js, pages/api/cases/get-sips-media.js, actions/services/caseDirectService.js, actions/services/searchDirectService.js, tests/phase22/api-grouping-facade-case-details.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Implement the next additive API grouping façade vertical slice for the bounded Case Details read journey by grouping only the proven case-specific read family under pages/api/cases/ and adopting those grouped routes in the existing owning service layers without changing bootstrap/search/documents behavior. impact: Runtime behaviour is intended to remain unchanged; grouped cases façade routes now cover the proven incident-id, case-message, linked-cases, and SIPS enrichment reads, legacy endpoint handlers remain canonical, and no route migration, deletion, contract change, document behaviour change, search behaviour change, auth change, storage change, or submission/orchestration change has occurred. status: completed

Summary:

  • Confirmed the required context was read before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Performed a bounded audit of the active Case Details read journey across pages, components, services, and endpoint usage.
  • Audit findings established that:
    • pages/case/[ticketnumber].js and pages/myportal/case/[ticketnumber].js still bootstrap primarily through the Public Search family using getBasicSearch(...) and getSearchDetails(...)
    • pages/case/id/[incident].js and pages/myportal/case/id/[incident].js actively use the case-specific incident-id read route through getIncidentbyID(...)
    • getCaseMessage(...) is actively used in case-page loading for banner/message content
    • getLinkedCases(...) is actively used inside components/case/summary.js as a case-details read concern
    • getSIPSEvents(...) and getSIPSMedia(...) are active case-page enrichments for relevant SIPS cases
    • components/case/documents.js and document metadata routes remain part of the documents slice, not this case-details slice
    • getcase_api.js, getcasebyid_api.js, and getportalmoduledetails_api.js are adjacent/support reads but were not proven to belong to the bounded active case-page read path for this slice
  • Added grouped façade routes under pages/api/cases/ for the proven case-specific read family only:
    • get-incident-by-id.js
    • get-case-message.js
    • get-linked-cases.js
    • get-sips-events.js
    • get-sips-media.js
  • Implemented each façade as the smallest safe compatibility wrapper:
    • import the existing legacy endpoint handler
    • delegate req and res directly to that existing handler
  • Updated only the existing owning service call sites needed for the bounded slice:
    • actions/services/caseDirectService.js
      • getIncidentbyID
      • getCaseMessage
      • getSIPSEvents
      • getSIPSMedia
    • actions/services/searchDirectService.js
      • getLinkedCases
  • Left the following unchanged:
    • legacy endpoint handlers
    • search bootstrap routes and search detail expansion routes
    • document metadata/download routes
    • CRM queries
    • transforms
    • query parameter names
    • response contracts
    • status codes
    • auth/session behavior
    • storage/queue/submission behavior
  • Added focused characterization coverage to prove:
    • grouped cases façade routes delegate correctly
    • legacy endpoint handlers remain present
    • adopted service methods now target grouped cases routes
    • request-contract cues remain unchanged
    • adjacent search/documents/support routes remain outside grouped adoption scope
  • Updated the adoption roadmap to record the audited scope boundary, included routes, excluded routes, service adoption status, and behaviour-preservation notes for the Case Details read slice.

Validation:

  • Focused validation only intended for this slice:
    • npx eslint pages/api/cases/*.js actions/services/caseDirectService.js actions/services/searchDirectService.js tests/phase22/api-grouping-facade-case-details.test.cjs context/api-grouping-adoption-roadmap.md memory-bank/change-log.md
    • node tests/phase22/api-grouping-facade-case-details.test.cjs
  • No repository-wide validation run.

Follow-ups:

  • The bounded Case Details read family is now a complete façade grouping slice only for the proven case-specific read routes adopted here.
  • Adjacent case bootstrap, document, and myportal aggregation/detail-enrichment routes should remain separate future slices if needed.

CL-2026-06-25-API-GROUPING-FACADE-SEARCH-VERTICAL-SLICE: active public search results grouping and service adoption

CL-2026-06-25-API-GROUPING-FACADE-ROLLOUT-CHECKPOINT: proven rollout pattern and guardrails checkpoint

date: 2026-06-25 author: Cline scope: context/api-grouping-adoption-roadmap.md, tests/phase22/api-grouping-facade-rollout.test.cjs, memory-bank/change-log.md type: milestone rationale: Record a short checkpoint after the first successful additive API grouping façade slices so the proven rollout pattern, completion criteria, and delay/guardrail criteria are documented before considering more complex API groups. impact: Documentation and characterization only; no runtime behaviour, handler implementation, service URL, route location, payload, contract, auth/session behaviour, or integration behaviour change. status: completed

Summary:

  • Confirmed the required checkpoint context was read before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
    • existing façade tests under tests/phase22
  • Confirmed the proven slice pattern now established by the completed façade areas:
    • pages/api/subscriptions/*
    • pages/api/documents/*
    • pages/api/search/*
  • Recorded the rollout checkpoint in the adoption roadmap with the proven shape:
    • UI journey
    • existing service layer
    • grouped façade route
    • legacy canonical handler
    • unchanged integration behaviour
  • Documented completion criteria for a vertical façade slice, including:
    • bounded active-journey audit
    • grouped façade coverage for in-scope active routes only
    • safe service-layer adoption
    • retained canonical legacy handlers
    • explicit out-of-scope treatment for inactive/support routes
    • characterization proof and scope documentation
  • Documented “do not group yet” criteria for cases such as:
    • unclear ownership
    • missing clear service layer
    • orchestration-heavy routes
    • storage + queue + CRM crossing routes
    • auth/session-critical routes
    • unproven activity
    • required frontend refactor
    • required contract change
  • Added a lightweight meta-test to characterize the checkpoint structure without introducing a larger framework.

Validation:

  • Focused validation only for this checkpoint:
    • npx eslint tests/phase22/api-grouping-facade-rollout.test.cjs
    • node tests/phase22/api-grouping-facade-rollout.test.cjs
    • node tests/phase22/api-grouping-facade-subscriptions.test.cjs
    • node tests/phase22/api-grouping-facade-documents.test.cjs
    • node tests/phase22/api-grouping-facade-search.test.cjs
  • No heavy repo-wide tooling run.

Follow-ups:

  • Use this checkpoint as the baseline before considering any further façade candidates.
  • Prefer the next candidate only where the same additive pattern can be proven without route movement, contract change, or orchestration-risk expansion.

CL-2026-06-25-API-GROUPING-FACADE-SEARCH-VERTICAL-SLICE: active public search results grouping and service adoption

date: 2026-06-25 author: Cline scope: pages/api/search/basic-paged.js, pages/api/search/advanced.js, pages/api/search/advanced-paged.js, pages/api/search/basic-details-paged.js, actions/services/searchDirectService.js, tests/phase22/api-grouping-facade-search.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Implement the next additive API grouping façade vertical slice by grouping the active Public Search results journey under pages/api/search/ and adopting the grouped routes only in the existing common public-search service layer, while preserving legacy endpoint handlers unchanged and leaving adjacent/excluded search journeys alone. impact: Runtime behaviour is intended to remain unchanged; grouped search façade routes now cover the proven active public-results path, actions/services/searchDirectService.js now targets those grouped routes for the bounded in-scope calls, legacy endpoint handlers remain canonical, and no migration, route deletion, query-parameter change, paging change, sorting change, payload change, or response-contract change has occurred. status: completed

Summary:

  • Confirmed the required context was read before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Performed a bounded audit of the active Public Search journey across pages, components, services, and endpoint usage.
  • Audit findings established that:
    • the active public results UI is driven through pages/searchresults.js and components/search/searchresults.js
    • the advanced results page pages/advancedsearchresults.js is part of the active public-search scope
    • the common owning service layer is actions/services/searchDirectService.js
    • components/search/searchresults.js actively uses:
      • getBasicSearchPaged
      • getAdvancedSearchPaged
      • getSearchDetailsPaged(...), which in turn uses getBasicSearchDetailsPaged
    • pages/advancedsearchresults.js actively uses getAdvancedSearch(...) for bootstrap
    • getbasicsearch_api.js and getbasicsearchdetails_api.js remain active in adjacent case-detail/bootstrap paths and therefore remained out of scope for this bounded public-results slice
    • address-search routes, DNS routes, and myportal search pages were intentionally excluded as separate journeys
  • Added grouped façade routes under pages/api/search/ for the proven active public-results path only:
    • basic-paged.js
    • advanced.js
    • advanced-paged.js
    • basic-details-paged.js
  • Implemented each façade as the smallest safe compatibility wrapper:
    • import the existing legacy endpoint handler
    • delegate req and res directly to that existing handler
  • Updated only the suitable common service layer in actions/services/searchDirectService.js to target grouped façade routes for:
    • getBasicSearchPaged
    • getAdvancedSearch
    • getAdvancedSearchPaged
    • getBasicSearchDetailsPaged
  • Left the following unchanged:
    • existing endpoint handlers
    • query parameter names
    • CRM queries
    • paging behaviour
    • sorting behaviour
    • search semantics
    • case-detail behaviour
    • document behaviour
    • excluded search journeys
  • Added focused characterization coverage to prove:
    • grouped search façade routes delegate correctly
    • active service methods now target grouped search routes
    • legacy endpoint handlers remain present
    • adopted service methods no longer target the legacy endpoint URLs directly
    • request-contract strings/parameter names remain unchanged
    • excluded routes remain outside grouped adoption scope
  • Updated the adoption roadmap to record the active Public Search grouping slice and its exact scope boundary.

Validation:

  • Focused validation only intended for this slice:
    • npx eslint actions/services/searchDirectService.js pages/api/search/*.js tests/phase22/api-grouping-facade-search.test.cjs
    • node tests/phase22/api-grouping-facade-search.test.cjs
  • No repository-wide validation run.

Follow-ups:

  • The active Public Search journey is now a complete vertical grouping slice for the bounded public-results scope:
    • grouped façade routes
    • active service-layer adoption
    • legacy canonical handlers retained
    • unchanged behaviour
  • Adjacent or excluded search journeys should remain separate future slices if needed:
    • case-detail bootstrap search
    • address search
    • DNS search
    • myportal search

CL-2026-06-25-API-GROUPING-FACADE-DOCUMENTS-VERTICAL-SLICE: active published-document metadata grouping and service adoption

date: 2026-06-25 author: Cline scope: pages/api/documents/get-search-document-details.js, pages/api/documents/get-search-document-details-paged.js, pages/api/documents/get-search-document-types.js, actions/services/searchDirectService.js, tests/phase22/api-grouping-facade-documents.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Implement the second additive API grouping façade vertical slice by grouping the active published-document metadata journey under pages/api/documents/ and adopting the grouped routes only in the existing common document metadata service layer, while preserving the existing download route and legacy endpoint handlers unchanged. impact: Runtime behaviour is intended to remain unchanged; grouped document façade routes now cover the active metadata/type journey calls, actions/services/searchDirectService.js now targets those grouped routes, legacy endpoint handlers remain canonical, the existing grouped download route remains unchanged, and no migration, route deletion, auth change, CRM query change, hash-link generation change, payload change, or response-contract change has occurred. status: completed

Summary:

  • Confirmed the required context was read before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Performed a bounded audit of the active published-documents journey across services, API handlers, and frontend components.
  • Audit findings established that:
    • active document metadata retrieval is surfaced through components/case/documents.js
    • active document metadata/type calls already route through the common service layer actions/services/searchDirectService.js
    • published-document downloads already use the grouped runtime route pages/api/documents/download/[id].js
    • legacy metadata handlers generate pinswg_hashlink values that continue to point at the unchanged grouped download route
    • getsearchdocumenthistory_api.js and getsearchdocumenthistorypaged_api.js remain present but were not surfaced in the currently active UI journey and therefore remained outside grouped adoption scope
  • Added grouped façade routes under pages/api/documents/ for the active metadata journey only:
    • get-search-document-details.js
    • get-search-document-details-paged.js
    • get-search-document-types.js
  • Implemented each façade as the smallest safe compatibility wrapper:
    • import the existing legacy endpoint handler
    • delegate req and res directly to that existing handler
  • Updated only the suitable common service layer in actions/services/searchDirectService.js to target grouped façade routes for:
    • getSearchDocumentDetails
    • getSearchDocumentDetailsPaged
    • getSearchDocumentTypes
  • Left the following unchanged:
    • CRM queries
    • download behaviour
    • hash-link generation
    • authentication
    • response contracts
    • payloads
    • file locations of legacy handlers
  • Added focused characterization coverage to prove:
    • grouped document façade routes delegate correctly
    • active document service methods now target grouped document routes
    • legacy document endpoint handlers remain present
    • active service-layer query-contract cues remain unchanged
    • the runtime download path remains /api/documents/download/[id]
  • Updated the adoption roadmap to record the active documents grouping slice and its bounded scope.

Validation:

  • Focused validation only intended for this slice:
    • npx eslint actions/services/searchDirectService.js pages/api/documents/get-search-document-details.js pages/api/documents/get-search-document-details-paged.js pages/api/documents/get-search-document-types.js tests/phase22/api-grouping-facade-documents.test.cjs context/api-grouping-adoption-roadmap.md memory-bank/change-log.md
    • node tests/phase22/api-grouping-facade-documents.test.cjs
  • No repository-wide validation run.

Follow-ups:

  • The active Documents journey is now a complete vertical grouping slice for the bounded published-document metadata/type path:
    • grouped façade routes
    • active service-layer adoption
    • legacy canonical handlers retained
    • unchanged grouped download path
    • unchanged behaviour
  • Any future expansion beyond this bounded scope should be a separate slice, for example if history/support routes are later proven to be part of an actively adopted user journey.

CL-2026-06-25-API-GROUPING-FACADE-SUBSCRIPTIONS-VERTICAL-SLICE-COMPLETION: watched-case proxy read adoption and scope closure

date: 2026-06-25 author: Cline scope: pages/api/subscriptions/get-watched-cases-proxy.js, actions/services/portalDirectService.js, tests/phase22/api-grouping-facade-subscriptions.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Complete the intended subscriptions/watched-cases vertical slice by covering the active proxy read path still used by the normal watched-case UI journey, while keeping legacy endpoint and proxy handlers in place as canonical/support implementation routes. impact: Runtime behaviour is intended to remain unchanged; the grouped subscriptions façade now covers the active watched-case journey service methods including proxy reads, while legacy handlers remain canonical and no route deletion, migration, auth/session change, CRM query change, payload change, or status-code change has occurred. status: completed

Summary:

  • Performed a bounded watched-case usage audit across services, pages, and components.
  • Audit findings established that:
    • no frontend components directly call legacy watched-case endpoint URLs
    • normal watched-case journey calls are routed through actions/services/portalDirectService.js
    • getWatchedCasesProxy() is actively used in the current watched-case UI journey
    • deletewatchedcasesproxy_api remains present but is not part of the currently adopted normal watched-case service path
  • Added grouped façade route:
    • pages/api/subscriptions/get-watched-cases-proxy.js
    • delegates directly to pages/api/endpoint/getwatchedcasesproxy_api.js
  • Updated actions/services/portalDirectService.js so getWatchedCasesProxy now targets:
    • /api/subscriptions/get-watched-cases-proxy
  • Extended the existing subscriptions façade characterization test to prove:
    • grouped proxy façade delegation works
    • legacy proxy handler remains present
    • watched-case service methods now target grouped subscriptions routes for both normal and proxy watched-case reads
    • adopted methods no longer target the legacy watched-case endpoint URLs directly
    • delete proxy remains outside grouped pilot scope and legacy support route remains present
  • Updated the adoption roadmap to define what “complete vertical slice” means for this pilot and to record the proxy-scope boundary.

Validation:

  • Focused validation only:
    • npx eslint actions/services/portalDirectService.js tests/phase22/api-grouping-facade-subscriptions.test.cjs pages/api/subscriptions/get-watched-cases.js pages/api/subscriptions/get-watched-cases-proxy.js pages/api/subscriptions/create-watched-case.js pages/api/subscriptions/delete-watched-case.js
    • node tests/phase22/api-grouping-facade-subscriptions.test.cjs
  • No repository-wide test suite run.

Follow-ups:

  • For the intended watched-case/subscriptions scope, the pilot now forms a complete vertical slice:
    • subscriptions journey
    • service layer
    • grouped façade routes
    • legacy canonical endpoint handlers
    • unchanged behaviour
  • Any future expansion beyond this scope should be a separate bounded slice (for example, deciding whether legacy/support proxy delete routes also need grouped façade coverage).

CL-2026-06-25-API-GROUPING-FACADE-SUBSCRIPTIONS-INTERNAL-ADOPTION: first internal consumer targets grouped watched-case routes

date: 2026-06-25 author: Cline scope: actions/services/portalDirectService.js, tests/phase22/api-grouping-facade-subscriptions.test.cjs, context/api-grouping-adoption-roadmap.md type: change rationale: Validate the subscriptions façade pilot through one carefully selected internal consumer by updating watched-case service methods in portalDirectService to call the new grouped subscriptions routes while leaving the legacy endpoint handlers unchanged and canonical behind the façade. impact: Runtime behaviour is intended to remain unchanged because the grouped routes still delegate to the existing watched-case handlers; validates incremental internal adoption without route migration, deprecation, auth/session change, CRM query change, payload change, or signed-request behaviour change. status: completed

Summary:

  • Re-read required continuation context before implementation:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • memory-bank/change-log.md
  • Updated only the watched-case methods in actions/services/portalDirectService.js to target grouped façade routes:
    • getWatchedCases -> /api/subscriptions/get-watched-cases
    • createWatchedCases -> /api/subscriptions/create-watched-case
    • deleteWatchedCases -> /api/subscriptions/delete-watched-case
  • Did not modify any other service methods in portalDirectService.js.
  • Did not modify underlying watched-case endpoint handlers or façade handler delegation.
  • Extended the existing façade characterization test to prove:
    • grouped façade delegation still works
    • legacy endpoint handler files remain present
    • the internal service layer now targets /api/subscriptions/...
    • the adopted watched-case methods no longer point at legacy /api/endpoint/... routes
    • key service-layer request-contract cues remain present (loggedInUserId, watchedCaseID, POST method)
  • Updated the adoption roadmap to record:
    • first internal consumer adoption has occurred
    • legacy routes remain canonical implementations
    • no migration or deprecation has occurred
    • this validates incremental adoption of grouped journey-owned routes

Validation:

  • Focused validation only:
    • npx eslint actions/services/portalDirectService.js tests/phase22/api-grouping-facade-subscriptions.test.cjs context/api-grouping-adoption-roadmap.md memory-bank/change-log.md
    • node tests/phase22/api-grouping-facade-subscriptions.test.cjs
  • No repository-wide test suite run.

Follow-ups:

  • The subscriptions façade pattern has now been validated through both additive route introduction and one successful internal service adoption.
  • Any further adoption should continue incrementally and only with the same behaviour-preserving characterization discipline.

CL-2026-06-25-API-GROUPING-FACADE-PILOT-SUBSCRIPTIONS: additive watched-case subscriptions façade routes

date: 2026-06-25 author: Cline scope: pages/api/subscriptions/*, watched-case API façade pilot, focused characterization tests, and grouping-plan/adoption-roadmap documentation type: change rationale: Implement the first additive API grouping façade pilot by adding journey-owned subscriptions wrapper routes for watched-case read/create/delete operations that delegate to the existing canonical endpoint handlers without changing current frontend call sites, contracts, or behaviour. impact: Runtime impact is intentionally additive only; existing watched-case endpoint routes remain canonical/stable; no auth/session, CRM query, hash/signing, payload, status-code, i18n, or frontend-callsite behaviour change intended; documentation now records the pilot and its non-migration status. status: completed

Summary:

  • Confirmed required implementation context was read before changes:
    • context/api-grouping-plan.md
    • context/api-grouping-adoption-roadmap.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Added the first grouped façade routes under pages/api/subscriptions/:
    • get-watched-cases.js
    • create-watched-case.js
    • delete-watched-case.js
  • Implemented each façade as the smallest safe compatibility wrapper:
    • import the existing watched-case endpoint handler
    • delegate req and res directly to that existing handler
  • Preserved the existing canonical watched-case routes unchanged:
    • pages/api/endpoint/getwatchedcases_api.js
    • pages/api/endpoint/createwatchedcases_api.js
    • pages/api/endpoint/deletewatchedcases_api.js
  • Did not change frontend call sites; actions/services/portalDirectService.js continues to call the legacy endpoint routes.
  • Added a focused characterization test file to prove:
    • grouped façade route files exist and delegate to the expected legacy handlers
    • legacy endpoint files still exist
    • frontend watched-case service call sites were not migrated to /api/subscriptions/
  • Updated the API grouping plan and adoption roadmap to record:
    • this is the first additive grouping façade pilot
    • existing watched-case endpoint routes remain canonical/stable
    • new subscriptions routes are grouped façade routes
    • no old route removal or migration has occurred

Validation:

  • Focused implementation only; no broad refactor performed.
  • Characterization coverage added for façade delegation and unchanged frontend call sites.
  • Intended validation set for this slice:
    • npx eslint pages/api/subscriptions/*.js tests/phase22/api-grouping-facade-subscriptions.test.cjs
    • node tests/phase22/api-grouping-facade-subscriptions.test.cjs
  • Existing watched-case endpoint files were preserved in place.

Follow-ups:

  • If the pilot is accepted, use the same additive façade pattern for future journey-owned grouping candidates only where behaviour preservation can be equally well characterized.

CL-2026-06-25-API-GROUPING-ADOPTION-ROADMAP: gradual adoption roadmap for future journey-owned API grouping

date: 2026-06-25 author: Cline scope: context/api-grouping-adoption-roadmap.md, architecture roadmap for gradual adoption of future API grouping concepts type: milestone rationale: Create a planning-only roadmap document describing how PEDW could gradually adopt the future journey-owned API grouping model over time through documentation guidance, additive consistency, and future-development discipline rather than migration or restructuring. impact: Documentation/context only; improves architecture planning clarity for gradual API grouping adoption, maintainability direction, and future decision support; no runtime, auth, CRM, storage, queue, notification, i18n, contract, or behaviour change. status: completed

Summary:

  • Confirmed the required roadmap context was read before drafting:
    • context/api-grouping-plan.md
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Added new document: context/api-grouping-adoption-roadmap.md.
  • Kept the roadmap explicitly scoped to architecture planning only.
  • Recorded the core adoption philosophy that PEDW should favour:
    • gradual evolution
    • behaviour preservation
    • contract preservation
    • incremental consistency
    • reuse of shared helpers over large restructures, wholesale moves, rewrites, or mass renaming.
  • Added a staged roadmap covering:
    • Stage 1 — Current state
    • Stage 2 — Future development guidance
    • Stage 3 — Documentation maturity
    • Stage 4 — Future opportunities
  • Added concise adoption principles emphasising:
    • preserve stable APIs
    • preserve contracts and integrations
    • prefer additive improvements
    • improve findability first
    • avoid unnecessary churn
    • never move APIs solely for cosmetic reasons
  • Added a future-development decision matrix covering:
    • new APIs
    • existing stable APIs
    • existing APIs being enhanced
    • shared/platform concerns
    • cross-cutting concerns
    • orchestration-heavy routes
  • Added qualitative success measures focused on maintainability outcomes rather than implementation metrics.
  • Added explicit non-goals including:
    • no migrations
    • no implementation
    • no route movement
    • no route renaming
    • no API deletion
    • no consolidation
    • no contract changes
    • no behaviour changes
  • Recommended the next architecture planning document only:
    • context/api-maintainer-guidance-v2.md

Validation:

  • Documentation-only planning work; no runtime code changed.
  • Non-destructive synthesis only:
    • reused the completed architecture programme as the evidence base
    • reused the newly completed API grouping plan rather than reopening discovery
    • remained at architecture-roadmap level and did not widen into implementation or migration guidance
  • Did not perform another API inventory.
  • Did not recommend implementation, migration, refactor, or route moves.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next architecture planning document only:
    • context/api-maintainer-guidance-v2.md

CL-2026-06-25-API-GROUPING-PLAN-PHASE-1: future journey-owned API grouping model

date: 2026-06-25 author: Cline scope: context/api-grouping-plan.md, architecture planning for future journey-owned API grouping concepts type: milestone rationale: Create a planning-only architecture document that synthesises the completed API platform, route map, journey map, integration map, and architecture findings into a future journey-owned API grouping model focused on maintainability, findability, consistency, and extensibility without reopening discovery or recommending implementation. impact: Documentation/context only; improves future architecture planning clarity around journey-owned API grouping, shared platform concerns, and API-family classification; no runtime, auth, CRM, storage, queue, notification, i18n, contract, or behaviour change. status: completed

Summary:

  • Confirmed the required planning context was read before drafting:
    • context/api-route-map.md
    • context/journey-architecture-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Added new document: context/api-grouping-plan.md.
  • Kept the document explicitly scoped to architecture planning only.
  • Recorded the key evidence-base finding that the main API maintenance problem is:
    • findability
    • ownership clarity
    • consistency
    • reuse discipline
  • Assessed the proposed future grouping concepts only as documentation guidance:
    • account/
    • admin/
    • appeals/
    • auth/
    • cases/
    • documents/
    • notifications/
    • platform/
    • representations/
    • search/
    • subscriptions/
    • shared/
  • For each proposed group, documented:
    • purpose
    • primary journeys supported
    • typical integrations
    • typical route types
    • representative existing routes
    • shared components used
    • relationship to other groups
    • migration cautions
  • Added a Shared Platform Components section classifying reusable helpers such as:
    • relay helpers
    • response helpers
    • hash helpers
    • signed request helpers
    • Azure Storage helpers
    • auth/session helpers
    • Notify helpers
    • logging helpers
    • validation helpers
  • Added a Journey-to-Group Mapping section working at journey/API-family level only and classifying areas as:
    • Natural fit
    • Likely fit
    • Shared / Platform concern
    • Cross-cutting concern
    • Leave unchanged for now
  • Added future guidance principles and explicit non-goals, including:
    • no implementation
    • no migrations
    • no folder restructuring
    • no route movement
    • no route renaming
    • no API deletions
    • no API consolidation
    • no behaviour change
    • no contract change
  • Recommended the next architecture planning document only:
    • context/api-rationalisation-planning.md

Validation:

  • Documentation-only planning work; no runtime code changed.
  • Non-destructive evidence gathering and synthesis only:
    • read required context files
    • targeted extraction from existing route/journey/platform architecture documents
    • top-level pages/api listing only to compare current shape with future grouping concepts without producing a new API inventory
  • Did not reopen architectural discovery.
  • Did not perform a new route inventory.
  • Did not recommend implementation, refactor, migration, or route moves.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next architecture planning document only:
    • context/api-rationalisation-planning.md

date: 2026-06-22 author: Cline scope: context/journey-architecture-map.md, case messages/notices and related published case communications architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting how public case-level notices are loaded and rendered on case pages, how adjacent published communication content such as SIPS events/media participates in the case-detail experience, and how the relevant routes classify under a future grouping view without proposing implementation changes. impact: Documentation/context only; improves maintainer understanding of the case-message retrieval path, the case-page notice rendering model, the split ownership between message props and event/media Redux state, and the boundary between on-page case communications, document delivery, and outbound notifications; no runtime, CRM, relay, auth, storage, notification, or i18n behaviour change. status: completed

Summary:

  • Confirmed the required Slice 8 context was read before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 8 covering:
    • Case Messages / Notices
    • Related Published Case Communications
    • Case Communication Architecture
    • Future API Grouping Assessment
    • Messages vs Documents vs Notifications Comparison
  • Documented, for each communication journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flow
    • change entry set
    • risk classification
  • Recorded the clearest visible notice/message model as:
    • case loader retrieves getCaseMessage(incidentid)
    • messagesObj is passed as page props
    • CaseNoticeBanner renders active banner-style notices on the case-details tab
  • Recorded the clearest visible adjacent published communication model as:
    • SIPS-only conditional event/media fetches
    • Redux eventDetailsObj / mediaDetailsObj
    • live-event banner plus events/media tab presentation in the case summary layer
  • Added the requested future grouping classification for relevant case communication routes using:
    • current location
    • journey owner
    • integration touched
    • future grouping candidate
    • migration caution
  • Added the requested comparison showing:
    • where case messages/notices overlap with published documents and notifications
    • where they differ
    • which one is case-page presentation
    • which one is document delivery
    • which one is outbound communication

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, components/case, actions/services, store, and pages/api/endpoint
    • direct review of public/DNS/myportal case loaders, components/case/summary.js, components/case/caseNoticeBanner.js, actions/services/caseDirectService.js, getcasemessage_api.js, and directly relevant SIPS event/media routes
  • Did not widen into notification email delivery or document download behaviour beyond the requested comparison.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Case Status / Lifecycle Presentation and Related Published Timeline Signals

CL-2026-06-22-JOURNEY-ARCHITECTURE-MAP-SLICE-7: published-document-discovery and download lifecycle map

date: 2026-06-22 author: Cline scope: context/journey-architecture-map.md, published document discovery and published document retrieval/download architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting how published documents are surfaced on case pages, how published-document metadata is retrieved and shaped, how download links are generated, how the dedicated download proxy delivers files, and how the relevant routes classify under a future grouping view without proposing implementation changes or reopening authorization assessment. impact: Documentation/context only; improves maintainer understanding of the case-document discovery path, the metadata-to-hashlink-to-download-proxy handoff, document-history route visibility boundaries, and journey ownership across the document route family; no runtime, CRM, relay, auth, storage, notification, or i18n behaviour change. status: completed

Summary:

  • Confirmed the required Slice 7 context was read before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 7 covering:
    • Published Document Discovery
    • Published Document Retrieval / Download
    • Document Delivery Architecture
    • Future API Grouping Assessment
    • Discovery vs Download Comparison
  • Documented, for each document journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flow
    • change entry set
    • risk classification
  • Recorded the clearest visible discovery model as:
    • search-to-case navigation
    • case documents component bootstrap
    • relay-backed CRM metadata retrieval
    • Redux documentDetailsObj
    • filtered/sorted/paged document presentation
  • Recorded the clearest visible delivery model as:
    • metadata-generated pinswg_hashlink
    • browser fetch of /api/documents/download/[id]?hash=...
    • dedicated download proxy stream
    • browser blob download
  • Recorded that document history routes are present in the document route family but were not visibly surfaced by the reviewed case-document UI path.
  • Added the requested future grouping classification for relevant document routes using:
    • current location
    • journey owner
    • integration touched
    • future grouping candidate
    • migration caution
  • Added the requested comparison showing:
    • shared APIs
    • shared integrations
    • shared ownership assumptions
    • where discovery and download diverge

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, components, actions/services, store, and pages/api
    • direct review of case detail entry, case documents UI, search navigation handoff, document metadata routes, document type route, document history routes, and the dedicated download proxy route
  • Did not reopen authorization or security posture assessment.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Case Messages / Notices and Related Published Case Communications

CL-2026-06-21-JOURNEY-ARCHITECTURE-MAP-SLICE-6: watchlist-subscriptions and unsubscribe-watchlist-removal lifecycle map

date: 2026-06-21 author: Cline scope: context/journey-architecture-map.md, watchlist/subscriptions and unsubscribe/watchlist-removal architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting watched-case creation, viewing, removal, unsubscribe paths, the visible CRM contact↔watched-case relationship model, and future grouping candidates for watched-case APIs without proposing implementation changes or reopening the completed authorization assessment. impact: Documentation/context only; improves maintainer understanding of the CRM watched-case relationship lifecycle, dashboard/search/case watch-state reuse, email-notification participation on watched-case records, and watched-case API ownership boundaries; no runtime, auth, CRM, Notify, storage, or i18n behaviour change. status: completed

Summary:

  • Confirmed the required Slice 6 context was read before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/portal-api-security-boundary-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 6 covering:
    • Watchlist Creation
    • Watchlist Viewing
    • Watchlist Removal
    • CRM Relationship Ownership Model
    • Future API Grouping Assessment
    • Watchlist vs Dashboard Comparison
  • Documented, for each watched-case journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flow
    • change entry set
    • risk classification
  • Recorded the strongest visible CRM relationship model as:
    • CRM Contact ↔ Watched Case
    • represented through pinswg_watchlists
    • with visible fields including watched-case id, contact id, case id, appeal type, and pinswg_emailnotifications
  • Recorded that email-notification participation is visibly expressed on the watched-case relationship record itself rather than through a separate subscription entity in the reviewed frontend code.
  • Added the requested future grouping classification for watched-case routes using:
    • journey ownership
    • integration touched
    • future grouping candidate
    • migration caution
  • Added the requested comparison with My Portal Dashboard, documenting shared dependencies, shared state, shared APIs, and ownership relationship without proposing changes.

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, components, actions/services, store, and pages/api
    • direct review of watched-case portal bootstrap pages, search/case watch-action components, dashboard/view-all watched-case components, watched-case routes, unsubscribe pages, and watched-case Redux ownership files
  • Did not reopen exploitability or security posture assessment.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Documents / Published Document Retrieval and Download

CL-2026-06-21-JOURNEY-ARCHITECTURE-MAP-SLICE-5: authentication-sign-in and notifications-email lifecycle map

date: 2026-06-21 author: Cline scope: context/journey-architecture-map.md, authentication/sign-in and notifications/email architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting authentication/sign-in and notifications/email as cross-cutting journeys, including future grouping classification for auth/email-related APIs and an explicit auth-vs-notification comparison, without reopening the completed authorization assessment or proposing implementation changes. impact: Documentation/context only; improves maintainer understanding of NextAuth-to-CRM bootstrap continuity, locale-aware sign-in behaviour, Notify usage across auth and business notifications, and journey ownership/grouping boundaries for auth/email routes; no runtime, auth, CRM, Notify, storage, or i18n behaviour change. status: completed

Summary:

  • Confirmed the required Slice 5 context was read before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 5 covering:
    • Authentication / Sign-In
    • Notifications / Email
    • Ownership / Identity Model
    • Future API Grouping Assessment
    • Auth vs Notification Comparison
  • Documented, for each auth/email journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership / identity model
    • architectural flow
    • change entry set
    • risk classification
  • Recorded the strongest visible sign-in continuity model as:
    • sign-in page locale resolution
    • NextAuth verification + callback
    • session creation
    • homepage bootstrap
    • getPortalLogin(session.user.email)
    • /myportal or /account/register
  • Recorded the strongest visible notifications model as split between:
    • thin direct Notify sends via pages/api/email/notify.js
    • orchestration-heavy aggregation/batch sends via pages/api/email/getall.js and supporting data routes
  • Added the requested future grouping classification for auth/email-related routes using:
    • current location
    • journey ownership
    • integration touched
    • future grouping candidate
    • migration caution
  • Added the requested comparison showing:
    • where auth and notifications are independent
    • where they overlap
    • where Notify acts as auth-support integration
    • where Notify acts as business-notification integration
  • Kept the grouping and comparison sections explicitly framed as documentation/discovery only and not implementation recommendations.

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, components, actions/services, lib, and pages/api
    • direct review of sign-in pages, verify-request page, homepage bootstrap, logout helpers, NextAuth handler, locale resolution route, email routes, Notify service helpers, and completion/watchlist notification callers
  • Did not reopen the completed authorization risk/security assessment.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Watchlist / Subscriptions and Unsubscribe Flows

CL-2026-06-21-JOURNEY-ARCHITECTURE-MAP-SLICE-4: account registration and personal-details/account-management lifecycle map

date: 2026-06-21 author: Cline scope: context/journey-architecture-map.md, account registration and personal-details/account-management architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting account registration and personal-details/account-management journeys, and by classifying relevant APIs against a future journey-based grouping model without proposing implementation changes. impact: Documentation/context only; improves maintainer understanding of the NextAuth-session-to-CRM-contact bootstrap model, account journey ownership, and future grouping candidates for account/auth/shared/platform-level APIs; no runtime, auth, storage, CRM, or i18n behaviour change. status: completed

Summary:

  • Re-read required Slice 4 context before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 4 covering:
    • Account Registration
    • Personal Details / Account Management
    • Ownership Model
    • Future API Grouping Assessment
  • Documented, for each account journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flows
    • change entry sets
    • risk classification
  • Recorded how the journeys strengthen the identity model:
    • registration bridges NextAuth session.user.email -> CRM Contact
    • account management depends on that bridge and reuses CRM contact identity for account reads/updates
  • Added a future grouping classification for relevant account/auth routes using:
    • journey owner
    • integration touched
    • future grouping candidate
    • migration caution
  • Kept the grouping section explicitly framed as a future grouping assessment only and not an implementation recommendation.

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, components/account, actions/services, pages/api, and store
    • direct review of homepage bootstrap, registration page/components, personal-details page/components, account service helpers, account endpoint handlers, and relevant auth support routes
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Authentication / Sign-In and Notifications / Email

CL-2026-06-21-JOURNEY-ARCHITECTURE-MAP-SLICE-3: draft representation and representation submission/finalisation lifecycle map

date: 2026-06-21 author: Cline scope: context/journey-architecture-map.md, representation draft creation and representation submission/finalisation architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting the representation draft lifecycle and the representation submission/finalisation lifecycle, including an explicit comparison against the already documented appeal lifecycle, without proposing implementation changes. impact: Documentation/context only; improves maintainer understanding of representation storage ownership, queue handoff, CRM representation boundaries, and appeal-vs-representation lifecycle differences; no runtime, auth, storage, queue, CRM, or i18n behaviour change. status: completed

Summary:

  • Re-read required Slice 3 context before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 3 covering:
    • Draft Representation Creation
    • Representation Submission / Finalisation
    • Appeal vs Representation Lifecycle Comparison
  • Documented, for each representation journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flows
    • change entry sets
    • risk classification
  • Added the requested comparison across:
    • ownership
    • storage
    • queue
    • CRM
    • maintainability
  • Recorded the main visible distinction from appeals as:
    • representation drafts are more tightly case-linked and repfile_name-keyed
    • representation completion concentrates more client-side side effects around involvement, queue handoff, email, and watched/submitted status updates

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, lib, actions/services, pages/api, and store
    • direct review of representation loaders, representation completion component, storage routes, queue/completion routes, and representation-specific Redux state
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Account Registration and Personal Details / Account Management

CL-2026-06-21-JOURNEY-ARCHITECTURE-MAP-SLICE-2: draft appeal and appeal submission/finalisation lifecycle map

date: 2026-06-21 author: Cline scope: context/journey-architecture-map.md, draft appeal creation and appeal submission/finalisation architecture documentation type: milestone rationale: Extend the Journey Architecture Map with the next bounded maintainability slice by documenting the draft appeal lifecycle and the appeal submission/finalisation lifecycle from page entry through state, services, APIs, storage, queue, and CRM transition without proposing implementation changes. impact: Documentation/context only; improves maintainer understanding of draft ownership, storage container boundaries, queue handoff, and submitted-appeal transition; no runtime, auth, storage, queue, CRM, or i18n behaviour change. status: completed

Summary:

  • Re-read required Slice 2 context before investigation:
    • context/journey-architecture-map.md
    • context/api-route-map.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Extended context/journey-architecture-map.md with Slice 2 covering:
    • Draft Appeal Creation
    • Appeal Submission / Finalisation
  • Documented, for each journey:
    • purpose
    • primary entry points
    • loaders / initialisation
    • state ownership
    • service layer
    • API layer
    • integration boundaries
    • ownership model
    • architectural flows
    • change entry sets
    • risk classification
  • Recorded the strongest visible draft ownership model as:
    • NextAuth session.user.id -> containerID -> Azure Storage container -> casefolder / draft blob state
  • Recorded the clearest visible submitted-appeal transition as:
    • draft blob state
    • finalisation route
    • Azure Queue message
    • adjacent CRM mutation boundary
  • Added Slice 2-specific investigation method, risks/cautions, validation summary, and a documentation-only recommendation for the next journey slice.

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted searches across pages, lib, components/newappeal, actions/services, actions, pages/api, and store
    • direct review of draft/resume loaders, Redux hydration helpers, new appeal flow components, storage helpers, finalisation handlers, and adjacent CRM mutation routes
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded documentation slice only:
    • Representation Draft Creation and Representation Submission / Finalisation

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-A: API family classification sample

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, sampled API families under pages/api/{endpoint,file,email,documents,auth} type: milestone rationale: Record the first bounded slice of the Portal Integration Contract & API Platform Assessment by classifying representative API families, integration responsibilities, repeated patterns, duplication candidates, and contract-critical areas without widening into a full inventory. impact: Documentation/context only; improves visibility of the portal API platform shape and integration-family boundaries; no runtime, contract, auth, storage, email, or i18n behaviour change. status: completed

Summary:

  • Added context/portal-api-platform-assessment.md.
  • Confirmed the required context files were read before starting the slice:
    • context/architecture.md
    • context/portal-api-security-boundary-assessment.md
    • context/integration-map.md
    • memory-bank/debt-list.md
    • memory-bank/change-log.md
  • Assessed only the requested first slice folders:
    • pages/api/endpoint
    • pages/api/file
    • pages/api/email
    • pages/api/documents
    • pages/api/auth
  • Used a representative bounded sample to classify the visible API platform families into:
    • CRM relay read
    • CRM relay write
    • storage/blob read
    • storage/blob write
    • queue/finalisation
    • email/notification
    • document download
    • auth/session
    • local utility/meta
    • middleware/helper
  • Recorded the integration responsibility map from the sample, showing a mix of:
    • CRM relay-backed
    • Azure Storage SDK-backed
    • GOV.UK Notify-backed
    • NextAuth-backed
    • local-only
    • mixed/orchestration routes
  • Identified repeated sample patterns including:
    • hash validation
    • helper-based relay forwarding
    • required query/body validation
    • respondSuccess / respondError response envelopes
    • raw CRM URL construction in older handlers
    • Azure blob path construction
    • mixed logging styles
  • Marked only high-level duplication candidates from the sample, distinguishing likely intentional vs likely historical vs unclear families without recommending consolidation yet.
  • Identified contract-critical sampled families including public search, myportal/dashboard, submission/finalisation, file upload/download, document download, auth/session, and email/notification.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Non-destructive evidence gathering only:
    • small directory listings of sampled API folders and pages/api/middleware
    • direct file inspection of representative sample handlers
    • targeted grep/search limited to sampled folders for relay helper usage, hash usage, axios/direct integration usage, Notify usage, and auth/locale/redirect patterns
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded slice: Slice B — Endpoint CRM Relay Shape Sample, restricted to a representative subset of pages/api/endpoint to distinguish newer helper-based relay routes from older direct relay wrappers and to classify main endpoint contract shapes without proposing implementation.

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-B: endpoint CRM relay contract shape sample

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, representative pages/api/endpoint route sample type: milestone rationale: Record the second bounded slice of the Portal Integration Contract & API Platform Assessment by classifying endpoint contract shapes inside pages/api/endpoint, comparing helper-oriented read contracts with older direct-wrapper mutation contracts, and assessing contract consistency without widening into a full endpoint inventory. impact: Documentation/context only; improves visibility of endpoint contract structure, implementation-style split, and maintainability shape in the CRM relay layer; no runtime, auth, storage, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required Slice B context before inspection:
    • context/portal-api-platform-assessment.md
    • context/portal-api-security-boundary-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Assessed only a bounded representative subset inside pages/api/endpoint across the requested route groups:
    • public read/search
    • authenticated/myportal read
    • CRM create
    • CRM update/patch/delete
    • proxy/pass-through
  • Classified the sampled endpoint layer into a small number of recurring contract shapes:
    • public CRM read
    • user-owned CRM read
    • CRM create
    • CRM patch/update
    • CRM delete
    • proxy/pass-through
    • lookup/config/support
    • hybrid upsert/orchestration
  • Recorded the strongest visible implementation split in pages/api/endpoint:
    • newer helper-oriented read routes using relayGet(...), shared response helpers, transforms, and relay policy presets
    • older direct-wrapper mutation routes using getToken(), axios(config), WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), and manual CRM method configuration
  • Recorded that response envelope style is more consistent than integration implementation style:
    • respondError(...) / respondSuccess(...) are broadly used across both newer and older route styles
  • Recorded that paged/search/document read routes repeatedly use transform/pagination sub-patterns:
    • transformData
    • @odata.nextLink normalization
    • custom request headers for paged reads
  • Concluded that the endpoint/ route count likely overstates uniqueness, because the sampled evidence suggests relatively few repeated contract shapes rather than many fully bespoke contracts.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Non-destructive evidence gathering only:
    • direct inspection of representative endpoint routes including:
      • getbasicsearch_api.js
      • getbasicsearchpaged_api.js
      • getadvancedsearch_api.js
      • getsearchdocumentdetails_api.js
      • getsearchdocumenthistory_api.js
      • getmycases_api.js
      • getmyrepresentations_api.js
      • getwatchedcases_api.js
      • getawaitingsubmission_api.js
      • getpersonalaccount_api.js
      • createcase_api.js
      • createaccount_api.js
      • createwatchedcases_api.js
      • updateaccount_api.js
      • patchcase_api.js
      • deletewatchedcases_api.js
      • deletemyrepresentations_api.js
      • getwatchedcasesproxy_api.js
    • targeted endpoint-only searches for helper/direct-wrapper indicators:
      • relayGet(...)
      • relayGetData(...)
      • axios(...)
      • hashAPIPath(...)
      • respondSuccess(...) / respondError(...)
      • transformData
      • @odata.nextLink
      • common status-code patterns
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded slice: Slice C — Endpoint Transform and Pagination Pattern Sample, restricted to representative pages/api/endpoint routes that use transforms, @odata.nextLink normalization, paged/unpaged variants, and supplementary relayGetData(...) enrichment so the transform/pagination sub-patterns can be classified without proposing implementation.

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-C: API maintenance map and reuse baseline

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, top-level pages/api maintenance structure and existing reuse primitives type: milestone rationale: Record the third bounded slice of the Portal Integration Contract & API Platform Assessment by mapping current folder responsibility, feature-to-API maintenance entry points, folder drift, reusable building blocks, and a future-facing consistency baseline without proposing implementation or file movement. impact: Documentation/context only; improves API findability and maintainability guidance for future work planning; no runtime, auth, storage, email, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required Slice C context before inspection:
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/debt-list.md
    • memory-bank/change-log.md
  • Built a bounded maintenance map for the top-level API areas:
    • endpoint
    • file
    • email
    • documents
    • auth
    • admin
    • middleware
    • top-level utility/meta files
  • Recorded that current API maintenance difficulty is driven primarily by:
    • folder responsibility overlap
    • historical naming drift
    • split document/account/auth-support behaviors across multiple areas
    • coexistence of older direct-wrapper and newer shared-helper implementation styles
  • Added a feature-to-API maintenance map covering major portal areas including:
    • search
    • case details
    • document download
    • my portal/dashboard
    • watched cases
    • representations
    • drafts
    • submission/finalisation
    • account/auth
    • email/notifications
    • admin/internal reporting
  • Identified reusable building blocks already present, including:
    • relayGet(...)
    • relayGetData(...)
    • respondSuccess(...) / respondError(...)
    • relay policy presets
    • signed request client helpers
    • hash/path validation helpers
    • Azure storage helpers
    • logging helpers
  • Added a future-facing consistency baseline as guidance only, emphasizing reuse of existing shared helpers for new work where suitable and avoiding blind copying of stable but older direct axios + hashAPIPath patterns.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Non-destructive evidence gathering only:
    • small top-level listings of pages/api and pages/api/admin
    • direct representative inspection of:
      • pages/api/admin/getnewappeals_api.js
      • pages/api/admin/getlatestdocuments_api.js
      • pages/api/health.js
      • pages/api/doc.ts
      • pages/api/notices/index.js
      • pages/api/middleware/{apiResponse,relayForwarding,relayPolicyPresets,middleware}.js
      • actions/azurestorage.js
      • actions/clients/signedRequestClient.js
    • targeted searches across pages/api for existing helper and integration-building-block usage
    • reuse of already completed bounded evidence from Slices A and B for folder/feature classification
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded step: Slice D — API Route Ownership & Change-Entry Sample, focused on a small set of high-value journeys (watched cases, account/personal details, public document retrieval, appeal submission/finalisation) to identify the minimum safe API entry set a maintainer would need to inspect for future changes.

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-D: route ownership and change-entry sample

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, bounded journey change-entry mapping across watched cases, account/personal details, public document retrieval, and appeal submission/finalisation type: milestone rationale: Record the fourth bounded slice of the Portal Integration Contract & API Platform Assessment by identifying maintainer-first change-entry sets, route ownership, change risk, first-look checklists, and reuse points for four high-value journeys without widening into a full dependency inventory. impact: Documentation/context only; improves maintainability and change-entry clarity for future API work; no runtime, auth, storage, queue, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required Slice D context before inspection:
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Assessed only the requested four journeys:
    • watched cases
    • account / personal details
    • public document retrieval
    • appeal submission / finalisation
  • Built maintainer-first change-entry sets for each journey, covering:
    • primary UI/component entry points
    • likely service helpers
    • API routes
    • shared clients/helpers
    • relevant state/store modules
    • integrations touched
  • Classified route ownership for sampled journey routes using:
    • feature-owned
    • integration-owned
    • orchestration-owned
    • helper/support
    • ambiguous/historical
  • Recorded journey-level change risk:
    • watched cases -> high
    • account/personal details -> high
    • public document retrieval -> medium-high
    • appeal submission/finalisation -> very high
  • Added short first-look checklists so a maintainer can identify the minimum safe inspection set before changing behavior in each sampled journey.
  • Identified reuse points already present for each journey, including relay helpers, response helpers, signing/hash helpers, Azure storage helpers, and logging helpers.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Non-destructive evidence gathering only:
    • targeted bounded searches across components, actions/services, pages, lib, and store for the four sampled journeys
    • direct representative inspection of:
      • components/myportal/viewall.js
      • pages/account/personaldetails.js
      • components/account/personaldetails.js
      • components/search/searchresults.js
      • lib/myportal/loadMyPortalAppealPage.js
      • components/case/representation/representationComplete.js
    • reuse of already reviewed route/service evidence from prior slices for linked API ownership and helper classification
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded step: Slice E — API Maintainer Decision Guide Sample, focused on a small sample of maintenance intents (for example: adding a CRM read route, extending a watched-case mutation, adding a document-related route, or extending a finalisation orchestration path) so preferred reusable patterns can be distinguished from older compatibility-driven ones without proposing implementation.

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-E: wider API surface pattern validation

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, top-level API surface validation across wider route families and implementation styles type: milestone rationale: Record the fifth bounded slice of the Portal Integration Contract & API Platform Assessment by validating whether the route-family, contract-shape, implementation-style, and folder-drift conclusions from earlier representative slices generalise across the wider API surface without generating a full endpoint inventory. impact: Documentation/context only; increases confidence that the architecture model is representative of the wider API platform; no runtime, auth, storage, queue, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required Slice E context before inspection:
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Performed bounded top-level API folder sizing and validation:
    • endpoint -> 74 files
    • file -> 26 files
    • email -> 6 files
    • documents -> 1 file
    • auth -> 2 files
    • admin -> 5 files
    • middleware -> 4 files
    • top-level files -> 4
  • Confirmed that the earlier API platform model still appears representative:
    • endpoint remains the dominant historical CRM relay catch-all
    • file remains the main secondary mixed storage/orchestration folder
    • smaller folders (email, documents, auth, admin, middleware) did not reveal a materially new route family or implementation style
  • Validated that the existing route-family model still covers the wider surface, including:
    • search/read
    • myportal reads
    • account/profile
    • create/update/delete
    • document retrieval
    • storage/blob
    • queue/finalisation
    • notifications
    • admin/reporting
    • auth/session
    • lookup/config/support
  • Confirmed that no genuinely new major contract shape was needed beyond the existing set:
    • Public CRM read
    • User-owned CRM read
    • CRM create
    • CRM update/patch
    • CRM delete
    • Proxy/pass-through
    • Lookup/config/support
    • Hybrid upsert/orchestration
  • Confirmed that the implementation-style model still holds across the wider surface:
    • helper-oriented relay routes
    • direct-wrapper routes
    • orchestration routes
    • with local/static support routes treated as small support variants, not a separate major style
  • Classified folder drift:
    • low drift: documents, admin, middleware, top-level utility routes
    • low-to-moderate drift: auth
    • moderate drift: email
    • high drift: endpoint, file
  • Identified main maintenance hotspots:
    • high: endpoint, file
    • medium-high: auth, middleware
    • medium: email
    • low/medium-low: documents, admin
  • Recorded a high-confidence conclusion that Slices AD are representative at the platform pattern level, even though route-local nuance still exists.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Non-destructive evidence gathering only:
    • bounded top-level API folder-size count pass
    • targeted route-name searches across pages/api, pages/api/endpoint, and pages/api/file
    • direct representative inspection of selected wider-surface outlier routes:
      • pages/api/endpoint/getmandatoryfields_api.js
      • pages/api/endpoint/createcrmtask_api.js
      • pages/api/file/createcaseinvolvement_api.js
      • pages/api/file/generateappealpdf.js
      • pages/api/email/getdocuments.js
      • pages/api/admin/getStatusCountsByAppealAndLPA_api.js
    • comparison against the documented conclusions from Slices AD
  • No full route inventory generated.
  • No repo-wide automated analysis performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next bounded step: Slice F — API Platform Final Synthesis, consolidating Slices AE into one stable architecture-level API platform view covering route families, contract shapes, implementation styles, folder drift, maintainer guidance, and final assessment conclusions without proposing implementation.

CL-2026-06-20-PORTAL-API-PLATFORM-ASSESSMENT-SLICE-F: final synthesis and stream closure

date: 2026-06-20 author: Cline scope: context/portal-api-platform-assessment.md, context/architecture.md, API platform assessment stream closure type: milestone rationale: Consolidate Slices AE into one concise architecture-level API platform view, record the stable route-family / contract-shape / implementation-style model, and formally close the Portal Integration Contract & API Platform Assessment stream. impact: Documentation/context only; improves long-term maintainability guidance and architectural clarity for future API planning work; no runtime, auth, storage, queue, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required Slice F context before synthesis:
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • memory-bank/change-log.md
  • Added a final synthesis section to context/portal-api-platform-assessment.md and marked the stream complete.
  • Recorded the stable architecture-level API platform model as:
    • large route surface
    • small route-family vocabulary
    • small contract-shape vocabulary
    • small implementation-style vocabulary
  • Consolidated the stable route-family model:
    • CRM relay routes
    • storage/blob routes
    • finalisation/orchestration routes
    • email/notification routes
    • document download routes
    • auth/session routes
    • admin/internal routes
    • middleware/helper routes
    • local utility/meta routes
  • Consolidated the stable contract-shape model:
    • Public CRM read
    • User-owned CRM read
    • CRM create
    • CRM update/patch
    • CRM delete
    • Proxy/pass-through
    • Lookup/config/support
    • Hybrid upsert/orchestration
    • Storage read/write/delete
    • Queue/finalisation
    • Notify send / notification orchestration
  • Consolidated the stable implementation-style model:
    • newer helper-oriented
    • older direct-wrapper
    • orchestration-heavy
  • Recorded the stable folder-drift and maintenance-hotspot model:
    • highest drift/hotspots remain endpoint and file
    • smaller folders are more coherent but still require sensitivity in auth and middleware
  • Added a maintainer guidance baseline emphasizing:
    • identify owning feature/journey first
    • identify integration touched
    • identify contract-criticality
    • prefer existing shared helpers where suitable
    • avoid blindly copying older direct-wrapper patterns into new work
    • avoid refactoring stable legacy routes without explicit approval and characterization
  • Updated context/architecture.md so the core architecture reference now includes the completed Portal API Platform Assessment and its stable final model.
  • Formally recorded that the Portal Integration Contract & API Platform Assessment should now be considered complete.

Validation:

  • Documentation-only synthesis and closure; no runtime code changed.
  • Non-destructive evidence base reused from completed Slices AE.
  • No new route inventory or automated analysis performed for closure.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Recommended future planning stream only:
    • API Route Map / Maintainer Guide
    • or API Rationalisation Planning
  • No implementation work is recommended from this assessment alone.

CL-2026-06-20-API-ROUTE-MAP-MAINTAINER-GUIDE: first-generation journey-owned route map

date: 2026-06-20 author: Cline scope: context/api-route-map.md, maintainability-focused journey-owned API documentation type: milestone rationale: Create a first-generation maintainer guide that converts the completed API platform assessment into a journey-owned route map so future contributors can identify where to start, which APIs/helpers matter, what integrations are touched, and where change risk is highest without reopening discovery. impact: Documentation/context only; improves API maintainability, findability, and ownership clarity for future planning and change review; no runtime, auth, storage, queue, i18n, or API behaviour change. status: completed

Summary:

  • Re-read required context before drafting the route map:
    • context/portal-api-platform-assessment.md
    • context/architecture.md
    • context/integration-map.md
    • memory-bank/change-log.md
  • Added new document: context/api-route-map.md.
  • Structured the guide around journey ownership, not folder ownership.
  • Documented the requested major journey catalogue, including:
    • Public Search
    • Case Details
    • Documents
    • My Portal Dashboard
    • Watched Cases
    • Representations
    • Draft Appeals
    • Draft Representations
    • Appeal Submission / Finalisation
    • Representation Submission / Finalisation
    • Account Registration
    • Personal Details / Account Management
    • Authentication / Sign-In
    • Notifications / Email
    • Admin / Reporting
  • For each journey, recorded:
    • purpose
    • primary UI entry points
    • service layer helpers
    • primary API routes a maintainer should inspect first
    • integrations touched
    • ownership type
    • change risk
    • first-look checklist
  • Added a shared platform section documenting reusable API building blocks such as:
    • relayGet
    • relayGetData
    • respondSuccess
    • respondError
    • relay policy helpers
    • hash helpers
    • signed request helpers
    • Azure storage helpers
    • Notify helpers
    • auth/session helpers
  • Added maintainer guidance describing the recommended decision sequence when adding a new API:
    • which journey owns it
    • which integration it touches
    • whether an existing route family exists
    • whether existing helpers can be reused
    • whether the route is contract-critical
  • Recorded that the resulting document is sufficient as a first-generation maintainer guide and that any future expansion should be treated as a separate planning/documentation stream rather than renewed platform discovery.

Validation:

  • Documentation-only work; no runtime code changed.
  • Non-destructive consolidation based on completed architecture streams and existing API platform conclusions.
  • No new discovery or route inventory performed.
  • No Python used.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Optional future documentation stream only:
    • deeper API Route Map / Maintainer Guide v2
    • or API Rationalisation Planning
  • No implementation work recommended from this guide alone.

CL-2026-06-19-ARCHITECTURE-PROGRAMME-MILESTONE: discovery close-out and transition to adoption planning

date: 2026-06-19 author: Architecture Review scope: architecture programme type: milestone rationale: Record the conclusion of the architectural discovery programme and the transition into the next architecture phase. impact: Documentation/context only; improves programme clarity, handoff readiness, and next-stream prioritisation; no runtime or implementation behaviour change. status: completed

Summary:

Architectural discovery programme concluded.

Final classifications established:

  • Business Decision Models
  • Presentation Models
  • CRM Compatibility Models
  • Workflow / Integration Models

Recommendation:

Transition architecture effort from discovery to adoption planning and API security assessment.

Validation:

  • Documentation-only update.
  • No implementation files changed.
  • No tests or lint run because this was a documentation-only milestone entry.

Follow-ups:

  • Use Portal API Security & Access Boundary Assessment as the recommended next architecture stream.

CL-2026-06-19-PORTAL-API-SECURITY-FIRST-PASS: endpoint inventory and access-boundary assessment

date: 2026-06-19 author: Cline scope: pages/api/**, context/portal-api-security-boundary-assessment.md type: milestone rationale: Record the first-pass architecture assessment of the portal API security and access boundary, focusing on endpoint inventory, authentication visibility, trust boundaries, and ownership enforcement evidence. impact: Documentation/context only; improves visibility of API security posture and next-step prioritisation; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Added context/portal-api-security-boundary-assessment.md as a concise first-pass assessment of pages/api/**.
  • Recorded a route-family inventory across auth, endpoint, file, email, documents, admin, and utility API areas.
  • Identified the main current architectural concern:
    • route-level authentication and ownership enforcement are not consistently visible in sensitive handlers
    • many routes trust caller-supplied identifiers such as loggedInUserId, contactId, incidentId, blob/container/path values, and record IDs
    • file/blob routes rely heavily on signed hash validation, but that is not equivalent to explicit per-route ownership verification
  • Recorded that the only explicit session gate found during the first-pass scan was pages/api/endpoint/gethash_api.js, which protects hash issuance for a narrow allowlist of sensitive downstream paths.
  • Prioritised the next pass as end-to-end tracing of authenticated hash issuance and downstream consumption in sensitive file/blob and user-owned CRM routes.

Validation:

  • Documentation-only assessment; no runtime code changed.
  • Read required architecture and memory-bank context files before assessment.
  • Non-destructive inventory and evidence commands used:
    • recursive listing of pages/api/**
    • route-family count command across pages/api
    • targeted code searches for session/auth usage and trusted identifiers
    • direct review of representative high-risk handlers in auth, file, email, documents, middleware, and endpoint families
  • Lint/tests not run because no implementation files were changed.

Follow-ups:

  • Next assessment pass: trace gethash_api consumers and determine whether sensitive downstream routes are effectively session-bound and ownership-bound, or only path-hash protected.

CL-2026-06-19-PORTAL-API-OWNERSHIP-TRACE: session-to-contact and ownership-enforcement trace

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, portal SSR loaders, account/portal/document service flows, selected user-owned API handlers type: milestone rationale: Record the ownership-enforcement trace for the Portal API Security & Access Boundary Assessment by identifying how the authenticated session becomes portal identity, CRM contact identity, blob/container identity, and user-owned API access. impact: Documentation/context only; clarifies current authorization architecture and ownership-enforcement locations; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended context/portal-api-security-boundary-assessment.md with an ownership-enforcement trace focused on:
    • session -> email -> portal user -> CRM contact flow
    • split identity model between CRM contact ownership and blob/container ownership
    • the role of pinsUser cookie as a CRM-contact shortcut in some SSR flows
    • location mapping for where ownership is established vs merely propagated
  • Documented that ownership enforcement is not primarily route-local in sampled APIs.
  • Recorded the dominant pattern as:
    • SSR/page loaders establish identity from session and/or cookie
    • service helpers propagate that identity into API calls
    • CRM ownership is often expressed as query filtering by contact ID
    • blob ownership is often expressed as container scoping by session.user.id
  • Traced high-risk flows end-to-end:
    • My Cases
    • My Representations
    • Watched Cases
    • Draft Appeals
    • Draft Representations
    • Document Retrieval
  • Concluded that ownership enforcement is partially centralized at session/bootstrap time but operationally distributed across SSR loaders, cookies, query construction, CRM filtering, and blob container naming.

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct code review of:
    • lib/auth/resolveMyPortalAuthContext.js
    • lib/representation/pageLoaders.js
    • lib/newappeal/loadNewAppealPage.js
    • lib/myportal/loadMyPortalAppealPage.js
    • pages/myportal/index.js
    • pages/myportal/case/[ticketnumber].js
    • pages/myportal/representation.js
    • actions/services/{accountDirectService,portalDirectService,documentDirectService}.js
    • pages/api/endpoint/createwatchedcases_api.js
    • previously reviewed user-owned API handlers from the first-pass assessment
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: trace the provenance and lifecycle of the pinsUser cookie and compare it against the getPortalLogin(session.user.email) path to determine which identity source is canonical and where divergence risk exists.

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, pinsUser cookie lifecycle, SSR loaders, homepage/login routing, account/search/myportal flows type: milestone rationale: Record the architectural role of pinsUser by tracing where it is created, refreshed, cleared, and consumed, and by comparing it to the canonical session-to-CRM-contact identity path. impact: Documentation/context only; clarifies current identity and trust-boundary model; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended the assessment with a dedicated pinsUser trace covering:
    • cookie contents
    • creation source
    • overwrite/refresh behavior
    • clear/delete paths
    • consumption across SSR and client flows
  • Determined that pinsUser stores a CRM contactid value.
  • Identified the primary creation path in pages/index.js:
    • NextAuth session -> session.user.email -> getPortalLogin(email) -> CRM contactid -> setCookie("pinsUser", contactid)
  • Identified that later flows frequently consume pinsUser directly without re-resolving CRM contact from the current session.
  • Recorded the architectural conclusion that pinsUser behaves as:
    • a cached CRM contact identity
    • a convenience shortcut
    • and likely a compatibility mechanism in cookie-driven flows rather than the canonical business authorization authority.
  • Confirmed that CRM Contact remains the strongest visible business authorization boundary for CRM-owned portal data, while session.user.id remains the visible ownership boundary for blob/draft flows.

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct review of:
    • pages/index.js
    • pages/account/personaldetails.js
    • components/search/searchresults.js
    • components/search/addresssearchresults.js
    • lib/auth/sessionClient.js
    • lib/auth/resolveMyPortalAuthContext.js
    • lib/newappeal/loadNewAppealPage.js
    • lib/myportal/loadMyPortalAppealPage.js
    • pages/error.js
    • pages/_error.js
    • pages/components search results for pinsUser, setCookie, destroyCookie, and parseCookies
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: trace registration and post-registration bootstrap to determine exactly how a NextAuth-authenticated user becomes a CRM Contact and where dashboard authorization is granted after contact creation.

CL-2026-06-19-PORTAL-API-ACCOUNT-MUTATION-TRACE: account/profile read and mutation boundary assessment

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, account/profile pages, account direct services, account endpoint handlers type: milestone rationale: Record the account/profile mutation assessment by tracing how account pages establish identity, how personal details are read and updated, whether email can diverge from session identity, and whether account/password APIs re-bind caller-supplied contact IDs to the authenticated session. impact: Documentation/context only; clarifies account/profile authorization posture and legacy-route risk; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended context/portal-api-security-boundary-assessment.md with a dedicated account/profile mutation trace.
  • Documented that normal account entry is session-gated at page level, but account identity is typically established earlier during dashboard SSR bootstrap:
    • getSession(ctx)
    • getPortalLogin(session.user.email)
    • CRM contactid
    • getPersonalAccount(contactid)
    • Redux loggedinUserId / accountDetails
  • Recorded that the live personal-details flow reads and mutates CRM contacts using a Redux-held loggedinUserId, then passes that ID into:
    • /api/endpoint/getpersonalaccount_api?contactid=...
    • /api/endpoint/updateaccount_api?contactId=...
  • Confirmed that sampled account read/write routes do not visibly:
    • resolve current session server-side
    • resolve CRM contact from session.user.email
    • compare caller-supplied contactId/contactid to a session-derived CRM contact
  • Confirmed that the reviewed personal-details UI does not allow direct email editing because emailaddress1 is rendered disabled, but also recorded that updateaccount_api.js forwards request bodies to CRM without a visible field allowlist or email/session reconciliation step.
  • Confirmed that the live change-password UI does not use updatepassword_api.js; it writes pinswg_custom_password through updateaccount_api.js, making the standalone password route appear exposed but likely legacy/inconsistent with passwordless NextAuth.
  • Concluded that account/profile mutation is strongest at session/bootstrap derivation time but weaker at the final API route boundary, where caller-supplied contact IDs are trusted.

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct review of:
    • pages/account/personaldetails.js
    • pages/account/changepassword.js
    • components/account/{personaldetails,personaldetailsCheck,personaldetailsComplete,changepassword}.js
    • components/myportal/youraccount.js
    • pages/index.js
    • pages/myportal/index.js
    • actions/services/accountDirectService.js
    • pages/api/endpoint/{getpersonalaccount_api,updateaccount_api,updatepassword_api,getemailaccountcheck_api,getportallogin_api}.js
    • store/accountDetails/{action,reducer}.js
  • Additional targeted searches performed for setLoggedInUserId, setAccountDetails, updatePassword, pinswg_custom_password, and updatepassword_api usage.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: trace other user-owned CRM mutation routes to determine whether the caller-supplied contact-ID trust pattern repeats across watchlists, involvements, representations, and case mutation endpoints.

CL-2026-06-19-PORTAL-API-USER-OWNED-MUTATION-SURFACE-TRACE: systemic caller-ID trust across watchlists, cases, involvements, and representations

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, watchlist/case/involvement/representation mutation routes, related service helpers, and completion/finalisation flows type: milestone rationale: Extend the security boundary assessment beyond account/profile routes to determine whether caller-supplied CRM identity and record-ID trust is isolated or systemic across other user-owned CRM mutation families. impact: Documentation/context only; clarifies systemic authorization-boundary posture for user-owned CRM mutations; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended context/portal-api-security-boundary-assessment.md with a dedicated user-owned CRM mutation route trace covering:
    • watchlist create/update and delete
    • case/appeal create, update, and patch
    • case and representation involvement creation
    • representation delete and completion/finalisation side effects
    • blob-side draft helper variants where relevant
  • Added a mutation-route inventory table recording, for each route:
    • purpose
    • primary callers/helpers
    • accepted identifiers
    • CRM entity affected
    • whether the route reads session
    • whether it resolves CRM contact from session.user.email
    • whether it trusts caller-supplied contact/record identifiers
    • whether it performs visible ownership checks before mutation
    • a classification label
  • Confirmed the account/profile pattern is not isolated:
    • contact-ID-bound caller trust appears in watchlist upsert, case creation, case involvement creation, and representation involvement creation
    • record-ID-bound mutation without visible ownership proof appears in watchlist delete, representation delete, case update, and case patch routes
  • Recorded that some flows perform duplicate/existence checks or CRM filtering using supplied IDs, but these checks do not amount to independent user-ownership verification.
  • Concluded that the current mutation authorization model is distributed and upstream-heavy:
    • session-to-contact derivation commonly happens in SSR/UI/bootstrap layers
    • service helpers propagate those identifiers
    • final mutation routes frequently trust supplied IDs directly rather than re-binding them to the authenticated session

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct review of:
    • pages/api/endpoint/{createwatchedcases_api,deletewatchedcases_api,createcase_api,updatecase_api,patchcase_api,deletemyrepresentations_api}.js
    • pages/api/file/{createcaseinvolvement_api,createrepinvolvement_api,createappealcompletemessage_api,createrepcompletemessage_api,createcase_api,updatecase_api}.js
    • actions/services/{portalDirectService,caseDirectService}.js
    • components/{case/summary,myportal/viewall,newappeal/createCase,newappeal/buildsection,case/representation/representationComplete}.js
    • lib/newappeal/journeyEffects.js
  • Additional targeted searches performed across pages/api, actions/services, components, and lib for mutation helpers and identifier propagation (contactid, contactId, loggedInUserId, watchedCaseID, myRepresentationsID, incidentid, mutation helper names).
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: trace gethash_api and signed-route consumption together to determine whether signed hash issuance materially strengthens mutation authorization boundaries or remains an integrity-only control layered on top of caller-supplied identity trust.

CL-2026-06-19-PORTAL-API-HASH-WATCHLIST-DELETE-VERTICAL-SLICE: request integrity vs referential ownership verification

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, gethash_api, signing helpers, watchlist delete route, and watched-case delete UI/service flow type: milestone rationale: Perform a focused vertical-slice assessment of signed hash issuance and watchlist deletion to determine whether the hash mechanism materially strengthens the mutation boundary beyond request/identifier integrity. impact: Documentation/context only; clarifies what the signed-hash model does and does not visibly protect; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended context/portal-api-security-boundary-assessment.md with a dedicated vertical-slice trace for:
    • pages/api/endpoint/gethash_api.js
    • client signing helpers (relayClient, signedRequestClient)
    • watchlist delete service + UI flows
    • pages/api/endpoint/deletewatchedcases_api.js
  • Recorded the visible hash issuance model as:
    • authenticated session required to obtain a hash
    • allowlisted route-prefix check in gethash_api
    • hash generated from the full raw query path (hashAPIPath(rawQueryPath))
    • signed URL built client-side as queryUrl + hash
  • Recorded that in the watchlist delete flow, the signed query path includes watchedCaseID, so the hash visibly protects:
    • route integrity
    • query/parameter integrity
    • identifier integrity for watchedCaseID
  • Recorded that the reviewed code does not visibly show hash issuance encoding CRM ownership or object authorization state.
  • Traced watchlist deletion end-to-end and concluded that, in the reviewed flow:
    • watchedCaseID originates from previously loaded watchlist data in normal portal UI flows
    • delete route performs direct CRM delete by record ID
    • no route-local referential ownership verification was visible before delete
  • Classified the current watchlist delete design as provenance-based rather than relationship-verified.

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via direct review of:
    • pages/api/endpoint/gethash_api.js
    • actions/clients/relayClient.js
    • actions/clients/signedRequestClient.js
    • actions/services/portalDirectService.js
    • pages/api/endpoint/deletewatchedcases_api.js
    • components/myportal/topthree.js
    • components/myportal/viewall.js
    • components/case/summary.js
    • components/search/searchresults.js
  • Additional targeted searches performed for gethash_api, buildHashedQueryUrl, buildSignedUrl, deleteWatchedCases, watchedCaseID, and pinswg_watchlistid across actions, components, and pages/api.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: perform the same integrity-vs-authorization vertical slice for deletemyrepresentations_api and one blob/container mutation route to compare whether the provenance-based signed-request model is consistent across CRM-record and blob/file deletion paths.

CL-2026-06-19-PORTAL-API-DRAFT-STORAGE-OWNERSHIP-ASSESSMENT: session user ID to container boundary

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, draft appeal/representation loaders, storage service helpers, Azure storage helpers, and file/blob draft APIs type: milestone rationale: Assess the draft-storage ownership boundary by tracing how session.user.id becomes container identity, how draft data/files are created/read/deleted/submitted, and whether storage operations remain container-scoped through the queue handoff to CRM creation. impact: Documentation/context only; clarifies pre-submission storage ownership architecture and the storage-to-CRM ownership transition; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended context/portal-api-security-boundary-assessment.md with a dedicated draft storage ownership assessment covering:
    • container identity generation
    • draft appeal and draft representation creation/resume flows
    • file upload/download/list/delete storage routes
    • draft delete flows
    • submission/finalisation queue handoff
  • Confirmed the strongest visible upstream storage ownership root is:
    • NextAuth session.user.id -> container identity
  • Recorded that SSR/page-loader flows consistently use session.user.id as the container identity for draft reads and store hydration.
  • Confirmed many file/blob APIs accept container / containerID as caller-supplied inputs and do not visibly re-derive container identity from session inside the reviewed handlers.
  • Classified the overall draft-storage model as hybrid:
    • upstream session-derived container ownership
    • downstream caller-supplied container/path values
    • hash-protected blob-path integrity
  • Identified the clearest ownership transition point as queue/finalisation:
    • storage-owned draft
    • completion route
    • queue message carrying container/storage paths
    • downstream CRM submitted-record creation

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct review of:
    • lib/newappeal/loadNewAppealPage.js
    • lib/myportal/loadMyPortalAppealPage.js
    • lib/representation/pageLoaders.js
    • actions/services/documentDirectService.js
    • actions/azurestorage.js
    • pages/api/file/{getprogressobjblob,getbloblist,getawaitingsubmissionfromblob,upload,uploadsinglefile,deleteblobcase,deleteblobrep,downloadblob,setupcontainer,createappealcompletemessage_api,createrepcompletemessage_api,editRepJson}.js
  • Additional searches performed across lib, pages, actions, and pages/api/file for session.user.id, containerID, getProgressFromBlob, getFilesFromBlob, getRepsFromBlob, getAwaitingSubmissionFromBlob, and queue helper names.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: perform a focused route-local verification pass on the highest-value storage APIs to determine whether any of them derive container ownership from session server-side elsewhere in the stack, or whether they rely entirely on upstream container provenance plus hash-protected path integrity.

CL-2026-06-19-PORTAL-API-AUTHORIZATION-ARCHITECTURE-MODEL: consolidated authorization roots, patterns, integrity controls, and risk framing

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, memory-bank/change-log.md type: milestone rationale: Consolidate the completed portal API assessment passes into one PEDW authorization architecture model that clearly distinguishes authorization roots, ownership patterns, integrity controls, proven findings, and non-proven findings without widening scope into a new endpoint review. impact: Documentation/context only; improves architectural clarity, auditability, and future review discipline; no runtime, contract, auth, storage, relay, or i18n behaviour change. status: completed

Summary:

  • Added a dedicated synthesis section to context/portal-api-security-boundary-assessment.md titled PEDW authorization architecture model.
  • Consolidated the completed investigations into four visible authorization roots:
    • anonymous public
    • NextAuth session
    • CRM Contact (session.user.email -> getPortalLogin(email) -> CRM Contact)
    • storage container (session.user.id -> user-specific Azure Storage container)
  • Added a pattern catalogue describing the main visible ownership / authorization models:
    • public anonymous
    • CRM contact scoped
    • CRM relationship scoped
    • record-ID provenance-based
    • storage container scoped
  • Added an integrity controls section clarifying that the signed hash most clearly protects route/query/path integrity and identifier integrity, and should be understood as an integrity control rather than object-authorization control.
  • Recorded the server-mediated execution model for storage and relay paths:
    • PEDW API -> Azure SDK -> Azure Storage
    • PEDW API -> signed path hash -> Azure Relay -> CRM
  • Added explicit synthesis of what has been proven:
    • distributed authorization model
    • route-local authorization not consistently visible
    • ownership usually established upstream and identifiers then propagated
    • signed hash strengthens integrity rather than object ownership proof
    • storage is server-mediated rather than direct browser-to-storage
  • Added explicit synthesis of what has not been proven:
    • no confirmed exploitability
    • no demonstrated User A -> User B mutation
    • no evidence invalidating existing health-check / OWASP / pentest posture
    • no evidence of direct browser-to-CRM or direct browser-to-storage exposure
  • Added high-level risk framing as:
    • architectural integrity / auditability risk
    • maintainability risk
    • future-change risk
    • not currently a confirmed exploitable vulnerability

Validation:

  • Documentation-only synthesis update; no runtime code changed.
  • Consolidation based on previously completed evidence in the assessment document covering:
    • endpoint inventory and risk classification
    • ownership-enforcement trace
    • pinsUser lifecycle and identity comparison
    • registration/bootstrap trace
    • account/profile mutation trace
    • user-owned CRM mutation trace
    • signed-hash watchlist delete vertical slice
    • draft storage ownership assessment
  • No new endpoint review performed for this synthesis step.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Next step: use this authorization architecture model as the baseline for future assessment/change review, and only if implementation work is later explicitly approved, consider narrow helper/guard patterns that re-bind selected sensitive CRM mutation routes to session-derived CRM contact and selected storage mutation routes to session-derived container identity while preserving existing behaviour and successful test posture.

CL-2026-06-19-PORTAL-API-SECURITY-STREAM-CLOSURE: formal close-out of authorization architecture assessment

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, context/architecture.md, memory-bank/change-log.md type: milestone rationale: Formally close the Portal API Security & Access Boundary Assessment stream and record the resulting stable architectural conclusions, programme status, and future framing in core project documentation. impact: Documentation/context only; clarifies that the stream is complete and records the final authorization architecture model for future review work; no runtime, contract, auth, relay, storage, or i18n behaviour change. status: completed

Summary:

  • Updated context/portal-api-security-boundary-assessment.md with a dedicated Programme status section stating:
    • Portal API Security & Access Boundary Assessment
    • Status: COMPLETE
  • Recorded stable stream conclusions in the assessment document:
    • PEDW uses a distributed authorization model
    • authorization is generally established upstream and propagated through later flows
    • integrity controls are meaningful but distinct from route-local object-authorization proof
    • no confirmed exploitability has been demonstrated by the assessment
  • Updated context/architecture.md to reflect that the portal authorization assessment stream is complete and to record the consolidated authorization architecture model as part of the architecture reference.
  • Added architecture-level conclusions covering:
    • principal authorization roots (public anonymous, CRM-owned, draft/storage-owned)
    • signed hash as an integrity control rather than object-authorization control
    • server-mediated storage execution via PEDW API and Azure SDK
    • relay path validation model via PEDW API and Azure Relay
    • proven vs not-proven findings
    • risk characterisation as architectural integrity/auditability/maintainability/future-change risk
  • Recorded that no immediate remediation programme is recommended and that any future work should be framed as authorization hardening, consistency improvement, and maintainability improvement rather than emergency remediation.

Validation:

  • Documentation-only closure update; no runtime code changed.
  • Reviewed existing assessment synthesis in context/portal-api-security-boundary-assessment.md before adding stream close-out language.
  • Reviewed context/architecture.md and aligned the architecture reference with the now-complete authorization assessment stream.
  • Reviewed memory-bank/open-questions.md; no update made because no genuinely new unresolved architecture/security question emerged from closure work.
  • Lint/tests not run because this was documentation-only work.

Follow-ups:

  • Portal authorization architecture stream should now be considered closed.
  • Recommended next architecture stream: authorization hardening / consistency planning, using the completed authorization architecture model as the baseline and only proceeding to implementation work by explicit approval.

CL-2026-06-19-PORTAL-API-REGISTRATION-TRACE: session-to-CRM-contact registration and dashboard bootstrap

date: 2026-06-19 author: Cline scope: context/portal-api-security-boundary-assessment.md, registration pages/components, account service helpers, createaccount_api, homepage signed-in bootstrap type: milestone rationale: Record how the portal transitions an authenticated NextAuth user with no CRM contact into a CRM-contact-backed portal user, and identify where dashboard access becomes valid. impact: Documentation/context only; improves architectural clarity around registration, identity binding, and dashboard authorization bootstrap; no runtime, contract, auth, or i18n behaviour change. status: completed

Summary:

  • Extended the assessment with a dedicated registration and post-registration bootstrap trace.
  • Identified the primary registration entry condition in pages/index.js:
    • signed-in session exists
    • getPortalLogin(session.user.email) returns no CRM contact
    • user is redirected to /account/register
  • Traced the registration flow across:
    • pages/account/register.js
    • components/account/registerform.js
    • components/account/registerCheck.js
    • components/account/registerComplete.js
    • actions/services/accountDirectService.createAccount
    • pages/api/endpoint/createaccount_api.js
  • Determined that registration uses the authenticated session email as the intended identity source:
    • loggedInUserEmail comes from getServerSideProps
    • form emailaddress1 is prefilled from session email
    • form email field is disabled in the reviewed UI
  • Determined that CRM contact creation is performed by forwarding the form body directly to CRM contacts via createaccount_api, with pinswg_typeofinvolvement set client-side in the registration completion flow.
  • Determined that dashboard access is not visibly granted immediately by registration completion itself.
  • Instead, dashboard access becomes valid after a subsequent signed-in bootstrap pass on / re-runs getPortalLogin(session.user.email), finds the newly created contact, sets pinsUser, and redirects to /myportal.

Validation:

  • Documentation-only assessment update; no runtime code changed.
  • Non-destructive evidence gathering performed via targeted searches and direct review of:
    • pages/index.js
    • pages/account/register.js
    • components/account/registerform.js
    • components/account/registerCheck.js
    • components/account/registerComplete.js
    • actions/services/accountDirectService.js
    • pages/api/endpoint/createaccount_api.js
    • pages/api/endpoint/getemailaccountcheck_api.js
    • pages/api/endpoint/getportallogin_api.js
  • No lint/tests run because this was documentation-only work.

Follow-ups:

  • Next assessment pass: trace account/profile mutation flows after registration to determine whether CRM-contact-backed users mutate account data through session-derived identity, pinsUser, or caller-supplied contact IDs.

CL-2026-06-18-CRM-CASE-PROGRESS-CONTEXT: record CRM Case Progress Display investigation conclusions

date: 2026-06-18 author: Cline scope: context/current-platform-state.md, memory-bank/{techContext,productContext,change-log}.md type: change rationale: Preserve the completed CRM Case Progress Display investigation conclusions in project context so future contributors do not re-open the same status/lifecycle ambiguity without need. impact: Documentation/context only; improves architectural clarity around case status display ownership and inputs; no runtime, auth, i18n, API, or behaviour change. status: completed

Summary:

  • Updated project context to record that the Case Status tab is a portal-owned journey interpretation layer.
  • Recorded the active input model as:
    • CRM statuscode
    • appeal type
    • specialist process (Rights of Way only)
  • Recorded that pinswg_casestage is not a significant active input to current status-tab lifecycle resolution.
  • Recorded that stage catalogues are best understood as:
    • user-facing journey models
    • appeal-type interpretation models
    • presentation-layer progress visualization
  • Recorded that shared catalogue families (PLANNING_S78, ENFORCEMENT, DNS/SIP, Rights of Way specialist-process variants) reflect a mixture of shared journey structures, presentation reuse, and historical consolidation.
  • Recorded the architectural conclusion that this area is presentation architecture / journey interpretation, not a new business-policy domain boundary candidate.

Validation:

  • Documentation/context update only.
  • No application code changed.
  • No tests changed.
  • Lint/tests skipped because this was documentation-only work.

Follow-ups:

  • Reopen only if a future business-validation or behaviour-change initiative requires deeper lifecycle/status decision work.

CL-2026-06-18-RPA-DOCS: representation participation availability documentation + context update

date: 2026-06-18 author: Cline scope: docs/representation-participation-availability.md, docs/representation-participation-business-review.md, context/current-platform-state.md, memory-bank/{techContext,productContext,open-questions,change-log}.md type: change rationale: Preserve the completed Representation Participation Availability investigation in repository documentation and project context so future contributors do not need to repeat the same discovery work. impact: Documentation/context only; improves architectural clarity and business-validation readiness; no runtime, auth, i18n, or API behaviour change. status: completed

Summary:

  • Added first-class technical documentation for Representation Participation Availability.
  • Added a plain-English business review document for product/business/SME validation.
  • Updated platform and memory-bank context to record:
    • the stream as complete from a technical discovery/documentation perspective
    • the architectural conclusion that representation participation is one coherent decision model with layered exceptions
    • the current state as awaiting business validation before further representation-policy adoption/expansion/change work
    • the next likely discovery candidate: Case Lifecycle / Status Decision Model Discovery
  • Added a concise open-questions entry pointing business stakeholders to the new review/technical documentation.

Validation:

  • Documentation/context update only.
  • No application code changed.
  • No tests changed.
  • Lint/tests skipped because this was documentation-only work.

Follow-ups:

  • Review docs/representation-participation-business-review.md with business stakeholders.
  • Do not broaden representation-policy boundaries further until validation outcomes are agreed.

date: 2026-04-09 author: Cline scope: lib/routing/routeState.js, components/breadcrumbs.js, components/case/summary.js, tests/phase22/{route-state-helper.test.cjs,index.test.cjs} type: change rationale: Action Priority 3 refactor backlog item by extracting duplicated route-state decision logic (va/adv/ads/key) into a shared pure helper and reusing it from breadcrumb and case-summary back-link flows to reduce drift/regression risk. impact: Refactor-only decision-layer consolidation for search/case/myportal navigation; no auth/session/CSP/API contract changes; EN/CY behavior intended unchanged as helper only resolves route targets and preserves existing query forwarding behavior. status: completed

Summary:

  • Created branch from origin/SIPS-Development: 22541-breadcrumb-route-state-helper.
  • Added lib/routing/routeState.js with:
    • normalizeRouteStateQuery(query)
    • resolveSearchResultsHref(options)
  • Updated components/breadcrumbs.js to consume the shared helper for:
    • breadcrumb href resolution (/myportal/viewall, advanced/address/default results)
    • case-results breadcrumb target on /case/[ticketnumber]
    • preserving existing label selection behavior via normalized flags.
  • Updated components/case/summary.js to replace local buildSearchHref with shared helper output (searchHref), including DNS-route override and no-flag fallback behavior.
  • Added table-driven unit coverage in tests/phase22/route-state-helper.test.cjs and registered it in tests/phase22/index.test.cjs.

Validation:

  • npx eslint lib/routing/routeState.js components/breadcrumbs.js components/case/summary.js tests/phase22/route-state-helper.test.cjs tests/phase22/index.test.cjs -> pass with 1 pre-existing warning in components/case/summary.js (react-hooks/exhaustive-deps).
  • node tests/phase22/route-state-helper.test.cjs -> pass (5/5).
  • node tests/phase22/index.test.cjs -> fails in existing auth suite (tests/phase22/auth-redirect-safety.test.cjs) with ReferenceError: resolveLocale is not defined in pages/api/auth/[...nextauth].js; unrelated to route-state changes.

Follow-ups:

  • If needed, triage/fix the existing phase22 auth redirect test harness failure separately to restore full combined suite execution.
  • Expand helper adoption in future slices to other navigation decision call sites if additional duplication emerges.

CL-22541-B: breadcrumb route-state helper expansion (label + DNS path helper)

date: 2026-04-09 author: Cline scope: lib/routing/routeState.js, components/breadcrumbs.js, components/case/summary.js, tests/phase22/route-state-helper.test.cjs type: change rationale: Continue Priority 3 breadcrumb refactor in a second bounded commit by extracting remaining repeated breadcrumb label and DNS-route-path decision logic into shared pure helpers. impact: Refactor-only extraction for navigation decision logic; no auth/session/CSP/API changes; no intended EN/CY behavior change beyond internal logic centralization. status: completed

Summary:

  • Extended lib/routing/routeState.js with:
    • resolveSearchBreadcrumbLabel(...)
    • isDnsRoutePath(pathname)
  • Updated components/breadcrumbs.js to use resolveSearchBreadcrumbLabel(...) and removed inline label decision IIFE.
  • Updated components/case/summary.js to use isDnsRoutePath(router.pathname) and removed inline DNS path checks.
  • Expanded tests/phase22/route-state-helper.test.cjs with coverage for:
    • breadcrumb label resolution matrix
    • DNS path detection helper

Validation:

  • npx eslint lib/routing/routeState.js components/breadcrumbs.js components/case/summary.js tests/phase22/route-state-helper.test.cjs -> pass with 1 pre-existing warning in components/case/summary.js (react-hooks/exhaustive-deps).
  • node tests/phase22/route-state-helper.test.cjs -> pass (7/7).
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next breadcrumbs slice can target incremental decomposition of large pathname branch rendering blocks in components/breadcrumbs.js into grouped render helpers with behavior parity.

CL-22541-C: breadcrumb case-state bundling helper (single-call resolver)

date: 2026-04-09 author: Cline scope: lib/routing/routeState.js, components/breadcrumbs.js, tests/phase22/route-state-helper.test.cjs type: change rationale: Continue Priority 3 breadcrumbs refactor by bundling repeatedly paired breadcrumb href/label resolution into one pure helper so component call sites stay thinner and less drift-prone. impact: Refactor-only centralization of existing route-state composition logic; no intended auth/session/API/i18n behavior change. status: completed

Summary:

  • Added resolveCaseBreadcrumbState(...) in lib/routing/routeState.js to return:
    • breadcrumbHref
    • caseResultsHref
    • breadcrumbLabel
  • Updated components/breadcrumbs.js to replace three separate helper invocations with one resolver call.
  • Extended tests/phase22/route-state-helper.test.cjs with bundled case-state resolver coverage.

Validation:

  • npx eslint lib/routing/routeState.js components/breadcrumbs.js tests/phase22/route-state-helper.test.cjs -> pass.
  • node tests/phase22/route-state-helper.test.cjs -> pass (8/8).
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next bounded slice can extract grouped pathname render blocks from components/breadcrumbs.js (data-driven map or small render helpers) while preserving route parity.

CL-22541-D: breadcrumbs shared my-portal crumb helper extraction

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue bounded breadcrumbs decomposition by extracting repeated my-portal breadcrumb <li> markup into one local render helper to reduce duplication and keep follow-on slices safer. impact: Refactor-only JSX deduplication in breadcrumb rendering; no intended route, auth/session, API, EN/CY, or accessibility behavior change. status: completed

Summary:

  • Added local renderMyPortalCrumb() helper in components/breadcrumbs.js.
  • Replaced repeated identical my-portal crumb JSX in multiple /myportal/* route branches with helper calls.
  • Kept special-case crumbs untouched where label/href differs (e.g. newappeal parent-title crumb, cyMyPortalHref account branches).

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next bounded slice can target additional repeated breadcrumb list-item patterns (e.g., repeated case-reference tail item blocks) with same behavior parity approach.

CL-22541-E: breadcrumbs case-reference crumb helper extraction

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue bounded breadcrumbs decomposition by extracting repeated case-reference tail breadcrumb markup into one local helper and replacing repeated inline blocks. impact: Refactor-only JSX deduplication in breadcrumb rendering; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added local renderCaseReferenceCrumb(referenceValue) helper in components/breadcrumbs.js.
  • Replaced repeated {t("common:breadcrumb-case-reference")}: ... list-item blocks across case/dns route branches with helper calls.
  • Corrected initial over-wrap by using helper calls directly (so generated <li> is not nested in another <li>).

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next bounded slice can target remaining repeated linked breadcrumb list-item patterns (e.g., recurring address-search result link pairs) via small local render helpers.

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Deliver a slightly larger bounded slice by extracting and reusing multiple breadcrumb rendering patterns (plain text crumb and linked crumb) across several route branches. impact: Refactor-only JSX deduplication and consistency improvement in breadcrumb rendering; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added reusable helpers in components/breadcrumbs.js:
    • renderTextCrumb(label)
    • renderLinkCrumb(href, label, onClick)
  • Replaced multiple repeated inline breadcrumb blocks across search/address/myportal/dns branches with helper calls.
  • Included onClick-capable link helper usage in the /myportal/case/id/[incident] address-results breadcrumb branch to preserve router.back() behavior.
  • Combined with existing renderMyPortalCrumb and renderCaseReferenceCrumb helpers for more consistent branch composition.

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: extract remaining repeated inline link crumbs for case/DNS branches that still hardcode <li><Link ...> (e.g., /myportal/case, /myportal/case/[ticketnumber], /dnsdetails, /dns/[developmentName]) to complete link-pattern consolidation.

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue the larger bounded breadcrumb refactor cadence by replacing the next batch of repeated inline <li><Link ...> crumbs with the shared link helper. impact: Refactor-only JSX deduplication and consistency improvement in breadcrumb rendering; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Reused renderLinkCrumb(href, label, onClick) for another broad set of previously inline Link crumbs, including:
    • service-name crumb in the shared shell
    • new appeal select-appeal parent/title crumbs
    • case and ticketnumber branches (/myportal/case, /case/[ticketnumber], /case/id/[incident], /myportal/case/[ticketnumber])
    • additional myportal/dns/account branches (/myportal/dns/[developmentName], /dnsdetails, /dns/[developmentName], /dns/application-view, account crumbs)
  • Kept special behavior intact where needed (e.g., existing callback-based crumbs that already use helper onClick).
  • Increased consistency of crumb rendering style by routing most link crumbs through one helper.

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: target remaining anchor/back-link duplication (<a href="#"> and occasional <a href={...}>) by introducing a bounded helper for action/back crumbs while preserving existing non-Link semantics.

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue the larger bounded breadcrumbs refactor cadence by extracting repeated anchor/back-link crumb markup into one local helper while preserving non-Link semantics. impact: Refactor-only JSX deduplication and consistency improvement in breadcrumb rendering; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added renderAnchorCrumb(href, label, onClick, listItemClass) in components/breadcrumbs.js for repeated <a ...> breadcrumb actions.
  • Replaced repeated anchor/back-link crumb blocks in:
    • /myportal/searchresults my-portal anchor crumb
    • /newappeal/[appealtypes] and /myportal/[appealtypes] step-back crumbs
    • /myportal/representation back-chevron action crumbs (all three state branches)
  • Preserved original click handlers, href values, and class semantics (govuk-breadcrumbs__link-item, backChevron) to keep behavior parity.

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: consolidate remaining one-off inline breadcrumb <li><Link ...> blocks still present in edge branches (e.g., /newappeal/[appealtypes], /myportal/[appealtypes], /case) and consider introducing an optional renderBackCrumb(...) semantic wrapper for readability.

CL-22541-I: breadcrumbs edge branch consolidation + semantic back-crumb wrapper

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue the same bounded breadcrumbs refactor cadence by consolidating remaining edge inline Link/back crumbs and introducing a semantic back-crumb wrapper for readability. impact: Refactor-only JSX deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added semantic helper renderBackCrumb(onClick, listItemClass?) that delegates to renderAnchorCrumb(...) with existing back-link text.
  • Replaced remaining one-off inline edge crumbs in:
    • /newappeal/[appealtypes] and /myportal/[appealtypes] (currentSection === 9999 service-name link and back-link branch)
    • /case search-results link crumb (including existing router.back() callback)
    • /myportal/representation back-link branches now use renderBackCrumb(...).
  • Preserved existing href targets, callback behavior, and class semantics (including special govuk-breadcrumbs__link-item usage).

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: consider extracting a small, route-keyed breadcrumb branch map/helper grouping in components/breadcrumbs.js (purely structural) to reduce the long inline conditional chain while keeping one-slice behavior parity.

CL-22541-J: breadcrumbs static text-only route crumb consolidation

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue the same bounded refactor cadence by consolidating repeated static text-only breadcrumb route branches into one route-label resolver. impact: Refactor-only structural deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added getStaticTextCrumbLabel(path) in components/breadcrumbs.js to centralize static text-only crumb labels by pathname.
  • Replaced repeated single-line static crumb branches with one generic render path:
    • renderTextCrumb(getStaticTextCrumbLabel(pathname)) when mapping returns a label.
  • Consolidated static branch handling for routes including:
    • account register
    • DNS index/help/contact/applications process pages
    • cookies/privacy/accessibility/static auth routes.
  • Preserved route labels (including translation keys and legacy hardcoded labels where already present).

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: extract a small grouped helper for recurring two-crumb route pairs (e.g., my-portal + section label, dns list + case reference) to reduce the remaining conditional chain while preserving explicit route behavior.

CL-22541-K: breadcrumbs grouped two-crumb helper extraction

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue the same bounded refactor cadence by extracting recurring two-crumb patterns into small grouped helpers while preserving explicit route branches. impact: Refactor-only readability/deduplication improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added grouped helper renderMyPortalSectionCrumbs(sectionLabel) for recurring my-portal + section text pairs.
  • Added grouped helper renderDnsCaseReferenceCrumbs(referenceValue) for recurring DNS applications link + case-reference pairs.
  • Replaced duplicated route branches with grouped helper usage for:
    • /myportal/addresssearch, /myportal/advancedsearch, /myportal/contactus
    • /dnsdetails, /dns/[developmentName]
  • Preserved existing href behavior (including EN/CY DNS applications link), labels, and case-reference rendering.

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: extract a small route-to-renderer map for static single-branch crumbs (where branch has no bespoke side-effects) so the main JSX conditional chain shrinks further without altering explicit behavior in dynamic/sensitive branches.

CL-22541-L: breadcrumbs simple-route renderer map introduction

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js type: change rationale: Continue bounded readability refactor by introducing a small route-to-renderer map for simple static branches, reducing conditional-chain length while preserving explicit dynamic branches. impact: Refactor-only structural deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added getSimpleRouteRenderer(path) in components/breadcrumbs.js for simple routes with no bespoke side effects.
  • Introduced a single invocation block that resolves and renders mapped simple routes when present.
  • Migrated simple route branches into the map, including:
    • /myportal, /searchresults, /advancedsearch, /addresssearch, /contactus
    • /viewall, /myportal/dnsapplications
  • Preserved existing label text, helper usage, and rendered crumb sequence semantics.

Validation:

  • npx eslint components/breadcrumbs.js -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next slice recommendation: extract a second tiny map for simple "link + text" pair routes (no callbacks, no side effects) to further shrink the conditional chain while keeping callback/dynamic branches explicit.

CL-22541-M: breadcrumbs simple link+text pair map + focused structure coverage

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/{breadcrumbs-route-map-structure,index}.test.cjs type: change rationale: Execute the next bounded slice by extracting simple link+text pair route branches into a tiny renderer map and adding focused regression checks that mapped and dynamic callback branches remain in the intended structure. impact: Refactor-only structural deduplication/readability improvement plus focused test coverage; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added getSimpleLinkTextPairRenderer(path) in components/breadcrumbs.js for simple no-callback "link + text" pair routes.
  • Migrated these routes into the new pair map:
    • /addresssearchresults
    • /advancedsearchresults
  • Kept dynamic/callback-driven branches explicit and untouched (e.g., /myportal/case/id/[incident] with router.back()).
  • Added focused phase22 suite tests/phase22/breadcrumbs-route-map-structure.test.cjs asserting:
    • mapped simple pair routes exist in the new map
    • explicit dynamic callback branch remains present.
  • Registered the new suite in tests/phase22/index.test.cjs.

Validation:

  • npx eslint components/breadcrumbs.js tests/phase22/index.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite, including new breadcrumbs-route-map tests 2/2).

Follow-ups:

  • Next slice recommendation: introduce a tiny local renderMappedRoute(path, resolver) helper to remove repeated inline IIFE map invocations, then optionally merge simple maps under one top-level resolver while preserving explicit ordering and side-effect-free constraints.

CL-22541-N: breadcrumbs unified mapped-route resolver + widened structural guardrails

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute the requested wider next slice by removing duplicated mapped-route invocation patterns, introducing a single top-level mapped resolver with explicit precedence, and migrating an additional safe my-portal route group into map-driven rendering while preserving explicit dynamic/callback branches. impact: Refactor-only structural consolidation/readability improvement with widened mapped-route coverage and stronger structure guardrail tests; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added getSimpleMyPortalRouteRenderer(path) in components/breadcrumbs.js and migrated additional safe map-friendly routes:
    • /myportal/searchresults
    • /myportal/addresssearch
    • /myportal/advancedsearch
    • /myportal/contactus
    • /myportal/viewall
  • Added resolveMappedRouteRenderer(path) to unify map precedence under one resolver.
  • Added renderMappedRoute(path, resolver?) helper and replaced duplicated inline map IIFE invocations with a single call:
    • {renderMappedRoute(pathname)}
  • Kept dynamic/stateful callback branches explicit and unchanged, especially /myportal/case/id/[incident] (router.back()) and other callback/state driven branches.
  • Expanded tests/phase22/breadcrumbs-route-map-structure.test.cjs to assert:
    • new my-portal route-map entries are present
    • unified resolver/helper signatures are present
    • single mapped-route invocation is used in JSX
    • dynamic callback branch remains explicit.

Validation:

  • npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumbs-route-map tests 3/3).

Follow-ups:

  • Next wider slice candidate: move a second safe myportal results pair group (/myportal/advancedsearchresults, /myportal/addresssearchresults) into the unified mapped resolver where callback-free, then consider splitting resolver maps into a dedicated local constant section for improved scanability.

CL-22541-O: breadcrumbs myportal results-pair migration into unified mapped resolver

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute the agreed next slice by migrating the remaining callback-free myportal results-pair branches into the unified mapped resolver so more safe branches are rendered through one consistent mapping flow. impact: Refactor-only structural consolidation/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Extended getSimpleMyPortalRouteRenderer(path) to include:
    • /myportal/advancedsearchresults
    • /myportal/addresssearchresults
  • Removed now-redundant explicit conditional branches for those two routes from the main JSX chain.
  • Kept callback/stateful branches explicit and unchanged (notably /myportal/case/id/[incident] with router.back()).
  • Expanded tests/phase22/breadcrumbs-route-map-structure.test.cjs guardrails to assert:
    • both myportal results-pair routes are mapped
    • legacy explicit isPath(...) branches for those routes are no longer present

Validation:

  • npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumbs-route-map tests 3/3).

Follow-ups:

  • Next wider slice candidate: split map resolver sections into clearly named grouped constants (simple/public/myportal) near one composition point, then optionally move map-only route renderers to a local pure helper module if continued growth impacts scanability.

CL-22541-P: breadcrumbs grouped route-map constants + unified map composition point

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute the next wider slice by replacing per-group resolver functions with grouped route-map constants and a single composition array to further improve scanability while preserving route precedence semantics. impact: Refactor-only structural readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Replaced function-based map accessors with grouped route-map constants in components/breadcrumbs.js:
    • simpleRouteRenderersByPath
    • simpleLinkTextPairRenderersByPath
    • simpleMyPortalRouteRenderersByPath
  • Added unified map composition point:
    • mappedRouteRendererMaps (ordered array preserving precedence)
    • getMappedRendererByPath(path, routeRendererMap) helper
  • Updated resolveMappedRouteRenderer(path) to iterate the composed map list while retaining previous resolution order and behavior.
  • Kept dynamic/callback branches explicit and unchanged outside map-driven paths.
  • Expanded structure tests to assert grouped map composition contracts (mappedRouteRendererMaps, getMappedRendererByPath) in addition to existing resolver and invocation guardrails.

Validation:

  • npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumbs-route-map tests 3/3).

Follow-ups:

  • Next slice option A (larger): extract map constants + resolver helpers into a local lib/routing/breadcrumbRouteMaps.js pure module with focused tests, keeping callback/stateful branch rendering in component.
  • Next slice option B (smaller): expand structure tests to assert explicit map ordering invariants so future reordering regressions are caught early.

CL-22541-Q: breadcrumbs route-map helper module extraction + map-order invariants

date: 2026-04-09 author: Cline scope: lib/routing/breadcrumbRouteMaps.js, components/breadcrumbs.js, tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure,index}.test.cjs type: change rationale: Execute both queued follow-up slices together by extracting map composition/resolution logic into a pure routing helper module and adding stronger structure + pure-helper guardrails for map-order precedence. impact: Refactor-only structural modularization and test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added new pure helper module lib/routing/breadcrumbRouteMaps.js:
    • buildBreadcrumbRendererMaps(...)
    • getMappedRendererByPath(...)
    • resolveMappedRouteRenderer(...)
  • Updated components/breadcrumbs.js to import/use shared helper logic:
    • map composition now via buildBreadcrumbRendererMaps(...)
    • resolver now delegates to resolveMappedRouteRendererByMaps(...)
    • dynamic/callback-sensitive explicit branches remain unchanged.
  • Added focused pure-helper tests in tests/phase22/breadcrumb-route-maps-helper.test.cjs for:
    • map build order
    • map lookup null/renderer behavior
    • resolver precedence behavior
  • Expanded tests/phase22/breadcrumbs-route-map-structure.test.cjs to assert:
    • component imports shared breadcrumb route-map helper module
    • resolver delegation uses helper module
    • map builder call preserves explicit ordering (simple -> link-text -> myportal)
  • Updated tests/phase22/index.test.cjs to include the new helper suite.

Validation:

  • npx eslint lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumb-route-maps-helper 3/3; breadcrumbs-route-map 3/3).

Follow-ups:

  • Next slice option A (larger): move per-path map object declarations out of components/breadcrumbs.js into module-level pure factories (still injected with t/router/currentView) to further shrink component body.
  • Next slice option B (smaller): add one focused parity test asserting mapped resolver fallback returns null in component rendering path for non-mapped routes (ensures no accidental render noise).

CL-22541-R: breadcrumbs mapped-group factory composition + unmapped-route null parity guard

date: 2026-04-09 author: Cline scope: lib/routing/breadcrumbRendererFactories.js, components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute both approved next slices in one commit by centralizing deterministic mapped route-group composition into a factory-level helper and adding explicit structure guard coverage for null fallback behavior on unmapped routes. impact: Refactor-only structural consolidation and test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added createMappedRouteRendererGroups(...) in lib/routing/breadcrumbRendererFactories.js to compose and return all deterministic mapped renderer groups in one place:
    • simpleRouteRenderersByPath
    • simpleLinkTextPairRenderersByPath
    • simpleMyPortalRouteRenderersByPath
    • caseDetailRouteRenderersByPath
    • detailAndAccountRouteRenderersByPath
  • Updated components/breadcrumbs.js to consume createMappedRouteRendererGroups(...) and remove local per-group factory composition boilerplate while preserving existing map precedence and resolver flow.
  • Expanded tests/phase22/breadcrumbs-route-map-structure.test.cjs to assert:
    • grouped renderer maps are composed via createMappedRouteRendererGroups(...)
    • mapped rendering path explicitly preserves null fallback (routeRenderer ? routeRenderer() : null)

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumbs-route-map 4/4).

Follow-ups:

  • Next slice option A (larger): extract remaining deterministic inline branches (/myportal/case, /case/id/[incident] if kept deterministic after constraints review) only if they remain callback/state free.
  • Next slice option B (smaller): add one focused assertion in helper-level tests that empty grouped map entries are tolerated without affecting precedence resolution.

CL-22541-S: breadcrumbs deterministic case-branch extraction (/myportal/case, /case/id/[incident])

date: 2026-04-09 author: Cline scope: lib/routing/breadcrumbRendererFactories.js, components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute the next deterministic extraction slice by migrating remaining callback-free case breadcrumb branches into the case-detail factory group while preserving map precedence and leaving stateful/callback routes inline. impact: Refactor-only structural extraction and test guardrail expansion; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Extended createCaseDetailRouteRenderers(...) in lib/routing/breadcrumbRendererFactories.js to map:
    • /myportal/case
    • /case/id/[incident]
  • Injected additional deterministic inputs required by these routes:
    • currentReference
    • nestedSearchString
  • Updated createMappedRouteRendererGroups(...) wiring to pass the new inputs to case-detail factory composition.
  • Updated components/breadcrumbs.js to pass nestedSearchString into grouped factory composition.
  • Removed now-redundant inline isPath(...) branches for:
    • /myportal/case
    • /case/id/[incident]
  • Expanded tests/phase22/breadcrumbs-route-map-structure.test.cjs to assert:
    • both new routes are mapped in createCaseDetailRouteRenderers
    • both inline branches are absent from components/breadcrumbs.js

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumbs-route-map 4/4).

Follow-ups:

  • Next slice option A (larger): evaluate whether any remaining deterministic inline branches can be extracted without violating callback/state constraints.
  • Next slice option B (smaller): add a focused helper-level precedence test where earlier map contains falsy/non-function values and later maps contain valid renderers.

CL-22541-T: breadcrumbs larger slice — new-appeal mapped group extraction (/newappeal/selectappeal)

date: 2026-04-09 author: Cline scope: lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js, components/breadcrumbs.js, tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs type: change rationale: Execute the next larger deterministic refactor slice by extracting callback-free new-appeal breadcrumb branching into a dedicated mapped renderer group and extending map-order guardrails. impact: Refactor-only structural extraction plus precedence-test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added createNewAppealRouteRenderers(...) in lib/routing/breadcrumbRendererFactories.js.
  • Mapped /newappeal/selectappeal into the new grouped renderer factory.
  • Extended grouped composition return from createMappedRouteRendererGroups(...) with newAppealRouteRenderersByPath.
  • Updated lib/routing/breadcrumbRouteMaps.js to include newAppealRouteRenderersByPath in explicit map precedence ordering.
  • Updated components/breadcrumbs.js to consume/pass newAppealRouteRenderersByPath into map builder.
  • Removed now-redundant inline isPath("/newappeal/selectappeal") branch from component JSX.
  • Expanded tests:
    • tests/phase22/breadcrumbs-route-map-structure.test.cjs
      • assert new factory export and mapped route presence
      • assert inline branch removal
      • assert updated map-order invariant (simple -> link-text -> myportal -> new-appeal -> case detail -> detail/account)
    • tests/phase22/breadcrumb-route-maps-helper.test.cjs
      • assert six-map ordering contract and updated grouped precedence wiring.

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next larger slice candidate: evaluate extraction viability for /case branch only if callback/router.back() behavior can remain explicit and parity-safe.
  • Next smaller slice candidate: add helper-level test coverage for unexpected non-function map values and explicit skip behavior (defensive precedence guard).

CL-22541-U: breadcrumbs smaller slice — defensive mapped-route resolver hardening

date: 2026-04-09 author: Cline scope: lib/routing/breadcrumbRouteMaps.js, tests/phase22/breadcrumb-route-maps-helper.test.cjs type: change rationale: Execute the queued smaller slice by hardening mapped-route lookup against malformed map entries and non-function values while keeping precedence behavior unchanged. impact: Refactor-hardening only; no intended breadcrumb route behavior change for valid mapped renderers. status: completed

Summary:

  • Updated getMappedRendererByPath(...) to safely handle invalid route-map entries:
    • returns null when map is missing/non-object
    • returns null when mapped value is not a function
  • Preserved existing resolver precedence semantics for valid function renderers.
  • Added focused helper test asserting resolver skips:
    • invalid map entries (null/undefined)
    • non-function mapped values and still resolves the first later valid renderer.

Validation:

  • npx eslint lib/routing/breadcrumbRouteMaps.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumb-route-maps-helper 5/5).

Follow-ups:

  • Next larger slice: extract remaining callback-bearing deterministic branches into mapped route groups with callback injection, then update structure guards accordingly.

CL-22541-V: breadcrumbs larger slice — callback route-group extraction (/myportal/case/id/[incident], /case)

date: 2026-04-09 author: Cline scope: lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js, components/breadcrumbs.js, tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs type: change rationale: Execute the next larger extraction slice by moving callback-bearing breadcrumb branches into a dedicated callback renderer map while preserving router.back() behavior through explicit callback injection. impact: Structural refactor with preserved callback semantics; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added createCallbackRouteRenderers(...) in lib/routing/breadcrumbRendererFactories.js to map:
    • /myportal/case/id/[incident]
    • /case
  • Introduced explicit callback injection (onBack) into grouped factory composition and route renderers, preserving router.back() behavior via injected callback.
  • Extended createMappedRouteRendererGroups(...) return with callbackRouteRenderersByPath.
  • Updated map builder in lib/routing/breadcrumbRouteMaps.js to include callback map in explicit precedence order:
    • simple -> link-text -> myportal -> new-appeal -> callback -> case detail -> detail/account.
  • Updated components/breadcrumbs.js:
    • pass onBack: () => { router.back(); } into grouped factory composition
    • include callback route map in buildBreadcrumbRendererMaps(...)
    • remove now-redundant inline isPath("/myportal/case/id/[incident]") and isPath("/case") branches.
  • Expanded tests:
    • tests/phase22/breadcrumb-route-maps-helper.test.cjs
      • update grouped map order assertions to seven maps including callback group.
    • tests/phase22/breadcrumbs-route-map-structure.test.cjs
      • assert callback factory export and mapped callback route presence
      • assert callback map inclusion in component grouped destructuring and map-order invariant
      • assert inline callback branches are removed while router.back(); remains preserved.

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next smaller slice candidate: add a focused helper test for empty-string/whitespace path lookups to assert strict null behavior for non-exact keys.
  • Next larger slice candidate: evaluate whether /newappeal/[appealtypes] and /myportal/[appealtypes] back-link branches can be extracted with explicit callback/setter injection while preserving state-step semantics.

CL-22541-W: breadcrumbs larger slice — step-back route-group extraction (/newappeal/[appealtypes], /myportal/[appealtypes])

date: 2026-04-09 author: Cline scope: lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js, components/breadcrumbs.js, tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs type: change rationale: Execute the next larger extraction slice by moving step-based back-link branches into a dedicated mapped route group with explicit setter callback injection, preserving section-navigation semantics. impact: Structural refactor with preserved back-link and step-state behavior; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added createStepBackRouteRenderers(...) in lib/routing/breadcrumbRendererFactories.js to map:
    • /newappeal/[appealtypes]
    • /myportal/[appealtypes]
  • Preserved existing step semantics in mapped handlers:
    • no crumb when currentSection <= 1
    • service-name crumb when currentSection === 9999
    • back-link crumb with existing class parity (govuk-breadcrumbs__link-item for new-appeal flow)
  • Introduced explicit injected handlers (onStepBack, onStepBackWithInlineClass) and injected crumb renderer dependency (renderBackCrumb) into grouped factory composition.
  • Extended map builder in lib/routing/breadcrumbRouteMaps.js with stepBackRouteRenderersByPath and updated precedence order:
    • simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> case detail -> detail/account.
  • Updated components/breadcrumbs.js:
    • pass currentSection and step-back callbacks into createMappedRouteRendererGroups(...)
    • include step-back map in buildBreadcrumbRendererMaps(...)
    • remove inline isPath("/newappeal/[appealtypes]") and isPath("/myportal/[appealtypes]") branches.
  • Expanded tests:
    • tests/phase22/breadcrumb-route-maps-helper.test.cjs
      • updated grouped map count/order to include step-back map (8 total)
    • tests/phase22/breadcrumbs-route-map-structure.test.cjs
      • assert step-back factory export + mapped route presence
      • assert grouped destructuring includes step-back map
      • assert inline step-back branches are removed
      • assert updated map-order invariant includes step-back group.

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next smaller slice candidate: add focused helper test for strict null behavior on empty-string/whitespace/non-exact path keys.
  • Next larger slice candidate: evaluate extractability of /myportal/representation back-link states via explicit callback injection, only if questionnaire/submit side-effects remain parity-safe and readable.

CL-22541-X: breadcrumbs smaller slice — strict null lookup guard coverage (empty/whitespace/non-exact paths)

date: 2026-04-09 author: Cline scope: tests/phase22/breadcrumb-route-maps-helper.test.cjs type: change rationale: Execute the queued smaller follow-up slice by hardening helper regression coverage for strict exact-match route lookup semantics. impact: Test-only hardening; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added focused helper-level test case in tests/phase22/breadcrumb-route-maps-helper.test.cjs:
    • resolveMappedRouteRenderer returns null for empty, whitespace, and non-exact path variants
  • New assertions verify resolver returns null for:
    • empty path ("")
    • whitespace-only path (" ")
    • trailing/leading whitespace variants ("/known ", " /known")
    • case-variant non-exact key ("/KNOWN")
  • Confirms route-map resolver remains strict/exact and does not auto-trim or case-normalize lookup keys.

Validation:

  • npx eslint tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite; breadcrumb-route-maps-helper 6/6).

Follow-ups:

  • Next larger slice candidate remains /myportal/representation callback/state branch extraction only if side-effects can be injected/parity-preserved cleanly.

CL-22541-Y: breadcrumbs larger slice — representation route-group extraction (/myportal/representation)

date: 2026-04-09 author: Cline scope: lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js, components/breadcrumbs.js, tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs type: change rationale: Execute the queued larger follow-up slice by extracting /myportal/representation callback/state breadcrumb branches into a dedicated mapped route group with explicit callback injection while preserving questionnaire/submit side-effects. impact: Structural refactor with preserved representation back-link state behavior; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added createRepresentationRouteRenderers(...) in lib/routing/breadcrumbRendererFactories.js mapping:
    • /myportal/representation
  • Preserved existing representation-state semantics in mapped handler:
    • submit/back from confirmation (setRepresentationSubmit(qcount))
    • non-questionnaire back path (setRepresentationSubmit(false))
    • questionnaire step-back path (setShowQuestionnaireSection(showQuestionnaireSection - 1) + setRepresentationSubmit(false))
  • Introduced explicit injected state/callback dependencies into grouped composition:
    • currentView, hasRepDetails, repDetails, showQuestionnaireSection
    • onRepresentationSubmitBackFromConfirmation
    • onRepresentationSubmitBackToDetails
    • onRepresentationQuestionnaireBack
  • Extended buildBreadcrumbRendererMaps(...) in lib/routing/breadcrumbRouteMaps.js with representationRouteRenderersByPath and updated precedence order:
    • simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> representation -> case detail -> detail/account.
  • Updated components/breadcrumbs.js:
    • pass representation state/callback injections into createMappedRouteRendererGroups(...)
    • include representationRouteRenderersByPath in map builder call
    • remove inline isPath("/myportal/representation") branch block.
  • Expanded tests:
    • tests/phase22/breadcrumb-route-maps-helper.test.cjs
      • updated map-count/order assertions to include representation group (9 total)
      • updated map build fixtures to include representationRouteRenderersByPath
    • tests/phase22/breadcrumbs-route-map-structure.test.cjs
      • assert representation factory export + mapped route presence
      • assert grouped destructuring includes representation map
      • assert inline representation branch removal
      • assert updated map-order invariant includes representation group.

Validation:

  • npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs -> pass.
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Next smaller slice candidate: helper-level assertion for missing/undefined representation dependency values yielding no renderer output regressions.
  • Next larger slice candidate: evaluate whether remaining /newappeal edge branch can be absorbed into mapped grouping without reducing readability or explicitness.

CL-22541-Z: breadcrumbs closure slice 1 — mapped-route precedence/callback invariants decision

date: 2026-04-09 author: Cline scope: memory-bank/decisions.md type: change rationale: Execute closure slice 1 by documenting explicit architectural invariants for breadcrumb mapped-route precedence and callback injection contracts so future refactors remain safe and auditable. impact: Documentation/governance hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added D-006 to memory-bank/decisions.md.
  • Captured accepted invariant contracts for:
    • explicit breadcrumb map precedence ordering (9 groups)
    • callback/state behavior dependency injection requirement (no ad-hoc inline reintroduction)
    • structure test guardrails as contract checks for intentional future changes.

Validation:

  • Documentation consistency review against current breadcrumb map structure and phase22 structure test expectations.

Follow-ups:

  • Closure slice 2: add focused negative-path representation map/dependency tolerance test coverage.
  • Closure slice 3: resolve and guard remaining /newappeal inline edge branch treatment.

CL-22541-Z2: breadcrumbs closure slice 2 — missing representation map negative-path guard

date: 2026-04-09 author: Cline scope: tests/phase22/breadcrumb-route-maps-helper.test.cjs type: change rationale: Execute closure slice 2 by adding focused negative-path coverage ensuring resolver behavior remains stable when representation route-map dependency is missing from grouped map input. impact: Test hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Added focused helper-level test:
    • resolveMappedRouteRenderer tolerates missing representation map entry in grouped map input
  • New assertions verify:
    • missing representationRouteRenderersByPath resolves /myportal/representation to null
    • later maps still resolve correctly (case detail fallback remains intact).

Validation:

  • node tests/phase22/breadcrumb-route-maps-helper.test.cjs -> pass (7/7).
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Closure slice 3: resolve and guard remaining /newappeal inline edge branch treatment.

CL-22541-Z3: breadcrumbs closure slice 3 — remove lingering /newappeal no-op inline branch

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Execute closure slice 3 by resolving the remaining inline /newappeal edge branch (a no-op render guard) and locking its removal with explicit structure coverage. impact: Refactor/test hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed

Summary:

  • Removed lingering no-op branch from breadcrumbs JSX:
    • deleted {isPath("/newappeal") && <></>}
  • Added structure guard assertion that /newappeal inline branch is absent.

Validation:

  • node tests/phase22/breadcrumbs-route-map-structure.test.cjs -> pass (4/4).
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Breadcrumb route-state extraction closure slices (1/2/3) complete.

CL-22541-Z4: breadcrumbs post-closure hotfix — callable label resolver parity (static + view-all)

date: 2026-04-09 author: Cline scope: components/breadcrumbs.js, tests/phase22/breadcrumbs-route-map-structure.test.cjs type: change rationale: Fix post-refactor regression where some breadcrumbs rendered blank labels because mapped label entries were returned as function references instead of resolved values. impact: Restores user-visible breadcrumb labels for static and view-all keyed routes; no auth/session/API/security behavior change. status: completed

Summary:

  • Fixed static text breadcrumb label resolver to invoke mapped label functions:
    • getStaticTextCrumbLabel(path) now resolves callable entries (resolver ? resolver() : null).
  • Fixed view-all label resolver parity to support both function-backed and string-backed map entries:
    • getViewAllLabel(viewKey) now invokes function entries and returns string entries directly.
  • Added structure guard assertions to prevent regression of callable label resolution behavior.

Validation:

  • node tests/phase22/breadcrumbs-route-map-structure.test.cjs -> pass (4/4).
  • node tests/phase22/index.test.cjs -> pass (combined suite).

Follow-ups:

  • Breadcrumb label resolver parity now aligned across mapped/static/view-all label paths.

CL-22541-Z5: architecture comparison overview refresh (senior architecture review)

date: 2026-04-09 author: Cline scope: context/architecture-overview-2026-04-09.md type: change rationale: User requested a fresh senior architecture review and comparison baseline covering scalability, maintainability, coupling, boundary quality, operational/deployment risk, and prioritized technical debt actions. impact: Documentation-only architecture guidance update; no runtime/auth/session/security/API behavior change. status: completed

Summary:

  • Added new architecture comparison baseline document:
    • context/architecture-overview-2026-04-09.md
  • Included requested structure:
    1. current architecture summary
    2. strengths
    3. risks (scalability, maintainability, coupling, weak boundaries, operational/deployment)
    4. prioritized recommendations
    5. low-risk next improvements
  • Added explicit comparison notes vs existing context/architecture.md and identified strategic focus areas for the next modernization wave.

Validation:

  • Documentation coherence review against current repo architecture docs (context/architecture.md, context/integration-map.md, context/project-overview.md).

Follow-ups:

  • Optionally elevate this architecture overview into a periodic architecture scorecard cadence and add measurable KPIs in memory-bank.

CL-00X: 22500 components/elements/index.js Phase 1 helper extraction

date: 2026-04-07 author: Cline scope: components/elements/index.js, components/elements/helpers/fileUploadHelpers.js, components/elements/helpers/translationHelpers.js, memory-bank/refactor-backlog.md type: change rationale: Execute Phase 1 of the approved components/elements/index.js decomposition plan by extracting pure helper logic only, reducing monolith coupling while preserving UI/component behavior. impact: No route/API contract changes; refactor-only extraction of translation/file-upload helper functions with expected behavior parity for EN/CY field labels, file naming, thumbnail icon mapping, and filename validation. status: completed

Summary:

  • Created work branch from origin/SIPS-Development: 22500-elements-index-phase1.
  • Added helper modules:
    • components/elements/helpers/fileUploadHelpers.js
      • getThumbnailIconByMimeType
      • getDocumentTypePrefix
      • validateUploadFilename
    • components/elements/helpers/translationHelpers.js
      • getFieldTranslation
      • getPickListTranslation
  • Updated components/elements/index.js to consume these helpers and removed duplicated inline helper implementations.
  • Kept field renderer/component placement and external prop contracts unchanged (Phase 1 non-goals respected).
  • Updated memory-bank/refactor-backlog.md with a phased Priority 6 track and Phase 1 guardrail-aligned acceptance criteria.

Validation:

  • npx eslint components/elements/index.js components/elements/helpers/fileUploadHelpers.js components/elements/helpers/translationHelpers.js -> pass

Follow-ups:

  • Phase 2: extract low-risk leaf field renderer components from components/elements/index.js in bounded slices.
  • Perform manual EN/CY + a11y smoke matrix on new appeal/myportal form journeys before merge.

CL-00Y: 22500 components/elements/index.js Phase 2 leaf renderer extraction (Rich multiline)

date: 2026-04-07 author: Cline scope: components/elements/index.js, components/elements/fields/renderRichMultiline.js type: change rationale: Continue the approved phased decomposition by extracting one low-risk leaf renderer (RenderRichMultiline) from the elements monolith while keeping existing field wiring and behavior intact. impact: Refactor-only move of rich multiline renderer implementation; no route/API/auth/security changes and no intended EN/CY behavior change. status: completed

Summary:

  • Added components/elements/fields/renderRichMultiline.js containing the extracted RenderRichMultiline renderer.
  • Updated components/elements/index.js to import the extracted renderer and removed the inline duplicate implementation.
  • Kept RichMultiLinefield usage and props unchanged (same Redux Field component wiring and validation flow).

Validation:

  • npx eslint components/elements/index.js components/elements/fields/renderRichMultiline.js -> pass

Follow-ups:

  • Continue Phase 2 in bounded slices by extracting additional low-risk leaf renderers (e.g., RenderMultiline / RenderTextfield) with no behavior change.

CL-00Z: 22500 components/elements/index.js Phase 2 leaf renderer extraction (Text + Multiline)

date: 2026-04-07 author: Cline scope: components/elements/index.js, components/elements/fields/renderTextfield.js, components/elements/fields/renderMultiline.js type: change rationale: Complete the requested next bounded phase by extracting the additional low-risk leaf renderers (RenderTextfield, RenderMultiline) from the elements monolith into dedicated field modules while preserving existing wiring and behavior. impact: Refactor-only move of two renderer components; no intended changes to auth/API/security and no intended EN/CY behavior change. status: completed

Summary:

  • Added components/elements/fields/renderTextfield.js and components/elements/fields/renderMultiline.js.
  • Updated components/elements/index.js to import the extracted renderers.
  • Removed inline RenderTextfield and RenderMultiline implementations from index.js.

Validation:

  • npx eslint components/elements/index.js components/elements/fields/renderTextfield.js components/elements/fields/renderMultiline.js -> pass

Follow-ups:

  • Continue Phase 2 by selecting the next lowest-risk leaf renderer extraction in a separate commit.

CL-001: TASK22211 endpoint search-document contract consistency slice

date: 2026-03-23 author: Cline scope: pages/api/endpoint/{getsearchdocumenthistory_api,getsearchdocumenthistorypaged_api,getsearchdocumentdetails_api,getsearchdocumentdetailspaged_api,getsearchdocumentTypes_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue the endpoint contract-consistency stream by normalizing a coherent search-document handler cluster that still used raw error passthrough and noisy legacy logging patterns. impact: Improved negative-path consistency and safer error contract handling in search-document endpoints while preserving success payload behavior. status: completed

Summary:

  • Branch created from SIPS-Development: TASK22211-endpoint-search-document-contract-consistency.
  • Standardized five search-document handlers to respondError/respondSuccess usage.
  • Added explicit required-input guards:
    • DOCUMENT_ID_REQUIRED for history/historypaged
    • INCIDENT_ID_REQUIRED for details/detailspaged/types
    • ORDER_BY_REQUIRED, FIELD_SORT_REQUIRED, SHOW_NUMBER_OF_RECORDS_REQUIRED for details-paged query requirements
  • Removed noisy direct logging in paged/details code paths.
  • Preserved success contract patterns (pass-through or transformed payloads where already established).
  • Expanded phase21 endpoint tests with missing-input, catch-path, and success parity assertions for this cluster.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 11/11
    • email-handler: 12/12
    • endpoint-handler: 53/53
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps warnings; no new lint errors)

Follow-ups:

  • Continue the next endpoint cluster using the same pattern (bounded slice + phase21 test expansion).
  • Keep response success payloads contract-stable and avoid broad relay/auth refactors in this stream.

CL-002: TASK22211 endpoint token handler contract consistency slice

date: 2026-03-23 author: Cline scope: pages/api/endpoint/getToken.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Close out remaining non-standard endpoint contract handling by normalizing the legacy token endpoint to shared API response helpers and explicit error coding. impact: Improved endpoint error consistency and test coverage for token acquisition failures while preserving successful token payload passthrough. status: completed

Summary:

  • Refactored getToken.js to use respondSuccess and respondError from pages/api/middleware/apiResponse.
  • Removed legacy raw res.status(...).json(...)/bare status assignment pattern and dead logging artifacts.
  • Added explicit catch-path contract: TOKEN_FETCH_FAILED with 400 status.
  • Added endpoint phase21 tests for:
    • success token payload passthrough
    • catch-path error contract assertion

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 11/11
    • email-handler: 12/12
    • endpoint-handler: 147/147
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps warnings; no new lint errors)

Follow-ups:

  • Remaining outlier API handler for this consistency stream is pages/api/file/generateappealpdfcopy.js (not yet on shared response helpers).

CL-003: TASK22211 endpoint contract-hardening stream backfill (all known slices)

date: 2026-03-23 author: Cline scope: pages/api/endpoint/*_api.js, pages/api/endpoint/getToken.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Backfill memory-bank traceability so the complete known TASK22211 contract-consistency stream is documented in one place now that memory-bank is being versioned. impact: Improves governance/auditability of API contract hardening, makes rollout and rollback analysis easier, and records exactly which endpoint clusters were normalized. status: completed

Summary:

  • Backfilled all known TASK22211 slices currently on branch (in commit order):
    • b57f3de search-document endpoint contracts + phase21 coverage
    • 9af541a my-portal retrieval endpoint contracts
    • b880364 basic search endpoint contracts
    • a106dea DNS basic search endpoint contracts
    • b5a3a62 portal module + LPA case endpoint contracts
    • 4601d7c case detail endpoint contracts
    • 2959c7d delete/watched-case endpoint contracts
    • b59f13a metadata + linked-case endpoint contracts
    • bcf03a6 form + publication endpoint contracts
    • e0e91c8 DNS + representation endpoint contracts
    • 98e159d case creation + media endpoint contracts
    • 88e4586 advanced-search-paged endpoint contract
    • cb69bbe case update + CRM task endpoint contracts
    • 722ef98 hash + metadata endpoint contracts
    • 134f99c address-search endpoint contract
    • 8b6ed73 new-appeal appeal-types endpoint contract
    • eec59e8 token endpoint contract handling
  • Across the stream, handlers were standardized toward respondSuccess/respondError, required-input guards, and explicit negative-path error codes while preserving success payload compatibility.
  • Phase21 endpoint contract suite was expanded incrementally alongside each slice.

Validation:

  • Stream validation baseline (latest known run):
    • node tests/phase21/api-contract-slice1.test.cjs -> pass (endpoint-handler 147/147)
    • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue with remaining non-standard API outlier(s), notably pages/api/file/generateappealpdfcopy.js.
  • Keep future slices logged in this file at commit-time now that memory-bank is versioned.

CL-004: TASK22224 file + static endpoint contract hardening bundle (phase21)

date: 2026-03-23 author: Cline scope: pages/api/file/{downloadblob,generateappealpdfcopy}.js, pages/api/endpoint/{getsipsmedia_api,getappealtypesfornewappeal_api}.js, tests/phase21/{file-handler-contract,endpoint-handler-contract}.test.cjs type: change rationale: Deliver the agreed larger bounded slice for remaining non-standard file/static handlers, improving negative-path consistency while preserving current success payload behavior. impact: Standardized error envelopes/codes for download and generated PDF copy flows, method guard parity for static endpoints, and expanded phase21 contract coverage for both file and endpoint handlers. status: completed

Summary:

  • downloadblob.js:
    • added explicit catch-path response via respondError with DOWNLOAD_BLOB_FAILED
    • kept success behavior intact (attachment header + raw file body)
    • removed dead internal helper (streamToBuffer) and tightened local declarations
  • generateappealpdfcopy.js:
    • removed unused imports/noisy console warnings
    • standardized required-input and negative-path contracts:
      • INCIDENT_ID_REQUIRED (400)
      • CASE_NOT_FOUND (404)
      • FORM_COLLECTION_NOT_FOUND (400)
      • APPEAL_PDF_COPY_GENERATION_FAILED (400)
    • preserved success output contract (PDF content headers + buffer body)
  • getsipsmedia_api.js and getappealtypesfornewappeal_api.js:
    • added method guard for non-GET requests using METHOD_NOT_ALLOWED (405)
    • preserved existing GET success payloads
  • Expanded phase21 tests:
    • file-handler-contract.test.cjs: added coverage for download failure + full generated PDF copy contract/negative paths
    • endpoint-handler-contract.test.cjs: added method guard tests for both static endpoints

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 17/17
    • email-handler: 12/12
    • endpoint-handler: 149/149
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • If desired, next slice can target remaining file-route parity candidates outside this bundle, but this closes the planned TASK22224 scope.

CL-005: TASK22224 downloadblob hotfix closure (path normalization + hash compatibility)

date: 2026-03-23 author: Cline scope: pages/api/file/downloadblob.js type: change rationale: Close post-merge runtime regressions reported on live links where download URLs alternated between filename-only/full-path blob names and mixed encoded/raw hash input variants. impact: Restored reliable blob downloads without relaxing hash security guarantees (still HMAC validated), and preserved existing caller compatibility across legacy/new URL encodings. status: completed

Summary:

  • Hotfix 1 (f09f3b7): normalized blob path resolution
    • accepts both forms of blobname input:
      • filename only (legacy)
      • full prefixed path (already includes casefolderID/...)
    • prevents double-prefix lookup failures
    • sets attachment filename from final path segment only
  • Hotfix 2 (bd3bf68): hash compatibility validation
    • validates against a bounded set of canonical query-path variants (raw/encoded combinations for casefolderID and blobname)
    • fixes INVALID_HASH false negatives for legitimate caller-generated links
    • keeps strict HMAC requirement in place (no unauthenticated bypass)

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (17/17)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 17/17
    • email-handler: 12/12
    • endpoint-handler: 149/149
  • User confirmation: "downloadblob now works"

Follow-ups:

  • Next recommended slice on this branch: complete file-route guard parity for deleteblob.js, deleteblobcase.js, and deleteblobrep.js by aligning hash validation canonicalization and explicit respondError contracts (MISSING_REQUIRED_QUERY, INVALID_HASH, operation-specific *_FAILED).
  • Extend tests/phase21/file-handler-contract.test.cjs for the above routes with mixed encoded/raw hash cases to lock compatibility.

CL-006: TASK22224 file delete-route guard parity slice

date: 2026-03-23 author: Cline scope: pages/api/file/{deleteblob,deleteblobcase,deleteblobrep}.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Execute the next planned slice to align hash/canonicalization behavior and negative-path contracts across high-risk file delete routes, matching the compatibility posture established for downloadblob. impact: Reduces false INVALID_HASH failures for legitimate encoded/raw caller variants while preserving strict hash enforcement and improving resilience via explicit catch-path contracts. status: completed

Summary:

  • deleteblob.js
    • added bounded hash candidate validation for encoded/raw combinations of casefolderID and blobname
    • normalized delete path handling for both filename-only and already-prefixed blob paths
    • added explicit catch-path contract: DELETE_BLOB_FAILED
  • deleteblobcase.js
    • added hash candidate validation for raw/encoded casefolderID
    • added explicit catch-path contract: DELETE_BLOB_CASE_FAILED
  • deleteblobrep.js
    • added hash candidate validation for encoded/raw casefolderID + repfile
    • added explicit catch-path contract: DELETE_BLOB_REP_FAILED
  • Phase21 tests expanded (file-handler-contract.test.cjs):
    • encoded hash-variant acceptance cases for all three delete routes
    • explicit dependency-failure contract assertions for all three delete routes

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (23/23)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 23/23
    • email-handler: 12/12
    • endpoint-handler: 149/149

Follow-ups:

  • Optional next slice: apply same bounded hash-canonicalization parity to remaining high-sensitivity file routes where mixed encoded/raw callers may exist (getbloblist, getprogressobjblob) and add regression cases to phase21.

CL-007: TASK22224 getrepsblob stability hotfix after delete representation flow

date: 2026-03-23 author: Cline scope: actions/azurestorage.js (getRepsBlobs), tests/phase21/file-handler-contract.test.cjs type: change rationale: Resolve reported runtime 400 (GET_REPS_BLOB_FAILED) after delete representation actions, caused by stale soft-deleted blob tag hits during representation blob enumeration. impact: Prevents transient/stale Azure tag index entries from breaking representation retrieval, improving reliability of post-delete refresh without relaxing route security contracts. status: completed

Summary:

  • Hardened getRepsBlobs(containerName) in actions/azurestorage.js:
    • fixed async misuse (blobClient.getProperties().contentLength without await)
    • added existence/property guard with explicit await blobClient.getProperties()
    • skips 404s (soft-deleted/stale tag index results) instead of throwing
    • preserves behavior for non-404 failures (rethrow for proper error visibility)
    • kept existing _rep.json/undefined name filtering intact
  • Added phase21 contract coverage for getrepsblob route:
    • success payload contract test
    • dependency failure contract test (GET_REPS_BLOB_FAILED)

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (25/25)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 25/25
    • email-handler: 12/12
    • endpoint-handler: 149/149

Follow-ups:

  • Optional: add the same stale-tag existence guard pattern to any remaining Azure tag-list readers that still consume findBlobsByTags results without property existence verification.

CL-008: TASK22224 awaiting-submission route resilience parity hardening

date: 2026-03-23 author: Cline scope: pages/api/file/getawaitingsubmissionfromblob.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Add explicit catch-path contract parity for awaiting-submission blob retrieval route so unexpected dependency failures return consistent, actionable error envelopes. impact: Improves reliability/diagnostics for post-delete case refresh and aligns file-route error handling style without changing success payload contract or hash verification behavior. status: completed

Summary:

  • Refactored getawaitingsubmissionfromblob handler to structured try/catch flow.
  • Preserved existing guard behavior:
    • MISSING_REQUIRED_QUERY for missing container/hash
    • INVALID_HASH for signature mismatch
  • Added explicit dependency failure contract:
    • GET_AWAITING_SUBMISSION_BLOB_FAILED (400)
    • message: Failed to retrieve awaiting submission blobs
  • Added phase21 coverage for this route:
    • success payload pass-through contract
    • dependency failure contract assertion

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (27/27)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 27/27
    • email-handler: 12/12
    • endpoint-handler: 149/149

Follow-ups:

  • Optional parity sweep: apply the same explicit catch-path contract pattern to remaining file routes that still rely on implicit promise-chain errors.

CL-009: TASK22224 proxy-route resilience and encoding parity bundle

date: 2026-03-23 author: Cline scope: pages/api/file/{getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy,createappealcompletemessageproxy_api}.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Continue larger-slice hardening by aligning proxy handlers with explicit async error handling and safer encoded upstream query forwarding for hash-based downstream calls. impact: Improves proxy reliability and compatibility for encoded query values while preserving existing proxy error contracts and response behavior. status: completed

Summary:

  • getbloblistproxy.js
    • converted .then/.catch chain to explicit try/catch
    • encoded forwarded container and casefolderID query values
    • preserved error contract: GET_BLOB_LIST_PROXY_FAILED
  • getrepsblobproxy.js
    • converted .then/.catch chain to explicit try/catch
    • encoded forwarded container
    • preserved error contract: GET_REPS_BLOB_PROXY_FAILED
  • getawaitingsubmissionfromblobproxy.js
    • converted .then/.catch chain to explicit try/catch
    • preserved error contract: GET_AWAITING_SUBMISSION_PROXY_FAILED
  • createappealcompletemessageproxy_api.js
    • converted .then/.catch chain to explicit try/catch
    • encoded forwarded container and tempcaseref
    • preserved error contract: CREATE_APPEAL_COMPLETE_MESSAGE_PROXY_FAILED
  • Phase21 tests expanded for proxy paths:
    • getbloblistproxy success + dependency failure
    • getrepsblobproxy success
    • getawaitingsubmissionfromblobproxy dependency failure
    • createappealcompletemessageproxy dependency failure

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (46/46)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 46/46
    • email-handler: 12/12
    • endpoint-handler: 149/149

Follow-ups:

  • Optional next big slice: bring remaining proxy/message routes using raw axios promise chains (createcaseinvolvement_api.js, createrepinvolvement_api.js, updatecase_api.js) onto the same async/await + explicit contract pattern.

CL-010: TASK22224 involvement/update route async contract hardening bundle

date: 2026-03-23 author: Cline scope: pages/api/file/{createcaseinvolvement_api,createrepinvolvement_api,updatecase_api}.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Execute the next requested slice by modernizing remaining relay-backed involvement/update handlers that still used axios promise chains and legacy dead imports. impact: Improves reliability/readability and preserves existing response contracts, including 412 "record exists" semantics for involvement creation flows. status: completed

Summary:

  • createcaseinvolvement_api.js
    • removed unused CryptoJS import
    • refactored axios .then/.catch to explicit try/catch
    • preserved conflict behavior: status 412 -> success { record: "exists" }
    • preserved failure contract: CREATE_CASE_INVOLVEMENT_FAILED
  • createrepinvolvement_api.js
    • removed unused CryptoJS import
    • refactored axios .then/.catch to explicit try/catch
    • preserved conflict behavior: status 412 -> success { record: "exists" }
    • preserved failure contract: CREATE_REP_INVOLVEMENT_FAILED
  • updatecase_api.js
    • removed unused CryptoJS import
    • refactored axios .then/.catch to explicit try/catch
    • preserved failure contract: UPDATE_CASE_FAILED
  • Phase21 tests expanded:
    • createcaseinvolvement 412 conflict success contract
    • createrepinvolvement dependency failure contract
    • updatecase dependency failure contract

Validation:

  • node tests/phase21/file-handler-contract.test.cjs -> pass (49/49)
  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 49/49
    • email-handler: 12/12
    • endpoint-handler: 149/149

Follow-ups:

  • Optional: apply equivalent modernization to any remaining relay-backed handlers outside pages/api/file/ that still use raw axios promise chains and have no explicit phase21 contract assertions.

CL-011: TASK22224 aggressive non-file bundle (email/admin/endpoint parity)

date: 2026-03-23 author: Cline scope: pages/api/email/{getmailinglist,getcaseref,notify}.js, pages/api/admin/{getnewappeals_api,getlatestdocuments_api}.js, pages/api/endpoint/getportallogin_api.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Execute requested aggressive bundling for remaining non-file modernization/parity candidates: remove legacy promise chains and improve hash compatibility on login endpoint while preserving existing contracts. impact: Improves consistency and resilience across email/admin/endpoint routes with no contract regressions; adds encoded hash-variant compatibility for portal login hash checks. status: completed

Summary:

  • pages/api/email/getmailinglist.js
    • converted axios .then/.catch to try/catch
    • preserved flattening behavior and error contract MAILING_LIST_FETCH_FAILED
  • pages/api/email/getcaseref.js
    • converted axios .then/.catch to try/catch
    • preserved flattening behavior and error contract CASE_REF_FETCH_FAILED
  • pages/api/email/notify.js
    • converted notify client .then/.catch to try/catch
    • preserved success payload and error contract EMAIL_NOTIFY_FAILED
  • pages/api/admin/getnewappeals_api.js
    • removed unused CryptoJS import
    • converted axios .then/.catch to try/catch
    • preserved @odata.nextLink normalization and error contract ADMIN_NEW_APPEALS_FETCH_FAILED
  • pages/api/admin/getlatestdocuments_api.js
    • converted axios .then/.catch to try/catch
    • preserved flatten/enrich behavior and error contract ADMIN_LATEST_DOCS_FETCH_FAILED
  • pages/api/endpoint/getportallogin_api.js
    • retained required query/hash guards
    • expanded hash validation to accept raw + encoded emailAddress query-path candidates
    • preserved error contract PORTAL_LOGIN_FETCH_FAILED
  • phase21 endpoint tests expanded:
    • getportallogin encoded hash variant success path
    • getnewappeals_api catch contract
    • getlatestdocuments_api catch contract

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 49/49
    • email-handler: 12/12
    • endpoint-handler: 152/152

Follow-ups:

  • Remaining major modernization candidate is pages/api/file/generateappealpdf.js (+ optional pages/api/file/generatepdf.js) if we continue final closure slices.

CL-012: TASK22224 generatepdf/generateappealpdf async hardening slice

date: 2026-03-23 author: Cline scope: pages/api/file/{generateappealpdf,generatepdf}.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Execute next requested slice to modernize remaining file PDF-generation handlers still using promise chains, while preserving existing hash/response behavior. impact: Improves maintainability and error-path consistency for PDF generation routes; phase21 coverage now includes explicit failure contracts for both handlers. status: completed

Summary:

  • pages/api/file/generateappealpdf.js
    • converted mixed promise-chain flow to async/await + try/catch
    • preserved existing guard contracts: MISSING_REQUIRED_QUERY, INVALID_HASH
    • preserved generation failure contract: GENERATE_APPEAL_PDF_FAILED
    • replaced JSX render call with React.createElement(...) compatibility form used by test loader
  • pages/api/file/generatepdf.js
    • converted create/upload promise-chain to async/await + try/catch
    • preserved existing guard contracts: HASH_REQUIRED, INVALID_HASH
    • preserved generation failure contract: GENERATE_PDF_FAILED
    • replaced JSX render call with React.createElement(...) compatibility form used by test loader
  • phase21 file tests expanded:
    • generatepdf catch-path contract (GENERATE_PDF_FAILED)
    • generateappealpdf catch-path contract (GENERATE_APPEAL_PDF_FAILED)

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 51/51
    • email-handler: 12/12
    • endpoint-handler: 152/152

Follow-ups:

  • Remaining optional cleanup in these handlers is dead import/unused local pruning (non-behavioral) if we want a final low-risk tidy pass.

CL-013: TASK22224 completion-message route parity closure slice

date: 2026-03-24 author: Cline scope: pages/api/file/createappealcompletemessage_api.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Continue next requested slice by closing the final promise-chain parity outlier in file completion-message flow and strengthening phase21 contract coverage. impact: Improves maintainability and async error hygiene while preserving route behavior and existing error contracts. status: completed

Summary:

  • pages/api/file/createappealcompletemessage_api.js
    • replaced inline .catch(...) on fire-and-forget updateAccount(...) with explicit async IIFE + try/catch and void invocation
    • preserved non-blocking behavior and logging semantics for account-update failure path
    • preserved primary route contracts and success payload ({ status: "success" })
  • phase21 file contract tests expanded:
    • success path for encoded hash candidate on createappealcompletemessage_api
    • dependency-failure contract assertion for CREATE_APPEAL_COMPLETE_MESSAGE_FAILED

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152

Follow-ups:

  • Optional final low-risk tidy sweep: remove dead imports/unused locals in legacy file handlers now that contract hardening stream is functionally complete.

CL-014: TASK22224 pdf render compatibility tidy slice

date: 2026-03-24 author: Cline scope: pages/api/file/{generatepdf,generateappealpdf}.js, tests/phase21/file-handler-contract.test.cjs type: change rationale: Apply a low-risk compatibility tidy so PDF render invocation remains stable across runtime and contract-test VM contexts. impact: Keeps functional behavior unchanged while reducing test/runtime mismatch risk in render path setup. status: completed

Summary:

  • pages/api/file/generatepdf.js
    • switched render call input from React.createElement(MyDocument, ...) to direct MyDocument(...) invocation in ReactPDF.renderToStream(...)
  • pages/api/file/generateappealpdf.js
    • switched render call input from React.createElement(MyDocument, ...) to direct MyDocument(...) invocation in ReactPDF.renderToStream(...)
  • tests/phase21/file-handler-contract.test.cjs
    • added Buffer injection for generatepdf catch-path test harness to align VM context expectations

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152

Follow-ups:

  • Optional: dead import cleanup (Document/Page/Text/View/StyleSheet/PDFViewer, middleware, nextConnect, fs, etc.) can be done in a dedicated non-behavioral hygiene PR.

CL-015: TASK22224 pdf handler dead-code hygiene slice

date: 2026-03-24 author: Cline scope: pages/api/file/{generatepdf,generateappealpdf}.js type: change rationale: Execute the requested next low-risk slice by removing dead imports and unused locals in recently hardened PDF handlers. impact: Non-behavioral maintainability cleanup; reduces lint noise and future edit risk while preserving existing contracts. status: completed

Summary:

  • pages/api/file/generatepdf.js
    • pruned unused Azure storage imports, leaving only createRepPDFBlob
    • pruned unused @react-pdf/renderer named imports
    • removed unused imports (middleware, nextConnect, fs)
    • removed unused locals (casefolderID, representationType, repRaiser, localeSelect, repCapacity, repType)
  • pages/api/file/generateappealpdf.js
    • pruned unused Azure storage imports to only required functions
    • pruned unused @react-pdf/renderer named imports
    • removed unused imports (middleware, nextConnect, fs, path, unused pdf templates)
    • removed unused local (caseRef)

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152

Follow-ups:

  • Optional: run full repo lint in a separate pass for broader non-slice hygiene now that targeted contract suite is stable.

CL-016: TASK22224 documents download contract slice

date: 2026-03-24 author: Cline scope: pages/api/documents/download/[id].js, tests/phase21/{documents-handler-contract,api-contract-slice1}.test.cjs type: change rationale: Execute next aggressive slice by standardizing document download guard behavior and bringing the route under phase21 contract coverage. impact: Improves reliability on invalid input and relay-failure paths while preserving existing user-visible fallback behavior (/filenotavailable) for download failures. status: completed

Summary:

  • pages/api/documents/download/[id].js
    • added explicit required-query guard for id and hash
    • unified fallback redirect path via constant (/filenotavailable)
    • preserved streaming download behavior and retry flow
  • added tests/phase21/documents-handler-contract.test.cjs covering:
    • missing query -> redirect contract
    • success -> attachment/content-type headers + stream pipe contract
    • relay failure -> redirect contract
  • updated combined runner (tests/phase21/api-contract-slice1.test.cjs) to include documents handler contract suite

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Optional future hardening: migrate documents route onto shared respondError/respondSuccess envelope if product requirements allow replacing redirect-style fallback.

CL-017: TASK22224 endpoint legacy-comment hygiene slice

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{createwatchedcases_api,getadvancedsearchpaged_api}.js type: change rationale: Complete second requested slice with low-risk maintainability cleanup by removing large obsolete commented legacy handler blocks. impact: Non-behavioral cleanup only; improves readability and reduces maintenance noise with no runtime contract changes. status: completed

Summary:

  • createwatchedcases_api.js
    • removed obsolete commented promise-chain implementation block
  • getadvancedsearchpaged_api.js
    • removed obsolete commented legacy implementation block retained below active handler

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Optional further hygiene pass can target remaining oversized commented historical sections in non-sensitive handlers.

CL-018: TASK22224 nextauth notify micro-refactor

date: 2026-03-24 author: Cline scope: pages/api/auth/[...nextauth].js type: change rationale: Execute the explicitly approved auth micro-slice by replacing inline promise .catch(...) with explicit try/catch while preserving existing auth behavior. impact: Auth-sensitive non-functional refactor only; keeps current sign-in flow, template/locale routing, and error-handling semantics unchanged. status: completed

Summary:

  • pages/api/auth/[...nextauth].js
    • replaced:
      • await notifyClient.sendEmail(...).catch((error) => consoleLogger(error))
    • with explicit:
      • try { await notifyClient.sendEmail(...) } catch (error) { consoleLogger(error) }
  • preserved behavior contracts:
    • Notify failures are still logged and do not throw through auth handler
    • no changes to callback URL construction, locale/template selection, NextAuth options, session/cookies/pages config

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Optional future auth hygiene (separate guarded slice): replace verbose auth console.log diagnostics with structured logger usage once production logging requirements are confirmed.

CL-019: TASK22229 P2-S1 relay forwarding pilot (proxy endpoint cluster)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, pages/api/endpoint/{getwatchedcasesproxy_api,getmyrepresentationsproxy_api,getrepresentationsproxy_api,getawaitingsubmissionproxy_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Start Priority-2 by piloting a shared relay forwarding helper on a bounded proxy endpoint cluster to reduce duplicated token/hash/header/axios boilerplate while preserving endpoint contracts. impact: Maintainability and consistency improvement with no intended behavioral contract changes; error code/status/message and success payload contracts remain unchanged for migrated endpoints. status: completed

Summary:

  • Added shared relay helper:
    • pages/api/middleware/relayForwarding.js
    • exports relayGet({ queryUrl, res, errorResponse, transformData })
    • centralizes token fetch, relay URL + hash composition, azureHeaders, GET execution, success/error response handling, and logging
  • Migrated pilot endpoint cluster to relayGet:
    • getwatchedcasesproxy_api.js (with existing payload transform preserved)
    • getmyrepresentationsproxy_api.js
    • getrepresentationsproxy_api.js
    • getawaitingsubmissionproxy_api.js (with existing payload transform preserved)
  • Updated endpoint contract tests to mock relayGet for migrated routes while preserving existing assertions.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • P2-S2 rollout: migrate the next relay-heavy endpoint batch onto relayGet/shared forwarding utility pattern.
  • P2-S3 hardening: add shared timeout/retry config and redacted structured relay error logging policy.

CL-020: TASK22229 P2-S2 Batch 1 (account/login relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getlogin_api,getpersonalaccount_api,getportalloginproxy_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Deliver first P2-S2 batch as a dedicated commit by migrating a bounded account/login endpoint cluster onto shared relayGet while preserving response contracts. impact: Reduced relay boilerplate and improved consistency with no intended endpoint contract changes. status: completed

Summary:

  • Extended relayGet to support optional requestOptionsBuilder for handlers requiring paged header variants.
  • Migrated Batch 1 endpoints to relayGet:
    • getaccounts_api.js
    • getemailaccountcheck_api.js
    • getpreferredlanguage_api.js
    • getlogin_api.js (uses azureHeadersPaged via requestOptionsBuilder)
    • getpersonalaccount_api.js
    • getportalloginproxy_api.js (uses azureHeadersPaged via requestOptionsBuilder)
  • Updated phase21 endpoint contract tests to mock relayGet for migrated handlers, preserving existing guard/catch/success assertions.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Continue P2-S2 with Batch 2 as next dedicated commit on this same branch.

CL-021: TASK22229 P2-S2 Batch 2 (my-portal + representation relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getmycases_api,getmyrepresentations_api,getwatchedcases_api,getawaitingsubmission_api,getrepresentations_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Deliver second P2-S2 commit by migrating the next bounded portal/representation GET endpoint cluster onto shared relayGet while preserving route contracts. impact: Reduced duplicated relay boilerplate and aligned forwarding behavior with no intended response contract changes. status: completed

Summary:

  • Migrated Batch 2 endpoints to relayGet:
    • getmycases_api.js (preserved title mapping transform)
    • getmyrepresentations_api.js
    • getwatchedcases_api.js (preserved watched-case projection transform)
    • getawaitingsubmission_api.js (preserved title mapping transform)
    • getrepresentations_api.js
  • Updated phase21 endpoint contract tests for migrated handlers by mocking relayGet in guard/catch test paths.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Continue P2-S2 with Batch 3 as the next dedicated commit on this branch.

CL-022: TASK22229 P2-S2 Batch 3 (case/event relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getcase_api,getcasebyid_api,getincidentbyid_api,getsipsevents_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Deliver third P2-S2 commit by migrating an additional bounded case/event endpoint cluster onto shared relayGet while preserving route contracts. impact: Further relay boilerplate reduction and consistent forwarding behavior with no intended contract changes. status: completed

Summary:

  • Migrated Batch 3 endpoints to relayGet:
    • getcase_api.js (preserved @odata.nextLink normalization)
    • getcasebyid_api.js (preserved @odata.nextLink normalization and array-wrapped success payload)
    • getincidentbyid_api.js
    • getsipsevents_api.js
  • Updated phase21 endpoint contract tests to mock relayGet for migrated handlers in guard/catch paths.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 152/152
    • documents-handler: 3/3

Follow-ups:

  • Continue P2-S2 with next bounded batch (e.g. search/listing cluster) as a separate commit if required.

CL-023: TASK22229 P2-S2 Batch 6 (profile/form/document-history/portal-module relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getpersonalaccount_api,getformdata_api,getsearchdocumenthistory_api,getsearchdocumenthistorypaged_api,getportalmoduledetails_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Execute requested Batch 6 by migrating the next bounded set of read-only endpoint handlers to shared relayGet while preserving existing request validation and response/error contracts. impact: Reduced endpoint relay boilerplate and improved consistency; no intended behavior contract changes. status: completed

Summary:

  • Migrated Batch 6 endpoints to shared relayGet:
    • getpersonalaccount_api.js
    • getformdata_api.js
    • getsearchdocumenthistory_api.js (uses requestOptionsBuilder with azureHeadersPaged)
    • getsearchdocumenthistorypaged_api.js (uses requestOptionsBuilder with azureHeadersPaged)
    • getportalmoduledetails_api.js
  • Preserved all existing required-query validation guards and existing error codes/messages.
  • Updated Phase 21 endpoint contract tests to inject relayGet mocks for migrated handlers (validation path, catch path, and success path where applicable).

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded batch: migrate remaining legacy relay GET handlers in advanced/basic search-document/detail clusters that still use direct axios relay patterns.

CL-024: TASK22229 P2-S2 Batch 7 (search-document + portal-proxy relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getportalmoduledetailsproxy_api,getsearchdocumentTypes_api,getsearchdocumentdetails_api,getsearchdocumentdetailspaged_api,getappealpdfdocuments_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue P2-S2 in bounded commits by migrating a coherent search-document/portal-proxy GET cluster onto shared relay forwarding while preserving existing validation, transforms, and error contracts. impact: Reduced duplicate relay plumbing and improved consistency in search-document handlers; no intended API contract changes. status: completed

Summary:

  • Migrated Batch 7 endpoints to shared relayGet:
    • getportalmoduledetailsproxy_api.js
    • getsearchdocumentTypes_api.js
    • getsearchdocumentdetails_api.js
    • getsearchdocumentdetailspaged_api.js
    • getappealpdfdocuments_api.js
  • Preserved existing guard behavior and error response contracts.
  • Preserved endpoint-specific transform behavior via transformData, including:
    • grouped search-document type payloads
    • document hashlink enrichment and published-date normalization
    • @odata.nextLink normalization where present
    • appeal PDF document name projection
  • Updated phase21 endpoint tests to mock relayGet for migrated handlers in validation/catch/success paths as applicable.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue with next bounded P2-S2 batch from remaining legacy GET endpoints (e.g., advanced/basic paged search-detail clusters and related non-migrated proxies).

CL-025: TASK22229 P2-S2 Batch 8 (basic search details + DNS details relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getbasicsearchpaged_api,getbasicsearchdetails_api,getbasicsearchdetailspaged_api,getbasicdnssearchdetails_api,getbasicdnssearchdetailspaged_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue the P2-S2 relay migration using bounded commits by moving the remaining basic-search-details and DNS-details GET handlers to shared relayGet, preserving existing guards and response contracts. impact: Reduced duplicated relay plumbing and more consistent forwarding behavior across search-detail handlers; no intended API contract changes. status: completed

Summary:

  • Migrated Batch 8 endpoints to shared relayGet:
    • getbasicsearchpaged_api.js
    • getbasicsearchdetails_api.js
    • getbasicsearchdetailspaged_api.js
    • getbasicdnssearchdetails_api.js
    • getbasicdnssearchdetailspaged_api.js
  • Preserved existing validation guards and error contracts.
  • Preserved existing endpoint-specific transforms:
    • @odata.nextLink normalization in paged responses
    • flattened ticketnumber enrichment for search detail handlers
  • Updated phase21 endpoint contract tests to inject relayGet mocks for migrated handlers in validation and catch-path tests.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue P2-S2 with next bounded batch from remaining legacy GET endpoints (currently: createwatchedcases_api, deletewatchedcasesproxy_api, getadvancedsearch_api, getadvancedsearchpaged_api, getappealid_api, getbasicdnssearchpaged_api, getbasicpartsaveddetails_api, getbasicsearch_by_address_api, getbasicsearch_by_lparref_api, getdnscoords_api, getdnslist_api, getmylpacases_api, getportallogin_api).

CL-026: TASK22229 P2-S2 Batch 9 (appeal-id + DNS list/paged + part-saved relay GET cluster)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getappealid_api,getbasicdnssearchpaged_api,getbasicpartsaveddetails_api,getdnslist_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue bounded P2-S2 relay migration by moving another coherent set of read-only handlers to shared relayGet, preserving existing guards, transforms, and error contracts. impact: Reduced duplicated relay plumbing and improved consistency for DNS list/paged and appeal detail lookup endpoints; no intended API contract changes. status: completed

Summary:

  • Migrated Batch 9 endpoints to shared relayGet:
    • getappealid_api.js
    • getbasicdnssearchpaged_api.js
    • getbasicpartsaveddetails_api.js
    • getdnslist_api.js
  • Preserved existing input validation guards and endpoint-specific error contracts.
  • Preserved endpoint-specific transform behavior (@odata.nextLink normalization in DNS list/paged handlers).
  • Updated phase21 endpoint contract tests to inject relayGet mocks for these migrated handlers in guard and catch-path assertions.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue P2-S2 with next bounded batch from remaining legacy relay GET endpoints (createwatchedcases_api, deletewatchedcasesproxy_api, getadvancedsearch_api, getadvancedsearchpaged_api, getbasicsearch_by_address_api, getbasicsearch_by_lparref_api, getdnscoords_api, getmylpacases_api, getportallogin_api).

CL-027: TASK22229 P2-S2 Batch 10 (portal login + my LPA cases relay GET pair)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getportallogin_api,getmylpacases_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue bounded relay migration by moving two remaining high-use portal retrieval endpoints to shared relayGet while preserving existing hash/lookup guards and response contracts. impact: Further relay boilerplate reduction and consistent forwarding behavior in portal login/LPA case retrieval flows; no intended API contract changes. status: completed

Summary:

  • Migrated Batch 10 endpoints to shared relayGet:
    • getportallogin_api.js (preserved hash validation guard and error contract)
    • getmylpacases_api.js (preserved LPA lookup/404 guard and title transform)
  • Preserved endpoint-specific behavior:
    • getportallogin_api: raw + encoded hash candidate validation before relay call
    • getmylpacases_api: JSONPath LPA lookup with LPA_NOT_FOUND handling and pinswg_title enrichment transform
  • Updated phase21 endpoint contract tests to inject relayGet mocks for migrated handlers in validation/catch/success paths.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue P2-S2 with the remaining legacy relay GET candidates (createwatchedcases_api, deletewatchedcasesproxy_api, getadvancedsearch_api, getadvancedsearchpaged_api, getbasicsearch_by_address_api, getbasicsearch_by_lparref_api, getdnscoords_api).

CL-028: TASK22229 P2-S2 Batch 11 (advanced-search-paged relay GET)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/getadvancedsearchpaged_api.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue bounded relay migration by moving the remaining advanced-search paged GET handler to shared relayGet while preserving query validation and response contracts. impact: Reduced duplicated relay plumbing and aligned advanced paged search route with shared forwarding; no intended API contract changes. status: completed

Summary:

  • Migrated getadvancedsearchpaged_api.js to shared relayGet.
  • Preserved existing guard behavior and error contracts:
    • SEARCH_STRING_REQUIRED
    • ORDER_BY_REQUIRED
    • FIELD_SORT_REQUIRED
    • SHOW_NUMBER_OF_RECORDS_REQUIRED
    • INVALID_SEARCH_STRING
    • ADVANCED_SEARCH_PAGED_FETCH_FAILED
  • Preserved endpoint-specific transform behavior (@odata.nextLink normalization via transformData).
  • Updated phase21 endpoint contract tests to inject relayGet mocks for getadvancedsearchpaged_api guard/catch assertions.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Continue P2-S2 with remaining legacy relay GET candidates (createwatchedcases_api, deletewatchedcasesproxy_api, getadvancedsearch_api, getbasicsearch_by_address_api, getbasicsearch_by_lparref_api, getdnscoords_api).

CL-029: TASK22229 P2-S2 Batch 12 (remaining relay GET candidates)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, pages/api/endpoint/{createwatchedcases_api,deletewatchedcasesproxy_api,getadvancedsearch_api,getbasicsearch_by_address_api,getbasicsearch_by_lparref_api,getdnscoords_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Complete Batch 12 by migrating the remaining listed legacy relay GET candidates to shared forwarding helpers while preserving endpoint-specific validation, transforms, and error contracts. impact: Consolidated relay GET behavior and reduced endpoint-level relay boilerplate; no intended API contract changes. status: completed

Summary:

  • Extended relay middleware with reusable helpers:
    • relayGetData now supports token reuse via transformData path
    • Added forwardGetData to support custom base URLs (used by proxy-to-local endpoint) while preserving hash behavior
  • Migrated remaining Batch 12 candidates:
    • getadvancedsearch_api.js -> relayGet + relayGetData for project-type enrichment loop
    • getdnscoords_api.js -> relayGetData for both DNS + SIPS source pulls
    • getbasicsearch_by_lparref_api.js -> relayGetData
    • getbasicsearch_by_address_api.js -> relayGetData for appeal-type and incident fetches
    • deletewatchedcasesproxy_api.js -> forwardGetData with BASE_URL
    • createwatchedcases_api.js -> relayGetData for record-exists pre-check (POST/PATCH upsert flow preserved)
  • Preserved endpoint-specific guard and error contracts (including status codes such as 500 for BASIC_SEARCH_BY_ADDRESS_FETCH_FAILED).
  • Updated phase21 endpoint contract tests for migrated handlers to mock relayGetData / forwardGetData where appropriate.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Batch 12 completes the previously listed remaining P2-S2 relay GET candidates.

CL-030: TASK22236 P2-S3 relay forwarding hardening (timeouts, retries, structured redacted logs)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, tests/phase21/relay-forwarding-hardening.test.cjs type: change rationale: Begin P2-S3 by hardening shared relay forwarding behavior with bounded timeout/retry controls and structured redacted operational logging, reducing transient failure impact while preserving endpoint contracts. impact: Improves resilience/observability for relay GET traffic; endpoint success/error contracts remain unchanged because caller handlers still manage response envelopes. status: completed

Summary:

  • Hardened forwardGetData in relayForwarding.js with:
    • configurable timeout (RELAY_TIMEOUT_MS, default 8000ms)
    • bounded retries (RELAY_RETRY_MAX, default 2)
    • exponential backoff with cap (RELAY_RETRY_BASE_DELAY_MS, RELAY_RETRY_MAX_DELAY_MS)
    • retry eligibility for transient statuses/codes (408/429/5xx, selected network timeout/reset codes)
  • Added structured, redacted operational relay logs:
    • relay_request_retrying
    • relay_request_failed
  • Preserved compatibility behaviors:
    • existing token/header/hash handling
    • optional appendHash and custom requestOptionsBuilder
    • endpoint-level relayGet error response semantics
  • Added focused Phase 21 hardening tests:
    • retries on retryable status and succeeds
    • does not retry non-retryable status
    • applies timeout and respects appendHash=false

Validation:

  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (3/3)
  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next hardening increment: introduce endpoint-specific retry overrides for write paths (if future non-GET use is introduced) to keep retry policy conservative by operation type.

CL-031: TASK22236 P2-S3 Batch 2A policy tightening (retry classification, config clamping, log de-dup)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, tests/phase21/relay-forwarding-hardening.test.cjs type: change rationale: Execute P2-S3 Batch 2A by tightening relay retry policy and operational safety bounds while preventing duplicate error noise between relay-layer and endpoint-layer logging. impact: Stronger resilience and cleaner observability with no endpoint contract changes; retry behavior is now explicitly conservative for deterministic client/auth failures. status: completed

Summary:

  • Updated relay retry policy:
    • explicitly non-retryable statuses: 400, 401, 403, 404, 422
    • retries still allowed for transient classes (408, 429, 5xx) and selected transport error codes
    • any other explicit numeric HTTP status now treated as non-retryable by default
  • Added runtime-safe config clamping for relay knobs:
    • timeout clamped to 100..30000ms
    • retries clamped to 0..4
    • retry delays clamped to 0..5000ms
    • both env-derived and per-call numeric overrides are sanitized
  • Reduced duplicate logging noise:
    • non-retry terminal relay failures are marked as already logged in middleware
    • relayGet catch now skips consoleLogger when relay layer has already emitted a structured log
  • Expanded relay hardening tests:
    • no retry on 401
    • duplicate logging suppression path through relayGet
    • env-value clamping behavior for timeout bounds

Validation:

  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (6/6)
  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Batch 2B: update memory/context docs with canonical relay hardening policy, env knobs, and rollback/tuning guidance.

CL-032: TASK22239 governance + operational rollout playbook bundle (relay hardening)

date: 2026-03-24 author: Cline scope: context/runbook.md, context/integration-map.md, memory-bank/{change-log,decisions,patterns}.md type: change rationale: Deliver a combined governance and operational rollout slice after P2-S3 code hardening so relay policy changes have explicit merge gates, smoke matrix coverage, and rollback/monitoring discipline. impact: Improves release safety and auditability for relay policy updates without changing runtime endpoint behavior. status: completed

Summary:

  • Added a dedicated Relay Hardening Rollout Playbook section to context/runbook.md covering:
    • pre-merge governance gate checklist
    • non-prod smoke matrix for deterministic and transient failure classes
    • progressive rollout guidance
    • Day 1/Day 3 monitoring checks
    • fast mitigation/rollback sequence
  • Added relay policy governance references in architecture/integration context docs to make rollout checks discoverable for future contributors.
  • Recorded governance baseline updates in memory-bank:
    • decision entry for relay policy-change governance gate
    • reusable pattern entry for required rollout/smoke/rollback workflow

Validation:

  • Documentation consistency review across context/runbook.md, context/integration-map.md, and memory-bank entries.

Follow-ups:

  • Optional next iteration: add a PR template block in Azure DevOps mirroring the runbook governance gate checklist.

CL-033: TASK22242 relay telemetry enrichment (lifecycle events + correlation fields)

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, tests/phase21/relay-forwarding-hardening.test.cjs type: change rationale: Add richer relay observability so operations can correlate retries and outcomes per request and track latency/status patterns without changing endpoint contracts. impact: Improves operational diagnostics and trend analysis for relay traffic while preserving existing API behavior. status: completed

Summary:

  • Enriched relay middleware telemetry with request lifecycle events:
    • relay_request_started
    • relay_request_retrying
    • relay_request_succeeded
    • relay_request_failed
  • Added shared telemetry fields for correlation and analysis:
    • relayRequestId (per request correlation id)
    • attemptsMade, retryCountUsed, remainingRetries
    • elapsedMs
    • statusClass (2xx/4xx/5xx style buckets)
    • resolved runtime knobs included at start event
  • Kept existing retry policy and endpoint response contracts unchanged.
  • Expanded phase21 relay hardening tests to assert telemetry behavior:
    • started/retrying/succeeded event presence
    • failed event telemetry fields
    • stable relayRequestId across lifecycle events for one request

Validation:

  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (7/7)
  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next step: map these lifecycle fields into central dashboards/alerts (retry rate, status-class distribution, p95 elapsedMs).

CL-034: TASK22242 per-endpoint relay overrides + idempotency-aware retry gating

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayForwarding.js, tests/phase21/relay-forwarding-hardening.test.cjs type: change rationale: Deliver the next functional relay enhancement by enabling route-level retry tuning while adding safe-by-default retry gating for non-idempotent methods. impact: Improves control and safety of relay retries without breaking existing endpoint contracts. status: completed

Summary:

  • Added relay policy override support (relayPolicy) to shared relay helpers (relayGet, relayGetData, forwardGetData):
    • per-call override of timeoutMs, maxRetries, retryBaseDelayMs, retryMaxDelayMs
    • optional method override via relayPolicy.method
  • Added idempotency-aware retry gating scaffolding:
    • retries allowed by default only for idempotent methods (GET, HEAD, OPTIONS)
    • non-idempotent retry behavior controlled by:
      • env flag RELAY_ALLOW_NON_IDEMPOTENT_RETRIES (default false)
      • per-call override relayPolicy.allowNonIdempotentRetries
  • Extended relay telemetry fields to include method and non-idempotent policy posture in start/failure/retry events.
  • Preserved existing route behavior:
    • existing GET endpoint flows continue to use retries per configured bounds
    • no endpoint response contract changes

Validation:

  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (10/10)
  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (152/152)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Future non-GET relay adoption should explicitly opt in/out per route using relayPolicy and include targeted negative-path tests.

CL-035: TASK22242 apply relayPolicy overrides across broader endpoint cluster

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getpersonalaccount_api,getlogin_api,getbasicsearch_api,getbasicsearchpaged_api,getadvancedsearch_api,getadvancedsearchpaged_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Expand practical adoption of per-endpoint relay policy tuning so high-traffic account/login/search handlers explicitly declare timeout/retry posture rather than relying only on global defaults. impact: Better operational control and predictable retry behavior per endpoint cluster, with no API contract changes. status: completed

Summary:

  • Added explicit relayPolicy usage to a broader endpoint set:
    • account/login: getaccounts, getemailaccountcheck, getpreferredlanguage, getpersonalaccount, getlogin
    • search: getbasicsearch, getbasicsearchpaged, getadvancedsearch, getadvancedsearchpaged
  • Applied conservative policy profiles by flow:
    • login endpoint (getlogin): no retries (maxRetries: 0) and tighter timeout
    • account lookup endpoints: low retry posture (maxRetries: 1)
    • search endpoints: bounded retry posture (maxRetries: 2) for transient resilience
  • Kept method explicit as GET in policy for clarity and future-proofing.
  • Extended phase21 endpoint tests with relayPolicy propagation assertions:
    • getaccounts relayPolicy pass-through
    • getlogin strict relayPolicy pass-through
    • getbasicsearchpaged relayPolicy pass-through

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (155/155)
  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (10/10)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next slice: apply relayPolicy declarations to remaining relayGet endpoints in coherent batches (portal module/documents/DNS groups) and standardize policy presets in one shared constants module.

CL-036: TASK22242 portal-facing relayPolicy parity (login + module endpoints)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getportallogin_api,getportalloginproxy_api,getportalmoduledetails_api,getportalmoduledetailsproxy_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Complete the next practical relay policy rollout slice by bringing portal-facing login/module endpoints onto explicit per-endpoint timeout/retry posture. impact: Improves predictability and operational tuning for portal-facing relay GET flows without changing API contracts. status: completed

Summary:

  • Added explicit relayPolicy for four portal-facing endpoints:
    • getportallogin_api -> strict/no-retry profile (maxRetries: 0, tighter timeout)
    • getportalloginproxy_api -> low-retry account lookup profile (maxRetries: 1)
    • getportalmoduledetails_api -> bounded read profile (maxRetries: 2)
    • getportalmoduledetailsproxy_api -> bounded read profile (maxRetries: 2)
  • Kept method explicit (GET) in each endpoint policy object.
  • Extended phase21 endpoint tests with relayPolicy propagation assertions for all four endpoints.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (159/159)
  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (10/10)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next slice: extract shared relay policy presets into constants to reduce duplication and enforce profile consistency across remaining relayGet endpoints.

CL-037: TASK22242 portal/my-cases relayPolicy parity (my portal + representations)

date: 2026-03-24 author: Cline scope: pages/api/endpoint/{getmycases_api,getmyrepresentations_api,getwatchedcases_api,getawaitingsubmission_api,getrepresentations_api}.js, tests/phase21/endpoint-handler-contract.test.cjs type: change rationale: Continue the branch-by-branch relay policy rollout by applying explicit policy posture to core my-portal retrieval endpoints. impact: Improves consistency and operational predictability of relay behavior for portal case/representation listing flows without changing endpoint contracts. status: completed

Summary:

  • Added explicit relayPolicy declarations to:
    • getmycases_api
    • getmyrepresentations_api
    • getwatchedcases_api
    • getawaitingsubmission_api
    • getrepresentations_api
  • Applied bounded read profile across the batch:
    • method: "GET"
    • timeoutMs: 8000
    • maxRetries: 2
    • retryBaseDelayMs: 150
    • retryMaxDelayMs: 800
  • Extended phase21 endpoint contract tests with relayPolicy pass-through assertions for each endpoint.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (164/164)
  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (10/10)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next slice: extract shared relay policy presets into a constants module and reference them from all relayGet endpoints to reduce duplication.

CL-038: TASK22242 P2-S3 closure slice — shared relay policy presets extraction

date: 2026-03-24 author: Cline scope: pages/api/middleware/relayPolicyPresets.js, pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getpersonalaccount_api,getlogin_api,getportallogin_api,getportalloginproxy_api,getbasicsearch_api,getbasicsearchpaged_api,getadvancedsearch_api,getadvancedsearchpaged_api,getportalmoduledetails_api,getportalmoduledetailsproxy_api,getmycases_api,getmyrepresentations_api,getawaitingsubmission_api,getrepresentations_api,getwatchedcases_api}.js, tests/phase21/_shared.cjs type: change rationale: Complete the planned P2-S3 final maintainability slice by centralizing repeated relay timeout/retry policy objects into shared presets used consistently across all targeted relayGet endpoints. impact: Eliminates duplicated policy literals, reduces drift risk, and preserves endpoint contracts/behavior by reusing equivalent policy values. status: completed

Summary:

  • Added new middleware constants module:
    • pages/api/middleware/relayPolicyPresets.js
    • RELAY_POLICY_STRICT_LOGIN
    • RELAY_POLICY_LOOKUP
    • RELAY_POLICY_BOUNDED_READ
    • RELAY_POLICY_SEARCH_PAGED
  • Refactored 18 relayGet endpoints to import and use shared presets instead of inline relayPolicy object literals:
    • lookup profile: getaccounts, getemailaccountcheck, getpreferredlanguage, getpersonalaccount, getportalloginproxy
    • strict login profile: getlogin, getportallogin
    • bounded read profile: getbasicsearch, getportalmoduledetails, getportalmoduledetailsproxy, getmycases, getmyrepresentations, getawaitingsubmission, getrepresentations, getwatchedcases
    • search paged profile: getbasicsearchpaged, getadvancedsearch, getadvancedsearchpaged
  • Updated phase21 VM test harness (tests/phase21/_shared.cjs) to inject preset constants so endpoint contract tests continue to execute with import-stripped modules.

Validation:

  • node tests/phase21/endpoint-handler-contract.test.cjs -> pass (164/164)
  • node tests/phase21/relay-forwarding-hardening.test.cjs -> pass (10/10)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • P2-S3 planned slices are now complete; no further mandatory relay policy rollout slices remain for this stream.

CL-039: TASK22260 actions façade increment — shared relay client extraction

date: 2026-03-25 author: Cline scope: actions/clients/{relayClient,index}.js, actions/services/{accountDirectService,portalDirectService,documentDirectService}.js, actions/index.js, actions/clients/README.md type: change rationale: Continue Priority 1 façade decomposition by extracting duplicated hash-signing relay helper logic into a dedicated client module while preserving existing service/public export contracts. impact: Reduces duplication and drift risk in security-sensitive relay signing helper logic without changing call-site behavior. status: completed

Summary:

  • Added a new shared client wrapper:
    • actions/clients/relayClient.js exporting buildHashedQueryUrl
  • Added actions/clients/index.js barrel and exposed client exports via actions/index.js.
  • Updated direct services to consume shared relay client helper instead of duplicating local helper implementations:
    • actions/services/accountDirectService.js
    • actions/services/portalDirectService.js
    • actions/services/documentDirectService.js
  • Updated actions/clients/README.md to reflect the now-implemented relay client extraction and future incremental client split path.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • Verified no remaining duplicated local buildHashedQueryUrl definitions across actions/services/*DirectService.js

Follow-ups:

  • Optional next TASK22260 increment: extract common axios invocation helpers into dedicated clients (endpointClient, fileClient, notifyClient) while keeping actions/index.js API stable.

Addendum (same TASK22260 slice):

  • Added shared endpointClient with getJson and requestJson helpers (actions/clients/endpointClient.js) and exported it via actions/clients/index.js.
  • Migrated additional direct services to consume shared endpoint client helpers:
    • actions/services/notifyDirectService.js (POST via requestJson)
    • actions/services/integrationDirectService.js (POST via requestJson)
    • actions/services/adminDirectService.js (GET flows via getJson)
  • Updated actions/clients/README.md to include endpointClient in current extracted clients.

CL-040: TASK22260 next slice — reference-data direct service endpointClient adoption

date: 2026-03-25 author: Cline scope: actions/services/referenceDataDirectService.js, actions/clients/README.md type: change rationale: Continue the incremental façade/client adoption stream by migrating another bounded direct-service module to shared endpoint request helpers. impact: Reduces axios boilerplate and centralizes JSON extraction behavior for reference-data requests without changing public call signatures. status: completed

Summary:

  • Migrated actions/services/referenceDataDirectService.js from direct axios.get(...).then(res => res.data) patterns to shared getJson(...) helper from actions/clients/endpointClient.
  • Preserved existing error behavior:
    • logAndReturnEmptyValueErrorResponse for appeals/project/LPA fetches
    • consoleLogger catch handling for form/mandatory/picklist/notice fetches
  • Updated actions/clients/README.md usage notes to include reference-data service reuse.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Next optional bounded slice: adopt getJson/requestJson for selected low-risk read paths in searchDirectService or caseDirectService while preserving per-function error semantics.

CL-041: TASK22260 next slice — account direct service endpointClient adoption

date: 2026-03-25 author: Cline scope: actions/services/accountDirectService.js type: change rationale: Continue incremental façade migration by moving account direct-service request plumbing onto shared endpoint client helpers while preserving existing error-return behavior contracts. impact: Reduces duplicated axios response extraction boilerplate and aligns account service request handling with the emerging client-layer pattern. status: completed

Summary:

  • Refactored actions/services/accountDirectService.js to consume shared endpoint client helpers:
    • getJson(...) for GET requests
    • requestJson(...) for config-based POST requests
  • Kept existing relay hash-signing behavior unchanged via buildHashedQueryUrl from relayClient.
  • Preserved existing catch-path semantics, including:
    • logging with consoleLogger
    • returning JSON.stringify(error) in portal login functions
    • returning error.response in preferred-language failure path

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: adopt endpoint client helpers in selected portalDirectService GET/POST helper paths while preserving delete/hash flow semantics.

CL-042: TASK22260 next slice — portal direct service partial endpointClient adoption

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js type: change rationale: Continue phased client-layer adoption by migrating low-risk portal direct-service read/create paths to shared endpoint request helpers while leaving hash-sensitive delete/message flows unchanged. impact: Reduces duplicated axios response extraction on high-traffic portal retrieval paths and keeps hashed delete/message semantics stable. status: completed

Summary:

  • Refactored selected portalDirectService functions to use shared endpoint client helpers:
    • getJson(...) for read/listing routes (getMyCases, getMyInvolvements, getMyLPACases, representations, watched, awaiting submission variants)
    • requestJson(...) for createWatchedCases
  • Preserved existing hash/delete/message flow implementations (deleteMyRepresentations, deleteWatchedCases, completion message functions) using existing axios + relay signing behavior.
  • Preserved existing catch-path logging behavior for all migrated functions.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: migrate remaining non-hash POST helpers in portalDirectService (setRepInvolvment, setCaseInvolvment) to requestJson for full internal consistency.

CL-043: TASK22260 next slice — portal involvement helper endpointClient completion

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js type: change rationale: Complete the next bounded internal-consistency slice by migrating remaining non-hash portal involvement POST helpers to shared endpoint client request plumbing. impact: Aligns portal service POST helper internals with established requestJson usage while preserving route semantics and error handling. status: completed

Summary:

  • Migrated remaining portal involvement helper POST functions to shared endpoint client:
    • setRepInvolvment
    • setCaseInvolvment
  • Both now use requestJson(config) while preserving existing payload shape, endpoint URLs, and catch-path logging behavior.
  • No changes made to hash-sensitive delete/message pathways.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: begin selective requestJson adoption for remaining config-based calls in documentDirectService where hash flow is already centralized.

CL-044: TASK22260 next slice — document direct service low-risk getJson adoption

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Continue incremental façade/client rollout by migrating low-risk document service GET wrappers that already return JSON and do not alter hash-signing semantics. impact: Reduces duplicated axios .get(...).then(res => res.data) boilerplate and aligns document retrieval helpers with shared endpoint client usage. status: completed

Summary:

  • Added getJson usage in selected document service helpers:
    • getRepsFromBlobProxy
    • getAwaitingSubmissionFromBlobProxy
    • getFilesFromBlobproxy
    • getFilesFromBlobHashed
    • getProgressFromBlob
    • createContainerProxy
  • Preserved existing behavior contracts:
    • same query composition and hash query fragments
    • same catch-path logging and return conventions (including JSON string return in createContainerProxy error path)
  • Left hash-sensitive delete/upload/generation flows unchanged in this slice.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: migrate selected requestJson-eligible upload/generation helpers in documentDirectService (non-download paths) while preserving multipart/blob behavior.

CL-045: TASK22260 next slice — document direct service requestJson adoption (uploads + PDF generation)

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Continue bounded client migration by moving config-based multipart/PDF POST helpers in document service to shared requestJson while preserving hashed URL generation and responseType behavior. impact: Reduces repeated axios config execution boilerplate and aligns document POST helper internals with shared endpoint client conventions. status: completed

Summary:

  • Migrated selected config-based document helper flows from axios(config) + res.data to requestJson(config):
    • uploadFiles
    • uploadSingleFile
    • uploadRepFiles
    • generateRepPDF
    • generateAppealPDF
  • Preserved behavior-critical aspects:
    • hashed URL creation via buildHashedQueryUrl(...)
    • multipart headers for upload flows
    • conditional responseType: "blob" for download PDF option paths
    • existing catch-path logging semantics
  • Left delete/download/hash-sensitive GET helpers unchanged in this slice.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: evaluate remaining legacy direct axios.get(...).then(res.data) helpers in documentDirectService (getAwaitingSubmissionFromBlob, getRepsFromBlob, getFilesFromBlob) for safe migration while preserving signed hash path behavior.

CL-046: TASK22260 next slice — document direct service remaining signed GET helper migration

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Complete the remaining low-risk read helper migration in document service by replacing final direct axios.get(...).then(res.data) patterns with shared getJson while retaining hash/signature query construction. impact: Finishes consistency pass for JSON-returning document read helpers and reduces duplicated response extraction logic. status: completed

Summary:

  • Migrated the remaining signed document read helpers to getJson(...):
    • getAwaitingSubmissionFromBlob
    • getRepsFromBlob
    • getFilesFromBlob
  • Preserved existing behavior:
    • same BASE_URL and hash query composition via hashAPIPath(...)
    • same catch-path logging behavior (consoleLogger)
    • no changes to delete/download flows or hash-signing helper usage in mutation paths

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: targeted hygiene in documentDirectService to isolate remaining non-migrated special-case flows (downloadBlob, delete helpers) and assess if any shared client abstraction is beneficial without altering behavior.

CL-047: TASK22260 next slice — case direct service low-risk getJson adoption

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js type: change rationale: Continue incremental endpoint client rollout with a bounded low-risk set of case service GET helpers that already return direct JSON payloads and have simple logging-only catch paths. impact: Reduces repeated axios GET/response extraction boilerplate and aligns additional case retrieval helpers with shared client conventions. status: completed

Summary:

  • Added getJson usage in selected caseDirectService helper functions:
    • getAppealPDFDocs
    • getPortalModuleDetails
    • getPortalModuleDetailsProxy
  • Preserved existing behavior contracts:
    • same request URL/query construction
    • same catch-path logging via consoleLogger
    • no change to handlers with bespoke error-return contracts (getAppealPDFDocument) or other non-targeted flows.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: migrate additional safe case service GET helpers that currently use axios.get(...).then(res.data) to getJson where custom catch behavior is compatible.

CL-048: TASK22260 next slice — case direct service GET cluster expansion

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js type: change rationale: Continue phased endpoint client adoption by migrating another bounded set of case service GET helpers that already use shared catch handling (logAndReturnResponse). impact: Further reduces duplicated axios GET/response extraction boilerplate while preserving existing error-handling contracts for migrated paths. status: completed

Summary:

  • Migrated additional case retrieval helpers from axios.get(...).then(res.data) to getJson(...):
    • getCaseMessage
    • getIncidentbyID
    • getIsPublishedbyID
    • getPartSavedAppeal
    • getSIPSEvents
    • getSIPSMedia
  • Preserved behavior contracts:
    • unchanged URLs/query parameter composition
    • unchanged catch behavior via logAndReturnResponse
    • left non-targeted/bespoke flows untouched (getAppealID, create/update/patch operations, and error-response-specialized helpers)

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: evaluate remaining GET helpers in caseDirectService with custom catches (getCase, getCaseByID, getAppealPDFDocument) for selective migration where return-shape contracts remain stable.

CL-049: TASK22260 next slice — case direct service remaining GET helper migration

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js type: change rationale: Complete the remaining safe GET-helper client migration in case service by moving custom-catch read functions to getJson while preserving their existing return-shape/error handling behavior. impact: Removes remaining direct axios GET response-extraction boilerplate in case read helpers and completes endpointClient read-path consistency for this service subset. status: completed

Summary:

  • Migrated remaining targeted case read helpers from direct axios.get(...).then(res.data) to getJson(...):
    • getCase
    • getCaseByID
    • getAppealPDFDocument
  • Preserved behavior contracts:
    • unchanged request URL/query construction
    • unchanged catch semantics:
      • getCase / getCaseByID still log via consoleLogger
      • getAppealPDFDocument still logs and returns error.response on failure
    • left non-targeted POST/update/create/patch flows unchanged.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: evaluate config-based POST helpers in caseDirectService (createNewCase, createNewCaseBlob, updateCase, updateCaseBlob) for selective requestJson(...) adoption while preserving existing side effects and error contracts.

CL-050: TASK22260 next slice — case direct service POST helper requestJson adoption

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js type: change rationale: Continue bounded client-layer migration by moving config-based case service POST helpers from direct axios(config) usage to shared requestJson(...) while preserving current behavior and error semantics. impact: Reduces duplicated config-execution/response-extraction boilerplate and aligns case service write-helper internals with existing endpoint client conventions. status: completed

Summary:

  • Migrated selected case service POST helpers to requestJson(config):
    • createNewCase
    • createNewCaseBlob
    • updateCase
    • updateCaseBlob
  • Preserved behavior contracts:
    • unchanged payload/query construction and URLs
    • unchanged catch-path logging via consoleLogger
    • no changes to non-targeted helper logic (getAppealID, patchCase, and already-migrated GET helpers)

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: assess patchCase and getAppealID for migration opportunities (if/when preserving their specific behavior contracts remains straightforward).

CL-051: TASK22260 next slice — case direct service final axios dependency removal

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js type: change rationale: Complete the bounded case service migration by replacing the remaining direct axios usage (getAppealID, patchCase) with shared endpoint client reads, enabling removal of the direct axios import. impact: Finalizes endpoint client consistency in case service and removes remaining direct axios dependency from this module without changing helper contracts. status: completed

Summary:

  • Migrated remaining direct axios-based read helpers to getJson(...):
    • getAppealID
    • patchCase
  • Preserved behavior contracts:
    • getAppealID still extracts first non-underscore key value from returned entity and logs on failure
    • patchCase still swallows failure (no explicit returned error contract introduced)
  • Removed now-unused axios import from caseDirectService.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: review other direct service modules for any remaining legacy axios import usage now that case service migration is complete.

CL-052: TASK22260 next slice — portal direct service requestJson parity for config-based reads/deletes

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js type: change rationale: Continue bounded direct-service consistency by migrating remaining config-based portal helper calls from axios(config) to shared requestJson(...) where no signed-delete/header-specific behavior is required. impact: Reduces repeated config execution/response extraction boilerplate and improves request helper consistency in portal service while preserving behavior. status: completed

Summary:

  • Migrated selected config-based helpers to requestJson(config):
    • deleteAwaitingSubmissions
    • sendCaseCompleteMessage
    • sendCaseCompleteMessageProxy
    • sendRepCompleteMessage
  • Preserved behavior contracts:
    • unchanged query/hash composition and request methods
    • unchanged catch-path logging via consoleLogger
    • left signed delete helpers with bespoke axios/header behavior unchanged (deleteMyRepresentations, deleteWatchedCases)

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: assess whether signed-delete helpers in portalDirectService should remain explicit axios calls (for clarity on headers/hash semantics) or move to a dedicated signed-request client helper.

CL-053: Architecture documentation update — current-state assessment + prioritised roadmap

date: 2026-03-25 author: Cline scope: context/architecture.md type: change rationale: User requested the architectural assessment be documented in-project so current state, residual risks, and recommended sequencing are explicitly captured for team planning. impact: Improves documentation clarity and planning alignment; no runtime behavior changes. status: completed

Summary:

  • Added a new section to context/architecture.md:
    • Current State Assessment and Prioritised Next Steps (2026-03-25)
  • Documented:
    • strengths (governance maturity, API/relay hardening progress, façade decomposition progress)
    • residual risks/gaps (remaining direct-service inconsistency, coverage concentration, logging variance, i18n parity automation gap)
    • prioritised next steps with rationale
    • recommended execution sequencing (immediate/next/after)

Validation:

  • Manual coherence check against existing guardrails/runbook/integration-map and memory-bank context.

Follow-ups:

  • Optional: convert the prioritised steps into a sprint-ready plan (tasks, acceptance criteria, validation matrix, rollback notes).

CL-054: Branch correction — include residual duplication/axios risk slices (search + signed-delete portal flows)

date: 2026-03-25 author: Cline scope: actions/services/{portalDirectService,searchDirectService}.js, context/architecture.md type: change rationale: User requested the previously identified primary remaining technical risk slices be explicitly included on this branch, specifically residual axios/duplication in search direct service and signed-delete portal helper flows. impact: Further reduces direct-service axios boilerplate/duplication and aligns additional high-use service paths to shared endpoint client patterns while preserving existing behavior contracts. status: completed

Summary:

  • Implemented the requested risk slices on branch:
    1. Portal signed-delete flow parity (portalDirectService)
      • migrated signed delete helpers from direct axios({...}).then(res.data) to requestJson({...}):
        • deleteMyRepresentations
        • deleteWatchedCases
      • removed now-unused axios import from module
      • preserved hash-signing flow and custom headers semantics
    2. Search direct service axios reduction (searchDirectService)
      • migrated service GET helpers from direct axios.get(...).then(res.data) and axios(config) to getJson(...)
      • preserved existing catch semantics (logAndReturnResponse, logAndReturnEmptyValueErrorResponse, and explicit throw path in getSearchDocumentDetails)
      • removed direct axios import from module
  • Documentation alignment:
    • retained architecture assessment section in context/architecture.md that calls out these residual-risk slices and prioritisation.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: assess whether a dedicated signed-request client helper should encapsulate hash + headers + method conventions to prevent future drift in remaining signed flows.

CL-055: TASK22260 next slice — document direct service signed/delete axios reduction

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Execute next bounded risk-reduction slice by migrating remaining non-download document-service delete and signed-get helper calls away from direct axios response extraction to shared endpoint clients. impact: Further reduces duplicated axios boilerplate and aligns document service internals with shared request-client conventions while preserving existing hash/query and catch-path behavior. status: completed

Summary:

  • Migrated signed hashed delete-helper flows from direct axios({...}).then(res.data) to requestJson({...}):
    • deleteAwaitingSubmissionsFromBlob
    • deleteMyRepresentationsFromBlob
  • Migrated delete helper GET calls from axios.get(...).then(res.data) to getJson(...):
    • deleteBlob
    • deleteRepBlob
  • Preserved behavior contracts:
    • unchanged query/hash composition and endpoint URLs
    • unchanged catch-path logging with consoleLogger
  • Left downloadBlob unchanged in this slice (special-case behavior path retained for separate focused handling).

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: isolate and correct downloadBlob behavior in documentDirectService (including legacy res usage) behind an explicit, tested contract.

CL-056: TASK22260 next slice — document direct service download helper contract fix

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Execute the next bounded follow-up by correcting the legacy downloadBlob service helper path that still relied on invalid res references and direct axios usage, aligning it to shared request client behavior. impact: Fixes a service-layer contract defect risk in document download helper and improves consistency by using shared request client patterns; no endpoint contract change. status: completed

Summary:

  • Refactored downloadBlob(containerName, blobName) in documentDirectService:
    • removed legacy direct axios.get(...).then(response => res.status(...)) pattern that referenced undefined res in service layer
    • now returns blob response data via requestJson({ method: "get", url, responseType: "blob" })
    • preserved catch-path logging (consoleLogger)
  • Removed now-unused module-level axios import from documentDirectService.

Validation:

  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add a focused test (or integration harness assertion) around downloadBlob service return contract to prevent regression to response-object assumptions.

CL-057: TASK22260 next slice — phase7 behavioural harness compatibility update

date: 2026-03-25 author: Cline scope: tests/phase7/service-behaviour.test.cjs type: change rationale: After service-layer client migration (getJson/requestJson/buildHashedQueryUrl), phase7 behavioural harness still assumed direct axios imports only; update harness defaults so legacy behavior assertions remain executable. impact: Restores service behavioural regression coverage (12/12) without changing production runtime code. status: completed

Summary:

  • Enhanced phase7 VM loader default injections for migrated service helpers:
    • added default getJson(...) mock delegating to axios.get(...).then(res.data)
    • added default requestJson(...) mock delegating to axios(config).then(res.data)
    • added default buildHashedQueryUrl(...) mock resolving hash via /api/endpoint/gethash_api compatibility path
  • Updated notify behavior assertions to align with shared request client usage (requestJson invokes axios config-style call):
    • switched notify test handlers from axios.postHandler to axios.requestHandler
    • assertions now inspect axios.calls[0].config.{url,method,data}

Validation:

  • node tests/phase7/service-behaviour.test.cjs -> pass (12/12)

Follow-ups:

  • Optional next bounded slice: add a small shared test utility for service harness client mocks to reduce future per-file drift as façade migration continues.

CL-058: TASK22260 next slice — phase6 behavioural harness compatibility parity

date: 2026-03-25 author: Cline scope: tests/phase6/service-behaviour.test.cjs type: change rationale: Keep older phase6 behavioural harness aligned with service client-wrapper migration by adding default helper injections required by getJson/requestJson-based direct services. impact: Restores phase6 behavioural regression execution parity (8/8) with no runtime code changes. status: completed

Summary:

  • Updated loadServiceModule default context in tests/phase6/service-behaviour.test.cjs:
    • added default getJson(...) mock backed by axios.get(...).then(res.data)
    • added default requestJson(...) mock backed by axios(config).then(res.data)
  • Preserved existing test assertions and behavior semantics; this is harness-compatibility only.

Validation:

  • node tests/phase6/service-behaviour.test.cjs -> pass (8/8)

Follow-ups:

  • Optional consolidation: extract shared phase6/phase7 VM loader helpers into a single test utility to reduce duplication.

CL-059: TASK22260 next slice — shared service harness extraction (continued bounded risk-reduction)

date: 2026-03-25 author: Cline scope: tests/{serviceHarness,phase6/service-behaviour,phase7/service-behaviour}.cjs type: change rationale: Continue the bounded risk-reduction stream by removing duplicated test harness infrastructure across phase6/phase7 service behavioural suites and centralizing client-wrapper-compatible mocks. impact: Reduces test harness drift risk and keeps client-wrapper migration verification stable across multiple suites, without runtime code changes. status: completed

Summary:

  • Added shared helper module tests/serviceHarness.cjs with reusable:
    • createAxiosMock
    • createLoggerMock
    • createAxiosError
    • loadServiceModule (with default getJson/requestJson/buildHashedQueryUrl injections)
    • normalize
  • Refactored tests/phase6/service-behaviour.test.cjs to import shared harness utilities and remove duplicated local harness implementation.
  • Refactored tests/phase7/service-behaviour.test.cjs to import shared harness utilities and remove duplicated local harness implementation.

Validation:

  • node tests/phase6/service-behaviour.test.cjs -> pass (8/8)
  • node tests/phase7/service-behaviour.test.cjs -> pass (12/12)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded risk-reduction slice: evaluate whether other legacy service test suites can adopt tests/serviceHarness.cjs to standardize migration-era service mocking behavior.

CL-060: TASK22260 next slice — core token helper client-wrapper migration (continued bounded risk-reduction)

date: 2026-03-25 author: Cline scope: actions/core/token.js type: change rationale: Include the identified remaining candidate outside actions/services and continue the bounded risk-reduction stream by removing direct axios response extraction from core token retrieval. impact: Aligns token helper request execution with shared endpoint client conventions while preserving existing token caching and error-return behavior. status: completed

Summary:

  • Refactored getToken in actions/core/token.js:
    • replaced direct axios.post(...).then(res => res.data) chain with shared requestJson({...})
    • migrated function to async/await with equivalent try/catch behavior
    • retained existing semantics:
      • successful token payload cached in cache.tokenResponse
      • failures logged via consoleLogger and returned to caller
  • Removed direct axios dependency from actions/core/token.js in favor of actions/clients/endpointClient.

Validation:

  • node tests/phase21/api-contract-slice1.test.cjs -> pass
    • helper: 4/4
    • file-handler: 53/53
    • email-handler: 12/12
    • endpoint-handler: 164/164
    • documents-handler: 3/3
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded risk-reduction slice: assess whether any remaining non-service utility modules still use promise-chain axios extraction patterns and migrate them to shared clients where behavior contracts remain unchanged.

CL-061: TASK22260 next slice — core token regression coverage addition (bounded hardening)

date: 2026-03-25 author: Cline scope: tests/phase22/core-token-behaviour.test.cjs type: change rationale: Follow the previous core token migration with a bounded verification slice to lock the request-client contract and prevent regression to direct axios extraction patterns. impact: Improves confidence in actions/core/token.js behavior (success + failure semantics) without runtime code changes. status: completed

Summary:

  • Added new focused Phase 22 behavioural test suite:
    • tests/phase22/core-token-behaviour.test.cjs
  • Coverage asserts:
    • getToken success path returns token payload and calls requestJson with expected URL/method/body/headers
    • failure path logs via consoleLogger and returns the original error object
  • Test harness uses VM import stripping consistent with existing phase behavioural suites.

Validation:

  • node tests/phase22/core-token-behaviour.test.cjs -> pass (2/2)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add this phase22 suite to any aggregate test runner used in CI if/when phase-level suites are centrally orchestrated.

CL-062: TASK22260 next slice — phase22 runner export guard parity (bounded test-harness consistency)

date: 2026-03-25 author: Cline scope: tests/phase22/core-token-behaviour.test.cjs type: change rationale: Continue bounded test-hardening by aligning phase22 test entry behavior with established suite conventions so it can be executed both directly and from aggregate runners. impact: Improves test harness composability and reduces accidental double-execution risk when importing phase22 test suites. status: completed

Summary:

  • Updated tests/phase22/core-token-behaviour.test.cjs to export run and add require.main === module guard.
  • Preserved direct CLI execution behavior while enabling safe module import by aggregate runners.

Validation:

  • node tests/phase22/core-token-behaviour.test.cjs -> pass (2/2)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add a dedicated tests/phase22/index.test.cjs aggregate entrypoint if additional phase22 suites are introduced.

CL-063: TASK22260 next slice — phase22 aggregate runner entrypoint (bounded test-runner hardening)

date: 2026-03-25 author: Cline scope: tests/phase22/index.test.cjs type: change rationale: Continue the bounded test-harness stream by introducing a phase-level aggregate runner for phase22, matching established conventions used in other phase suites. impact: Improves consistency and future scalability of phase22 tests by enabling a single entry command as additional phase22 suites are added. status: completed

Summary:

  • Added tests/phase22/index.test.cjs aggregate runner.
  • Runner currently executes core-token-behaviour.test.cjs and prints a phase-level completion line.
  • Exported run and kept direct CLI execution guard parity (require.main === module).

Validation:

  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add additional phase22 suites (e.g., shared-client utility behaviour tests) under this aggregate runner as migration coverage expands.

CL-064: TASK22260 next slice — phase22 client utility behaviour coverage expansion

date: 2026-03-25 author: Cline scope: tests/phase22/{client-utils-behaviour,index}.test.cjs type: change rationale: Execute the next bounded phase22 slice by adding focused behavioural coverage for shared client utilities to reduce regression risk as direct-service/client-wrapper migration continues. impact: Improves confidence in shared client helper contracts (endpointClient, relayClient) and keeps phase22 aggregate suite aligned with new coverage. status: completed

Summary:

  • Added new suite: tests/phase22/client-utils-behaviour.test.cjs.
  • Added assertions for shared client utility behavior:
    • endpointClient.getJson returns axios.get(...).data
    • endpointClient.requestJson returns axios(config).data
    • relayClient.buildHashedQueryUrl appends browser hash-service response
    • server fallback path uses hashAPIPath when HASHKEY is present
    • browser/no-HASHKEY failure path rethrows hash-service error
  • Updated tests/phase22/index.test.cjs to include the new client-utils suite in the phase aggregate runner.

Validation:

  • node tests/phase22/client-utils-behaviour.test.cjs -> pass (5/5)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add focused phase22 behavioural coverage for any future shared client wrappers introduced beyond endpointClient/relayClient.

CL-065: TASK22260 next slice — fileClient extraction + phase22 behavioural coverage

date: 2026-03-25 author: Cline scope: actions/clients/{fileClient,index}.js, actions/services/documentDirectService.js, tests/phase22/{file-client-behaviour,index}.test.cjs type: change rationale: Continue bounded shared-client decomposition by extracting repeated file-route request patterns into fileClient and hardening behaviour with dedicated phase22 tests. impact: Reduces request-boilerplate duplication in document service and increases regression confidence for extracted file client helper contracts. status: completed

Summary:

  • Added new shared client wrapper: actions/clients/fileClient.js:
    • getFileJson(url)
    • getSignedFileJson(queryUrl)
    • downloadFileBlob(url)
  • Exported fileClient from actions/clients/index.js (and therefore via actions/index.js barrel path).
  • Migrated a bounded subset of actions/services/documentDirectService.js call sites to fileClient while preserving catch-path logging behavior:
    • getFilesFromBlobproxy -> getFileJson
    • deleteAwaitingSubmissionsFromBlob -> getSignedFileJson
    • deleteMyRepresentationsFromBlob -> getSignedFileJson
    • deleteBlob -> getFileJson
    • deleteRepBlob -> getFileJson
    • downloadBlob -> downloadFileBlob
  • Added tests/phase22/file-client-behaviour.test.cjs covering:
    • delegation to getJson
    • signed URL generation + requestJson invocation
    • blob download config contract (responseType: "blob")
  • Updated aggregate runner tests/phase22/index.test.cjs to include file-client suite.

Validation:

  • node tests/phase22/file-client-behaviour.test.cjs -> pass (3/3)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • file-client: 3/3
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: evaluate whether additional documentDirectService file-route call sites can adopt fileClient without altering current behavior contracts.

CL-066: TASK22260 next slice — service harness parity for fileClient helper injections

date: 2026-03-25 author: Cline scope: tests/serviceHarness.cjs type: change rationale: Follow the previous fileClient extraction with a bounded harness-compatibility slice so legacy VM-based service behavioural suites continue to execute without requiring per-test manual injections. impact: Restores migration-era behavioural regression stability (phase7) by aligning shared harness defaults with newly introduced file client helper symbols. status: completed

Summary:

  • Updated shared test harness defaults in tests/serviceHarness.cjs to inject file-client compatible helpers when not explicitly provided:
    • getFileJson (delegates to default getJson)
    • getSignedFileJson (signs via buildHashedQueryUrl then calls requestJson with GET config)
    • downloadFileBlob (calls requestJson with GET + responseType: "blob")
  • This preserves existing VM import-stripping strategy while preventing ReferenceError in migrated services that import from ../clients/fileClient.

Validation:

  • node tests/phase7/service-behaviour.test.cjs -> pass (12/12)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • file-client: 3/3
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: add a focused phase6/phase7 behavioural assertion for documentDirectService.downloadBlob to explicitly lock the downloadFileBlob delegation contract.

CL-067: TASK22260 next slice — phase7 downloadBlob delegation behavioural lock

date: 2026-03-25 author: Cline scope: tests/phase7/service-behaviour.test.cjs type: change rationale: Execute the queued follow-up by adding explicit phase7 behavioural coverage for documentDirectService.downloadBlob so file-client delegation and blob request config remain contract-stable. impact: Increases regression confidence for document download helper behaviour after fileClient extraction, without runtime code changes. status: completed

Summary:

  • Added new phase7 behavioural test:
    • document/downloadBlob delegates blob request config via file client helper
  • The test asserts:
    • downloadBlob lower-cases container in URL composition
    • request is issued through config-style request path (axios.request in harness)
    • request method is get
    • responseType is blob
    • returned payload contract is preserved from request helper data.

Validation:

  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • file-client: 3/3
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next bounded slice: evaluate adding equivalent focused behavioural coverage in phase6 if download helper behavior becomes part of that suites scope.

CL-068: TASK22260 widened module-completion slice — documentDirectService signed POST flows via fileClient

date: 2026-03-25 author: Cline scope: actions/clients/fileClient.js, actions/services/documentDirectService.js, tests/phase22/file-client-behaviour.test.cjs type: change rationale: Per user request to widen slices, complete a larger coherent module-level increment by moving the remaining signed POST file-route flows in document service onto fileClient. impact: Further reduces request/signing boilerplate in document service and centralizes signed file-route behavior in client wrapper layer with added regression coverage. status: completed

Summary:

  • Extended actions/clients/fileClient.js with:
    • postSignedFileJson(queryUrl, data, config = {})
    • signs query URL via buildHashedQueryUrl and executes POST via requestJson
  • Migrated all remaining signed POST helper paths in actions/services/documentDirectService.js to postSignedFileJson:
    • uploadFiles
    • uploadSingleFile
    • uploadRepFiles
    • generateRepPDF
    • generateAppealPDF
  • Preserved existing catch-path logging and request-option semantics:
    • multipart headers for upload flows
    • conditional responseType: "blob" for download variants
  • Expanded phase22 file-client behavior suite with explicit POST-signed contract test:
    • URL signing + POST method
    • data passthrough
    • config/header passthrough

Validation:

  • node tests/phase22/file-client-behaviour.test.cjs -> pass (4/4)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • file-client: 4/4
    • phase22 combined: pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next widened slice: evaluate consolidating remaining direct getJson file-read flows in documentDirectService behind fileClient for full per-module client symmetry.

CL-069: TASK22260 widened module-completion slice — documentDirectService file-read client symmetry

date: 2026-03-25 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Continue widened slice cadence by completing per-module client symmetry in documentDirectService, moving all file-read helper calls to fileClient instead of mixed endpoint client usage. impact: Simplifies module dependency shape and centralizes file-route read behavior through a single client abstraction without changing runtime contracts. status: completed

Summary:

  • Removed mixed endpointClient usage from documentDirectService for file reads.
  • Migrated remaining file-read/helper routes from getJson to getFileJson:
    • getAwaitingSubmissionFromBlob
    • getRepsFromBlob
    • getRepsFromBlobProxy
    • getAwaitingSubmissionFromBlobProxy
    • getFilesFromBlob
    • getFilesFromBlobHashed
    • getProgressFromBlob
    • createContainerProxy
  • Removed now-unused imports from documentDirectService:
    • buildHashedQueryUrl
    • getJson
    • requestJson

Validation:

  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 5/5
    • file-client: 4/4
    • phase22 combined: pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next widened slice: introduce a small fileClient URL-builder helper set for repeated query-string composition in documentDirectService (container/casefolder/blob parameters) to reduce string-concat drift risk.

CL-070: TASK22260 widened cross-file slice — file route builder extraction + document service query normalization

date: 2026-03-25 author: Cline scope: actions/clients/{fileRouteBuilder,index}.js, actions/services/documentDirectService.js, tests/{serviceHarness,phase22/client-utils-behaviour}.cjs type: change rationale: Deliver a wider-than-previous slice by extracting reusable file-route query composition helpers and applying them across document service paths, reducing repeated string concatenation and encoding drift risk. impact: Improves maintainability and consistency of file-route URL construction while preserving existing runtime contracts and hash behavior. status: completed

Summary:

  • Added new shared helper module:
    • actions/clients/fileRouteBuilder.js
    • exports:
      • buildFileQuery(path, params, options) (supports optional encoded query composition)
      • withBaseUrl(baseUrl, route)
      • appendQuerySuffix(route, suffix)
  • Exported route-builder helpers via actions/clients/index.js.
  • Refactored actions/services/documentDirectService.js to use route-builder helpers across read/delete/download/query flows:
    • normalized composition for file routes and hash suffix append behavior
    • preserved encoded-path behavior for sensitive params (casefolderID, blobname) where previously encoded
    • preserved base URL prefix behavior and existing logger/catch semantics
  • Updated test harness defaults in tests/serviceHarness.cjs for new helper symbols:
    • buildFileQuery
    • withBaseUrl
    • appendQuerySuffix
  • Expanded phase22 utility coverage in tests/phase22/client-utils-behaviour.test.cjs with file route-builder behavior assertions.

Validation:

  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • phase22 combined: pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next widened slice: evaluate applying fileRouteBuilder to portal/case service file-route call sites for cross-module query-builder consistency.

CL-071: TASK22260 next widened cross-module slice — portal service query normalization via fileRouteBuilder

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js type: change rationale: Deliver the requested next wider slice by extending fileRouteBuilder adoption beyond document service into portal service, reducing duplicated query string concatenation and improving consistency in signed/unsigned route construction. impact: Improves maintainability and query-construction consistency across high-use portal service flows while preserving existing runtime behavior and hash-signing contracts. status: completed

Summary:

  • Refactored actions/services/portalDirectService.js to use shared route helpers:
    • buildFileQuery
    • withBaseUrl
    • appendQuerySuffix
  • Normalized query composition across portal service GET/DELETE/message flows:
    • read/list endpoints (getMyCases, getMyInvolvements, getMyLPACases, getMyRepresentations, proxy and watched/awaiting variants)
    • delete endpoints (deleteMyRepresentations, deleteAwaitingSubmissions, deleteWatchedCases)
    • file-message endpoints (sendCaseCompleteMessage, sendCaseCompleteMessageProxy, sendRepCompleteMessage)
  • Preserved behavior contracts:
    • retained BASE_URL usage patterns for existing BASE_URL-prefixed routes
    • retained hash-signing flow via buildHashedQueryUrl
    • retained append semantics for signed suffixes in sendCaseCompleteMessage
    • retained request methods, headers, payloads, and catch-path logging

Validation:

  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next widened slice: apply the same query-normalization helpers in caseDirectService and add dedicated phase22 behavioral assertions for portalDirectService route-building/signing composition.

CL-072: TASK22260 next widened cross-module slice — case service query normalization via fileRouteBuilder

date: 2026-03-25 author: Cline scope: actions/services/caseDirectService.js, tests/phase6/service-behaviour.test.cjs type: change rationale: Continue widened cross-module rollout by applying shared query/route composition helpers to caseDirectService, reducing repeated string concatenation and aligning route construction style with document/portal services. impact: Improves maintainability and consistency in case service URL/query composition while preserving existing runtime behavior and error contracts. status: completed

Summary:

  • Refactored actions/services/caseDirectService.js to use fileRouteBuilder helpers:
    • buildFileQuery
    • withBaseUrl
  • Normalized route composition for read and write helpers, including:
    • case retrieval/search flows (getCaseMessage, getIncidentbyID, getIsPublishedbyID, getPartSavedAppeal, getSIPSEvents, getSIPSMedia)
    • appeal resolution/update/create flows (getAppealID, createNewCase, createNewCaseBlob, updateCase, updateCaseBlob, patchCase)
    • case/detail/document/module reads (getCase, getCaseByID, getAppealPDFDocs, getAppealPDFDocument, getPortalModuleDetails, getPortalModuleDetailsProxy)
  • Preserved existing contracts:
    • BASE_URL usage patterns where previously applied
    • method/payload semantics for requestJson paths
    • catch-path logging and return behavior (logAndReturnResponse, consoleLogger, error.response paths)
  • Expanded phase6 behavioural coverage with a focused assertion for case route composition:
    • case/getPortalModuleDetails composes BASE_URL route with encoded case reference

Validation:

  • node tests/phase6/service-behaviour.test.cjs -> pass (9/9)
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional next widened slice: add a focused phase22 behavioral suite for caseDirectService and normalize any remaining specialized encoding usage behind explicit helper options where appropriate.

CL-073: TASK22260 essential condensed slice — case phase22 behavioural coverage + encoding contract lock

date: 2026-03-25 author: Cline scope: tests/phase22/{case-service-behaviour,index}.test.cjs type: change rationale: Condense remaining core work into one essential slice by adding explicit phase22 behavioural coverage for caseDirectService route composition and encoding-sensitive contracts. impact: Improves regression confidence for case service route-building behavior (BASE_URL composition, case-reference encoding/escaping, error-return contracts) without runtime behavior changes. status: completed

Summary:

  • Added new suite tests/phase22/case-service-behaviour.test.cjs with focused behavioural assertions for:
    • getPortalModuleDetails BASE_URL + encoded case reference composition
    • getPortalModuleDetailsProxy apostrophe escape behavior in case reference
    • getAppealID query composition and non-underscore value extraction
    • getAppealPDFDocument failure-path logging + error.response passthrough
  • Updated tests/phase22/index.test.cjs aggregate runner to include case-service-behaviour suite.

Validation:

  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • case-service: 4/4
    • phase22 combined: pass
  • node tests/phase6/service-behaviour.test.cjs -> pass (9/9)
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Optional closure slice: add a dedicated phase22 portal-service behavioural suite and finish harmonization of remaining direct query string composition in portalDirectService write helpers.

CL-074: TASK22260 optional closure condensed slice — portal phase22 behavioural coverage + final write-helper query harmonization

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js, tests/phase22/{portal-service-behaviour,index}.test.cjs type: change rationale: Complete optional closure work as one condensed slice by adding explicit portal behavioral coverage and removing remaining direct literal query strings in portal write helpers. impact: Improves regression confidence for signed portal flows and closes remaining route-composition harmonization gap in portal service write helpers without changing runtime behavior contracts. status: completed

Summary:

  • Harmonized remaining portal write-helper route literals to buildFileQuery(...):
    • createWatchedCases
    • setRepInvolvment
    • setCaseInvolvment
  • Added new phase22 suite tests/phase22/portal-service-behaviour.test.cjs covering:
    • signed hash suffix append path in sendCaseCompleteMessage
    • signed delete request contract + headers in deleteMyRepresentations
    • harmonized route helper URL in createWatchedCases
    • signed pre-request rejection contract in sendRepCompleteMessage when hash-signing fails
  • Updated tests/phase22/index.test.cjs aggregate runner to include portal-service-behaviour.

Validation:

  • node tests/phase22/portal-service-behaviour.test.cjs -> pass (4/4)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • case-service: 4/4
    • portal-service: 4/4
    • phase22 combined: pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Closure for this condensed stream complete; any further work should be a separate expansion stream (e.g., additional service-level phase22 coverage breadth).

CL-075: TASK22260 sequence-A step3 completion slice — auth redirect safety + EN/CY route parity automation

date: 2026-03-25 author: Cline scope: tests/phase22/{auth-redirect-safety,i18n-route-parity,index}.test.cjs type: change rationale: Continue on this branch to complete the remaining sequence-A step3 gaps by adding explicit automated checks for auth callback/redirect safety and EN/CY route parity. impact: Improves confidence in auth redirect safety behavior and bilingual rewrite parity with targeted, low-risk regression checks and no runtime code changes. status: completed

Summary:

  • Added tests/phase22/auth-redirect-safety.test.cjs:
    • validates locale resolution precedence (query -> body -> cookie -> default en)
    • validates redirect callback behavior for:
      • relative URL to same base
      • same-origin absolute URL passthrough
      • external URL rewritten to locale-safe base origin with preserved path/query
  • Added tests/phase22/i18n-route-parity.test.cjs:
    • asserts presence of required CY rewrite aliases for auth/policy routes in next.config.js
    • includes checks for signin/email/error/verify-request + privacy/accessibility/terms routes
  • Updated tests/phase22/index.test.cjs to include both new suites in aggregate phase22 execution.

Validation:

  • node tests/phase22/auth-redirect-safety.test.cjs -> pass (4/4)
  • node tests/phase22/i18n-route-parity.test.cjs -> pass (1/1)
  • node tests/phase22/index.test.cjs -> pass
    • core-token: 2/2
    • client-utils: 6/6
    • file-client: 4/4
    • case-service: 4/4
    • portal-service: 4/4
    • auth-redirect: 4/4
    • i18n-route: 1/1
    • phase22 combined: pass
  • npm run lint -> warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)

Follow-ups:

  • Sequence A step3 targeted gaps are now covered; further test expansion should be treated as new scope (e.g., deeper end-to-end journey assertions).

CL-076: TASK22269 Slice B1.1 — signed-request helper set + portal pilot signed-flow migration

date: 2026-03-25 author: Cline scope: actions/clients/{signedRequestClient,index}.js, actions/services/portalDirectService.js, tests/{serviceHarness,phase22/portal-service-behaviour}.cjs type: change rationale: Execute Sequence B Workstream B1 pilot by introducing shared signed request helpers (GET/POST/DELETE) and migrating one bounded portal signed flow without broader module rollout. impact: Reduces duplication and drift risk in hash-signing + method execution paths while preserving existing signed-flow behavior contracts. status: completed

Summary:

  • Added new shared signed-request client helper module:
    • actions/clients/signedRequestClient.js
    • exports:
      • getSignedJson(queryUrl, config?)
      • postSignedJson(queryUrl, data, config?)
      • deleteSignedJson(queryUrl, config?)
    • all helpers use existing buildHashedQueryUrl(...) + requestJson(...) composition to preserve signing semantics
  • Exported new helper module via actions/clients/index.js.
  • Migrated exactly one pilot signed flow in portal service:
    • deleteWatchedCases in actions/services/portalDirectService.js
    • from inline buildHashedQueryUrl(...).then(requestJson(...)) to deleteSignedJson(queryUrl)
    • preserved existing catch/log behavior (consoleLogger + undefined return on catch)
  • Added test harness compatibility for VM import-stripping suites:
    • tests/serviceHarness.cjs now injects default deleteSignedJson mock behavior.
  • Expanded portal behavioral tests with explicit negative-path assertion:
    • tests/phase22/portal-service-behaviour.test.cjs
    • verifies deleteWatchedCases logs and safely returns undefined when signed delete fails.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
    • portal-service suite now 5/5 including signed-delete failure path
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Continue Sequence B B1 in future bounded slices by migrating additional signed flows one module/function cluster at a time (outside this slice).

CL-077: TASK22269 Slice B1.2 — portal signed-delete bundle (headered delete migration)

date: 2026-03-25 author: Cline scope: actions/services/portalDirectService.js type: change rationale: Continue signed-request consolidation using bounded grouping by migrating the remaining portal signed delete flow (deleteMyRepresentations) onto shared signed helper while preserving required OData headers. impact: Further reduces duplicated sign+delete boilerplate in portal service and centralizes signed DELETE execution semantics. status: completed

Summary:

  • Migrated deleteMyRepresentations from inline buildHashedQueryUrl(...).then(requestJson(...)) to shared deleteSignedJson(queryUrl, { headers }).
  • Preserved behavior-critical headers exactly:
    • OData-MaxVersion
    • OData-Version
    • Accept
    • Prefer
    • Content-Type
  • Preserved existing catch/log behavior (consoleLogger with safe undefined return on failure).

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Next bounded signed GET candidate in portal service is sendRepCompleteMessage (single signed URL + GET request path).

CL-078: TASK22269 Slice B1.3 — fileClient signed helper delegation bundle

date: 2026-03-25 author: Cline scope: actions/clients/fileClient.js, tests/phase22/file-client-behaviour.test.cjs type: change rationale: Continue grouped signed-request consolidation by reducing duplicate signing logic in fileClient and delegating signed GET/POST operations to shared signedRequestClient helpers. impact: Centralizes signed method execution behavior in one helper layer and lowers drift risk across file-service call paths. status: completed

Summary:

  • Updated actions/clients/fileClient.js:
    • replaced direct buildHashedQueryUrl + requestJson logic in:
      • getSignedFileJson -> now delegates to getSignedJson
      • postSignedFileJson -> now delegates to postSignedJson
    • retained downloadFileBlob and getFileJson behavior unchanged.
  • Updated tests/phase22/file-client-behaviour.test.cjs to assert delegation contracts for getSignedJson and postSignedJson rather than direct signing internals.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Candidate map now indicates remaining explicit signed request composition is primarily in account/portal signed GET edge paths (getPortalLogin, sendRepCompleteMessage, and signed suffix append flow in sendCaseCompleteMessage) for future bounded slices.

CL-079: TASK22269 Slice B1.4 — signed GET consolidation bundle (portal + account)

date: 2026-03-25 author: Cline scope: actions/clients/signedRequestClient.js, actions/services/{portalDirectService,accountDirectService}.js, tests/{serviceHarness,phase22/portal-service-behaviour,phase7/service-behaviour}.cjs type: change rationale: Continue grouped signed-request migration by consolidating remaining direct signed-GET composition paths onto shared signed helper primitives while preserving route behavior contracts. impact: Reduces residual signing duplication and standardizes signed URL creation across portal/account service read/message flows. status: completed

Summary:

  • Enhanced signedRequestClient:
    • added buildSignedUrl(queryUrl, { baseUrl? }) helper for signed URL generation reuse
    • updated internal signed request execution to use buildSignedUrl
  • Migrated account signed GET candidate:
    • accountDirectService.getPortalLogin now uses getSignedJson(queryUrl, { baseUrl: BASE_URL })
    • preserved existing error semantics (consoleLogger + JSON.stringify(error))
  • Migrated portal signed GET candidates:
    • portalDirectService.sendRepCompleteMessage now uses buildSignedUrl(hashQueryPath)
    • portalDirectService.sendCaseCompleteMessage now uses buildSignedUrl(hashQueryPath) + existing signed suffix append behavior
    • preserved existing request method/URL shape and catch-path behavior
  • Updated test harness and suites:
    • tests/serviceHarness.cjs now provides defaults for buildSignedUrl, getSignedJson, postSignedJson
    • tests/phase22/portal-service-behaviour.test.cjs includes assertion for sendRepCompleteMessage signed-helper delegation
    • tests/phase7/service-behaviour.test.cjs account portal-login expectations aligned to request-config path used by shared signed helper

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Remaining special-case signed pattern is now primarily the signed-suffix append composition in sendCaseCompleteMessage (already using shared buildSignedUrl), with broader module migrations to be planned in future bounded slices.

CL-080: TASK22269 Slice B1.5 — document hash-suffix route normalization helper

date: 2026-03-25 author: Cline scope: actions/clients/fileRouteBuilder.js, actions/services/documentDirectService.js, tests/{serviceHarness,phase22/client-utils-behaviour}.cjs type: change rationale: Continue grouped follow-on candidates by normalizing repeated deterministic hash-suffix route assembly in document service behind one shared route-builder helper. impact: Reduces repeated appendQuerySuffix(route, hashAPIPath(route)) composition drift risk while preserving route/query/hash behavior. status: completed

Summary:

  • Added appendHashSuffix(route, hashBuilder) to fileRouteBuilder.
  • Migrated document service deterministic hash-suffix paths to new helper:
    • getAwaitingSubmissionFromBlob
    • getRepsFromBlob
    • getFilesFromBlob
    • getProgressFromBlob
    • createContainerProxy
  • Updated shared VM harness defaults (tests/serviceHarness.cjs) to inject appendHashSuffix.
  • Expanded phase22 utility test to cover new helper behavior (tests/phase22/client-utils-behaviour.test.cjs).

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Remaining non-service candidate for this stream is actions/azurestorage.js direct hashAPIPath metadata assembly (separate bounded slice if desired).

CL-081: TASK22269 Slice B1.6 — azurestorage hash-query metadata builder normalization

date: 2026-03-25 author: Cline scope: actions/azurestorage.js type: change rationale: Continue requested follow-on slice by reducing repeated hash-query path string composition in azure storage metadata builders behind local helper functions. impact: Lowers duplication/drift risk in hashed metadata path generation while preserving existing route and encoding behavior. status: completed

Summary:

  • Added internal helper builders in actions/azurestorage.js:
    • buildDownloadBlobQueryPath(...)
    • buildDeleteBlobQueryPath(...)
    • buildGetBlobListQueryPath(...)
  • Replaced repeated inline hash path literals with helper usage in targeted metadata object builders:
    • getBlobs
    • getProgressBlobs
    • getRepsFilesBlobs
  • Preserved existing behavior semantics for hash path construction:
    • encoded casefolderID/blobname where previously encoded
    • unchanged containerName and casefolderID value sourcing
    • unchanged returned object field names and shape

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Remaining potential cleanups in actions/azurestorage.js are broader non-slice refactors (legacy logging verbosity, large function decomposition) and should be handled separately to keep risk bounded.

CL-082: TASK22269 Slice B1.7 — azurestorage hash metadata helper consolidation

date: 2026-03-25 author: Cline scope: actions/azurestorage.js type: change rationale: Continue bounded normalization by consolidating repeated hash metadata object field population into a single local helper. impact: Reduces duplicated metadata field assembly and drift risk while preserving existing output shape and hash behavior. status: completed

Summary:

  • Added buildHashMetadataPaths({ containerName, casefolderID, blobname }) helper.
  • Replaced repeated per-object hash metadata assignment in:
    • getBlobs
    • getProgressBlobs
    • getRepsFilesBlobs
  • Preserved existing metadata contracts:
    • keys unchanged: hashedfilepath, hasheddeletepath, hashgetblobs
    • same encoded query path inputs and route semantics.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Any further azurestorage.js cleanup should remain bounded (e.g., logging-only normalization) and separated from behavior-affecting refactors.

CL-083: TASK22269 Slice B1.8 — phase22 azurestorage helper contract coverage

date: 2026-03-26 author: Cline scope: tests/phase22/{azurestorage-helper-behaviour,index}.test.cjs type: change rationale: Execute the selected bounded test-only follow-up by adding focused regression coverage for recently added azurestorage helper contracts. impact: Improves confidence in query-path and hash-metadata helper output stability without changing runtime behavior. status: completed

Summary:

  • Added new phase22 suite: tests/phase22/azurestorage-helper-behaviour.test.cjs.
  • Test suite isolates helper block from actions/azurestorage.js and verifies:
    • buildDownloadBlobQueryPath default encoding output
    • buildDeleteBlobQueryPath non-encoded option behavior
    • buildGetBlobListQueryPath query output contract
    • buildHashMetadataPaths key/value shape (hashedfilepath, hasheddeletepath, hashgetblobs)
  • Wired suite into aggregate runner tests/phase22/index.test.cjs.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass (includes new azurestorage-helper 4/4)
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: add an explicit assertion for encoded casefolderID variants containing reserved query characters (?, &) if those inputs are expected in future flows.

CL-084: TASK22269 Slice B1.9 — azurestorage local split-value tidy in touched helper consumers

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the selected next bounded readability-only slice by reducing repeated blob.name.split("/") access in the recently touched helper-consumer functions. impact: Non-behavioral maintainability improvement in azurestorage helper-consumer paths; no API/route contract changes. status: completed

Summary:

  • In targeted functions (getBlobs, getProgressBlobs, getRepsFilesBlobs), introduced local path-part variables to avoid repeated inline splitting:
    • blobPathParts
    • fileName / appealBlobName / repFileName
    • casefolderPath
  • Replaced repeated field reads and helper arguments with these locals in object construction and hash metadata composition.
  • Preserved existing query composition and output shape/keys (including hashed path metadata fields).

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: logging-only normalization in these same azurestorage functions (no behavior change), done separately from structural refactors.

CL-085: TASK22269 Slice B1.10 — azurestorage touched-function logging normalization

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the next bounded, logging-only slice by normalizing selected touched-function logs to consoleLogger for consistency with current helper/error logging style. impact: Observability consistency improvement only; no API/route behavior or payload contract changes. status: completed

Summary:

  • In previously touched helper-consumer functions only:
    • getProgressBlobs
    • getRepsFilesBlobs
  • Replaced selected direct console.log(...) calls with consoleLogger(...):
    • progress blob path-parts trace
    • per-blob name trace in reps file listing
    • final blobObj trace in reps file listing
  • Scope intentionally excludes broader file-wide logging normalization to keep risk bounded.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: prune currently-unused local blobDocumentType variables in the same touched functions (readability-only, no behavior change).

CL-086: TASK22269 Slice B1.11 — azurestorage touched-function unused-local prune

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the next bounded readability-only slice by removing now-unused local variables left in recently touched helper-consumer functions. impact: Maintainability/readability improvement only; no API/route behavior changes. status: completed

Summary:

  • Removed unused local blobDocumentType declarations from:
    • getBlobs
    • getRepsFilesBlobs
  • No object shape, query generation, hash metadata logic, or routing behavior changed.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: align remaining low-risk direct console.log calls in these functions to consoleLogger only where already touched and safe.

CL-087: TASK22269 Slice B1.12 — azurestorage touched-function path assembly helper reuse

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the next bounded maintainability slice by reusing existing local query-path helpers for touched filepath/deletepath assembly, reducing repeated literal concatenation. impact: Readability/consistency improvement only; preserves query parameter values and route behavior. status: completed

Summary:

  • In touched functions:
    • getBlobs
    • getRepsFilesBlobs
  • Replaced inline filepath string concatenation with buildDownloadBlobQueryPath(...).
  • Replaced inline deletepath string concatenation with buildDeleteBlobQueryPath(...).
  • Preserved previous encoding behavior where required by passing explicit options:
    • kept non-encoded casefolderID/blobname behavior in getRepsFilesBlobs.deletepath via helper options.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: targeted helper-consumer tidy in the same functions for any remaining repeated query-path literals outside touched object fields.

CL-088: TASK22269 Slice B1.13 — azurestorage touched-function caseObj helper reuse

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the next bounded readability slice by centralizing repeated case-object path composition in touched helper-consumer functions. impact: Maintainability/readability improvement only; no route/query behavior changes. status: completed

Summary:

  • Added local helper buildCaseObjectPath(casefolderID).
  • Replaced repeated caseObj string assembly in touched functions:
    • getBlobs
    • getProgressBlobs
  • Preserved existing caseObj output format (<caseRef>/<caseRef>_case.json).

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: continue tiny helper reuse in touched functions only if any duplicated path literals remain and can be reduced without behavior change.

CL-089: TASK22269 Slice B1.14 — azurestorage touched-function contentLength local reuse

date: 2026-03-26 author: Cline scope: actions/azurestorage.js type: change rationale: Execute the next tiny bounded readability slice by reusing local contentLength values in touched helper-consumer functions to reduce repeated property access and keep object assembly consistent. impact: Maintainability/readability improvement only; no route/query/output behavior changes. status: completed

Summary:

  • In touched functions:
    • getBlobs
    • getProgressBlobs
    • getRepsFilesBlobs
  • Added local contentLength variable (blob.properties.contentLength) per loop iteration.
  • Replaced repeated inline blob.properties.contentLength assignments in object assembly with the local variable.
  • Preserved field contracts (contentLength, size) and values.

Validation:

  • npm run lint -> pass with warnings only (pre-existing react-hooks/exhaustive-deps; no new lint errors)
  • node tests/phase22/index.test.cjs -> pass
  • node tests/phase7/service-behaviour.test.cjs -> pass (13/13)

Follow-ups:

  • Optional next bounded slice: stop or switch scope; touched-function micro-tidies in this area are now largely exhausted.

CL-090: uploadsinglefile API batch upload chunking (10 files per pass)

date: 2026-04-02 author: Cline scope: pages/api/file/uploadsinglefile.js type: change rationale: Prevent oversized single-pass uploads by splitting validated files into bounded batches and invoking existing upload logic per batch. impact: Upload flow now processes validated files in deterministic chunks of 10 while preserving existing hash guards, validation behavior, and response contract (data, invalidFiles). status: completed

Summary:

  • Added MAX_FILES_PER_UPLOAD_BATCH = 10 in uploadsinglefile API route.
  • Replaced single uploadSingleFile(...) invocation with chunked processing:
    • converts allowed files object to entries
    • slices into batches of 10
    • awaits uploadSingleFile(...) once per batch
    • aggregates batch results into one data array for response
  • Kept existing error handling unchanged (UPLOAD_SINGLE_FILE_FAILED on catch).

Validation:

  • npx eslint pages/api/file/uploadsinglefile.js -> executed with no lint output.

Follow-ups:

  • Optional: add a focused API contract/unit test to assert that 11+ files cause multiple uploadSingleFile invocations with max chunk size 10.

CL-091: uploadsinglefile client-side batch upload chunking parity (10 files per pass)

date: 2026-04-02 author: Cline scope: actions/services/documentDirectService.js type: change rationale: Ensure client upload flow aligns with server batching requirement by splitting outbound uploadsinglefile requests into chunks of 10 files. impact: Client now sends multiple sequential API requests (max 10 files each) and merges per-chunk responses into one contract-compatible payload (data, invalidFiles) for existing UI handlers. status: completed

Summary:

  • Added MAX_FILES_PER_UPLOAD_BATCH = 10 to document direct service.
  • Updated uploadSingleFile(filesObj, containerID, casefolderID) to:
    • split selected files into batches of 10
    • create a fresh FormData per batch
    • call /api/file/uploadsinglefile once per batch (sequential await)
    • aggregate data and invalidFiles from all chunk responses
  • Preserved function return shape used by current upload UIs.

Validation:

  • npx eslint pages/api/file/uploadsinglefile.js actions/services/documentDirectService.js -> executed with no lint output.

Follow-ups:

  • Optional: add a focused service-behaviour test that verifies uploadSingleFile issues N requests for N/10 chunks and merges all chunk responses.

CL-092: per-chunk upload UI progress updates (new appeal + representations)

date: 2026-04-02 author: Cline scope: actions/services/documentDirectService.js, components/elements/index.js, components/case/representation/representationElements.js type: change rationale: Update UX so upload progress reflects completed chunks incrementally instead of waiting for all chunk requests to finish. impact: Upload status message now updates after each chunk completes, showing users progressive completion for large multi-file uploads while preserving existing response/error contracts. status: completed

Summary:

  • Extended uploadSingleFile(...) service signature with optional callback support:
    • new options argument
    • invokes options.onChunkComplete(...) after each chunk upload
    • emits cumulative counters (cumulativeUploaded, cumulativeInvalid, processedFiles, chunk index metadata)
  • Wired per-chunk UI progress updates in both upload entry points:
    • components/elements/index.js
    • components/case/representation/representationElements.js
  • Both now pass onChunkComplete and update uploadCountMessage from cumulative uploaded count as each chunk finishes.

Validation:

  • npx eslint pages/api/file/uploadsinglefile.js actions/services/documentDirectService.js components/elements/index.js components/case/representation/representationElements.js -> executed with no lint output.

Follow-ups:

  • Optional: add a focused UI behaviour test to assert upload progress increments per completed chunk for >10 file uploads.

CL-093: upload progress message format X of Y during chunked uploads

date: 2026-04-02 author: Cline scope: components/elements/index.js, components/case/representation/representationElements.js type: change rationale: User requested clearer in-progress feedback showing uploaded count relative to total files (e.g. 10 of 30) during chunked uploads. impact: Upload UI now shows progressive message in X of Y format while upload is in flight, improving clarity for large batch uploads. status: completed

Summary:

  • Added totalUploadFiles state in both upload UIs (new appeal + representations).
  • In-progress upload message now renders as:
    • ${uploadCountMessage} of ${totalUploadFiles}
  • Upload start now initializes as 0 of Y and updates after each completed chunk callback.
  • Empty-drop/reset path clears both counters to avoid stale totals.

Validation:

  • npx eslint actions/services/documentDirectService.js components/elements/index.js components/case/representation/representationElements.js -> executed with no lint output.

Follow-ups:

  • Optional: localize a dedicated upload-progress-x-of-y translation key if copy needs stronger grammatical control per locale.

CL-094: 22500 components/elements/index.js Phase 2 bounded cleanup (remove dead renderField)

date: 2026-04-07 author: Cline scope: components/elements/index.js type: change rationale: Execute the next smallest low-risk Phase 2 slice by removing the local renderField utility after confirming it is unused in the repo. impact: No behavior change intended; dead code removal only. No auth/security/middleware/API changes. EN/CY and accessibility behavior remain unchanged. status: completed

Summary:

  • Confirmed renderField had no usages outside its declaration.
  • Removed the unused local renderField function from components/elements/index.js.
  • Kept all field component exports, routing, and existing render paths unchanged.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue Phase 2 with one bounded no-behavior-change slice, likely next lowest-risk renderer extraction from components/elements/index.js.

CL-095: 22500 components/elements/index.js hook-order hotfix (MultiLinefield)

date: 2026-04-07 author: Cline scope: components/elements/index.js type: change rationale: Fix runtime React warning caused by conditional hook execution path in MultiLinefield after dead-code cleanup. impact: No functional behavior change intended; resolves Rules of Hooks ordering warning by making label translation hook usage unconditional per render. status: completed

Summary:

  • Root cause: FieldsTranslations(props.label) (which internally uses useRouter) was invoked within conditional render branches in MultiLinefield, causing hook order mismatch when branch conditions changed.
  • Fix: precomputed translatedLabel once in MultiLinefield render body and reused in both branches.
  • Kept EN/CY text resolution logic and rendered output unchanged.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue bounded Phase 2 slices; when touching field components, prefer top-level computed hook-backed values reused across conditional branches.

CL-096: 22500 RenderSubFields render-phase update warning hotfix

date: 2026-04-07 author: Cline scope: components/elements/fields/renderSubFields.js type: change rationale: Fix React warning about updating parent-connected state during RenderSubFields render. impact: No intended behavior change; initial empty FieldArray row initialization moved out of render phase to effect phase to satisfy React rendering constraints. status: completed

Summary:

  • Root cause: fields.length == 0 && fields.push({}) executed inside render, triggering state updates while rendering RenderSubFields.
  • Fix: moved initial row insertion into useEffect, guarded by fields.length === 0.
  • Preserved existing UX intent: ensure at least one subfield row appears when array starts empty.

Validation:

  • npx eslint components/elements/fields/renderSubFields.js -> pass

Follow-ups:

  • Keep redux-form fields.push/remove calls event/effect-driven (not render-driven) in future slices.

CL-097: 22500 FieldArrayForm render-phase dispatch warning hotfix

date: 2026-04-07 author: Cline scope: components/elements/index.js type: change rationale: Fix React warning caused by dispatching redux-form state updates during FieldArrayForm render. impact: No intended behavior change; clearing hidden FieldArray values remains intact but now executes in effect phase instead of render phase. status: completed

Summary:

  • Root cause: dispatch(change("appealForm", name, null)) was called inline in render when parent condition was false.
  • Fix: moved that dispatch into useEffect guarded by !showIfHasParentShowValue.
  • Added useEffect import in components/elements/index.js.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue avoiding dispatch/state mutations inside render for field visibility toggles.

CL-098: 22500 FieldArrayForm bounded dead-code cleanup

date: 2026-04-07 author: Cline scope: components/elements/index.js type: change rationale: Continue bounded Phase 2 cleanup with a lowest-risk slice by removing unused locals/destructured props in FieldArrayForm. impact: No intended behavior change; purely removes unused values left from legacy implementation. status: completed

Summary:

  • Removed unused destructured props from FieldArrayForm: label, validation, maxFieldLength.
  • Removed no-op/dead lines in FieldArrayForm:
    • redundant boolean expression line
    • unused parentFieldShowOnValue; expression
    • unused handleSubmit/pristine/reset/submitting destructure
  • Kept visibility logic, effect-driven clearing behavior, and FieldArray rendering path unchanged.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue Phase 2 with one bounded slice at a time; next low-risk target can be similar dead-code/no-op cleanup in another isolated renderer block.

CL-099: 22500 components/elements/index.js bounded extraction bundle (RenderFileUpload + FieldArrayForm)

date: 2026-04-07 author: Cline scope: components/elements/index.js, components/elements/fields/renderFileUpload.js, components/elements/fields/fieldArrayForm.js type: change rationale: Execute a slightly larger but still bounded Phase 2 slice by extracting two self-contained blocks from the monolith (RenderFileUpload and FieldArrayForm) into dedicated field modules. impact: No intended behavior change; preserves EN/CY output, upload flow, and accessibility semantics while reducing index.js size/coupling. status: completed

Summary:

  • Added components/elements/fields/renderFileUpload.js and moved the full existing RenderFileUpload implementation unchanged.
  • Added components/elements/fields/fieldArrayForm.js and moved the full existing FieldArrayForm implementation unchanged.
  • Updated components/elements/index.js imports to consume extracted modules.
  • Removed inline RenderFileUpload/FieldArrayForm implementations and related now-unused imports/constants from index.js.

Validation:

  • npx eslint components/elements/index.js components/elements/fields/renderFileUpload.js components/elements/fields/fieldArrayForm.js -> pass

Follow-ups:

  • Continue Phase 2 with bounded renderer/module extractions from components/elements/index.js (one cohesive bundle per commit).

CL-100: 22500 components/elements/index.js helper normalization (validation messages + visibility checks)

date: 2026-04-07 author: Cline scope: components/elements/index.js type: change rationale: Apply the requested next bounded refactor slice by consolidating repeated validation message setup and parent-field visibility logic into shared local helpers. impact: No intended behavior change; EN/CY and accessibility behavior preserved while reducing repeated logic and future drift risk. status: completed

Summary:

  • Added getValidationMessages(t) helper for repeated required/emoji/postcode message retrieval.
  • Added visibility helpers:
    • hasParentFieldValue(...)
    • isVisibleByEquality(...)
    • isVisibleByInclusion(...)
  • Replaced repeated inline visibility and validation-message setup across field wrappers with helper usage (Textfield, MultiLinefield, RichMultiLinefield, DateFieldPicker, YesNofield, Radiofield, NumericField, DecimalField).
  • Kept existing field render paths, conditions, and validation calls intact.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue bounded no-behavior-change slices by removing dead locals/comments and extracting one additional low-risk field wrapper at a time.

CL-101: 22500 PickList wrapper extraction from components/elements/index.js

date: 2026-04-08 author: Cline scope: components/elements/index.js, components/elements/fields/pickListField.js type: change rationale: Execute one bounded Phase 2 renderer/wrapper extraction slice by moving the PickList wrapper out of the elements monolith into a dedicated field module. impact: No intended behavior change; preserves existing EN/CY translation behavior and validation wiring while reducing index.js size/coupling. status: completed

Summary:

  • Added components/elements/fields/pickListField.js and moved the existing PickList wrapper implementation.
  • Updated components/elements/index.js to import/export PickList from the new field module.
  • Removed inline PickList wrapper implementation from index.js.
  • Removed now-unused RenderPickList import from index.js after extraction.

Validation:

  • npx eslint components/elements/index.js components/elements/fields/pickListField.js -> pass

Follow-ups:

  • Continue bounded no-behavior-change slices by extracting one additional low-risk wrapper (e.g., CheckBoxfield) or removing dead locals/debug logging in place.

CL-102: 22500 components/elements/index.js dead/debug-only cleanup slice

date: 2026-04-08 author: Cline scope: components/elements/index.js type: change rationale: Execute requested bounded cleanup slice by removing dead code and debug-only artifacts from the elements monolith without changing behavior. impact: No intended behavior change; EN/CY and accessibility behavior preserved while reducing noise and unused code paths. status: completed

Summary:

  • Removed debug-only runtime log in CheckBoxfield (console.log(props)).
  • Removed unused/dead locals and helpers inside components/elements/index.js, including:
    • top-level unused imports (axios, pickListLookup, setFileCount action import, redux hooks import)
    • unused local validators and helpers in wrappers (e.g., unused required/postcode/normalizeDecimal variants)
    • unused placeholder constant RenderCaseID
    • unused local fallbacks in FileUploadField (uploadCount, local setFileCount)
  • Kept functional field wiring, labels/translations, and validation behavior in active render paths unchanged.

Validation:

  • npx eslint components/elements/index.js -> pass

Follow-ups:

  • Continue bounded no-behavior-change slices only (e.g., extract one additional low-risk wrapper such as CheckBoxfield).

CL-103: 22500 wrapper extraction bundle (CheckBoxfield, DateFieldPicker, YesNofield)

date: 2026-04-08 author: Cline scope: components/elements/index.js, components/elements/fields/{checkBoxField,dateFieldPicker,yesNoField}.js type: change rationale: Execute the requested bundled wrapper slice by extracting wrappers 1/2/3 in one commit while keeping behavior unchanged. impact: No intended behavior change; keeps EN/CY output, visibility logic, and accessibility structure intact while reducing components/elements/index.js size. status: completed

Summary:

  • Added components/elements/fields/checkBoxField.js and moved CheckBoxfield wrapper.
  • Added components/elements/fields/dateFieldPicker.js and moved DateFieldPicker wrapper logic.
  • Added components/elements/fields/yesNoField.js and moved YesNofield wrapper logic.
  • Updated components/elements/index.js to import/export these wrappers from field modules.
  • Removed inline implementations of CheckBoxfield, DateFieldPicker, and YesNofield from index.js.

Validation:

  • npx eslint components/elements/index.js components/elements/fields/checkBoxField.js components/elements/fields/dateFieldPicker.js components/elements/fields/yesNoField.js -> pass

Follow-ups:

  • Remaining wrappers can continue as bounded slices (Radiofield, NumericField, DecimalField) if required.

CL-104: 22500 wrapper extraction bundle (Radiofield, NumericField, DecimalField)

date: 2026-04-08 author: Cline scope: components/elements/index.js, components/elements/fields/{radioField,numericField,decimalField}.js type: change rationale: Continue Phase 2 with the next bounded wrapper bundle by extracting wrappers 4/5/6 from components/elements/index.js into dedicated field modules without behavior change. impact: No intended behavior change; preserves EN/CY behavior, validation wiring, and accessibility semantics while reducing monolith size. status: completed

Summary:

  • Added components/elements/fields/radioField.js for Radiofield.
  • Added components/elements/fields/numericField.js for NumericField.
  • Added components/elements/fields/decimalField.js for DecimalField.
  • Updated components/elements/index.js to import/export these wrappers from field modules.
  • Removed inline Radiofield, NumericField, and DecimalField implementations from index.js.

Validation:

  • npx eslint components/elements/index.js components/elements/fields/radioField.js components/elements/fields/numericField.js components/elements/fields/decimalField.js -> pass

Follow-ups:

  • Next bounded wrappers (if needed): ReadOnlyfield/remaining small wrappers or additional dead-code cleanup slices.