337 KiB
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-API-GROUPING-FACADE-SEARCH-VERTICAL-SLICE: active public search results grouping and service adoption
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.mdcontext/api-grouping-adoption-roadmap.mdcontext/api-route-map.mdcontext/journey-architecture-map.mdcontext/architecture.mdmemory-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].jsandpages/myportal/case/[ticketnumber].jsstill bootstrap primarily through the Public Search family usinggetBasicSearch(...)andgetSearchDetails(...)pages/case/id/[incident].jsandpages/myportal/case/id/[incident].jsactively use the case-specific incident-id read route throughgetIncidentbyID(...)getCaseMessage(...)is actively used in case-page loading for banner/message contentgetLinkedCases(...)is actively used insidecomponents/case/summary.jsas a case-details read concerngetSIPSEvents(...)andgetSIPSMedia(...)are active case-page enrichments for relevant SIPS casescomponents/case/documents.jsand document metadata routes remain part of the documents slice, not this case-details slicegetcase_api.js,getcasebyid_api.js, andgetportalmoduledetails_api.jsare 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.jsget-case-message.jsget-linked-cases.jsget-sips-events.jsget-sips-media.js
- Implemented each façade as the smallest safe compatibility wrapper:
- import the existing legacy endpoint handler
- delegate
reqandresdirectly to that existing handler
- Updated only the existing owning service call sites needed for the bounded slice:
actions/services/caseDirectService.jsgetIncidentbyIDgetCaseMessagegetSIPSEventsgetSIPSMedia
actions/services/searchDirectService.jsgetLinkedCases
- 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.mdnode 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.mdcontext/api-grouping-adoption-roadmap.mdcontext/api-route-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdmemory-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.cjsnode tests/phase22/api-grouping-facade-rollout.test.cjsnode tests/phase22/api-grouping-facade-subscriptions.test.cjsnode tests/phase22/api-grouping-facade-documents.test.cjsnode 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.mdcontext/api-grouping-adoption-roadmap.mdcontext/api-route-map.mdcontext/journey-architecture-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdmemory-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.jsandcomponents/search/searchresults.js - the advanced results page
pages/advancedsearchresults.jsis part of the active public-search scope - the common owning service layer is
actions/services/searchDirectService.js components/search/searchresults.jsactively uses:getBasicSearchPagedgetAdvancedSearchPagedgetSearchDetailsPaged(...), which in turn usesgetBasicSearchDetailsPaged
pages/advancedsearchresults.jsactively usesgetAdvancedSearch(...)for bootstrapgetbasicsearch_api.jsandgetbasicsearchdetails_api.jsremain 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
- the active public results UI is driven through
- Added grouped façade routes under
pages/api/search/for the proven active public-results path only:basic-paged.jsadvanced.jsadvanced-paged.jsbasic-details-paged.js
- Implemented each façade as the smallest safe compatibility wrapper:
- import the existing legacy endpoint handler
- delegate
reqandresdirectly to that existing handler
- Updated only the suitable common service layer in
actions/services/searchDirectService.jsto target grouped façade routes for:getBasicSearchPagedgetAdvancedSearchgetAdvancedSearchPagedgetBasicSearchDetailsPaged
- 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.cjsnode 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.mdcontext/api-grouping-adoption-roadmap.mdcontext/journey-architecture-map.mdcontext/api-route-map.mdcontext/architecture.mdmemory-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_hashlinkvalues that continue to point at the unchanged grouped download route getsearchdocumenthistory_api.jsandgetsearchdocumenthistorypaged_api.jsremain present but were not surfaced in the currently active UI journey and therefore remained outside grouped adoption scope
- active document metadata retrieval is surfaced through
- Added grouped façade routes under
pages/api/documents/for the active metadata journey only:get-search-document-details.jsget-search-document-details-paged.jsget-search-document-types.js
- Implemented each façade as the smallest safe compatibility wrapper:
- import the existing legacy endpoint handler
- delegate
reqandresdirectly to that existing handler
- Updated only the suitable common service layer in
actions/services/searchDirectService.jsto target grouped façade routes for:getSearchDocumentDetailsgetSearchDocumentDetailsPagedgetSearchDocumentTypes
- 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.mdnode 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 journeydeletewatchedcasesproxy_apiremains 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.jssogetWatchedCasesProxynow 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.jsnode 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.mdcontext/api-grouping-adoption-roadmap.mdcontext/api-route-map.mdmemory-bank/change-log.md
- Updated only the watched-case methods in
actions/services/portalDirectService.jsto target grouped façade routes:getWatchedCases->/api/subscriptions/get-watched-casescreateWatchedCases->/api/subscriptions/create-watched-casedeleteWatchedCases->/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.mdnode 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.mdcontext/api-grouping-adoption-roadmap.mdcontext/api-route-map.mdcontext/journey-architecture-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdmemory-bank/change-log.md
- Added the first grouped façade routes under
pages/api/subscriptions/:get-watched-cases.jscreate-watched-case.jsdelete-watched-case.js
- Implemented each façade as the smallest safe compatibility wrapper:
- import the existing watched-case endpoint handler
- delegate
reqandresdirectly to that existing handler
- Preserved the existing canonical watched-case routes unchanged:
pages/api/endpoint/getwatchedcases_api.jspages/api/endpoint/createwatchedcases_api.jspages/api/endpoint/deletewatchedcases_api.js
- Did not change frontend call sites;
actions/services/portalDirectService.jscontinues 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.cjsnode 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.mdcontext/api-route-map.mdcontext/journey-architecture-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-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.mdcontext/journey-architecture-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-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/apilisting 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
CL-2026-06-22-JOURNEY-ARCHITECTURE-MAP-SLICE-8: case-messages-notices and related-published-case-communications lifecycle map
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.mdcontext/api-route-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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) messagesObjis passed as page propsCaseNoticeBannerrenders active banner-style notices on the case-details tab
- case loader retrieves
- 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, andpages/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
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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
- metadata-generated
- 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, andpages/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
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/portal-api-security-boundary-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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, andpages/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
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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)/myportalor/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.jsand supporting data routes
- thin direct Notify sends via
- 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, andpages/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
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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
- registration bridges
- 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, andstore - direct review of homepage bootstrap, registration page/components, personal-details page/components, account service helpers, account endpoint handlers, and relevant auth support routes
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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
- representation drafts are more tightly case-linked and
Validation:
- Documentation-only work; no runtime code changed.
- Non-destructive evidence gathering only:
- targeted searches across
pages,lib,actions/services,pages/api, andstore - direct review of representation loaders, representation completion component, storage routes, queue/completion routes, and representation-specific Redux state
- targeted searches across
- 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.mdcontext/api-route-map.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Extended
context/journey-architecture-map.mdwith 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, andstore - direct review of draft/resume loaders, Redux hydration helpers, new appeal flow components, storage helpers, finalisation handlers, and adjacent CRM mutation routes
- targeted searches across
- 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.mdcontext/portal-api-security-boundary-assessment.mdcontext/integration-map.mdmemory-bank/debt-list.mdmemory-bank/change-log.md
- Assessed only the requested first slice folders:
pages/api/endpointpages/api/filepages/api/emailpages/api/documentspages/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/respondErrorresponse 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
- small directory listings of sampled API folders and
- 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 ofpages/api/endpointto 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.mdcontext/portal-api-security-boundary-assessment.mdcontext/architecture.mdmemory-bank/change-log.md
- Assessed only a bounded representative subset inside
pages/api/endpointacross 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
- newer helper-oriented read routes using
- 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.nextLinknormalization- 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.jsgetbasicsearchpaged_api.jsgetadvancedsearch_api.jsgetsearchdocumentdetails_api.jsgetsearchdocumenthistory_api.jsgetmycases_api.jsgetmyrepresentations_api.jsgetwatchedcases_api.jsgetawaitingsubmission_api.jsgetpersonalaccount_api.jscreatecase_api.jscreateaccount_api.jscreatewatchedcases_api.jsupdateaccount_api.jspatchcase_api.jsdeletewatchedcases_api.jsdeletemyrepresentations_api.jsgetwatchedcasesproxy_api.js
- targeted endpoint-only searches for helper/direct-wrapper indicators:
relayGet(...)relayGetData(...)axios(...)hashAPIPath(...)respondSuccess(...)/respondError(...)transformData@odata.nextLink- common status-code patterns
- direct inspection of representative endpoint routes including:
- 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 representativepages/api/endpointroutes that use transforms,@odata.nextLinknormalization, paged/unpaged variants, and supplementaryrelayGetData(...)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.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/debt-list.mdmemory-bank/change-log.md
- Built a bounded maintenance map for the top-level API areas:
endpointfileemaildocumentsauthadminmiddleware- 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 + hashAPIPathpatterns.
Validation:
- Documentation-only assessment; no runtime code changed.
- Non-destructive evidence gathering only:
- small top-level listings of
pages/apiandpages/api/admin - direct representative inspection of:
pages/api/admin/getnewappeals_api.jspages/api/admin/getlatestdocuments_api.jspages/api/health.jspages/api/doc.tspages/api/notices/index.jspages/api/middleware/{apiResponse,relayForwarding,relayPolicyPresets,middleware}.jsactions/azurestorage.jsactions/clients/signedRequestClient.js
- targeted searches across
pages/apifor existing helper and integration-building-block usage - reuse of already completed bounded evidence from Slices A and B for folder/feature classification
- small top-level listings of
- 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.mdcontext/architecture.mdcontext/integration-map.mdmemory-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, andstorefor the four sampled journeys - direct representative inspection of:
components/myportal/viewall.jspages/account/personaldetails.jscomponents/account/personaldetails.jscomponents/search/searchresults.jslib/myportal/loadMyPortalAppealPage.jscomponents/case/representation/representationComplete.js
- reuse of already reviewed route/service evidence from prior slices for linked API ownership and helper classification
- targeted bounded searches across
- 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.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
- Performed bounded top-level API folder sizing and validation:
endpoint-> 74 filesfile-> 26 filesemail-> 6 filesdocuments-> 1 fileauth-> 2 filesadmin-> 5 filesmiddleware-> 4 files- top-level files -> 4
- Confirmed that the earlier API platform model still appears representative:
endpointremains the dominant historical CRM relay catch-allfileremains 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
- low drift:
- Identified main maintenance hotspots:
- high:
endpoint,file - medium-high:
auth,middleware - medium:
email - low/medium-low:
documents,admin
- high:
- Recorded a high-confidence conclusion that Slices A–D 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, andpages/api/file - direct representative inspection of selected wider-surface outlier routes:
pages/api/endpoint/getmandatoryfields_api.jspages/api/endpoint/createcrmtask_api.jspages/api/file/createcaseinvolvement_api.jspages/api/file/generateappealpdf.jspages/api/email/getdocuments.jspages/api/admin/getStatusCountsByAppealAndLPA_api.js
- comparison against the documented conclusions from Slices A–D
- 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 A–E 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 A–E 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.mdcontext/architecture.mdmemory-bank/change-log.md
- Added a final synthesis section to
context/portal-api-platform-assessment.mdand 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
endpointandfile - smaller folders are more coherent but still require sensitivity in
authandmiddleware
- highest drift/hotspots remain
- 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.mdso 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 A–E.
- 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.mdcontext/architecture.mdcontext/integration-map.mdmemory-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:
relayGetrelayGetDatarespondSuccessrespondError- 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
- deeper
- 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.mdas a concise first-pass assessment ofpages/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
- recursive listing of
- Lint/tests not run because no implementation files were changed.
Follow-ups:
- Next assessment pass: trace
gethash_apiconsumers 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.mdwith 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
pinsUsercookie 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.jslib/representation/pageLoaders.jslib/newappeal/loadNewAppealPage.jslib/myportal/loadMyPortalAppealPage.jspages/myportal/index.jspages/myportal/case/[ticketnumber].jspages/myportal/representation.jsactions/services/{accountDirectService,portalDirectService,documentDirectService}.jspages/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
pinsUsercookie and compare it against thegetPortalLogin(session.user.email)path to determine which identity source is canonical and where divergence risk exists.
CL-2026-06-19-PORTAL-API-PINSUSER-TRACE: cookie identity provenance and comparison with CRM contact resolution
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
pinsUsertrace covering:- cookie contents
- creation source
- overwrite/refresh behavior
- clear/delete paths
- consumption across SSR and client flows
- Determined that
pinsUserstores a CRMcontactidvalue. - Identified the primary creation path in
pages/index.js:NextAuth session->session.user.email->getPortalLogin(email)-> CRMcontactid->setCookie("pinsUser", contactid)
- Identified that later flows frequently consume
pinsUserdirectly without re-resolving CRM contact from the current session. - Recorded the architectural conclusion that
pinsUserbehaves 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.idremains 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.jspages/account/personaldetails.jscomponents/search/searchresults.jscomponents/search/addresssearchresults.jslib/auth/sessionClient.jslib/auth/resolveMyPortalAuthContext.jslib/newappeal/loadNewAppealPage.jslib/myportal/loadMyPortalAppealPage.jspages/error.jspages/_error.jspages/componentssearch results forpinsUser,setCookie,destroyCookie, andparseCookies
- 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.mdwith 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/contactidto a session-derived CRM contact
- Confirmed that the reviewed personal-details UI does not allow direct email editing because
emailaddress1is rendered disabled, but also recorded thatupdateaccount_api.jsforwards 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 writespinswg_custom_passwordthroughupdateaccount_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.jspages/account/changepassword.jscomponents/account/{personaldetails,personaldetailsCheck,personaldetailsComplete,changepassword}.jscomponents/myportal/youraccount.jspages/index.jspages/myportal/index.jsactions/services/accountDirectService.jspages/api/endpoint/{getpersonalaccount_api,updateaccount_api,updatepassword_api,getemailaccountcheck_api,getportallogin_api}.jsstore/accountDetails/{action,reducer}.js
- Additional targeted searches performed for
setLoggedInUserId,setAccountDetails,updatePassword,pinswg_custom_password, andupdatepassword_apiusage. - 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.mdwith 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}.jspages/api/file/{createcaseinvolvement_api,createrepinvolvement_api,createappealcompletemessage_api,createrepcompletemessage_api,createcase_api,updatecase_api}.jsactions/services/{portalDirectService,caseDirectService}.jscomponents/{case/summary,myportal/viewall,newappeal/createCase,newappeal/buildsection,case/representation/representationComplete}.jslib/newappeal/journeyEffects.js
- Additional targeted searches performed across
pages/api,actions/services,components, andlibfor 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_apiand 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.mdwith 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:
watchedCaseIDoriginates 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.jsactions/clients/relayClient.jsactions/clients/signedRequestClient.jsactions/services/portalDirectService.jspages/api/endpoint/deletewatchedcases_api.jscomponents/myportal/topthree.jscomponents/myportal/viewall.jscomponents/case/summary.jscomponents/search/searchresults.js
- Additional targeted searches performed for
gethash_api,buildHashedQueryUrl,buildSignedUrl,deleteWatchedCases,watchedCaseID, andpinswg_watchlistidacrossactions,components, andpages/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_apiand 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.mdwith 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.idas the container identity for draft reads and store hydration. - Confirmed many file/blob APIs accept
container/containerIDas 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.jslib/myportal/loadMyPortalAppealPage.jslib/representation/pageLoaders.jsactions/services/documentDirectService.jsactions/azurestorage.jspages/api/file/{getprogressobjblob,getbloblist,getawaitingsubmissionfromblob,upload,uploadsinglefile,deleteblobcase,deleteblobrep,downloadblob,setupcontainer,createappealcompletemessage_api,createrepcompletemessage_api,editRepJson}.js
- Additional searches performed across
lib,pages,actions, andpages/api/fileforsession.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.mdtitled 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
pinsUserlifecycle 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.mdwith a dedicated Programme status section stating:Portal API Security & Access Boundary AssessmentStatus: 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.mdto 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.mdbefore adding stream close-out language. - Reviewed
context/architecture.mdand 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.jscomponents/account/registerform.jscomponents/account/registerCheck.jscomponents/account/registerComplete.jsactions/services/accountDirectService.createAccountpages/api/endpoint/createaccount_api.js
- Determined that registration uses the authenticated session email as the intended identity source:
loggedInUserEmailcomes fromgetServerSideProps- form
emailaddress1is 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
contactsviacreateaccount_api, withpinswg_typeofinvolvementset 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-runsgetPortalLogin(session.user.email), finds the newly created contact, setspinsUser, 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.jspages/account/register.jscomponents/account/registerform.jscomponents/account/registerCheck.jscomponents/account/registerComplete.jsactions/services/accountDirectService.jspages/api/endpoint/createaccount_api.jspages/api/endpoint/getemailaccountcheck_api.jspages/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)
- CRM
- Recorded that
pinswg_casestageis 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.mdwith business stakeholders. - Do not broaden representation-policy boundaries further until validation outcomes are agreed.
CL-22541: breadcrumb/back-link route-state helper extraction (va/adv/ads/key)
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.jswith:normalizeRouteStateQuery(query)resolveSearchResultsHref(options)
- Updated
components/breadcrumbs.jsto 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.
- breadcrumb href resolution (
- Updated
components/case/summary.jsto replace localbuildSearchHrefwith 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.cjsand registered it intests/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 incomponents/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) withReferenceError: resolveLocale is not definedinpages/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.jswith:resolveSearchBreadcrumbLabel(...)isDnsRoutePath(pathname)
- Updated
components/breadcrumbs.jsto useresolveSearchBreadcrumbLabel(...)and removed inline label decision IIFE. - Updated
components/case/summary.jsto useisDnsRoutePath(router.pathname)and removed inline DNS path checks. - Expanded
tests/phase22/route-state-helper.test.cjswith 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 incomponents/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.jsinto 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(...)inlib/routing/routeState.jsto return:breadcrumbHrefcaseResultsHrefbreadcrumbLabel
- Updated
components/breadcrumbs.jsto replace three separate helper invocations with one resolver call. - Extended
tests/phase22/route-state-helper.test.cjswith 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 incomponents/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.
newappealparent-title crumb,cyMyPortalHrefaccount 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 incomponents/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.
CL-22541-F: breadcrumbs multi-pattern helper bundle (text + link crumbs)
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 preserverouter.back()behavior. - Combined with existing
renderMyPortalCrumbandrenderCaseReferenceCrumbhelpers 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.
CL-22541-G: breadcrumbs inline Link-crumb consolidation bundle
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.
CL-22541-H: breadcrumbs anchor/back-link helper consolidation bundle
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)incomponents/breadcrumbs.jsfor repeated<a ...>breadcrumb actions. - Replaced repeated anchor/back-link crumb blocks in:
/myportal/searchresultsmy-portal anchor crumb/newappeal/[appealtypes]and/myportal/[appealtypes]step-back crumbs/myportal/representationback-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 optionalrenderBackCrumb(...)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 torenderAnchorCrumb(...)with existing back-link text. - Replaced remaining one-off inline edge crumbs in:
/newappeal/[appealtypes]and/myportal/[appealtypes](currentSection === 9999service-name link and back-link branch)/casesearch-results link crumb (including existingrouter.back()callback)/myportal/representationback-link branches now userenderBackCrumb(...).
- Preserved existing href targets, callback behavior, and class semantics (including special
govuk-breadcrumbs__link-itemusage).
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)incomponents/breadcrumbs.jsto 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)incomponents/breadcrumbs.jsfor 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)incomponents/breadcrumbs.jsfor 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]withrouter.back()). - Added focused phase22 suite
tests/phase22/breadcrumbs-route-map-structure.test.cjsasserting:- 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)incomponents/breadcrumbs.jsand 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.cjsto 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]withrouter.back()). - Expanded
tests/phase22/breadcrumbs-route-map-structure.test.cjsguardrails 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:simpleRouteRenderersByPathsimpleLinkTextPairRenderersByPathsimpleMyPortalRouteRenderersByPath
- 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.jspure 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.jsto import/use shared helper logic:- map composition now via
buildBreadcrumbRendererMaps(...) - resolver now delegates to
resolveMappedRouteRendererByMaps(...) - dynamic/callback-sensitive explicit branches remain unchanged.
- map composition now via
- Added focused pure-helper tests in
tests/phase22/breadcrumb-route-maps-helper.test.cjsfor:- map build order
- map lookup null/renderer behavior
- resolver precedence behavior
- Expanded
tests/phase22/breadcrumbs-route-map-structure.test.cjsto 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.cjsto 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.jsinto module-level pure factories (still injected witht/router/currentView) to further shrink component body. - Next slice option B (smaller): add one focused parity test asserting mapped resolver fallback returns
nullin 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(...)inlib/routing/breadcrumbRendererFactories.jsto compose and return all deterministic mapped renderer groups in one place:simpleRouteRenderersByPathsimpleLinkTextPairRenderersByPathsimpleMyPortalRouteRenderersByPathcaseDetailRouteRenderersByPathdetailAndAccountRouteRenderersByPath
- Updated
components/breadcrumbs.jsto consumecreateMappedRouteRendererGroups(...)and remove local per-group factory composition boilerplate while preserving existing map precedence and resolver flow. - Expanded
tests/phase22/breadcrumbs-route-map-structure.test.cjsto assert:- grouped renderer maps are composed via
createMappedRouteRendererGroups(...) - mapped rendering path explicitly preserves null fallback (
routeRenderer ? routeRenderer() : null)
- grouped renderer maps are composed via
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(...)inlib/routing/breadcrumbRendererFactories.jsto map:/myportal/case/case/id/[incident]
- Injected additional deterministic inputs required by these routes:
currentReferencenestedSearchString
- Updated
createMappedRouteRendererGroups(...)wiring to pass the new inputs to case-detail factory composition. - Updated
components/breadcrumbs.jsto passnestedSearchStringinto grouped factory composition. - Removed now-redundant inline
isPath(...)branches for:/myportal/case/case/id/[incident]
- Expanded
tests/phase22/breadcrumbs-route-map-structure.test.cjsto assert:- both new routes are mapped in
createCaseDetailRouteRenderers - both inline branches are absent from
components/breadcrumbs.js
- both new routes are mapped in
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(...)inlib/routing/breadcrumbRendererFactories.js. - Mapped
/newappeal/selectappealinto the new grouped renderer factory. - Extended grouped composition return from
createMappedRouteRendererGroups(...)withnewAppealRouteRenderersByPath. - Updated
lib/routing/breadcrumbRouteMaps.jsto includenewAppealRouteRenderersByPathin explicit map precedence ordering. - Updated
components/breadcrumbs.jsto consume/passnewAppealRouteRenderersByPathinto 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
/casebranch 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
nullwhen map is missing/non-object - returns
nullwhen mapped value is not a function
- returns
- 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.
- invalid map entries (
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(...)inlib/routing/breadcrumbRendererFactories.jsto map:/myportal/case/id/[incident]/case
- Introduced explicit callback injection (
onBack) into grouped factory composition and route renderers, preservingrouter.back()behavior via injected callback. - Extended
createMappedRouteRendererGroups(...)return withcallbackRouteRenderersByPath. - Updated map builder in
lib/routing/breadcrumbRouteMaps.jsto 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]")andisPath("/case")branches.
- pass
- 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(...)inlib/routing/breadcrumbRendererFactories.jsto 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-itemfor new-appeal flow)
- no crumb when
- Introduced explicit injected handlers (
onStepBack,onStepBackWithInlineClass) and injected crumb renderer dependency (renderBackCrumb) into grouped factory composition. - Extended map builder in
lib/routing/breadcrumbRouteMaps.jswithstepBackRouteRenderersByPathand updated precedence order:- simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> case detail -> detail/account.
- Updated
components/breadcrumbs.js:- pass
currentSectionand step-back callbacks intocreateMappedRouteRendererGroups(...) - include step-back map in
buildBreadcrumbRendererMaps(...) - remove inline
isPath("/newappeal/[appealtypes]")andisPath("/myportal/[appealtypes]")branches.
- pass
- 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/representationback-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
nullfor:- empty path (
"") - whitespace-only path (
" ") - trailing/leading whitespace variants (
"/known "," /known") - case-variant non-exact key (
"/KNOWN")
- empty path (
- 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/representationcallback/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(...)inlib/routing/breadcrumbRendererFactories.jsmapping:/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))
- submit/back from confirmation (
- Introduced explicit injected state/callback dependencies into grouped composition:
currentView,hasRepDetails,repDetails,showQuestionnaireSectiononRepresentationSubmitBackFromConfirmationonRepresentationSubmitBackToDetailsonRepresentationQuestionnaireBack
- Extended
buildBreadcrumbRendererMaps(...)inlib/routing/breadcrumbRouteMaps.jswithrepresentationRouteRenderersByPathand 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
representationRouteRenderersByPathin map builder call - remove inline
isPath("/myportal/representation")branch block.
- pass representation state/callback injections into
- 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
/newappealedge 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-006tomemory-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
/newappealinline 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
representationRouteRenderersByPathresolves/myportal/representationtonull - later maps still resolve correctly (case detail fallback remains intact).
- missing
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
/newappealinline 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") && <></>}
- deleted
- Added structure guard assertion that
/newappealinline 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:
- current architecture summary
- strengths
- risks (scalability, maintainability, coupling, weak boundaries, operational/deployment)
- prioritized recommendations
- low-risk next improvements
- Added explicit comparison notes vs existing
context/architecture.mdand 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.jsgetThumbnailIconByMimeTypegetDocumentTypePrefixvalidateUploadFilename
components/elements/helpers/translationHelpers.jsgetFieldTranslationgetPickListTranslation
- Updated
components/elements/index.jsto 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.mdwith 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.jsin 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.jscontaining the extractedRenderRichMultilinerenderer. - Updated
components/elements/index.jsto import the extracted renderer and removed the inline duplicate implementation. - Kept
RichMultiLinefieldusage 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.jsandcomponents/elements/fields/renderMultiline.js. - Updated
components/elements/index.jsto import the extracted renderers. - Removed inline
RenderTextfieldandRenderMultilineimplementations fromindex.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/respondSuccessusage. - Added explicit required-input guards:
DOCUMENT_ID_REQUIREDfor history/historypagedINCIDENT_ID_REQUIREDfor details/detailspaged/typesORDER_BY_REQUIRED,FIELD_SORT_REQUIRED,SHOW_NUMBER_OF_RECORDS_REQUIREDfor 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-existingreact-hooks/exhaustive-depswarnings; 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.jsto userespondSuccessandrespondErrorfrompages/api/middleware/apiResponse. - Removed legacy raw
res.status(...).json(...)/bare status assignment pattern and dead logging artifacts. - Added explicit catch-path contract:
TOKEN_FETCH_FAILEDwith 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-existingreact-hooks/exhaustive-depswarnings; 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):
b57f3desearch-document endpoint contracts + phase21 coverage9af541amy-portal retrieval endpoint contractsb880364basic search endpoint contractsa106deaDNS basic search endpoint contractsb5a3a62portal module + LPA case endpoint contracts4601d7ccase detail endpoint contracts2959c7ddelete/watched-case endpoint contractsb59f13ametadata + linked-case endpoint contractsbcf03a6form + publication endpoint contractse0e91c8DNS + representation endpoint contracts98e159dcase creation + media endpoint contracts88e4586advanced-search-paged endpoint contractcb69bbecase update + CRM task endpoint contracts722ef98hash + metadata endpoint contracts134f99caddress-search endpoint contract8b6ed73new-appeal appeal-types endpoint contracteec59e8token 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-existingreact-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
respondErrorwithDOWNLOAD_BLOB_FAILED - kept success behavior intact (attachment header + raw file body)
- removed dead internal helper (
streamToBuffer) and tightened local declarations
- added explicit catch-path response via
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.jsandgetappealtypesfornewappeal_api.js:- added method guard for non-GET requests using
METHOD_NOT_ALLOWED(405) - preserved existing GET success payloads
- added method guard for non-GET requests using
- Expanded phase21 tests:
file-handler-contract.test.cjs: added coverage for download failure + full generated PDF copy contract/negative pathsendpoint-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-existingreact-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
blobnameinput:- filename only (legacy)
- full prefixed path (already includes
casefolderID/...)
- prevents double-prefix lookup failures
- sets attachment filename from final path segment only
- accepts both forms of
- Hotfix 2 (
bd3bf68): hash compatibility validation- validates against a bounded set of canonical query-path variants (raw/encoded combinations for
casefolderIDandblobname) - fixes
INVALID_HASHfalse negatives for legitimate caller-generated links - keeps strict HMAC requirement in place (no unauthenticated bypass)
- validates against a bounded set of canonical query-path variants (raw/encoded combinations for
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, anddeleteblobrep.jsby aligning hash validation canonicalization and explicitrespondErrorcontracts (MISSING_REQUIRED_QUERY,INVALID_HASH, operation-specific*_FAILED). - Extend
tests/phase21/file-handler-contract.test.cjsfor 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
casefolderIDandblobname - normalized delete path handling for both filename-only and already-prefixed blob paths
- added explicit catch-path contract:
DELETE_BLOB_FAILED
- added bounded hash candidate validation for encoded/raw combinations of
deleteblobcase.js- added hash candidate validation for raw/encoded
casefolderID - added explicit catch-path contract:
DELETE_BLOB_CASE_FAILED
- added hash candidate validation for raw/encoded
deleteblobrep.js- added hash candidate validation for encoded/raw
casefolderID+repfile - added explicit catch-path contract:
DELETE_BLOB_REP_FAILED
- added hash candidate validation for encoded/raw
- 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)inactions/azurestorage.js:- fixed async misuse (
blobClient.getProperties().contentLengthwithout 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/undefinedname filtering intact
- fixed async misuse (
- Added phase21 contract coverage for
getrepsblobroute:- 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
findBlobsByTagsresults 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
getawaitingsubmissionfromblobhandler to structuredtry/catchflow. - Preserved existing guard behavior:
MISSING_REQUIRED_QUERYfor missing container/hashINVALID_HASHfor 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/.catchchain to explicittry/catch - encoded forwarded
containerandcasefolderIDquery values - preserved error contract:
GET_BLOB_LIST_PROXY_FAILED
- converted
getrepsblobproxy.js- converted
.then/.catchchain to explicittry/catch - encoded forwarded
container - preserved error contract:
GET_REPS_BLOB_PROXY_FAILED
- converted
getawaitingsubmissionfromblobproxy.js- converted
.then/.catchchain to explicittry/catch - preserved error contract:
GET_AWAITING_SUBMISSION_PROXY_FAILED
- converted
createappealcompletemessageproxy_api.js- converted
.then/.catchchain to explicittry/catch - encoded forwarded
containerandtempcaseref - preserved error contract:
CREATE_APPEAL_COMPLETE_MESSAGE_PROXY_FAILED
- converted
- 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
CryptoJSimport - refactored axios
.then/.catchto explicittry/catch - preserved conflict behavior: status 412 -> success
{ record: "exists" } - preserved failure contract:
CREATE_CASE_INVOLVEMENT_FAILED
- removed unused
createrepinvolvement_api.js- removed unused
CryptoJSimport - refactored axios
.then/.catchto explicittry/catch - preserved conflict behavior: status 412 -> success
{ record: "exists" } - preserved failure contract:
CREATE_REP_INVOLVEMENT_FAILED
- removed unused
updatecase_api.js- removed unused
CryptoJSimport - refactored axios
.then/.catchto explicittry/catch - preserved failure contract:
UPDATE_CASE_FAILED
- removed unused
- 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/.catchtotry/catch - preserved flattening behavior and error contract
MAILING_LIST_FETCH_FAILED
- converted axios
pages/api/email/getcaseref.js- converted axios
.then/.catchtotry/catch - preserved flattening behavior and error contract
CASE_REF_FETCH_FAILED
- converted axios
pages/api/email/notify.js- converted notify client
.then/.catchtotry/catch - preserved success payload and error contract
EMAIL_NOTIFY_FAILED
- converted notify client
pages/api/admin/getnewappeals_api.js- removed unused
CryptoJSimport - converted axios
.then/.catchtotry/catch - preserved
@odata.nextLinknormalization and error contractADMIN_NEW_APPEALS_FETCH_FAILED
- removed unused
pages/api/admin/getlatestdocuments_api.js- converted axios
.then/.catchtotry/catch - preserved flatten/enrich behavior and error contract
ADMIN_LATEST_DOCS_FETCH_FAILED
- converted axios
pages/api/endpoint/getportallogin_api.js- retained required query/hash guards
- expanded hash validation to accept raw + encoded
emailAddressquery-path candidates - preserved error contract
PORTAL_LOGIN_FETCH_FAILED
- phase21 endpoint tests expanded:
getportalloginencoded hash variant success pathgetnewappeals_apicatch contractgetlatestdocuments_apicatch 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(+ optionalpages/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
- converted mixed promise-chain flow to
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
- converted create/upload promise-chain to
- phase21 file tests expanded:
generatepdfcatch-path contract (GENERATE_PDF_FAILED)generateappealpdfcatch-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-forgetupdateAccount(...)with explicit async IIFE +try/catchandvoidinvocation - preserved non-blocking behavior and logging semantics for account-update failure path
- preserved primary route contracts and success payload (
{ status: "success" })
- replaced inline
- phase21 file contract tests expanded:
- success path for encoded hash candidate on
createappealcompletemessage_api - dependency-failure contract assertion for
CREATE_APPEAL_COMPLETE_MESSAGE_FAILED
- success path for encoded hash candidate on
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 directMyDocument(...)invocation inReactPDF.renderToStream(...)
- switched render call input from
pages/api/file/generateappealpdf.js- switched render call input from
React.createElement(MyDocument, ...)to directMyDocument(...)invocation inReactPDF.renderToStream(...)
- switched render call input from
tests/phase21/file-handler-contract.test.cjs- added
Bufferinjection forgeneratepdfcatch-path test harness to align VM context expectations
- added
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/renderernamed imports - removed unused imports (
middleware,nextConnect,fs) - removed unused locals (
casefolderID,representationType,repRaiser,localeSelect,repCapacity,repType)
- pruned unused Azure storage imports, leaving only
pages/api/file/generateappealpdf.js- pruned unused Azure storage imports to only required functions
- pruned unused
@react-pdf/renderernamed 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
idandhash - unified fallback redirect path via constant (
/filenotavailable) - preserved streaming download behavior and retry flow
- added explicit required-query guard for
- added
tests/phase21/documents-handler-contract.test.cjscovering:- 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/respondSuccessenvelope 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) }
- replaced:
- 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.logdiagnostics 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.jsgetrepresentationsproxy_api.jsgetawaitingsubmissionproxy_api.js(with existing payload transform preserved)
- Updated endpoint contract tests to mock
relayGetfor 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
relayGetto support optionalrequestOptionsBuilderfor handlers requiring paged header variants. - Migrated Batch 1 endpoints to
relayGet:getaccounts_api.jsgetemailaccountcheck_api.jsgetpreferredlanguage_api.jsgetlogin_api.js(usesazureHeadersPagedviarequestOptionsBuilder)getpersonalaccount_api.jsgetportalloginproxy_api.js(usesazureHeadersPagedviarequestOptionsBuilder)
- Updated phase21 endpoint contract tests to mock
relayGetfor 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.jsgetwatchedcases_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
relayGetin 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.nextLinknormalization)getcasebyid_api.js(preserved@odata.nextLinknormalization and array-wrapped success payload)getincidentbyid_api.jsgetsipsevents_api.js
- Updated phase21 endpoint contract tests to mock
relayGetfor 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.jsgetformdata_api.jsgetsearchdocumenthistory_api.js(usesrequestOptionsBuilderwithazureHeadersPaged)getsearchdocumenthistorypaged_api.js(usesrequestOptionsBuilderwithazureHeadersPaged)getportalmoduledetails_api.js
- Preserved all existing required-query validation guards and existing error codes/messages.
- Updated Phase 21 endpoint contract tests to inject
relayGetmocks 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-existingreact-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.jsgetsearchdocumentTypes_api.jsgetsearchdocumentdetails_api.jsgetsearchdocumentdetailspaged_api.jsgetappealpdfdocuments_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.nextLinknormalization where present- appeal PDF document name projection
- Updated phase21 endpoint tests to mock
relayGetfor 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-existingreact-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.jsgetbasicsearchdetails_api.jsgetbasicsearchdetailspaged_api.jsgetbasicdnssearchdetails_api.jsgetbasicdnssearchdetailspaged_api.js
- Preserved existing validation guards and error contracts.
- Preserved existing endpoint-specific transforms:
@odata.nextLinknormalization in paged responses- flattened ticketnumber enrichment for search detail handlers
- Updated phase21 endpoint contract tests to inject
relayGetmocks 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-existingreact-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.jsgetbasicdnssearchpaged_api.jsgetbasicpartsaveddetails_api.jsgetdnslist_api.js
- Preserved existing input validation guards and endpoint-specific error contracts.
- Preserved endpoint-specific transform behavior (
@odata.nextLinknormalization in DNS list/paged handlers). - Updated phase21 endpoint contract tests to inject
relayGetmocks 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-existingreact-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 callgetmylpacases_api: JSONPath LPA lookup withLPA_NOT_FOUNDhandling andpinswg_titleenrichment transform
- Updated phase21 endpoint contract tests to inject
relayGetmocks 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-existingreact-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.jsto sharedrelayGet. - Preserved existing guard behavior and error contracts:
SEARCH_STRING_REQUIREDORDER_BY_REQUIREDFIELD_SORT_REQUIREDSHOW_NUMBER_OF_RECORDS_REQUIREDINVALID_SEARCH_STRINGADVANCED_SEARCH_PAGED_FETCH_FAILED
- Preserved endpoint-specific transform behavior (
@odata.nextLinknormalization viatransformData). - Updated phase21 endpoint contract tests to inject
relayGetmocks forgetadvancedsearchpaged_apiguard/catch assertions.
Validation:
node tests/phase21/endpoint-handler-contract.test.cjs-> pass (152/152)npm run lint-> warnings only (pre-existingreact-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:
relayGetDatanow supports token reuse viatransformDatapath- Added
forwardGetDatato support custom base URLs (used by proxy-to-local endpoint) while preserving hash behavior
- Migrated remaining Batch 12 candidates:
getadvancedsearch_api.js->relayGet+relayGetDatafor project-type enrichment loopgetdnscoords_api.js->relayGetDatafor both DNS + SIPS source pullsgetbasicsearch_by_lparref_api.js->relayGetDatagetbasicsearch_by_address_api.js->relayGetDatafor appeal-type and incident fetchesdeletewatchedcasesproxy_api.js->forwardGetDatawithBASE_URLcreatewatchedcases_api.js->relayGetDatafor 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/forwardGetDatawhere appropriate.
Validation:
node tests/phase21/endpoint-handler-contract.test.cjs-> pass (152/152)npm run lint-> warnings only (pre-existingreact-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
forwardGetDatainrelayForwarding.jswith:- 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)
- configurable timeout (
- Added structured, redacted operational relay logs:
relay_request_retryingrelay_request_failed
- Preserved compatibility behaviors:
- existing token/header/hash handling
- optional
appendHashand customrequestOptionsBuilder - endpoint-level
relayGeterror 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-existingreact-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
- explicitly non-retryable statuses:
- 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
- timeout clamped to
- Reduced duplicate logging noise:
- non-retry terminal relay failures are marked as already logged in middleware
relayGetcatch now skipsconsoleLoggerwhen 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
- no retry on
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-existingreact-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.mdcovering:- 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_startedrelay_request_retryingrelay_request_succeededrelay_request_failed
- Added shared telemetry fields for correlation and analysis:
relayRequestId(per request correlation id)attemptsMade,retryCountUsed,remainingRetrieselapsedMsstatusClass(2xx/4xx/5xxstyle 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
relayRequestIdacross 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-existingreact-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
- per-call override of
- 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
- env flag
- retries allowed by default only for idempotent methods (
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Future non-GET relay adoption should explicitly opt in/out per route using
relayPolicyand 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
relayPolicyusage to a broader endpoint set:- account/login:
getaccounts,getemailaccountcheck,getpreferredlanguage,getpersonalaccount,getlogin - search:
getbasicsearch,getbasicsearchpaged,getadvancedsearch,getadvancedsearchpaged
- account/login:
- 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
- login endpoint (
- Kept method explicit as
GETin policy for clarity and future-proofing. - Extended phase21 endpoint tests with relayPolicy propagation assertions:
getaccountsrelayPolicy pass-throughgetloginstrict relayPolicy pass-throughgetbasicsearchpagedrelayPolicy 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-existingreact-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
relayPolicyfor 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-existingreact-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
relayPolicydeclarations to:getmycases_apigetmyrepresentations_apigetwatchedcases_apigetawaitingsubmission_apigetrepresentations_api
- Applied bounded read profile across the batch:
method: "GET"timeoutMs: 8000maxRetries: 2retryBaseDelayMs: 150retryMaxDelayMs: 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-existingreact-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.jsRELAY_POLICY_STRICT_LOGINRELAY_POLICY_LOOKUPRELAY_POLICY_BOUNDED_READRELAY_POLICY_SEARCH_PAGED
- Refactored 18 relayGet endpoints to import and use shared presets instead of inline
relayPolicyobject 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
- lookup profile:
- 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-existingreact-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.jsexportingbuildHashedQueryUrl
- Added
actions/clients/index.jsbarrel and exposed client exports viaactions/index.js. - Updated direct services to consume shared relay client helper instead of duplicating local helper implementations:
actions/services/accountDirectService.jsactions/services/portalDirectService.jsactions/services/documentDirectService.js
- Updated
actions/clients/README.mdto reflect the now-implemented relay client extraction and future incremental client split path.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)- Verified no remaining duplicated local
buildHashedQueryUrldefinitions acrossactions/services/*DirectService.js
Follow-ups:
- Optional next TASK22260 increment: extract common axios invocation helpers into dedicated clients (
endpointClient,fileClient,notifyClient) while keepingactions/index.jsAPI stable.
Addendum (same TASK22260 slice):
- Added shared
endpointClientwithgetJsonandrequestJsonhelpers (actions/clients/endpointClient.js) and exported it viaactions/clients/index.js. - Migrated additional direct services to consume shared endpoint client helpers:
actions/services/notifyDirectService.js(POST viarequestJson)actions/services/integrationDirectService.js(POST viarequestJson)actions/services/adminDirectService.js(GET flows viagetJson)
- Updated
actions/clients/README.mdto includeendpointClientin 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.jsfrom directaxios.get(...).then(res => res.data)patterns to sharedgetJson(...)helper fromactions/clients/endpointClient. - Preserved existing error behavior:
logAndReturnEmptyValueErrorResponsefor appeals/project/LPA fetchesconsoleLoggercatch handling for form/mandatory/picklist/notice fetches
- Updated
actions/clients/README.mdusage notes to include reference-data service reuse.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Next optional bounded slice: adopt
getJson/requestJsonfor selected low-risk read paths insearchDirectServiceorcaseDirectServicewhile 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.jsto consume shared endpoint client helpers:getJson(...)for GET requestsrequestJson(...)for config-based POST requests
- Kept existing relay hash-signing behavior unchanged via
buildHashedQueryUrlfromrelayClient. - Preserved existing catch-path semantics, including:
- logging with
consoleLogger - returning
JSON.stringify(error)in portal login functions - returning
error.responsein preferred-language failure path
- logging with
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: adopt endpoint client helpers in selected
portalDirectServiceGET/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
portalDirectServicefunctions to use shared endpoint client helpers:getJson(...)for read/listing routes (getMyCases,getMyInvolvements,getMyLPACases, representations, watched, awaiting submission variants)requestJson(...)forcreateWatchedCases
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: migrate remaining non-hash POST helpers in
portalDirectService(setRepInvolvment,setCaseInvolvment) torequestJsonfor 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:
setRepInvolvmentsetCaseInvolvment
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: begin selective
requestJsonadoption for remaining config-based calls indocumentDirectServicewhere 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
getJsonusage in selected document service helpers:getRepsFromBlobProxygetAwaitingSubmissionFromBlobProxygetFilesFromBlobproxygetFilesFromBlobHashedgetProgressFromBlobcreateContainerProxy
- Preserved existing behavior contracts:
- same query composition and hash query fragments
- same catch-path logging and return conventions (including JSON string return in
createContainerProxyerror path)
- Left hash-sensitive delete/upload/generation flows unchanged in this slice.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: migrate selected
requestJson-eligible upload/generation helpers indocumentDirectService(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.datatorequestJson(config):uploadFilesuploadSingleFileuploadRepFilesgenerateRepPDFgenerateAppealPDF
- 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
- hashed URL creation via
- Left delete/download/hash-sensitive GET helpers unchanged in this slice.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: evaluate remaining legacy direct
axios.get(...).then(res.data)helpers indocumentDirectService(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(...):getAwaitingSubmissionFromBlobgetRepsFromBlobgetFilesFromBlob
- 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
- same BASE_URL and hash query composition via
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: targeted hygiene in
documentDirectServiceto 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
getJsonusage in selectedcaseDirectServicehelper functions:getAppealPDFDocsgetPortalModuleDetailsgetPortalModuleDetailsProxy
- 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-existingreact-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)togetJsonwhere 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)togetJson(...):getCaseMessagegetIncidentbyIDgetIsPublishedbyIDgetPartSavedAppealgetSIPSEventsgetSIPSMedia
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: evaluate remaining GET helpers in
caseDirectServicewith 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)togetJson(...):getCasegetCaseByIDgetAppealPDFDocument
- Preserved behavior contracts:
- unchanged request URL/query construction
- unchanged catch semantics:
getCase/getCaseByIDstill log viaconsoleLoggergetAppealPDFDocumentstill logs and returnserror.responseon failure
- left non-targeted POST/update/create/patch flows unchanged.
Validation:
npm run lint-> warnings only (pre-existingreact-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 selectiverequestJson(...)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):createNewCasecreateNewCaseBlobupdateCaseupdateCaseBlob
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: assess
patchCaseandgetAppealIDfor 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(...):getAppealIDpatchCase
- Preserved behavior contracts:
getAppealIDstill extracts first non-underscore key value from returned entity and logs on failurepatchCasestill swallows failure (no explicit returned error contract introduced)
- Removed now-unused
axiosimport fromcaseDirectService.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: review other direct service modules for any remaining legacy
axiosimport 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):deleteAwaitingSubmissionssendCaseCompleteMessagesendCaseCompleteMessageProxysendRepCompleteMessage
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: assess whether signed-delete helpers in
portalDirectServiceshould 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:
- Portal signed-delete flow parity (
portalDirectService)- migrated signed delete helpers from direct
axios({...}).then(res.data)torequestJson({...}):deleteMyRepresentationsdeleteWatchedCases
- removed now-unused
axiosimport from module - preserved hash-signing flow and custom headers semantics
- migrated signed delete helpers from direct
- Search direct service axios reduction (
searchDirectService)- migrated service GET helpers from direct
axios.get(...).then(res.data)andaxios(config)togetJson(...) - preserved existing catch semantics (
logAndReturnResponse,logAndReturnEmptyValueErrorResponse, and explicit throw path ingetSearchDocumentDetails) - removed direct
axiosimport from module
- migrated service GET helpers from direct
- Portal signed-delete flow parity (
- Documentation alignment:
- retained architecture assessment section in
context/architecture.mdthat calls out these residual-risk slices and prioritisation.
- retained architecture assessment section in
Validation:
npm run lint-> warnings only (pre-existingreact-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)torequestJson({...}):deleteAwaitingSubmissionsFromBlobdeleteMyRepresentationsFromBlob
- Migrated delete helper GET calls from
axios.get(...).then(res.data)togetJson(...):deleteBlobdeleteRepBlob
- Preserved behavior contracts:
- unchanged query/hash composition and endpoint URLs
- unchanged catch-path logging with
consoleLogger
- Left
downloadBlobunchanged in this slice (special-case behavior path retained for separate focused handling).
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: isolate and correct
downloadBlobbehavior indocumentDirectService(including legacyresusage) 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)indocumentDirectService:- removed legacy direct
axios.get(...).then(response => res.status(...))pattern that referenced undefinedresin service layer - now returns blob response data via
requestJson({ method: "get", url, responseType: "blob" }) - preserved catch-path logging (
consoleLogger)
- removed legacy direct
- Removed now-unused module-level
axiosimport fromdocumentDirectService.
Validation:
npm run lint-> warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: add a focused test (or integration harness assertion) around
downloadBlobservice 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 toaxios.get(...).then(res.data) - added default
requestJson(...)mock delegating toaxios(config).then(res.data) - added default
buildHashedQueryUrl(...)mock resolving hash via/api/endpoint/gethash_apicompatibility path
- added default
- Updated notify behavior assertions to align with shared request client usage (
requestJsoninvokes axios config-style call):- switched notify test handlers from
axios.postHandlertoaxios.requestHandler - assertions now inspect
axios.calls[0].config.{url,method,data}
- switched notify test handlers from
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
loadServiceModuledefault context intests/phase6/service-behaviour.test.cjs:- added default
getJson(...)mock backed byaxios.get(...).then(res.data) - added default
requestJson(...)mock backed byaxios(config).then(res.data)
- added default
- 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.cjswith reusable:createAxiosMockcreateLoggerMockcreateAxiosErrorloadServiceModule(with defaultgetJson/requestJson/buildHashedQueryUrlinjections)normalize
- Refactored
tests/phase6/service-behaviour.test.cjsto import shared harness utilities and remove duplicated local harness implementation. - Refactored
tests/phase7/service-behaviour.test.cjsto 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-existingreact-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.cjsto 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
getTokeninactions/core/token.js:- replaced direct
axios.post(...).then(res => res.data)chain with sharedrequestJson({...}) - migrated function to
async/awaitwith equivalenttry/catchbehavior - retained existing semantics:
- successful token payload cached in
cache.tokenResponse - failures logged via
consoleLoggerand returned to caller
- successful token payload cached in
- replaced direct
- Removed direct
axiosdependency fromactions/core/token.jsin favor ofactions/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-existingreact-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:
getTokensuccess path returns token payload and callsrequestJsonwith expected URL/method/body/headers- failure path logs via
consoleLoggerand 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-existingreact-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.cjsto exportrunand addrequire.main === moduleguard. - 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: add a dedicated
tests/phase22/index.test.cjsaggregate 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.cjsaggregate runner. - Runner currently executes
core-token-behaviour.test.cjsand prints a phase-level completion line. - Exported
runand 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-existingreact-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.getJsonreturnsaxios.get(...).dataendpointClient.requestJsonreturnsaxios(config).datarelayClient.buildHashedQueryUrlappends browser hash-service response- server fallback path uses
hashAPIPathwhenHASHKEYis present - browser/no-HASHKEY failure path rethrows hash-service error
- Updated
tests/phase22/index.test.cjsto 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-existingreact-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
fileClientfromactions/clients/index.js(and therefore viaactions/index.jsbarrel path). - Migrated a bounded subset of
actions/services/documentDirectService.jscall sites tofileClientwhile preserving catch-path logging behavior:getFilesFromBlobproxy->getFileJsondeleteAwaitingSubmissionsFromBlob->getSignedFileJsondeleteMyRepresentationsFromBlob->getSignedFileJsondeleteBlob->getFileJsondeleteRepBlob->getFileJsondownloadBlob->downloadFileBlob
- Added
tests/phase22/file-client-behaviour.test.cjscovering:- delegation to
getJson - signed URL generation +
requestJsoninvocation - blob download config contract (
responseType: "blob")
- delegation to
- Updated aggregate runner
tests/phase22/index.test.cjsto 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: evaluate whether additional
documentDirectServicefile-route call sites can adoptfileClientwithout 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.cjsto inject file-client compatible helpers when not explicitly provided:getFileJson(delegates to defaultgetJson)getSignedFileJson(signs viabuildHashedQueryUrlthen callsrequestJsonwith GET config)downloadFileBlob(callsrequestJsonwith GET +responseType: "blob")
- This preserves existing VM import-stripping strategy while preventing
ReferenceErrorin 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next bounded slice: add a focused phase6/phase7 behavioural assertion for
documentDirectService.downloadBlobto explicitly lock thedownloadFileBlobdelegation 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:
downloadBloblower-cases container in URL composition- request is issued through config-style request path (
axios.requestin harness) - request method is
get responseTypeisblob- 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-existingreact-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 suite’s 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.jswith:postSignedFileJson(queryUrl, data, config = {})- signs query URL via
buildHashedQueryUrland executes POST viarequestJson
- Migrated all remaining signed POST helper paths in
actions/services/documentDirectService.jstopostSignedFileJson:uploadFilesuploadSingleFileuploadRepFilesgenerateRepPDFgenerateAppealPDF
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next widened slice: evaluate consolidating remaining direct
getJsonfile-read flows indocumentDirectServicebehindfileClientfor 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
endpointClientusage fromdocumentDirectServicefor file reads. - Migrated remaining file-read/helper routes from
getJsontogetFileJson:getAwaitingSubmissionFromBlobgetRepsFromBlobgetRepsFromBlobProxygetAwaitingSubmissionFromBlobProxygetFilesFromBlobgetFilesFromBlobHashedgetProgressFromBlobcreateContainerProxy
- Removed now-unused imports from
documentDirectService:buildHashedQueryUrlgetJsonrequestJson
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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next widened slice: introduce a small
fileClientURL-builder helper set for repeated query-string composition indocumentDirectService(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.jsto 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.cjsfor new helper symbols:buildFileQuerywithBaseUrlappendQuerySuffix
- Expanded phase22 utility coverage in
tests/phase22/client-utils-behaviour.test.cjswith 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next widened slice: evaluate applying
fileRouteBuilderto 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.jsto use shared route helpers:buildFileQuerywithBaseUrlappendQuerySuffix
- 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)
- read/list endpoints (
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next widened slice: apply the same query-normalization helpers in
caseDirectServiceand add dedicated phase22 behavioral assertions forportalDirectServiceroute-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.jsto usefileRouteBuilderhelpers:buildFileQuerywithBaseUrl
- 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)
- case retrieval/search flows (
- Preserved existing contracts:
- BASE_URL usage patterns where previously applied
- method/payload semantics for
requestJsonpaths - catch-path logging and return behavior (
logAndReturnResponse,consoleLogger,error.responsepaths)
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)
Follow-ups:
- Optional next widened slice: add a focused phase22 behavioral suite for
caseDirectServiceand 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.cjswith focused behavioural assertions for:getPortalModuleDetailsBASE_URL + encoded case reference compositiongetPortalModuleDetailsProxyapostrophe escape behavior in case referencegetAppealIDquery composition and non-underscore value extractiongetAppealPDFDocumentfailure-path logging +error.responsepassthrough
- Updated
tests/phase22/index.test.cjsaggregate runner to includecase-service-behavioursuite.
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-existingreact-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
portalDirectServicewrite 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(...):createWatchedCasessetRepInvolvmentsetCaseInvolvment
- Added new phase22 suite
tests/phase22/portal-service-behaviour.test.cjscovering:- 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
sendRepCompleteMessagewhen hash-signing fails
- signed hash suffix append path in
- Updated
tests/phase22/index.test.cjsaggregate runner to includeportal-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-existingreact-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
- validates locale resolution precedence (
- 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
- asserts presence of required CY rewrite aliases for auth/policy routes in
- Updated
tests/phase22/index.test.cjsto 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-existingreact-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:
deleteWatchedCasesinactions/services/portalDirectService.js- from inline
buildHashedQueryUrl(...).then(requestJson(...))todeleteSignedJson(queryUrl) - preserved existing catch/log behavior (
consoleLogger+undefinedreturn on catch)
- Added test harness compatibility for VM import-stripping suites:
tests/serviceHarness.cjsnow injects defaultdeleteSignedJsonmock behavior.
- Expanded portal behavioral tests with explicit negative-path assertion:
tests/phase22/portal-service-behaviour.test.cjs- verifies
deleteWatchedCaseslogs and safely returnsundefinedwhen signed delete fails.
Validation:
npm run lint-> pass with warnings only (pre-existingreact-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
deleteMyRepresentationsfrom inlinebuildHashedQueryUrl(...).then(requestJson(...))to shareddeleteSignedJson(queryUrl, { headers }). - Preserved behavior-critical headers exactly:
OData-MaxVersionOData-VersionAcceptPreferContent-Type
- Preserved existing catch/log behavior (
consoleLoggerwith safe undefined return on failure).
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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 + requestJsonlogic in:getSignedFileJson-> now delegates togetSignedJsonpostSignedFileJson-> now delegates topostSignedJson
- retained
downloadFileBlobandgetFileJsonbehavior unchanged.
- replaced direct
- Updated
tests/phase22/file-client-behaviour.test.cjsto assert delegation contracts forgetSignedJsonandpostSignedJsonrather than direct signing internals.
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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 insendCaseCompleteMessage) 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
- added
- Migrated account signed GET candidate:
accountDirectService.getPortalLoginnow usesgetSignedJson(queryUrl, { baseUrl: BASE_URL })- preserved existing error semantics (
consoleLogger+JSON.stringify(error))
- Migrated portal signed GET candidates:
portalDirectService.sendRepCompleteMessagenow usesbuildSignedUrl(hashQueryPath)portalDirectService.sendCaseCompleteMessagenow usesbuildSignedUrl(hashQueryPath)+ existing signed suffix append behavior- preserved existing request method/URL shape and catch-path behavior
- Updated test harness and suites:
tests/serviceHarness.cjsnow provides defaults forbuildSignedUrl,getSignedJson,postSignedJsontests/phase22/portal-service-behaviour.test.cjsincludes assertion forsendRepCompleteMessagesigned-helper delegationtests/phase7/service-behaviour.test.cjsaccount portal-login expectations aligned to request-config path used by shared signed helper
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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 sharedbuildSignedUrl), 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)tofileRouteBuilder. - Migrated document service deterministic hash-suffix paths to new helper:
getAwaitingSubmissionFromBlobgetRepsFromBlobgetFilesFromBlobgetProgressFromBlobcreateContainerProxy
- Updated shared VM harness defaults (
tests/serviceHarness.cjs) to injectappendHashSuffix. - 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-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode tests/phase7/service-behaviour.test.cjs-> pass (13/13)
Follow-ups:
- Remaining non-service candidate for this stream is
actions/azurestorage.jsdirecthashAPIPathmetadata 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:
getBlobsgetProgressBlobsgetRepsFilesBlobs
- Preserved existing behavior semantics for hash path construction:
- encoded
casefolderID/blobnamewhere previously encoded - unchanged
containerNameandcasefolderIDvalue sourcing - unchanged returned object field names and shape
- encoded
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode tests/phase7/service-behaviour.test.cjs-> pass (13/13)
Follow-ups:
- Remaining potential cleanups in
actions/azurestorage.jsare 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:
getBlobsgetProgressBlobsgetRepsFilesBlobs
- Preserved existing metadata contracts:
- keys unchanged:
hashedfilepath,hasheddeletepath,hashgetblobs - same encoded query path inputs and route semantics.
- keys unchanged:
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode tests/phase7/service-behaviour.test.cjs-> pass (13/13)
Follow-ups:
- Any further
azurestorage.jscleanup 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.jsand verifies:buildDownloadBlobQueryPathdefault encoding outputbuildDeleteBlobQueryPathnon-encoded option behaviorbuildGetBlobListQueryPathquery output contractbuildHashMetadataPathskey/value shape (hashedfilepath,hasheddeletepath,hashgetblobs)
- Wired suite into aggregate runner
tests/phase22/index.test.cjs.
Validation:
npm run lint-> pass with warnings only (pre-existingreact-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
casefolderIDvariants 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:blobPathPartsfileName/appealBlobName/repFileNamecasefolderPath
- 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-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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:
getProgressBlobsgetRepsFilesBlobs
- Replaced selected direct
console.log(...)calls withconsoleLogger(...):- progress blob path-parts trace
- per-blob name trace in reps file listing
- final
blobObjtrace 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-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode tests/phase7/service-behaviour.test.cjs-> pass (13/13)
Follow-ups:
- Optional next bounded slice: prune currently-unused local
blobDocumentTypevariables 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
blobDocumentTypedeclarations from:getBlobsgetRepsFilesBlobs
- No object shape, query generation, hash metadata logic, or routing behavior changed.
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode tests/phase7/service-behaviour.test.cjs-> pass (13/13)
Follow-ups:
- Optional next bounded slice: align remaining low-risk direct
console.logcalls in these functions toconsoleLoggeronly 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:
getBlobsgetRepsFilesBlobs
- Replaced inline
filepathstring concatenation withbuildDownloadBlobQueryPath(...). - Replaced inline
deletepathstring concatenation withbuildDeleteBlobQueryPath(...). - Preserved previous encoding behavior where required by passing explicit options:
- kept non-encoded
casefolderID/blobnamebehavior ingetRepsFilesBlobs.deletepathvia helper options.
- kept non-encoded
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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
caseObjstring assembly in touched functions:getBlobsgetProgressBlobs
- Preserved existing
caseObjoutput format (<caseRef>/<caseRef>_case.json).
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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:
getBlobsgetProgressBlobsgetRepsFilesBlobs
- Added local
contentLengthvariable (blob.properties.contentLength) per loop iteration. - Replaced repeated inline
blob.properties.contentLengthassignments in object assembly with the local variable. - Preserved field contracts (
contentLength,size) and values.
Validation:
npm run lint-> pass with warnings only (pre-existingreact-hooks/exhaustive-deps; no new lint errors)node tests/phase22/index.test.cjs-> passnode 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 = 10inuploadsinglefileAPI 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
dataarray for response
- Kept existing error handling unchanged (
UPLOAD_SINGLE_FILE_FAILEDon 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
uploadSingleFileinvocations 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 = 10to document direct service. - Updated
uploadSingleFile(filesObj, containerID, casefolderID)to:- split selected files into batches of 10
- create a fresh
FormDataper batch - call
/api/file/uploadsinglefileonce per batch (sequentialawait) - aggregate
dataandinvalidFilesfrom 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
uploadSingleFileissues 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
optionsargument - invokes
options.onChunkComplete(...)after each chunk upload - emits cumulative counters (
cumulativeUploaded,cumulativeInvalid,processedFiles, chunk index metadata)
- new
- Wired per-chunk UI progress updates in both upload entry points:
components/elements/index.jscomponents/case/representation/representationElements.js
- Both now pass
onChunkCompleteand updateuploadCountMessagefrom 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
totalUploadFilesstate in both upload UIs (new appeal + representations). - In-progress upload message now renders as:
${uploadCountMessage} of ${totalUploadFiles}
- Upload start now initializes as
0 of Yand 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-ytranslation 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
renderFieldhad no usages outside its declaration. - Removed the unused local
renderFieldfunction fromcomponents/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 usesuseRouter) was invoked within conditional render branches inMultiLinefield, causing hook order mismatch when branch conditions changed. - Fix: precomputed
translatedLabelonce inMultiLinefieldrender 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 renderingRenderSubFields. - Fix: moved initial row insertion into
useEffect, guarded byfields.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/removecalls 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
useEffectguarded by!showIfHasParentShowValue. - Added
useEffectimport incomponents/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/submittingdestructure
- Kept visibility logic, effect-driven clearing behavior, and
FieldArrayrendering 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.jsand moved the full existingRenderFileUploadimplementation unchanged. - Added
components/elements/fields/fieldArrayForm.jsand moved the full existingFieldArrayFormimplementation unchanged. - Updated
components/elements/index.jsimports to consume extracted modules. - Removed inline
RenderFileUpload/FieldArrayFormimplementations and related now-unused imports/constants fromindex.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 repeatedrequired/emoji/postcodemessage 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.jsand moved the existingPickListwrapper implementation. - Updated
components/elements/index.jsto import/exportPickListfrom the new field module. - Removed inline
PickListwrapper implementation fromindex.js. - Removed now-unused
RenderPickListimport fromindex.jsafter 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,setFileCountaction import, redux hooks import) - unused local validators and helpers in wrappers (e.g., unused
required/postcode/normalizeDecimalvariants) - unused placeholder constant
RenderCaseID - unused local fallbacks in
FileUploadField(uploadCount, localsetFileCount)
- top-level unused imports (
- 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.jsand movedCheckBoxfieldwrapper. - Added
components/elements/fields/dateFieldPicker.jsand movedDateFieldPickerwrapper logic. - Added
components/elements/fields/yesNoField.jsand movedYesNofieldwrapper logic. - Updated
components/elements/index.jsto import/export these wrappers from field modules. - Removed inline implementations of
CheckBoxfield,DateFieldPicker, andYesNofieldfromindex.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.jsforRadiofield. - Added
components/elements/fields/numericField.jsforNumericField. - Added
components/elements/fields/decimalField.jsforDecimalField. - Updated
components/elements/index.jsto import/export these wrappers from field modules. - Removed inline
Radiofield,NumericField, andDecimalFieldimplementations fromindex.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.